How to handle exception in AWS Lambda in C# for reprocessing - c#

I am a beginner in AWS and at present, I am sending data from DyanmoDB leveraging on TTL to AWS Lambda and then to an End Point. My manager wants me to handle a situation where Lambda throws some exception thus fails to deliver the events to an endpoint.
In case of exception from Lambda he wants me to send the entry back to the DynamoDB table. I am sure it should be doable by using Put-Item command. But I want to know is there any out of the box solution that Lambda provides with which I can handle the failure condition and reprocess that received event data, and thus not lose the entries from DyanmoDB Stream during an exception. By doing this I won't have to send the data back to DynamoDB.
Below is working code for AWS Lambda
public class Function
{
private JsonSerializer _jsonSerializer = new JsonSerializer();
private readonly IQueueClient client;
public async Task FunctionHandler(DynamoDBEvent dynamoEvent, ILambdaContext context)
{
try
{
foreach (var record in dynamoEvent.Records)
{
try
{
if (record.EventName == OperationType.REMOVE)
{
context.Logger.LogLine("Calling SerializeStreamRecord function");
string streamRecordJson = SerializeStreamRecord(record.Dynamodb);
Debug.Write(streamRecordJson);
await SendAsync(streamRecordJson, context);
context.Logger.LogLine("Data Sent");
}
}
catch (Exception ex)
{
throw ex;
}
}
}
catch (Exception ex)
{
context.Logger.LogLine("Exception Occurred" + ex.Message);
}
context.Logger.LogLine("Stream processing complete.");
}
private async Task SendAsync(string stream, ILambdaContext context)
{
try
{
var message = new Message(Encoding.UTF8.GetBytes(stream));
await client.SendAsync(message); // SEND MESSAGE
}
catch (Exception ex)
{
throw ex;
}
}
private string SerializeStreamRecord(StreamRecord streamRecord)
{
try
{
using (var writer = new StringWriter())
{
_jsonSerializer.Serialize(writer, streamRecord);
return writer.ToString();
}
}
catch (Exception ex)
{
throw ex;
}
}
}

Related

How do i catch or throw an exception in asp.net core?

I'm kind of not sure as to where to catch an application and any other unexpected exception, but i do want to show on the front end which exception occurred either an application or any other exception.
If i just 'throw' from service manager then it will be catched in the controller, but what if there was an exception in the service manager and the controller?
This also seems verboose.
This is my service manager where I'm calling an API.
public async Task<int> CreateCategory(CategoryViewModel model)
{
logger.LogInformation("In {service}, Creating {CategoryModel}", nameof(CategoryServiceManager), model.ToString());
try
{
model.Guard(model.ToString());
int categoryId = await apiClient.PostAsync<int, CategoryViewModel>("Category", model);
return categoryId;
}
// Guard wil throw
catch (ApplicationException ex)
{
logger.LogError("Exception thrown for {model}: {Message}, {Stacktrace}", model.ToString(),ex.Message, ex.StackTrace);
throw new ApplicationException($"Exception thrown in service when creating category: {ex.Message}");
}
catch (Exception ex)
{
logger.LogError("Unexpected error thrown in service when creating a category : {Message}, {Stacktrace}", ex.Message, ex.StackTrace);
throw new Exception("Unexpected error thrown in service when creating a category");
}
}
This is the Guard extension used in the service manager.
public static class GuardExtensions
{
public static void Guard(this string input, string inputName)
{
if (string.IsNullOrEmpty(input))
{
throw new ApplicationException($"{inputName} must be provided");
}
}
public static void Guard(this object input, string inputType)
{
if (input == null)
{
throw new ApplicationException($"{inputType} must be provided");
}
}
}
This is the controller where I'm using the the service manager.
public async Task<IActionResult> Create(CategoryViewModel model)
{
logger.LogInformation("In {controller}, Creating {CategoryViewModel}", nameof(CategoryController), model.ToString());
try
{
if (ModelState.IsValid)
{
int createdCategoryId = await categoryService.CreateCategory(model);
List<CategoryPictureViewModel> categoryPictureViewModels = new List<CategoryPictureViewModel>();
foreach (int picId in TransformTypes.SplitStringIntoListOfInt(model.uploadedImageIds))
{
categoryPictureViewModels.Add(new CategoryPictureViewModel
{
CategoryId = createdCategoryId,
PictureId = picId
});
//model.CategoryPictures.ToList().Add(new CategoryPictureViewModel
//{
// CategoryId = createdCategoryId,
// PictureId = item
//});
}
int res = await categoryPictureService.CreateCategoryPictureAsync(categoryPictureViewModels);
return RedirectToAction(nameof(Index));
}
}
catch (ApplicationException ex)
{
logger.LogError("In {controller}, Creating category: {Message}, {Stacktrace}", nameof(CategoryController), ex.Message, ex.StackTrace);
throw new ApplicationException($"Exception thrown controller when creating category: {ex.Message}");
}
catch (Exception ex)
{
logger.LogError("Unexpected error in {controller} when creating category: {Message}, {Stacktrace}", nameof(CategoryController), ex.Message, ex.StackTrace);
throw new Exception($"Unexpected error in controller when creating category: {ex.Message}");
}
return StatusCode(StatusCodes.Status422UnprocessableEntity);
}
You can handle your exception by Action filter or using a custom exception handling middleware.
It depends on your scenario. but Having a custom exception middleware or exception filter to handle your exception can work and it's better for sake of separation of concern.
using Middleware :
Microsoft
ExceptionFilter:
StackOverflow

