Why is AWS Lambda failing to reach the FunctionHandler? - c#

I am:
deploying a C# app to Lambda to the first time.
using Mac so can't use the Visual Studio AWS Toolkit Extension.
using C# .NET core 3.1.
deploying using: dotnet lambda deploy-serverless
The deployment seems to work without errors, the Lambda is visible in the AWS Console.
When I test the Lambda from AWS Console log output is generated, some of which is from my C# code. Such as this line "LambdaEntryPoint - init".
However none of the log output in my handler (FunctionHandlerZ) is written to the log.
I see this exception when I use the AWS Console Test facility:
{
"errorType": "NullReferenceException",
"errorMessage": "Object reference not set to an instance of an object.",
"stackTrace": [
"at Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction.MarshallRequest(InvokeFeatures features, APIGatewayProxyRequest apiGatewayRequest, ILambdaContext lambdaContext)",
"at Amazon.Lambda.AspNetCoreServer.AbstractAspNetCoreFunction`2.FunctionHandlerAsync(TREQUEST request, ILambdaContext lambdaContext)",
"at Amazon.Lambda.RuntimeSupport.HandlerWrapper.<>c__DisplayClass25_0`2.<<GetHandlerWrapper>b__0>d.MoveNext()",
"--- End of stack trace from previous location where exception was thrown ---",
"at Amazon.Lambda.RuntimeSupport.LambdaBootstrap.InvokeOnceAsync(CancellationToken cancellationToken)"
]
}
LambdaEntryPoint.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using System.IO;
using Amazon.Lambda.Core;
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace aspDemo3B
{
public class LambdaEntryPoint :
// When using an ELB's Application Load Balancer as the event source change
// the base class to Amazon.Lambda.AspNetCoreServer.ApplicationLoadBalancerFunction
Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction
{
/// <summary>
/// The builder has configuration, logging and Amazon API Gateway already configured. The startup class
/// needs to be configured in this method using the UseStartup<>() method.
/// </summary>
/// <param name="builder"></param>
protected override void Init(IWebHostBuilder builder)
{
Console.WriteLine("LambdaEntryPoint - init");
builder
.UseStartup<Startup>();
}
public string FunctionHandlerZ(string input, ILambdaContext context)
{
Console.WriteLine("FunctionHandlerZ");
Console.WriteLine($"Calling function name: {context.FunctionName}\\n");
return input?.ToUpper();
}
}
}
serverless.template
{
"AWSTemplateFormatVersion": "2010-09-09",
"Transform": "AWS::Serverless-2016-10-31",
"Description": "An AWS Serverless Application that uses the ASP.NET Core framework running in Amazon Lambda.",
"Parameters": {},
"Conditions": {},
"Resources": {
"AspNetCoreFunction": {
"Type": "AWS::Serverless::Function",
"Properties": {
"Handler": "aspDemo3B::aspDemo3B.LambdaEntryPoint:FunctionHandlerZ",
"Runtime": "dotnetcore3.1",
"CodeUri": "",
"MemorySize": 256,
"Timeout": 30,
"Role": null,
"Policies": [
"AWSLambdaFullAccess"
],
"Environment": {
"Variables": {
"LAMBDA_NET_SERIALIZER_DEBUG": "true"
}
},
"Events": {
"ProxyResource": {
"Type": "Api",
"Properties": {
"Path": "/{proxy+}",
"Method": "ANY"
}
},
"RootResource": {
"Type": "Api",
"Properties": {
"Path": "/",
"Method": "ANY"
}
}
}
}
}
},
"Outputs": {
"ApiURL": {
"Description": "API endpoint URL for Prod environment",
"Value": {
"Fn::Sub": "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/"
}
}
}
}
I am happy to start from scratch with a simple helloWorld style Lambda that:
Does not require AWS Toolkit Extension, as it is not available on Mac.
Uses .NET core 3.1 (there have been some changes from 3.0 to 3.1 for AWS Lambda)
Is initiated by a HTTP request via API GW and returns a simple response

Below is will help you
public class LambdaFunctionHandler : APIGatewayProxyFunction
{
protected override void Init(IWebHostBuilder builder)
{
builder.UseStartup<Startup>();
// DemoWebApi::DemoWebApi.ALBLambdaFunction::FunctionHandlerAsync
}
}
not required FunctionHandlerZ function
For any Lambda API you are using API Gateway FunctionHandlerAsync will be the entry point.
Lambda Function Handler should be as [AssemblyName]::[NameSpace].[Classname]::FunctionHandlerAsync

Related

Dependency Injection of services for GraphQL

