I'm having trouble getting a Lambda function written using the AWS Annotations Framework to accept input parameters. This is the article I'm using: https://aws.amazon.com/blogs/developer/introducing-net-annotations-lambda-framework-preview/, but it only goes so far. When I publish the functions to Amazon and test clicking the TEST button, the input parameters aren't populated.
This is my function:
[LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
[LambdaFunction()]
[HttpApi(LambdaHttpMethod.Get, "/add/{x}/{y}")]
public int Add(int x, int y, ILambdaContext context)
{
context.Logger.LogInformation($"{x} plus {y} is {x + y}");
return x + y;
}
and this is the Event JSON within the AWS test harness
The log shows that the parameters have no value:
2022-05-09T10:47:02.435Z 51291252-f7cb-4a1e-9f4a-f7aebdec6b02 info 0
plus 0 is 0
I'm using this as an example, I don't actually need a calculator, but I do need to pass input parameters from an Amazon Connect contact flow and I will be passing in parameters like this:
I've spent a few days Googling and reading articles, but so far I've not found anything that helps, so any assistance is gratefully received!
Using the HttpApi attribute exposes the Lambda function as a REST API called via some http client. Amazon Connect invokes your Lambda function directly using its own event object documented here https://docs.aws.amazon.com/connect/latest/adminguide/connect-lambda-functions.html#function-contact-flow. In .NET the event object is represented as the Amazon.Lambda.ConnectEvents.ContactFlowEvent type from the Amazon.Lambda.ConnectEvents NuGet package.
Currently the Amazon.Lambda.Annotations has support for breaking up the HTTP API event object to follow typical .NET REST patterns. We haven't done that for other types of event sources like Connect, although this is something we want to do.
You can still use Amazon.Lambda.Annotations for your use case to get the dependency injection and syncing CloudFormation template features by using just the LambdaFunction attribute and then having your function take in the Connect event object. Something like this.
[LambdaFunction()]
public IDictionary<string, string> ProcessConnectContactFlow(Amazon.Lambda.ConnectEvents.ContactFlowEvent contactFlowEvent)
{
// Process the event
var response = new Dictionary<string, string>()
{
{ "Name", "CustomerName" },
{ "Address", "1234 Main Road" },
{ "CallerType", "Patient" }
};
return response;
}
Related
I'm using AWS firehose with an S3 backup and an S3 destination bucket, and it works great. The problem arises when I try to transform the data with a Lambda function.
I'm using the .NET AWS SDK, my Lambda function is written in C# and is using the included firehose transform example:
[assembly:LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.JsonSerializer))]
namespace LambdaFunctions
{
public class Function
{
public KinesisFirehoseResponse FunctionHandler(KinesisFirehoseEvent evnt, ILambdaContext context)
{
context.Logger.LogLine($"InvocationId: {evnt.InvocationId}");
context.Logger.LogLine($"DeliveryStreamArn: {evnt.DeliveryStreamArn}");
context.Logger.LogLine($"Region: {evnt.Region}");
KinesisFirehoseResponse response = new KinesisFirehoseResponse
{
Records = new List<KinesisFirehoseResponse.FirehoseRecord>()
};
foreach (KinesisFirehoseEvent.FirehoseRecord record in evnt.Records)
{
context.Logger.LogLine($"\tRecordId: {record.RecordId}");
context.Logger.LogLine($"\t\tApproximateArrivalEpoch: {record.ApproximateArrivalEpoch}");
context.Logger.LogLine($"\t\tApproximateArrivalTimestamp: {record.ApproximateArrivalTimestamp}");
context.Logger.LogLine($"\t\tData: {record.DecodeData()}");
// Transform data: For example ToUpper the data
KinesisFirehoseResponse.FirehoseRecord transformedRecord = new KinesisFirehoseResponse.FirehoseRecord
{
RecordId = record.RecordId,
Result = KinesisFirehoseResponse.TRANSFORMED_STATE_OK
};
transformedRecord.EncodeData(record.DecodeData().ToUpperInvariant());
response.Records.Add(transformedRecord);
}
return response;
}
}
}
The data is successfully & correctly processed by the transform Lambda function (as indicated by tests & logs).
However, the data is not successfully returned by the Lambda function to the S3 destination bucket, all of the records are unsuccessfully processed.
This error is returned for each record:
{
"attemptsMade": 1,
"arrivalTimestamp": 1590656820209,
"errorCode": "Lambda.MissingRecordId",
"errorMessage": "One or more record Ids were not returned. Ensure that the Lambda function returns all received record Ids.",
"attemptEndingTimestamp": 1590656883464,
"rawData": "dGVzdDE=",
"lambdaArn": "arn:aws:lambda:Region:AccountNumber:function:transform-function:$LATEST"
}
I'm at a loss as to why or where this error is occurring. I know the Lambda function is returning the correct response, recordId included.
I've recreated all the resources, applied and re-applied permissions, done just about everything I can think of.
This issue doesn't happen when using the Node.js or Python versions, it seems to be unique to the .NET implementation.
EDIT:
I forgot to add the serializer assembly attribute to the original code block which ended up being the source of the issue.
The C# example provided by AWS is out of date, specifically this serialization package:
Amazon.Lambda.Serialization.SystemTextJson
To solve this issue, simply replace the package with this one:
Amazon.Lambda.Serialization.Json
and update the assembly attribute like so:
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]
namespace LambdaFunctions
{
...
This serialization package is mentioned in the AWS Documentation here, under "Serializing Lambda functions".
However, Amazon have not yet updated the SDK examples to reflect this change (or at least, this example specifically), causing the function to fail when deployed.
I've made a bot using BotFramework, and I want to have an azure function triggered every 5 minutes (for example). And when it's triggered my bot must be notified.
But I have no idea how to do this, I read this https://docs.botframework.com/en-us/azure-bot-service/templates/proactive/ but the thing is he didn't use a Timmer Trigger Azure Function but a Queue Trigger.
I tryed to do something like that :
using System;
using System.Net;
using System.Net.Http;
using Microsoft.Azure.WebJobs.Host;
public class BotMessage
{
public string Source { get; set; }
public string Message { get; set; }
}
public static HttpResponseMessage Run(TimerInfo myTimer,out BotMessage message ,TraceWriter log)
{
message = new BotMessage()
{
Source = "AzureFunction",
Message = "Testing"
};
return new HttpResponseMessage(HttpStatusCode.OK);
}
but i have this error :
2017-03-02T14:49:40.460 Microsoft.Azure.WebJobs.Host: Error indexing method 'Functions.TimerTriggerCSharp1'. Microsoft.Azure.WebJobs.Host: Cannot bind parameter 'message' to type BotMessage&. Make sure the parameter Type is supported by the binding. If you're using binding extensions (e.g. ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. config.UseServiceBus(), config.UseTimers(), etc.).
Plus, to indicate which bot has to be notified where the event is triggered is added a output with the direct line key :
but as u can see there is the same error than above ...
Does someone have some docs or example for that.
Thank you for reading me.
Your binding configuration is set to use the return value of your function (also, in this case, that doesn't match any of the types supported by the binding)
You have a couple of options:
Uncheck the box to use the return value of of your function and name the parameter message
Or
Change the return type of your function to BotMessage return the message instance from your Run method and remove the out BotMessage message parameter.
Either option should fix this problem.
I'm having problem with MassTransit in Request-Respond model (using MassTransit.RabbitMQ 3.0.14).
TLDR; Request-Respond does not work when response type is List/IEnumerable.
In client I'm creating instance of IRequestClient:
var RequestObjects = busControl.CreateRequestClient<MyObjectsRequest, List<MyObject>>(
new Uri(configuration["MassTransit:ServerAddress"] + "/" + configuration["MassTransit:TestQueueName"]),
TimeSpan.FromSeconds(15));
Next, I call server for a response:
RequestObjects.Request(new MyObjectsRequest{ Id = 1 });
On server side I have registered consumer:
public async Task Consume(ConsumeContext<MyObjectRequest> context)
{
var myList = new List<MyObject>
{
new MyObject { Id = 1 },
new MyObject { Id = 2 }
}
context.Respond(myList);
}
And the problem is that response go to some temporary _skipped queue (I'm tracking it via RabbitMQ's web panel) and I'm getting RequestTimeOutException.
I've tried also with IEnumerable<> - same thing.
In fact, Array<MyObject> works well - response is going back to my client.
AFAIR when I was using MassTransit 2.x subscribing on Lists worked well. Is there a possibility to do the same on MassTransit 3.x?
What's curious, the message type seems to be erased when it's getting to RabbitMQ while I'm using List/IEnumerable:
The snippet of the messageType when single object is sent:
And the snippet of the messageType when Array of the objects is sent:
Using an array is definitely preferred over a List<T> or an IEnumerable<T> - for reasons of which are different. Arrays are immutable (generally, anyway) and cannot typically be modified.
That being said, I'm pretty sure that all of the signatures you've mentioned should work if you're using JSON, BSON, or XML. The relevant line of code is at https://github.com/MassTransit/MassTransit/blob/develop/src/MassTransit/Serialization/JsonConverters/ListJsonConverter.cs#L59 -- clearly both List and IEnumerable are present.
Do you have a failing unit test? If so, can you share it?
I'm following this OData V4 tutorial and now have a problem with the bound function MostExpensive.
This function is bound to the Productscollection and is registered in WebApiConfig.Register() like suggested in the tutorial:
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.Namespace = "ProductService";
builder.EntityType<Product>().Collection.Function("MostExpensive").Returns<decimal>();
There is only described a rudimentary client for this service in part 2 of this tutorial. So I want to extend it so that I also can call the functions described in the later parts of the tutorial.
I have created the client using OData Client Code Generator as suggested in the tutorial. I then add some products and suppliers and then want to get the most expensive product:
static void Main(string[] args)
{
const string serviceUri = "http://localhost:52542";
Container container = new Container(new Uri(serviceUri));
AddProducts(container, GenerateSomeProducts());
AddSuppliers(container, GenerateSomeSuppliers());
Console.WriteLine("Most expensive product is: {0}", container.Products.MostExpensive().GetValue());
...
}
When calling GetValue() I am getting an InvalidOperationException stating that http://localhost:52542/$metadata refers to a Edm.Decimal type but a Collection(Edm-Decimal) type is expected.
When calling http://localhost:52542/Products/ProductService.MostExpensive() directly in the browser I'm getting
{
"#odata.context":"http://localhost:52542/$metadata#Edm.Decimal","value":40000.95
}
Which seems to be correct.
Do I do anything wrong? I have no idea how to fix this. So any suggestions about that?
I guess you are using T4 2.2.0, right?
There is a bug in T4 2.2.0 which causes this issue. You can use the content in following link to replace your ttinclude file and regenerate your proxy to work around the issue.
https://raw.githubusercontent.com/LaylaLiu/odata.net/T4TempFix/src/CodeGen/ODataT4CodeGenerator.ttinclude
I've been using MassTransit for handling e-mail messages. Using this code: http://meandaspnet.blogspot.com/2009/10/how-to-binary-serialize-mailmessage-for.html I'm able to binary serialize my e-mails and publish them to my service bus. They're handled correctly too.
Bus.Initialize(
sbc =>
{
sbc.EnableMessageTracing();
sbc.ReceiveFrom("msmq://localhost/MyQueue");
sbc.UseMsmq();
sbc.VerifyMsmqConfiguration();
sbc.UseMulticastSubscriptionClient();
sbc.UseBinarySerializer();
sbc.Subscribe(subs => subs.Instance(new MessageHandler()));
});
Now I added a new type and handler:
// Check out the sequence of the Consumes<> !
public class MessageHandler :
Consumes<SerializeableMailMessage>.All,
Consumes<AangifteOmzetbelasting>.All
{
public void Consume(AangifteOmzetbelasting message)
{
// Some code - method will NOT be called
}
public void Consume(SerializeableMailMessage mailMessage)
{
// Some code - this method is called by Mass Transit
}
}
The weird thing is that this works if I Publish a SerializableMailMessage - but not for AangifteOmzetbelasting. If I change the interface order - it works for AangifteOmzetbelasting and not for SerializableMailMessage. Like so:
// Check out the sequence of the Consumes<> !
public class MessageHandler :
Consumes<AangifteOmzetbelasting>.All,
Consumes<SerializeableMailMessage>.All
In the latter case, the SerializedMailMessges do not appear on the service bus either. Both are published using:
Bus.Instance.Publish(object)
What am I doing wrong here?
Publishing messages without type information is a real struggle; the type information is hugely important for routing.
What I would look at doing here, if you must publish as object, is we have FastActivator helpers you can take a peek at (should be in the referenced Magnum library) that would be like Bus.Instance.FastActivator("Publish", message, { message.GetType() }). I might have the order of the parameters wrong, but you need the method name, parameters, and generic type parameters.
Additionally, I'd suggest joining the MT mailing list to help with this issue further if you need it. https://groups.google.com/forum/#!forum/masstransit-discuss