Error handling in the repository (API REST)

I have this situation (method in Repository):
public string Get(string name)
{
string response;
try
{
using (var context = new MyDB())
{
var row = context.TblSomething.FirstOrDefault();
response = row.GetType().GetProperty(name).GetValue(row, null).ToString();
}
return response;
}
catch (SqlException e)
{
throw e;
}
catch (Exception e)
{
throw e;
}
}
When there is content other than the Property in the name field, it throws an exception
The method is called in the Controller
public IActionResult Get(string name)
{
string response;
try
{
response = _module.MyRepository().Get(name);
}
catch (ValidationException e)
{
return BadRequest(new { error = new { message = e.Message, value = e.Value } });
}
return Ok(response);
}
How to make it not return a 500 error to the user but should be BadRequest?
The way to make it return 400 instead of 500 is to actually catch the exception. You already have a catch block that returns BadRequest, so the only assumption that can be made is that ValidationException is not what's being thrown. Catch the actual exception being thrown and you're good.
That said, absolute do not catch an exception merely to throw the same exception. All you're doing is slowing down your app. You should also never catch Exception, unless you're simply trying to generally log all exceptions and then rethrow. If you don't have a specific handler for an exception type, then don't catch it. In other words, remove these lines:
catch (SqlException e)
{
throw e;
}
catch (Exception e)
{
throw e;
}
If you're not going to handle any exceptions as your repo code does, then don't use a try block at all.
It's also worth mentioning that you shouldn't rely on exceptions unless you have to. Throwing exceptions is a drain on performance. In a situation like this, you should simply return null, instead of throwing an exception when there's no matching property. Then, you can do a null check to verify instead of a try/catch.
You could create your own Exception Handling Middleware to catch 500 error and return your custom error status code and message.
1.Create the middleware:
public class ExceptionHandlingMiddleware
{
private readonly RequestDelegate _next;
public ExceptionHandlingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context )
{
try
{
await _next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private static Task HandleExceptionAsync(HttpContext context, Exception exception)
{
HttpStatusCode httpStatusCode = HttpStatusCode.InternalServerError;
string message = "Something is wrong!";
httpStatusCode = HttpStatusCode.BadRequest; // Or whatever status code you want to return
message = exception.Message; // Or whatever message you want to return
string result = JsonConvert.SerializeObject(new
{
error = message,
});
context.Response.StatusCode = (int)httpStatusCode;
context.Response.ContentType = "application/json";
return context.Response.WriteAsync(result);
}
}
2.Add it into the middleware pipeline after app.UseDeveloperExceptionPage();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMiddleware(typeof(ExceptionHandlingMiddleware));
}

Unable to catch DbUpdateConcurrencyException and throw UserFriendlyException

