Reputation: 309
I'm trying to deploy an API that manipulates the AWS DynamoDB database. I used the serverless API template provided by the AWS .Net SDK. The .Net Core API works fine locally, but will return an "Internal server error" whenever I try to access the API after I published it to AWS Lambda.
In the CloudWatch Logs Insights, the log message returns something like this
An exception was thrown when the constructor for type 'ProjectAPI.Controllers.MyController' was invoked. Check inner exception for more details.: LambdaException
at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean wrapExceptions, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor)
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean wrapExceptions, Boolean skipCheckThis, Boolean fillCache)
In the constructor of MyController I instantiate a service and that service will fetch credentials and setup the DynamoDBContext.
In MyController:
private readonly IMyService _myService;
public CoffeeController(IMyService myService){
_myService = myService;
}
In MyService: IMyService
private readonly DynamoDBContext _context;
public CoffeeService()
{
var chain = new CredentialProfileStoreChain();
AWSCredentials awsCredentials;
if (chain.TryGetAWSCredentials("Hackathon-coffee", out awsCredentials)){
AmazonDynamoDBClient client = new AmazonDynamoDBClient(awsCredentials, RegionEndpoint.APSoutheast2);
_context = new DynamoDBContext(client, new DynamoDBContextConfig { ConsistentRead = true, SkipVersionCheck = true });
}else
LambdaLogger.Log("Cannot Fetch Credentials");
}
In Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddSingleton<IMyService, MyService>();
}
I presume there is something wrong when fetching the credentials, but i'm not sure how to do it appropriately in .Net Core environment.
Upvotes: 0
Views: 1162
Reputation: 3177
I assume "Hackathon-coffee"
is referring to a credentials profile stored on your local development environment. That profile won't exist in the Lambda environment.
In Lambda you most likely want to use the credentials for the IAM Role that is assigned to the Lambda function when you created it.
Basically when running in Lambda you want to construct your AmazonDynamoDBClient
without passing in a AWSCredentials
. The SDK will automatically resolve the credentials for the assigned role. This is also true for region parameter in the constructor. If you construct an AmazonDynamoDBClient
with the empty constructor it will configure the client with credentials for the IAM role and the region the function is running in.
A handy trick I use in my code sometimes to figure out if I'm running in Lambda is check to see if the LAMBDA_TASK_ROOT
environment variable is set.
private readonly DynamoDBContext _context;
public CoffeeService()
{
if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("LAMBDA_TASK_ROOT")))
{
var chain = new CredentialProfileStoreChain();
AWSCredentials awsCredentials;
if (chain.TryGetAWSCredentials("Hackathon-coffee", out awsCredentials))
{
AmazonDynamoDBClient client = new AmazonDynamoDBClient(awsCredentials, RegionEndpoint.APSoutheast2);
_context = new DynamoDBContext(client, new DynamoDBContextConfig { ConsistentRead = true, SkipVersionCheck = true });
}
else
{
LambdaLogger.Log("Cannot Fetch Credentials");
}
}
else
{
// Use credentials from IAM Role and region the function is running in.
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
_context = new DynamoDBContext(client, new DynamoDBContextConfig { ConsistentRead = true, SkipVersionCheck = true });
}
}
Upvotes: 1