I am using app.UseExceptionHandler(GlobalErrorHandler) in AspNetCore and after that a custom middleware. When using this separately they work fine but when using them simultaneous the exception is thrown inside my custom middleware and crashes the call. This happens on await _next.Invoke(context). I also tried to use an ExceptionFilter but the results where the same. My global exception handling looks like this. Is there a way to stop the exception from bubbling up?
app.UseCustomMiddleware();
app.UseExceptionHandler(GlobalErrorHandler);
app.UseMvc();
private void GlobalErrorHandler(IApplicationBuilder applicationBuilder)
{
applicationBuilder.Run(
async context =>
{
context.Response.ContentType = "text/html";
var ex = context.Features.Get<IExceptionHandlerFeature>();
if (ex != null)
{
string errorMessage;
var webFault = ex.Error as WebFaultException<string>;
if (webFault != null)
{
context.Response.StatusCode = (int)webFault.StatusCode;
errorMessage = webFault.Detail;
}
else
{
if (ex.Error is UnauthorizedAccessException)
{
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
errorMessage = string.Empty;
}
else
{
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
errorMessage = ex.Error.Message + new StackTrace(ex.Error, true).GetFrame(0).ToString();
}
_logger.Error(errorMessage, ex.Error);
}
await context.Response.WriteAsync(errorMessage).ConfigureAwait(false);
}
});
}
The problem is with the order in which you add middlewares to the application. Since you add exception handler after the custom middleware, any exception thrown by this middleware will not be covered by the exception filter.
The fix is very simple. Just change the order of middleware registration, so that exception filter is registered first:
app.UseExceptionHandler(GlobalErrorHandler);
app.UseCustomMiddleware();
app.UseMvc();
Now the exception thrown from the custom middleware will be successfully processed by the exception handler.
Related
I can't get past this error in my simple code. Why does SignInManager keep throwing error:
OnStarting cannot be set because the response has already started.
I am calling my _SignIn method from blazor Onclick Event
public async Task _SignIn()
{
SignInByUsernamePasswordModel model = new();
model.Username = this.Username;
model.Password = this.Password;
try
{
await signInComponent._SignInByUsernamePassword(model);
}
catch (Exception ex)
{
}
}
public async Task<SignInResult> _SignInByUsernamePassword(SignInByUsernamePasswordModel model)
{
string username = model.Username;
string password = model.Password;
SignInResult signInResult2 = new SignInResult() ;
try
{
SignInResult signInResult = await _SignInManager.PasswordSignInAsync(model.Username, model.Password, false, false); ;
return signInResult;
}
catch (Exception ex){
*****Exception is thrown here!****
}
return signInResult2;
}
Cookie Settings were previously giving me another error until I fixed this code, however, this can't be the culprit. I can't imagine at what point it is throwing error i.e at the time of creating a cookie?
builder.Services.AddAuthenticationCore().AddAuthentication()
.AddCookie(IdentityConstants.ApplicationScheme, options =>
{
options.ExpireTimeSpan = TimeSpan.FromMinutes(20);
options.SlidingExpiration = true;
});
Researching Top errors in below Error Stack, led to the conclusion that the SigninManager would immediately start sending out the Response or reversing the Request flow to Response flow in Request/Response Pipeline. The cause behind it is, Signin Manager makes use of HTTPContext to create cookies.
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ThrowResponseAlreadyStartedException(String value)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.OnStarting(Func`2 callback, Object state)
This article describes https://startblazoring.com/Blog/SignInManager
that SigninManager cannot be used with Blazor directly.
In my minimal API I try to save entity to database. The table contains UNIQUE constraint on license_plate column, so DbUpdateException would be thrown if same license plate would be passed in. I used try..catch in order to handle this situation:
app.MapPost("/vehicles", (VehiclesContext db, Vehicle vehicle) =>
{
var entity = db.Add(vehicle);
try
{
db.SaveChanges();
return Results.CreatedAtRoute("GetVehicle", new { inventoryNumber = entity.Entity.InventoryNumber }, entity.Entity);
}
catch (DbUpdateException)
{
var error = new JsonObject
{
["error"] = $"Creating vehicle failed because such license plate already exists: {vehicle.LicensePlate}"
};
return Results.BadRequest(error);
}
}).AddFilter<ValidationFilter<Vehicle>>();
However, when I pass duplicate license plate, I see this exception in console:
So, why does this exception show up in console? I tried to play with LogLevel for Microsoft.AspNetCore in appsettings.json (and appsettings.Development.json also) by changing Warning to Information, but still exceptions shows up.
The exception is logged prior to throwing, so you cannot stop the logging mechanism from being invoked.
However, you should be able to control output using LogLevel.
Note that the log comes from "Microsoft.EntityFrameworkCore" not "Microsoft.AspNetCore".
I just don't want to see errors which I handle in try...catch block!
Do you mean you don't want to see the fail ? Use Try-catch in minimal API?
Below is a demo, you can refer to it.
without try-catch
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () =>{
string s = null;
if (s == null)
{
throw new ArgumentNullException(paramName: nameof(s), message: "parameter can't be null.");
}}
);
app.Run();
result:
use try-catch:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () =>{
try
{
string s = null;
if (s == null)
{
throw new ArgumentNullException(paramName: nameof(s), message: "parameter can't be null.");
}
}
catch (Exception e)
{
Console.WriteLine("{0} Exception caught.", e);
}
}
);
app.Run();
result:
I have been pulling my hair out with this one.
I have a very simple test class that throws this error:
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.Text.Json.JsonException: A possible object cycle was detected. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32. Consider using ReferenceHandler.Preserve on JsonSerializerOptions to support cycles.
It doesn't seem to break much, as the put request is successful and the serialize is also successful.
EDIT
I have chased the serialize exception out if it was ever really there. I am starting to think it is a problem with typed HttpClient. It throws the exception that comes out on the console and in the response on Postman. However, it doesn't allow me to catch the exception in the code and the PUT call works. So the exception is happening after the PUT request and is handled before it returns control to my app.
I am going to try to use a standard HttpClientFactor instead of a typed client and see if that works. I know that the JSON exception is a red herring, but it is ugly and breaking the response.
Any suggestions would be welcome.
public virtual async Task<CouchResponse> Create(string id, string db, TObj info)
{
CouchResponse ret = new() { Reason = "Unknown and unExpected error", Ok = false };
HttpResponseMessage rc = null;
if (id is null)
{
return new CouchResponse() { Id = "missing", Ok = false, Rev = "missing" };
}
string url = $"{db}/1";
try
{
// login to Couchdb servwer
await CouchLogin();
try
{
//var jsonInfo = JsonUtils.Serialize<TestJson>(jTest);
var jsonInfo = JsonSerializer.Serialize<TObj>(info, options);
HttpContent content = new StringContent(jsonInfo, Encoding.UTF8,
"application/json");
rc = await client.PutAsync(url, content);
}
catch (Exception eNewton)
{
Console.WriteLine($"Json Exception: {eNewton.Message}");
}
if (rc is not null)
{
var str = await rc.Content.ReadAsStringAsync();
var ret = JsonSerializer.Deserialize<CouchResponse>(str,options);
rc.EnsureSuccessStatusCode();
}
return ret;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
//return ret;
}
return ret;
}
Suggestions?
What a crazy bug. The diagnostic was very missing leading. Everything I was doing in the create method was correct.
What is missed was an await when I called the create method. This made it appear that the sendAsync was having the issue when it was really the controller trying to format the task return as a response. This caused the stack trace in the response message. Thanks for all the help.
Change this
var jsonSerializerSettings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
};
To this
var jsonSerializerSettings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
MaxDepth = null,
};
I'm working on a web api using dotnet core 2.2 and we want to catch serialization exception and return a 400 badRequest to distinguish from the validation errors 422UnprocessableEntity. We tried to create an exception handler
public void JsonSerializerExceptionHandler(object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args)
{
args.ErrorContext.Handled = true;
var errorContext = args.ErrorContext;
if (errorContext == null)
{
return;
}
var error = errorContext.Error;
throw new SerializationException(error.Message, error.InnerException);
}
but when it throw it throw an other Exception of type InvalidOperationException with message
Current error context error is different to requested error.
We tried different approach but can't find a solution. Can someone help?
Maybe my solution will be useful for somebody.
I need to catch JSON.NET serialization or deserialization exception and handle it in my .NET Core middleware.
Add rethrow json.net exception in JSON.NET SerializerSettings
services.AddControllers().AddNewtonsoftJson(options => {
//your options here
options.SerializerSettings.Error += (sender, args) => throw args.ErrorContext.Error;
});
Add catch on middleware handler and override JsonSerializationException:
if (exception is JsonSerializationException)
{
var exceptionMessage = exception.InnerException != null ?
exception.InnerException.Message : exception.Message;
exception = new BadRequestException(ApiErrorCode.InvalidResourceModel,
exceptionMessage);
}
I have a WCF request in WP8 environment that I wrapped according to this
http://msdn.microsoft.com/en-us/library/hh873178%28v=vs.110%29.aspx#EAP
My call to the WCF service proceeds as follows:
try
{
var result = await mWCFClient.PerformRequestAsync();
}
catch(Exception e)
{
}
where PerformRequestAsync is an extension method. i.e.
public static ResultType PerformRequestAsync(this WCFClient client)
{
// EAP wrapper code
}
What happens is that occasionally something goes wrong on the WCF service and it returns "NotFound". I am not 100% sure why this happens and it seems like a rare occasion. The problem, however, is not the WCF service behavior, but the fact that it breaks in the EndPerformRequestAsync() in the automatically generated WCF code instead of going to my exception handler.
How and where should I be catching this exception as it never reaches my intended handler?!
[Edit]
As per Stephen's request, I've included the wrapper code here:
public static Task<RegistrationResult> RegisterAsync(this StoreServiceReference.StoreServiceClient client, string token, bool dummy)
{
var tcs = new TaskCompletionSource<RegistrationResult>();
EventHandler<RegisterCompletedEventArgs> handler = null;
handler = (_, e) =>
{
client.RegisterCompleted -= handler;
if (e.Error != null)
tcs.TrySetException(e.Error);
else if (e.Cancelled)
tcs.TrySetCanceled();
else
tcs.TrySetResult(e.Result);
};
client.RegisterCompleted += handler;
PerformStoreRequest(client, () => client.RegisterAsync(), token);
return tcs.Task;
}
private static void PerformStoreRequest(StoreServiceClient client, Action action, string token)
{
using (new OperationContextScope(client.InnerChannel))
{
HttpRequestMessageProperty requestMessage = new HttpRequestMessageProperty();
requestMessage.Headers[STORE_TOKEN_HTTP_HEADER] = token;
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestMessage;
action.Invoke();
// TODO: Do we need to add handler here?
}
}
Now that I look at it, I think the problem stems from the nature of action invoke. But adding custom headers to WP8 WCF services already is a pain.
The action inside is an async operation, but Invoke as far as I know is not.
What's the proper way to go about it here?