I am using ASP.NET Boilerplate with Code-First Entity Framework and MVC 5.
I want to handle concurrency. In the Update method, I put Timestamp data annotation for RowVersion field in my entity.
In the manager of my entity and in Update operation, I am trying to catch DbUpdateConcurrencyException exception and throw UserFriendlyException but because UpdateAsync is asynchronous, I don't know where to handle the exception.
Where should I handle this exception to be user-friendly and not to see Internal Server Error?
public abstract class BaseFullAuditedEntity : FullAuditedEntity<Guid>
{
[Timestamp]
public byte[] RowVersion { get; set; }
}
public class Branch : BaseFullAuditedEntity
{
public string Name { get; set; }
}
Manager code:
public interface IBranchManager : IDomainService
{
Task<Branch> Update(Branch branch, byte[] RowVersion);
}
public class BranchManager : DomainService, IBranchManager
{
private IRepository<Branch, Guid> _branchRepository { get; }
public async Task<Branch> Update(Branch branch, byte[] RowVersion)
{
try
{
return await _branchRepository.UpdateAsync(branch);
}
catch (DbUpdateConcurrencyException ex)
{
throw new UserFriendlyException("Update Concurrency Happened");
}
}
}
UpdateAsync(branch) only adds branch to the context.
Inject IUnitOfWorkManager and await SaveChangesAsync():
try
{
await _branchRepository.UpdateAsync(branch);
await _unitOfWorkManager.Current.SaveChangesAsync(); // Add this
return branch;
}
catch (DbUpdateConcurrencyException ex)
{
throw new UserFriendlyException("Update Concurrency Happened");
}
Alternatively, override SaveChanges and SaveChangesAsync in your DbContext to catch for all entities:
public override int SaveChanges()
{
try
{
return base.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
throw new UserFriendlyException("Update Concurrency Happened");
}
}
public override async Task<int> SaveChangesAsync()
{
try
{
return await base.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException ex)
{
throw new UserFriendlyException("Update Concurrency Happened");
}
}
Try catching as an aggregate exception...
(Sometimes, the real exception is being wrapped.)
try
{
// code...
}
catch (Exception ex)
{
if (ex is AggregateException)
{
var exMsg = FlattenAggregate((AggregateException)ex);
throw new UserFriendlyException(exMsg );
}
throw;
}
public static string FlattenAggregate(AggregateException aggregateException)
{
var sbErr = new StringBuilder();
var exceptions = aggregateException.Flatten();
foreach (var exception in exceptions.InnerExceptions)
{
sbErr.AppendLine(exception.ToString());
}
return sbErr.ToString();
}

Assert Method not reached in Try-Catch statement

