I have a global ErrorHanlder (Derive from HandleErrorAttribute) that works fine and catches all errors that occur. But I have a situation in which, home controller can throw exception. I inspected and saw that error thrown from controller is not handled in my custom ErrorHandler and asp.net gives this:
Exception of type 'Exception' was thrown.
An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Would you help me please ?
Code:
public HomeController()
{
_ServiceAsync = new ServiceAsyncProvider();
}
class ServiceAsyncProvider
{
public ServiceAsyncProvider()
{
throw new Exception();
}
}
While your code snippet is a little unclear on this point, it looks like your _ServiceAsync is being initialized in your controller's constructor. Exceptions thrown during controller construction are not handled by the HandleError filter.
See this related question for more information: Handling Exceptions that happen in a asp.net MVC Controller Constructor
You are throwing an exception in the constructor. These exceptions are not handled by the filter.
Related
public UserMailDto getUserByEmail(String email) throws UserExceptionMessage {
try {
return userRepository.searchByMail(email);
} catch (DataAccessException | JDBCConnectionException accessException) {
com.example.user_service.config.log.Logger.errorLog("UserService", accessException.getMessage());
throw new DataAccessExceptionMessage(Messages.ERROR_TRY_AGAIN + accessException.getMessage());
}
}
In my view you should handle it, but not with a try..catch block in what seems to be your service. Why are you catching the Exception and then rethrowing you own custom Exception with a message? You will need to handle that Exception at some point in your code to. So you are not really handling it here.
It looks like you are building a web app, so I would recommend that you handle your Exceptions in one central place in a #ControllerAdvice class. You can read about it here. This way you can really handle the Exception, by returning a corresponding status code to the user. 503 in your case.
I am getting this exception in a Blazor Server-Side app when a UI component is called from an async method. More specifically, the app is getting data from the database, and when it is done, it calls a Toast component at which time the exception is thrown:
This is the code that throws the exception:
ToastModel model = new ToastModel() { Content = message.MessageToShow, Timeout = message.Timeout};
this.ToastObj.Show(model);
This is the exception:
[2021-01-19T11:35:49.358Z] Error: System.InvalidOperationException: The current thread is not associated with the Dispatcher. Use InvokeAsync() to switch execution to the Dispatcher when triggering rendering or component state.
at Microsoft.AspNetCore.Components.Dispatcher.AssertAccess()
at Microsoft.AspNetCore.Components.RenderTree.Renderer.AddToRenderQueue(Int32 componentId, RenderFragment renderFragment)
at Microsoft.AspNetCore.Components.ComponentBase.StateHasChanged()
at Syncfusion.Blazor.Notifications.SfToast.Show(ToastModel toastModel)
at CDS.Pages.Accounts.AccountsView.HandleAsync(StatusBarMessage message) in C:\Dev\cds-order-entry.visualstudio.com\CDSBlazor\CDS\CDS\Pages\Accounts\AccountsView.razor.cs:line 43
at CDS.Core.EventAggregator.EventAggregator.PublishAsync(Object message) in C:\Dev\cds-order-entry.visualstudio.com\CDSBlazor\CDS\CDS\Core\EventAggregator\EventAggregator.cs:line 78
at CDS.Pages.Accounts.Search.SearchView.ShowMessage(String message) in C:\Dev\cds-order-entry.visualstudio.com\CDSBlazor\CDS\CDS\Pages\Accounts\Search\SearchView.razor.cs:line 1916
at CDS.Pages.Accounts.Search.SearchView.DoSearch() in C:\Dev\cds-order-entry.visualstudio.com\CDSBlazor\CDS\CDS\Pages\Accounts\Search\SearchView.razor.cs:line 1397
at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
at Syncfusion.Blazor.Internal.SfBaseUtils.InvokeEvent[T](Object eventFn, T eventArgs)
at Syncfusion.Blazor.Buttons.SfButton.OnClickHandler(MouseEventArgs args)
at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle)
Note that this exception only occurred when the app was published to IIS. When running in VS, the exception is not thrown.
(Note: This will be self-answered. It took me much time to debug this, and I want to make it easier for the next guy.)
The fix is actually very easy: Just wrap it in InvokeAysnc like this:
InvokeAsync(() =>
{
this.ToastObj.Show(model);
});
This method is ONLY available on the ComponentBase call, meaning it must be called from the codebehind of the page.
The exception message actually says exactly what the issue is: Use InvokeAsync() to switch execution to the Dispatcher when triggering rendering or component state.
The moral of the story is that if you are in an async method, wrap any rendering or component state change in InvokeAsync to ensure it is executed on the UI thread, not a background thread.
I am using serilog with asp net core 3
It is setup and logging exceptions automatically - so i have no error handling to log the errors.
I was attempting to add extra context properties to logged items, and have added middleware to log these.
LogContext.PushProperty("Email", email);
LogContext.PushProperty("Url", url);
These are added if i manually log myself but any logs added automatically when an error occurs does not have these items added.
Any ideas?
NOTE: i have read this...
https://blog.datalust.co/smart-logging-middleware-for-asp-net-core/
This is the closest i have found to working around the issue, but this catches the exception and manually logs it, which is a shame if this is the only way it can be done.
At first, LogContext is a stack; properties that are pushed onto the stack must be popped back off by disposing the object returned from PushProperty():
using (LogContext.PushProperty("Email", email))
using (LogContext.PushProperty("Url", url)){
// middleware code
...
}
Otherwise, the behavior may be non-deterministic.
but any logs added automatically when an error occurs does not have these items added
I assume that error logging occurs outside of the scope, where these properties don't exist. In this case, try ThrowContextEnricher to enrich the exception log with properties from the original context where the exception was thrown.
// call it once on app startup
ThrowContextEnricher.EnsureInitialized();
...
// then each throwing will capture context,
// so you can enrich log in exception handler:
catch (Exception ex)
{
using (LogContext.Push(new ThrowContextEnricher()))
{
Log.Error(ex, "Exception!");
}
}
Or simply register ThrowContextEnricher globally at LoggerConfiguration (in this case ThrowContextEnricher.EnsureInitialized() is not required). So every exception log will be enriched:
Log.Logger = new LoggerConfiguration()
.Enrich.With<ThrowContextEnricher>()
.Enrich.FromLogContext()
...
.CreateLogger();
Disclaimer: I am the author of that library, and I also left an example in this answer.
Scenario is a Silverlight client using Wcf service & custom authentication. To mitigate the 500/200 status code problem (avoid EndPointNotFound exception) I've applied the SilverLightFaultBehaviour. However, this does not work with UserNamePasswordValidator - When a FaultException is thrown from Validate(), it is not caught by the SilverLightFaultMessageInspector's implementation of BeforeSendReply.
So far, the only workaround I've found is using the alternative client stack instead ( WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);), but there are complications with using it which can no longer be ignored as a lot of our clients are on virtual machines, the silverlight client keeps crashing ( Silverlight 5 - Debugging npctrl.dll crash , http://communities.vmware.com/thread/394306?tstart=0 ).
My primary motivation is that I want to be able to distinguish a failed login from a connection error (the following code is from a client-side async callback method, and only works with the Client stack):
if (e.Error is MessageSecurityException)
{
this.HasLoginFailed.Value = Captions.Login_FailedLogin;
}
else
{
this.HasLoginFailed.Value = Captions.Login_FailedConnection;
}
Is there any other way of modifying the message sent when throwing a FaultException from UserNamePasswordValidator? Or any conceptually different way of doing custom authentication rather than what I am using which enables me to modify the message status or to keep it 200, or just to be able to distinguish a connection failure from bad credentials?
my server-side code for usernamepassword reg:
var serviceCredential = host.Description.Behaviors.Find<ServiceCredentials>();
serviceCredential.UserNameAuthentication.UserNamePasswordValidationMode =
UserNamePasswordValidationMode.Custom;
serviceCredential.UserNameAuthentication.CustomUserNamePasswordValidator =
new MyValidator();
When you throw a FaultException from MyValidator, it is wrapped as the InnerException of a MessageSecurityException, that's probably why you weren't able to catch it directly as a FaultException.
To add some information to the fault you are throwing, what you can do is adding a FaultCode:
throw new FaultException(
"Invalid user name or bad password.",
new FaultCode("BadUserNameOrPassword")
);
Then, catch the exception client-side and retrieve your FaultCode:
try { ... }
catch (MessageSecurityException e)
{
FaultException fault = (FaultException) e.InnerException;
String faultCode = fault.Code.Name;
// you can now display a meaningful error with the faultCode
}
I hope it will help!
I have a WCF service configured to use custom UserName validation via the overriden Validate() method of the System.IdentityModel.Selectors.UserNamePasswordValidator class.
All methods of the contract have been decorated with the FaultContractAttribute to specify a custom SOAP fault as being returnable.
When throwing FaultException<T>, where T is the type specified in the FaultContractAttribute, everything behaves as expected and I get the custom fault in the response XML.
However, if I try and throw FaultException<T> in the overriden Validate() method of the username authentication class, I get a generic SOAP fault with the following reason:
"The creator of this fault did not specify a Reason."
However, if I change the code to throw the general SOAP fault as in:
throw new FaultException("Authentication failed.");
I will at least get "Authentication failed." in the reason element.
My questions are:
Why aren't the FaultException<T> exceptions treated the same if they're thrown in the Validate() as they are within the service implementation?
Is it possible to have exceptions thrown in the Validate() method conform to the FaultContractAttribute specified on the contract methods?
Any help greatly appreciated. My own guess is that the authentication comes before the message is associated with any method of the contract, and therefore, is not associated with the FaultContractAttribute, but any article confirming this and giving a workaround would be very useful.
Tali
It's a bit annoying but I got round it by doing this:
SecurityTokenValidationException stve
= new SecurityTokenValidationException("Invalid username or password");
throw new FaultException<SecurityTokenValidationException>(stve, stve.Message);
Including the message additionally means that you don't get the silly "did not specify a reason" message.
The problem is that the custom validation code is running outside of the context of any specific OperationContract, so there is no FaultContract is place for WCF to handle. So the short answer is no, you cannot get the exceptions thrown from your custom validator to honor the FaultContract.
You have a few options here. The one I prefer is to throw the non-generic FaultException and provide a pre-determined FaultCode; this way my catch blocks can differentiate contract faults from "plumbing" faults. Note that any exception you throw from a custom validator should come back as a MessageSecurityException, as shown below:
// Custom Validator:
public override void Validate(string userName, string password)
{
throw new FaultException(
"Invalid username or password.",
new FaultCode("AUTHENTICATION_FAILURE"));
}
// Client Code:
try
{
client.DoSomething();
}
catch ( MessageSecurityException ex )
{
var inner = ex.InnerException as FaultException;
if (inner != null && inner.Code.Name.Equals("AUTHENTICATION_FAILURE"))
{
// Security failure.
}
}
catch ( FaultException<SomethingFault> ex )
{
// Exception from the method itself.
}