I'm using NET5 webapi with HotChocolate package and am trying to inject a service.
I've followed both standard and method based approach documented here however it doesn't work at all. All i get is the following message:
{
"errors": [
{
"message": "Unexpected Execution Error",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"tests"
]
}
],
"data": {
"tests": null
}
}
My query:
query{
tests {
id
}
}
My code currently reflects the method approach as documented.
In startup:
services
.AddSingleton<ITestService, TestService>()
.AddGraphQLServer()
.AddDefaultTransactionScopeHandler()
.AddQueryType<Queries>()
.AddMutationType<Mutations>()
.AddFiltering()
.AddSorting()
.AddProjections()
.AddType<Test>();
The query setup:
[UseProjection]
[UseFiltering]
[UseSorting]
public IQueryable<Test> GetTests([Service] ITestService testService) => testService.GetTests();
My TestService:
private readonly IDbContextFactory<TestDbContext> contextFactory;
public TestService(IDbContextFactory<TestDbContext> contextFactory)
{
this.contextFactory = contextFactory;
}
public IQueryable<Test> GetTests()
{
using var context = contextFactory.CreateDbContext();
return context.Test;
}
I'm sure I'm missing something simple to make this work.
Your DB Context is disposed. The using in GetTests is scoped for this method. On the end of this method the db context gets disposed and a Queryable is returned. Once the execution engine executes the Queryable, the exception is thrown
Checkout the EF Core integration of HotChocolate:
https://chillicream.com/docs/hotchocolate/integrations/entity-framework

Complex object app settings in Azure Function

I have these entries in my local.settings.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "whateverstorageaccountconnectionstring",
"FUNCTIONS_WORKER_RUNTIME": "dotnet"
},
"BusinessUnitMapping": {
"Values": {
"Connections": "CON",
"Products": "PRD",
"Credit & Affordability": "CAA",
"Accounts Receivable": "ARC",
"Identity": "IDT"
}
}
}
I have this code to read the values in startup
services.Configure<BusinessUnitMapping>(options => configuration.GetSection("BusinessUnitMapping").Bind(options));
where BusinessUnitMapping is
public class BusinessUnitMapping
{
public Dictionary<string, string> Values { get; set; }
public BusinessUnitMapping()
{
Values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
}
when the I run the function app locally, it can read these settings into BusinessUnitMapping without any issue.
Advanced Edit for Application Settings in Azure Portal only allows simple Key Value pair as below
[
{
"name": "AzureWebJobsDashboard",
"value": "DefaultEndpointsProtocol=Somevalue",
"slotSetting": false
},
{
"name": "AzureWebJobsStorage",
"value": "DefaultEndpointsProtocol=Somevalue",
"slotSetting": false
},
...
]
The questions
Is this a correct approach to store the complex app settings in Azure Function?
How do I get BusinessUnitMapping configured in Azure Portal for the Function App that I have deployed?
-Alan-
Is this a correct approach to store the complex app settings in Azure Function?
This is still an open question: see this github issue asking exactly this
How do I get BusinessUnitMapping configured in Azure Portal for the Function App that I have deployed?
My current preferred approach is to use the options pattern with a delegate that uses GetEnvironmentVariable which will work both locally and in Azure. The downside is that you can't create complex types in the local settings file itself, but your object can be as complex as you like.
A simple example:
In local.settings.json:
{
...
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
...
"SomeSection:Setting1": "abc",
"SomeSection:Setting2": "xyz",
},
...
}
In your startup:
services.Configure<MySettingsPoco>(o =>
{
o.Setting1 = Environment.GetEnvironmentVariable("SomeSection:Setting1");
o.Setting2 = Environment.GetEnvironmentVariable("SomeSection:Setting2");
});
Then in Azure you can create these settings as follows:
1. Is this a correct approach to store the complex app settings in Azure Function?
We can save these entries in the app settings. For more details, please refer to the document. The detailed steps are as below.
Set app settings on Azure Portal
2. How do I get BusinessUnitMapping configured in Azure Portal for the Function App that I have deployed?
According to my test, we can use the following code to do that
#r "Newtonsoft.Json"
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
using System.Collections.Generic;
public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
var test =Environment.GetEnvironmentVariable("test",EnvironmentVariableTarget.Process);
log.LogInformation(test);
var values= JsonConvert.DeserializeObject<Dictionary<string, string>>(test);
var businessUnitMapping = new BusinessUnitMapping();
businessUnitMapping.Values = values;
log.LogInformation(businessUnitMapping.Values["Products"]);
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
return name != null
? (ActionResult)new OkObjectResult($"Hello, {name}")
: new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}
public class BusinessUnitMapping
{
public Dictionary<string, string> Values { get; set; }
public BusinessUnitMapping()
{
}
}

How to retrieve, with devops api on TFS 2015 the list of all the "project collections"

