taashibhulani
taashibhulani

Reputation: 117

How to capture EF exception

I want to capture the error from entity framework.

So i have the below code

 return await _context.SaveChangesAsync(cancellationToken);

if something goes wrong in the above code i want it to be captured as a warning in database, but as of now it is automatically saving in the database as error which has to be warning actually.

below is the error that i get

An exception occurred in the database while saving changes for context type 'ValuationsReporting.Models.ValuationsReportingContext'. System.InvalidOperationException: The property 'TemplateTypeId' on entity type 'ValuationFundTemplate' has a temporary value. Either set a permanent value explicitly or ensure that the database is configured to generate values for this property. at Microsoft.EntityFrameworkCore.Update.Internal.CommandBatchPreparer.Validate(ModificationCommand modificationCommand) at Microsoft.EntityFrameworkCore.Update.Internal.CommandBatchPreparer.BatchCommands(IReadOnlyList1 entries)+MoveNext() at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(DbContext _, ValueTuple2 parameters, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func4 operation, Func4 verifySucceeded, TState state, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func4 operation, Func4 verifySucceeded, TState state, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IReadOnlyList`1 entriesToSave, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)

System.InvalidOperationException

Microsoft.EntityFrameworkCore.Update

I tried using try catch but as soon as it goes to that line the error is logged in database.

Actual code :

try
                {
                    foreach (var template in snapshotDto.SnapshopFundTemplateDtos)
                    {
                        if (template.FundId != null)
                        {
                            foreach (var fundId in template.FundId)
                            {
                                var tempTemplate = allFundTemplates.Where(x => x.ValuationId == valuation.Id && x.FundId == fundId && x.TemplateTypeId == template.TemplateTypeId).FirstOrDefault();

                                //var tempTemplate = await _valuationFundTemplateRepository.GetOne(valuation.Id, fundId, template.TemplateTypeId, true, cancellationToken);
                                if (tempTemplate == null)
                                {
                                    tempTemplate = new ValuationFundTemplate();
                                    tempTemplate.CreatedBy = _userRepository.claimsPrincipal.Identity.Name;
                                    tempTemplate.CreatedOn = DateTime.Now.ToUniversalTime();
                                    isTemplateUpdate = false;
                                }
                                //tempTemplate.IsDeleted = false;
                                //if (template.IsDeleted)
                                //{
                                //     _valuationFundTemplateRepository.Delete(tempTemplate);
                                //}
                                //else
                                //{
                                //tempTemplate.IsDeleted = template.IsDeleted;

                                tempTemplate.IsDeleted = false;
                                tempTemplate.IsDefaultFundTemplate = template.IsDefault;
                                tempTemplate.FundId = fundId;
                                tempTemplate.ValuationId = valuation.Id;
                                tempTemplate.TemplateTypeId = 0;
                                tempTemplate.TemplateId = template.TemplateId;
                                tempTemplate.ModifiedBy = _userRepository.claimsPrincipal.Identity.Name;
                                tempTemplate.ModifiedOn = DateTime.Now.ToUniversalTime();
                                tempTemplates.Add(tempTemplate);
                                if (isTemplateUpdate)
                                {
                                    _valuationFundTemplateRepository.Update(tempTemplate);
                                }
                                else
                                {
                                    await _valuationFundTemplateRepository.Insert(tempTemplate, cancellationToken);
                                }
                                //  }

                                await _valuationFundTemplateRepository.SaveAsync(cancellationToken);//here is where the error occurs which i dont want to capture in database.
                                if (!isTemplateUpdate)
                                    valuation.ValuationFundTemplate.Add(tempTemplate);
                            }

                        }
                    }
                }catch(Exception e)
                {
                    var z = e.Message;
                }



public virtual async Task<int> SaveAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            return await _context.SaveChangesAsync(cancellationToken);
        }

Upvotes: 4

Views: 2278

Answers (2)

Kieran Benton
Kieran Benton

Reputation: 8890

Following on from my comment on the other answer - I have found a solution to this.

There are two things not immediately clear here, so to clarify:

  1. There are legitimate reasons for wanting to suppress some DB errors and treat them as warnings (for instance) e.g. custom triggers checking data integrity

  2. This is NOTHING to do with capturing an exception coming from EF Core, EF Core is DIRECTLY emitting error log lines for DbUpdateExceptions AS WELL AS throwing that exception to be caught by the application

So the solution here is to configure EF Core to change its behaviour and log failures to save changes as warnings instead of errors (could suppress completely - but I'm playing safe). I haven't found actual documentation on this, but with some experimentation have found configuring your context like this works correctly:

protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
    base.OnConfiguring(builder);

    builder
        .ConfigureWarnings(x => x
            .Log(
                (CoreEventId.SaveChangesFailed, LogLevel.Warning)
            )
        );
}

Upvotes: 0

Mohan Rajput
Mohan Rajput

Reputation: 642

Agreed with the @PrashantPimpale you can simply use try catch.

But for the advanced approach, I would suggest you can use a Global Error Handling Middleware. Through which you can capture any error occurred in the whole dotnet API/Application.

Just and Elaboration below:

// Extension method used to add the middleware to the HTTP request pipeline.
    public static class ErrorHandlingMiddlewareExtensions
    {
        public static IApplicationBuilder UseErrorHandlingMiddleware(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<ErrorHandlingMiddleware>();
        }
    }

Then add app.UseErrorHandlingMiddleware(); in the Startup's Configure() method.

You have to first create a ErrorHandlingMiddleware class.

 public class ErrorHandlingMiddleware
    {
        private readonly RequestDelegate _next;

        public ErrorHandlingMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task Invoke(HttpContext httpContext)
        {
            try
            {
                await _next(httpContext);
            }
            catch (Exception ex)
            {
                await HandleExceptionAsync(httpContext, ex);
            }
        }

        private static async Task HandleExceptionAsync(HttpContext context, Exception exception)
        {
          // Implement how you want to handle the error.
        }
}

Upvotes: 2

Related Questions