I have an MVC 4 web application. Using ELMAH, and Elmah.Contrib.WebApi, any exceptions that occur within my controllers, or API controllers (or their underlying services) are logged perfectly.
Where I run into trouble is with manually logging of errors. Specifically, inside my Global.asax, I have lots of initialization code (setting up automapper and the like). In order to catch problems which might happen in the initialization code, I have the following:
protected void Application_Start()
{
try
{
ControllerBuilder.Current.SetControllerFactory(new ErrorHandlingControllerFactory());
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
GlobalConfiguration.Configuration.Filters.Add(new ElmahHandleErrorApiAttribute());
AutoMapperConfiguration.Configure();
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
DatabaseConfig.Initialize();
SecurityConfig.Initialize();
}
catch (Exception e)
{
var context = HttpContext.Current;
var signal = ErrorSignal.FromContext(context);
if (signal != null)
{
signal.Raise(e, context);
}
}
}
Any exception caught inside the "catch" block will never be logged by ELMAH. Yet, I know that ELMAH is working because any other exceptions that will occur from this point on, inside any controller, will be logged. Therefore I have ruled out problems in the web.config, and the like.
Any suggestions? Thanks.
When the Applicaiton is executing the code in Application_Start it is still being initialized, and it is not handling any HttpRequest.
So the problem with your code is that HttpContext is null. In fact, the line ´ErrorSignal.FromContext(context);´ will throw an ArgumentNullException.
However, you can still use Elmah when there is no HttpContext (and it will basically log the error message and stack trace) as explained in this question.
So your catch would be:
catch (Exception e)
{
ErrorLog.GetDefault(null).Log(new Error(e));
}
Hope it helps!
I'm a newbie to Elmah but have had luck with something like this:
catch (Exception ex)
{
ErrorSignal.FromCurrentContext().Raise(ex);
return Json(string.Format("Failure: {0}", ex.Message), JsonRequestBehavior.AllowGet);
}
Related
I'm testing centralized exception handling in my ASPNetCore application and wanted to see if an unexpected exception is thrown it is going to be correctly handled by app.UseExceptionHandler() middleware and logged to a specific logging target. I disconnected the SQL database expecting to see Database.EnsureCreated() method in the DbContext class constructor throwing System.Data.SqlClient.SqlException. The problem is that it does throw such an exception, but it appears locally instead of being handled by centrelized error handler. The final result is that a client never gets a response message explaining what happened with the status code 500.
It seems to be strange as the handler works correctly with an exception which I throw inside controllers.
Here is my centralized exception handler configuration:
app.UseExceptionHandler(appError =>
{
appError.Run(async context =>
{
var errorFeature = context.Features.Get<IExceptionHandlerFeature>();
if (errorFeature != null)
{
var exception = errorFeature.Error;
logger.LogError(exception.ToString());
await context.Response.WriteAsync("An unexpected error occurred! Try again later");
}
});
});
Could anyone tell me give me a hint on what I might be doing wrong? Has anyone come across a similar problem?
Your code looks fine to me. What you are experiencing is a First-Chance-Exception. This means that an exception has been thrown that might eventually get handled. During runtime your ExceptionHandler should perfectly handle your exception.
At debugging time however, Visual Studio breaks for that exception. The behaviour of Visual Studio can be configured in the Exception Settings (Debug > Windows > Exception Settings). See Microsoft Docs for more information on that.
So what you basically have to do is to tell Visual Studio to continue debugging on a SqlException
You can use own middleware to handle exception as first-person
public class ExceptionFilter: IExceptionFilter
{
public void OnException(ExceptionContext context)
{
String message = String.Empty;
Type exceptionType = context.Exception.GetType();
if (exceptionType == typeof(NotImplementedException))
{
message = "A server error occurred.";
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.NotImplemented;
context.Result = new RedirectResult("/Home/Index");
}
else if (exceptionType == typeof(AppException))
{
message = context.Exception.ToString();
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Result = new RedirectResult("/Home/Index");
}
//HttpResponse response = context.HttpContext.Response;
//response.StatusCode = (int)status;
//context.Result = new RedirectResult("/Home/Index");
}
}
And in your Startup.cs
app.UseMiddleware(typeof(ExceptionFilter));
I understand that this is a RuntimeException but for my usecase I need to catch it and set some attributes.
Context: I am using JPA EntityListeners for auditing and everything works fine when user accesses the application. The problem occurs when the application is accessed remotely using RemoteEJB. I am using a session object (Credentials which captures the user) in the EntityListener, so when the call is from RemoteEJB and because there is no session it fails as expected. This is the only exception I anticipate so I want to catch it and hardcode the auditing in this RemoteEJB accessing case. But somehow I am not able to catch it. I tried to catch javax.enterprise.context.ContextNotActiveException but to no avail.
public class CreateListener {
#Inject #Named("credentials") private Credentials credentials;
#PrePersist
public void setCreateAttributes(Auditable entity){
try {
entity.setCreateUserName(credentials.getUserName());
} catch (RuntimeException e) {
entity.setCreateUserName("RemoteEJB");
}
entity.setCreateTmstmp(new Date());
}
}
Environment: JDK 1.8, JBOSS EAP 7.1, hibernate-jpa-2.1-api, Hibernate 5.2.12.Final
Any help of alternative approach is appreciated.
TIA
-Avi
I have a WCF service that receives messages from the Microsoft Message Queue (netMsmqBinding).
I want my service to recover if the message queue is unavailable. My code should fail to open the service, but then try again after a delay.
I have code to recognize the error when the queue is unavailable:
static bool ExceptionIsBecauseMsmqNotStarted(TypeInitializationException ex)
{
MsmqException msmqException = ex.InnerException as MsmqException;
return ((msmqException != null) && msmqException.HResult == (unchecked((int)(0xc00e000b))));
}
So this should be straightforward: I call ServiceHost.Open(), catch this exception, wait for a second or two, then repeat until my Open call is successful.
The problem is, if this exception gets thrown once, it continues to be thrown. The message queue might have become available, but my running process is in a bad state and I continue to get the TypeInitializationException until I shut down my process and restart it.
Is there a way around this problem? Can I make WCF forgive the queue and genuinely try to listen to it again?
Here is my service opening code:
public async void Start()
{
try
{
_log.Debug("Starting the data warehouse service");
while(!_cancellationTokenSource.IsCancellationRequested)
{
try
{
_serviceHost = new ServiceHost(_dataWarehouseWriter);
_serviceHost.Open();
return;
}
catch (TypeInitializationException ex)
{
_serviceHost.Abort();
if(!ExceptionIsBecauseMsmqNotStarted(ex))
{
throw;
}
}
await Task.Delay(1000, _cancellationTokenSource.Token);
}
}
catch (Exception ex)
{
_log.Error("Failed to start the service host", ex);
}
}
And here is the stack information. The first time it is thrown the stack trace of the inner exception is:
at System.ServiceModel.Channels.MsmqQueue.GetMsmqInformation(Version& version, Boolean& activeDirectoryEnabled)
at System.ServiceModel.Channels.Msmq..cctor()
And the top entries of the outer exception stack:
at System.ServiceModel.Channels.MsmqChannelListenerBase`1.get_TransportManagerTable()
at System.ServiceModel.Channels.TransportManagerContainer..ctor(TransportChannelListener listener)
Microsoft have made the source code to WCF visible, so now we can work out exactly what's going on.
The bad news: WCF is implemented in such a way that if the initial call to ServiceModel.Start() triggers a queueing error there is no way to recover.
The WCF framework includes an internal class called MsmqQueue. This class has a static constructor. The static constructor invokes GetMsmqInformation, which can throw an exception.
Reading the C# Programming Guide on static constructors:
If a static constructor throws an exception, the runtime will not invoke it a second time, and the type will remain uninitialized for the lifetime of the application domain in which your program is running.
There is a programming lesson here: Don't put exception throwing code in a static constructor!
The obvious solution lies outside of the code. When I create my hosting service, I could add a service dependency on the message queue service. However, I would rather fix this problem with code then configuration.
Another solution is to manually check that the queue is available using non-WCF code.
The method System.Messaging.MessageQueue.Exists returns false if the message queue service is unavailable. Knowing this, the following works:
private const string KNOWN_QUEUE_PATH = #".\Private$\datawarehouse";
private static string GetMessageQueuePath()
{
// We can improve this by extracting the queue path from the configuration file
return KNOWN_QUEUE_PATH;
}
public async void Start()
{
try
{
_log.Debug("Starting the data warehouse service");
string queuePath = GetMessageQueuePath();
while(!_cancellationTokenSource.IsCancellationRequested)
{
if (!(System.Messaging.MessageQueue.Exists(queuePath)))
{
_log.Warn($"Unable to find the queue {queuePath}. Will try again shortly");
await Task.Delay(60000, _cancellationTokenSource.Token);
}
else
{
_serviceHost = new ServiceHost(_dataWarehouseWriter);
_serviceHost.Open();
return;
}
}
}
catch(System.OperationCanceledException)
{
_log.Debug("The service start operation was cancelled");
}
catch (Exception ex)
{
_log.Error("Failed to start the service host", ex);
}
}
I have made a Silverlight Application WCF RIA Services which have's a login page that verify the username and password in a database ... it has worked perfectly when I debug from VS2010 but when I publish to IIS7 it doesn't connect with database any more ... I've made all the settings in the Web.config ... I've added the clientaccesspolicy.xml and crossdomain.xml to my project ... added the MIME types to IIS7 with no result ... I find an error with development tools from IE9 and it says :
SCRIPT5022: Unhandled Error in Silverlight Application An exception occurred during the operation, making the result invalid. Check InnerException for exception details. at System.ComponentModel.AsyncCompletedEventArgs.RaiseExceptionIfNecessary()
at MaG.ServiceReference1.LoginCompletedEventArgs.get_Result()
at MaG.MainPage.connection_LoginCompleted(Object sender, LoginCompletedEventArgs e)
at MaG.ServiceReference1.Service1Client.OnLoginCompleted(Object state)
MaGTestPage.html, line 1 character 1
I appeal the Login method client to webservice like this:
try
{
ServiceReference1.Service1Client connection = new ServiceReference1.Service1Client();
connection.LoginCompleted += new EventHandler<ServiceReference1.LoginCompletedEventArgs>(connection_LoginCompleted);
connection.LoginAsync(textBox1.Text, passwordBox1.Password);
}
catch (Exception ex)
{
Console.Write(ex.InnerException);
}
The reason for this will be found in your event handler, connection_LoginCompleted. Use this approach to check, first, for any service error:
void connection_LoginCompleted(object sender, LoginCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(e.Error.ToString());
}
else
{
// handle result
}
}
If you try to access e.Result when there is an error, the object will throw the exception you see.
I'm developing a WPF desktop application with caliburn.micro framework, and I want to configure ninject interceptors so that I can intercept method calls. I would like to do this to handle exceptions in a centralized place, so that I don't have many try-catch blocks everywhere around my code.
I haven't been able to acomplish this, because everytime I wire everything up with ninject, the system throws an exception.
So here's some code:
The AppBootstrapper configure method looks like this:
protected override void Configure()
{
_kernel = new StandardKernel(new NinjectServiceModule());
_kernel.Bind<IWindowManager>().To<WindowManager>().InSingletonScope();
_kernel.Bind<IEventAggregator>().To<EventAggregator>().InSingletonScope();
_kernel.Bind<ISomeViewModel>().To<SomeViewModel>().Intercept().With<SomeInterceptor>() //this is where the exception is thrown;
_kernel.Bind<IShell>().To<ShellViewModel>();
}
Now the intercept method in my interceptor:
public void Intercept(IInvocation invocation)
{
if (invocation.Request.Method.Name == "TheMethodIWantIntercepted")
{
try
{
invocation.Proceed();
}
catch (Exception)
{
Console.WriteLine("I Handled exception");
}
}
else
{
invocation.Proceed();
}
}
The method in the view model looks like this:
public virtual void TheMethodIWantIntercepted()
{
//Some logic here
}
So that's how interceptors are supposed to work. But it doesn't work, everytime I run the program, and ninject tries to inject the instance of SomeViewModel into ISomeViewModel, the program execution fails, and this is the exception that is thrown (and the stack trace):
http://pastebin.com/qerZAjVr
Hope you can help me with this, thank you in advance.
You have to load either DynamicProxy(2)Module or LinFuModule depending on what proxy library you prefer.
Also be aware that Ninject 2.2 will create a class proxy for SomeViewModel which requires:
a parameterless constructor
virtual methods
Interface proxies don't have this restriction but this requires Ninject 3.0.0