I'm trying to retrieve the list of all project collection on TFS 2015 server, with c# via devops API. I don't have direct access to the TFS configuration database.
More of the solutions that I have found use old or deprecated methods like tfsConfigurationServerFactory class.
Have you tried the Project Collections API?
Sample Request:
GET https://mytfsserver/DefaultCollection/_apis/projectCollections/d81542e4-cdfa-4333-b082-1ae2d6c3ad16?api-version=1.0-preview.2
Sample Response:
{
"id": "d81542e4-cdfa-4333-b082-1ae2d6c3ad16",
"name": "DefaultCollection",
"url": "https://mytfsserver/DefaultCollection/_apis/projectCollections/d81542e4-cdfa-4333-b082-1ae2d6c3ad16",
"state": "Started",
"_links": {
"self": {
"href": "https://mytfsserver/DefaultCollection/_apis/projectCollections/d81542e4-cdfa-4333-b082-1ae2d6c3ad16"
},
"web": {
"href": "https://mytfsserver/DefaultCollection"
}
}
}
There is also a link to some sample C# code.
using Microsoft.TeamFoundation.Core.WebApi;
using Microsoft.VisualStudio.Services.Common;
using Microsoft.VisualStudio.Services.WebApi;
using System;
using System.Collections.Generic;
namespace Microsoft.TeamServices.Samples.Client.ProjectsAndTeams
{
[ClientSample(CoreConstants.AreaName, CoreConstants.ProjectCollectionsResource)]
public class ProjectCollectionsSample : ClientSample
{
[ClientSampleMethod]
public IEnumerable<TeamProjectCollectionReference> ListProjectCollections()
{
VssConnection connection = Context.Connection;
ProjectCollectionHttpClient projectCollectionClient = connection.GetClient<ProjectCollectionHttpClient>();
IEnumerable<TeamProjectCollectionReference> projectCollections = projectCollectionClient.GetProjectCollections().Result;
foreach(var collection in projectCollections)
{
Console.WriteLine(collection.Name);
}
return projectCollections;
}
}
}

using azure functions in VS2017, cannot bind to ServiceBus Queue as an output

I'm running Visual Studio v15.3 and trying to create an Azure Function. I'm having trouble binding an output to a Service Bus Queue. I get the following error when I startup:
Microsoft.Azure.WebJobs.Host: Error indexing method
'CreateRawTransactions.Run'. Microsoft.Azure.WebJobs.Host: Cannot bind
parameter 'outputSbQueue' to type String&. 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.).
My function.cs code...
public static class CreateRawTransactions
{
[FunctionName("CreateRawTransactions")]
public static HttpResponseMessage Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequestMessage req,
TraceWriter log,
[ServiceBus("outqueue", AccessRights.Manage, Connection = "ServiceBusConnection")] out string outputSbQueue)
{
outputSbQueue = "Hello ";
}
}
and the function.json
{
"bindings": [
{
"name": "outputSbQueue",
"type": "serviceBus",
"queueName": "testqueue",
"connection": "ServiceBusConnection",
"direction": "out",
"accessRights": "listen"
}
],
"disabled": false
}
and the local.settings.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "",
"AzureWebJobsDashboard": ""
},
"ConnectionStrings": {
"ServiceBusConnection": "Endpoint=sb://..."
}
}
As an update, I changed the input trigger from an HttpTrigger to a ServiceBusTrigger and it works. Seems like it is something to do with using an HttpTrigger.
This sounds like https://github.com/Azure/azure-webjobs-sdk-script/pull/1804, and has been fixed. If you get an updated CLI, it should work.

Azure Function Table Storage in binding violates the constraint of type parameter 'TElement'

I am working on reading data from Table Storage in my Azure Function. I have created HttpTrigger function with in Table Storage binding. Project is using storage package:
"WindowsAzure.Storage": "8.0.0"
and binding:
{
"bindings": [
{
"authLevel": "anonymous",
"name": "req",
"type": "httpTrigger",
"direction": "in"
},
{
"name": "$return",
"type": "http",
"direction": "out"
},
{
"name": "metadataTable",
"type": "table",
"direction": "in",
"tableName": "metadata",
"connection": "StorageConnectionString",
"partitionkey": "some_partition_key"
}
],
"disabled": false
}
Having code generated by template I have added new in parameter:
#r "Microsoft.WindowsAzure.Storage"
using System;
using System.Net;
using Microsoft.WindowsAzure.Storage.Table;
using Microsoft.WindowsAzure.Storage;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req,
IQueryable<MetadataTable> metadataTable, TraceWriter log)
{
.....
}
public class MetadataTable: TableEntity
{
public MetadataTable():base() { }
public MetadataTable(string partitionkey, string rowkey):base(partitionkey,rowkey) {}
public string Data { get; set; }
}
During save and run process I am getting compile error:
Microsoft.Azure.WebJobs.Host: Error indexing method
'Functions.HttpTriggerCSharp1'. Microsoft.Azure.WebJobs.Host:
GenericArguments[0], 'Submission#0+MetadataTable', on
'Microsoft.Azure.WebJobs.Host.Tables.TableAttributeBindingProvider+TableToIQueryableConverter1[TElement]'
violates the constraint of type 'TElement'. mscorlib:
GenericArguments[0], 'Submission#0+MetadataTable', on
'Microsoft.Azure.WebJobs.Host.Tables.TableAttributeBindingProvider+TableToIQueryableConverter1[TElement]'
violates the constraint of type parameter 'TElement'.
Can anyone help me with this or meet same error?
The error message looks a bit weird, but try removing WindowsAzure.Storage reference from project.json file. This package is referenced automatically by the runtime, and if you include it explicitly you get all kinds of errors due to version mismatch.
I created a clean Azure Function from your code without the package reference and it compiled and worked just fine. Try the same.

Categories