I am trying to unit test my code to see if I try to view an account's details without a sessionKey, it will throw an exception. The unit test will go and execute the statement in the try-catch and despite knowing an exception will occur, it lists the test as successful even though Assert should be false. Assert is reached in similar functions, but not always. What would be the cause of the problem?
Original Function
/// <summary>
/// Displays the account details to the user
/// </summary>
/// <returns>HttpResponseMessage deserialized into AccountResponses object</returns>
public async Task<AccountResponse> Details()
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Session-Key", sessionKey);
try
{
HttpResponseMessage response = await client.GetAsync(_baseUrl + "/Account/Details");
response.EnsureSuccessStatusCode();
string details = await response.Content.ReadAsStringAsync();
AccountResponse temp = JsonConvert.DeserializeObject<AccountResponse>(details);
return temp
}
catch (HttpRequestException ex)
{
throw ex;
}
}
Working Live Unit Test Function
[TestCategory("Account/Logon")]
[TestMethod]
public void LogOnNegativeBadPasswordTest()
{
try
{
string sessionKey = dmWeb.Account.LogOn(new DMWeb_REST.AccountLogOn { Password = "test#pasasdfasfsword" }).GetAwaiter().GetResult().ToString();
}
catch (HttpRequestException ex)
{
Assert.IsTrue(ex.Message.Contains("400"));
}
}
Not Working Live Unit Test Function
[TestCategory("Account/Details")]
[TestMethod]
public void DisplayDetailsNegativeNoSessionKeyTest()
{
try
{
string details = dmWeb.Account.Details().GetAwaiter().GetResult().ToString();
}
catch (HttpRequestException ex)
{
Assert.IsTrue(ex.Message.Contains("401"));
}
}
The test will be treated as successful as long as no errors are thrown. If no error is being caught in the catch block, this almost definitely means that no error was thrown by the code you're testing.
So place an Assert.Fail() after the statement that's supposed to throw an error:
public void TestMethod()
{
try
{
string details = ThingIAmTesting();
// shouldn't get here
Assert.Fail();
}
catch (Exception ex)
{
Assert.IsTrue(ex.Message.Contains("401");
}
}

return await Method.Invoke()

I am a big fan of DRY coding, and I like to avoid boiler plate code as much as possible. Hence I have refactored all of my WCF channel faff into an AOP class, which deals with the lifecycle of the WCF channel.
I also am a big fan of async-await, especially with WCF, as it would in theory free up a thread that would normally be sleep-waiting for the response.
So I created an interceptor in the fluentAOP lib
private static object InvokeOnChannel(IMethodInvocation methodInvocation)
{
var proxy = _factory.CreateChannel();
var channel = (IChannel) proxy;
try
{
channel.Open();
var ret = methodInvocation.Method.Invoke(proxy, methodInvocation.Arguments);
channel.Close();
return ret;
}
catch (FaultException ex)
{
if (ex.InnerException != null)
throw ex.InnerException;
throw;
}
catch(Exception)
{
channel.Abort();
throw;
}
}
However, when thinking a little about the solution I noted that in the case of a WCF contract of the form
[ServiceContract]
public interface IFoo
{
[OperationContract]
Task<int> GetInt();
}
GetInt would have unexpected results. Firstly the catch FaultException would do nothing. Secondly I would be closing the channel before the request returns. I could in theory switch to another code path if the return type is of Task. But I can't figure out how to await the results of a Task<> and then return an awaitable.
This of course is especially difficult since with runtime AOP I would not have access be able to use generics of the return type (without the whole bodge of reflection).
Any ideas how to implement this function as an awaitable, which closes the channel on complete and catches/marshals exceptions to the calling thread?
To do async injection, you'll have to replace your returned task. For code readability, I recommend replacing it with an async method instead of using ContinueWith.
I'm not familiar with fluentAOP, but I've done async injection with Castle DynamicProxy.
If you want to use reflection, what you'll want to do is first determine if it's an async call (i.e., if the return type is a subclass of or is equal to typeof(Task). If it's an async call, then you will need to use reflection to pull the T out of Task<T> and apply it to your own async method:
private static MethodInfo handleAsync = ...; // point this to HandleAsync<T>
// Only called if the return type is Task/Task<T>
private static object InvokeAsyncOnChannel(IMethodInvocation methodInvocation)
{
var proxy = _factory.CreateChannel();
var channel = (IChannel) proxy;
try
{
channel.Open();
var task = methodInvocation.Method.Invoke(proxy, methodInvocation.Arguments) as Task;
object ret;
if (task.GetType() == typeof(Task))
ret = HandleAsync(task, channel);
else
ret = handleAsync.MakeGenericMethod(task.GetType().GetGenericParameters()).Invoke(this, task, channel);
return ret;
}
catch (FaultException ex)
{
if (ex.InnerException != null)
throw ex.InnerException;
throw;
}
catch(Exception)
{
channel.Abort();
throw;
}
}
private static async Task HandleAsync(Task task, IChannel channel)
{
try
{
await task;
channel.Close();
}
catch (FaultException ex)
{
if (ex.InnerException != null)
throw ex.InnerException;
throw;
}
catch(Exception)
{
channel.Abort();
throw;
}
}
private static async Task<T> HandleAsync<T>(Task task, IChannel channel)
{
try
{
var ret = await (Task<T>)task;
channel.Close();
return ret;
}
catch (FaultException ex)
{
if (ex.InnerException != null)
throw ex.InnerException;
throw;
}
catch(Exception)
{
channel.Abort();
throw;
}
}
An alternative is to use dynamic:
private static object InvokeOnChannel(IMethodInvocation methodInvocation)
{
var proxy = _factory.CreateChannel();
var channel = (IChannel) proxy;
try
{
channel.Open();
dynamic result = methodInvocation.Method.Invoke(proxy, methodInvocation.Arguments);
return Handle(result, channel);
}
catch (FaultException ex)
{
if (ex.InnerException != null)
throw ex.InnerException;
throw;
}
catch(Exception)
{
channel.Abort();
throw;
}
}
private static async Task Handle(Task task, IChannel channel)
{
try
{
await task;
channel.Close();
}
catch (FaultException ex)
{
if (ex.InnerException != null)
throw ex.InnerException;
throw;
}
catch(Exception)
{
channel.Abort();
throw;
}
}
private static async Task<T> Handle<T>(Task<T> task, IChannel channel)
{
await Handle((Task)task, channel);
return await task;
}
private static T Handle<T>(T result, IChannel channel)
{
channel.Close();
return result;
}

Categories

Resources