Reputation: 117
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(IReadOnlyList
1 entries)+MoveNext() at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(DbContext _, ValueTuple
2 parameters, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func4 operation, Func
4 verifySucceeded, TState state, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func4 operation, Func
4 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
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:
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
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
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