I need some Elmah logging in a async task executing on my webserver. But when I try to log the error it fails because of the HttpContext.
var httpContext = HttpContext.Current;
Task.Factory.StartNew(() =>
{
HttpContext.Current = httpContext;
try
{
//Execute some code
}
catch (Exception ex)
{
//Generate some error for the user and log the error in Elmah
try
{
ErrorLog.GetDefault(HttpContext.Current).Log(new Error(ex));
}
catch(Exception ex)
{
}
}
});
To get the progress for the task I implemented some polling mechanism. Currently none of the errors are logged to Elmah which make it difficult to solve them.
Also providing the context as parameter doesn't work.
It doesn't work. I get an ArgumentException telling me the expected value doesn't fall within the expected range. With the following stacktrace:
at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
at System.Web.Hosting.IIS7WorkerRequest.GetServerVariableInternal(String name)
at System.Web.HttpRequest.AddServerVariableToCollection(String name)
at System.Web.HttpRequest.FillInServerVariablesCollection()
at System.Web.HttpServerVarsCollection.Populate()
at System.Web.HttpServerVarsCollection.Get(String name)
at Elmah.ErrorLog.InferApplicationName(HttpContext context)
at Elmah.ErrorLog.GetDefaultImpl(HttpContext context)
at Elmah.ServiceContainer.GetService(Type serviceType)
at Elmah.ServiceCenter.GetService(Object context, Type serviceType)
at Elmah.ErrorLog.GetDefault(HttpContext context)
at Bis.Utilities.Log.ElmahErrorLog.TryLogError(Exception exeption) in D:\Users\A500535\Documents\Projecten\Biobank\Bis\src\Utilities\Log\ElmahErrorLog.cs:line 13
Below is one ugly hack that might get the job done. Essentially, it creates an Error object on a bogus Exception (the prototype) so that the context can be captured while the request is still in flight. Later, when the task started as a result of the request fails, another Error object is created off the actual exception that occurred and then the interesting and contextual bits are selectively copied off the earlier prototype. Unfortunately, the prototype Error has to be created whether or not an exception will occur.
// Create an error that will capture the context
// and serve as a prototype in case a real exception
// needs logging
var prototype = new Error(new Exception(), context);
Task.Factory.StartNew(() =>
{
try
{
// Execute some code
}
catch (Exception ex)
{
// Generate some error for the user and log the error in ELMAH
try
{
// Create a new error without contextual information
// but then copy over the interesting bits from the
// prototype capture at time of request.
var error = new Error(ex)
{
HostName = prototype.HostName,
User = prototype.User,
};
error.ServerVariables.Add(prototype.ServerVariables);
error.QueryString.Add(prototype.QueryString);
error.Cookies.Add(prototype.Cookies);
error.Form.Add(prototype.Form);
ErrorLog.GetDefault(null).Log(error);
}
catch(Exception)
{
}
}
});
When you start a new thread it doesn't get the HttpContext structure. Since Elmah logging requires the HttpContext data, it will fail.
See the following QA:
Elmah Does not email in a fire and forget scenario
for me this worked in a async task called with Task.Run:
Elmah.ErrorLog.GetDefault(null).Log(new Elmah.Error(new NotSupportedException("elmah logging test")));
Related
I have a CRM plugin registered on Create (synchronous, post-operation) of a custom entity that performs some actions, and I want the Create operation to succeed in spite of errors in the plugin. For performance reasons, I also want the plugin to fire immediately when a record is created, so making the plugin asynchronous is undesirable. I've implemented this by doing something like the following:
public class FooPlugin : IPlugin
{
public FooPlugin(string unsecureInfo, string secureInfo) { }
public void Execute(IServiceProvider serviceProvider)
{
try
{
// Boilerplate
var context = (IPluginExecutionContext) serviceProvider.GetService(typeof (IPluginExecutionContext));
var serviceFactory = (IOrganizationServiceFactory) serviceProvider.GetService(typeof (IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
// Additional validation omitted
var targetEntity = (Entity) context.InputParameters["Target"];
UpdateFrobber(service, (EntityReference)targetEntity["new_frobberid"]);
CreateFollowUpFlibber(service, targetEntity);
CloseTheEntity(service, targetEntity);
}
catch (Exception ex)
{
// Send an email but do not re-throw the exception
// because we don't want a failure to roll-back the transaction.
try
{
SendEmailForException(ex, context);
}
catch { }
}
}
}
However, when an error occurs (e.g. in UpdateFrobber(...)), the service client receives this exception:
System.ServiceModel.FaultException`1[Microsoft.Xrm.Sdk.OrganizationServiceFault]:
There is no active transaction. This error is usually caused by custom plug-ins
that ignore errors from service calls and continue processing.
Server stack trace:
at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ref ProxyRpc rpc)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(ref MessageData msgData, Int32 type)
at Microsoft.Xrm.Sdk.IOrganizationService.Create(Entity entity)
at Microsoft.Xrm.Sdk.Client.OrganizationServiceProxy.CreateCore(Entity entity)
at Microsoft.Xrm.Sdk.Client.OrganizationServiceProxy.Create(Entity entity)
at Microsoft.Xrm.Client.Services.OrganizationService.<>c__DisplayClassd.<Create>b__c(IOrganizationService s)
at Microsoft.Xrm.Client.Services.OrganizationService.InnerOrganizationService.UsingService(Func`2 action)
at Microsoft.Xrm.Client.Services.OrganizationService.Create(Entity entity)
at MyClientCode() in MyClientCode.cs: line 100
My guess is that this happens because UpdateFrobber(...) uses the IOrganizationService instance derived from the plugin, so any CRM service calls that it makes participate in the same transaction as the plugin, and if those "child" operations fail, it causes the entire transaction to rollback. Is this correct? Is there a "safe" way to ignore an error from a "child" operation in a synchronous plugin? Perhaps a way of instantiating an IOrganizationService instance that doesn't re-use the plugin's context?
In case it's relevant, we're running CRM 2013, on-premises.
You cannot ignore unhandled exceptions from child plugins when your plugin is participating in a database transaction.
However, when your plugin is operating On Premise in partial trusted mode, you can actually create a OrganizationServiceProxy instance of your own and use that to access CRM. Be sure you reference the server your plugin is executing on to avoid "double hop" problems.
If really needed, I would create an ExecuteMultipleRequest with ContinueOnError = true, for your email you could just check the ExecuteMultipleResponse...
But it looks a bit overkill.
You can catch exceptions if running in async mode. Be sure to verify your mode when catching the exception.
Sample Code:
try
{
ExecuteTransactionResponse response =
(ExecuteTransactionResponse)service.Execute(exMultReq);
}
catch (Exception ex)
{
errored = true;
if (context.Mode == 0) //0 sync, 1 Async.
throw new InvalidPluginExecutionException(
$"Execute Multiple Transaction
Failed.\n{ex.Message}\n{innermessage}", ex);
}
if(errored == true)
{
//Do more stuff to handle it, such as Log the failure.
}
It is not possible to do so for a synchronous plugin.
A more detailed summary, explaining the execution mode and use case can be found on my blog: https://helpfulbit.com/handling-exceptions-in-plugins/
Cheers.
I have a global ExceptionHandler in my web api 2.0, which handles all unhandled exceptions in order to return a friendly error message to the api caller.
I also have a global ExceptionFilter, which handles a very specific exception in my web api and returns a specific response. The ExceptionFilter is added dynamically by a plugin to my web api so I cannot do what it does in my ExceptionHandler.
I am wondering if I have both the ExceptionHandler and the ExceptionFilter registered globally, which one will take priority and be executed first? Right now I can see that the ExceptionFilter is being executed before the ExceptionHandler. And I can also see that in my ExceptionFilter if I create a response the ExceptionHandler is not being executed.
Will it be safe to assume that:
ExceptionFilters are executed before ExceptionHandlers.
If the ExceptionFilter creates a response, the ExceptionHandler will not be executed.
I had to debug through the System.Web.Http in order to find the answer to my question. So the answer is:
It is safe to assume that ExceptionFilters will be executed before ExceptionHandlers
If the ExceptionFilter creates a response the ExceptionHandler would not be executed.
Why this is so:
When you have an ExceptionFilter registered to execute globally or for your controller action, the ApiController base class from which all the api Controllers inherit will wrap the result in an ExceptionFilterResult and call its ExecuteAsync method. This is the code in the ApiController, which does this:
if (exceptionFilters.Length > 0)
{
IExceptionLogger exceptionLogger = ExceptionServices.GetLogger(controllerServices);
IExceptionHandler exceptionHandler = ExceptionServices.GetHandler(controllerServices);
result = new ExceptionFilterResult(ActionContext, exceptionFilters, exceptionLogger, exceptionHandler,
result);
}
return result.ExecuteAsync(cancellationToken);
Looking at the ExceptionFilterResult.ExecuteAsync method:
try
{
return await _innerResult.ExecuteAsync(cancellationToken);
}
catch (Exception e)
{
exceptionInfo = ExceptionDispatchInfo.Capture(e);
}
// This code path only runs if the task is faulted with an exception
Exception exception = exceptionInfo.SourceException;
Debug.Assert(exception != null);
bool isCancellationException = exception is OperationCanceledException;
ExceptionContext exceptionContext = new ExceptionContext(
exception,
ExceptionCatchBlocks.IExceptionFilter,
_context);
if (!isCancellationException)
{
// We don't log cancellation exceptions because it doesn't represent an error.
await _exceptionLogger.LogAsync(exceptionContext, cancellationToken);
}
HttpActionExecutedContext executedContext = new HttpActionExecutedContext(_context, exception);
// Note: exception filters need to be scheduled in the reverse order so that
// the more specific filter (e.g. Action) executes before the less specific ones (e.g. Global)
for (int i = _filters.Length - 1; i >= 0; i--)
{
IExceptionFilter exceptionFilter = _filters[i];
await exceptionFilter.ExecuteExceptionFilterAsync(executedContext, cancellationToken);
}
if (executedContext.Response == null && !isCancellationException)
{
// We don't log cancellation exceptions because it doesn't represent an error.
executedContext.Response = await _exceptionHandler.HandleAsync(exceptionContext, cancellationToken);
}
You can see that the ExceptionLogger is executed first, then all ExceptionFilters are executed and then if if executedContext.Response == null, the ExceptionHandler is executed.
I hope this is useful!
I have a simple method for sending emails:
public void notifyEmail(string messageSubject, string messageBody)
{
MailMessage message = new MailMessage(from, to);
message.Subject = messageSubject;
message.Body = messageBody;
SmtpClient client = new SmtpClient(smtp_client);
client.Send(message);
message.Dispose();//release everything related
}
And a unit test (I'm learning):
[TestMethod()]
public void notifyEmailTest()
{
eMail target = new eMail("TEST Subject","TEST Body"); // TODO: Initialize to an appropriate value
bool testSent = true;
try
{
target.notifyEmail();
}
catch (Exception)
{
testSent = false;
}
Assert.IsTrue(testSent);
}
I deliberately set the smtp_client variable value to something invalid.
Running the code in my project results in an error.
Running the test method results in a Pass. Should my test or method be structured differently so that errors will fail the test?
I always do everything I can to avoid putting try-catch clauses on my unit tests. Instead try using the ExpectedException attribute (the attribute is the same for NUnit and MSTest) and set the type to the exception you are expecting i.e.
[TestMethod]
[ExpectedException(typeof(NetworkException))]
public void ShouldThrowNetworkExceptionIfSmtpServerIsInvalid)
{
//... test code here.
}
Another approach that I have used is to create a static class with an AssertExpectedException method since sometimes a method can throw the same type of exception for different reasons and the only way to know for sure if the accurate message is being returned is with custom code since the attribute does not assert the message the thrown exception is returning.
Hope this helps.
Regards.
If you expect that target.notifyEmail() should be throwing an exception, then that's what you should be testing for. If you were using NUnit you could use Assert.Throws<T>, e.g.
[Test]
public void notifyEmailTestFails()
{
// TODO: Initialize to an appropriate value
eMail target = new eMail("TEST Subject","TEST Body");
Assert.Throws<InvalidOperationException>(target.notifyEmail());
}
However, now I see you're using VSUnit you should be using [ExpectedException(typeof(...))]
as mentioned in other answers.
In general you should have separate tests for success, failure, and for exception conditions.
The way I normally do this is to decorate the test with ExpectedException (
http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.expectedexceptionattribute(v=vs.80).aspx)
. But you want to catch something MUCH less generic than "Exception."
If you don't want to use expected exception, then instead of:
bool testSent = true;
try
{
target.notifyEmail();
}
catch (Exception)
{
testSent = false;
}
Assert.IsTrue(testSent);
You can be a little less verbose:
try{
target.notifyEmail();
Assert.Fail("Expected an exception here");
}
catch (SmtpException){
}
I would highly recommend you to try the FluenAssertions:
http://fluentassertions.codeplex.com/
They are simple awesome and Elegant
And they let you check the exception message (You can not do that with the ExpectedException attribute)
Example:
using FluentAssertions;
[TestMethod]
public void notifyEmailTest()
{
eMail target = new eMail("TEST Subject","TEST Body"); // TODO: Initialize to an appropriate value
target.Invoking(x => x.notifyEmail())
.ShouldThrow<YourExcpectedException>()
.WithMessage("Your expected message", FluentAssertions.Assertions.ComparisonMode.Substring);
}
Currently i am using spring declarative transaction manager in my application. During DB operations if any constraint violated i want to check the error code against the database. i mean i want to run one select query after the exception happened. So i am catching the DataIntegrityViolationException inside my Catch block and then i am trying to execute one more error code query. But that query is not get executed . I am assuming since i am using the transaction manager if any exception happened the next query is not getting executed. Is that right?. i want to execute that error code query before i am returning the results to the client. Any way to do this?
#Override
#Transactional
public LineOfBusinessResponse create(
CreateLineOfBusiness createLineOfBusiness)
throws GenericUpcException {
logger.info("Start of createLineOfBusinessEntity()");
LineOfBusinessEntity lineOfBusinessEntity =
setLineOfBusinessEntityProperties(createLineOfBusiness);
try {
lineOfBusinessDao.create(lineOfBusinessEntity);
return setUpcLineOfBusinessResponseProperties(lineOfBusinessEntity);
}
// Some db constraints is failed
catch (DataIntegrityViolationException dav) {
String errorMessage =
errorCodesBd.findErrorCodeByErrorMessage(dav.getMessage());
throw new GenericUpcException(errorMessage);
}
// General Exceptions handling
catch (Exception exc) {
logger.debug("<<<<Coming inside General >>>>");
System.out.print("<<<<Coming inside General >>>>");
throw new GenericUpcException(exc.getMessage());
}
}
public String findErrorCodeByErrorMessage(String errorMessage)throws GenericUpcException {
try{
int first=errorMessage.indexOf("[",errorMessage.indexOf("constraint"));
int last=errorMessage.indexOf("]",first);
String errorCode=errorMessage.substring(first+1, last);
//return errorCodesDao.find(errorCode);
return errorCode;
}
catch(Exception e)
{
throw new GenericUpcException(e.getMessage());
}
}
Please help me.
I don't think problem you're describing has anything to do with Transaction management. If DataIntegrityViolationException happens within your try() block you code within catch() should execute. Perhaps exception different from DataIntegrityViolationException happens or your findErrorCodeByErrorMessage() throwing another exception. In general, Transaction logic would be applied only once you return from your method call, until then you could do whatever you like using normal Java language constructs. I suggest you put breakpoint in your error error handler or some debug statements to see what's actually happening.
I have an issue with VS2010 where the debugger stops with an Unhandled Exception. However, the exception is definitely handled. In fact, if I put code in the catch block, I'll hit it when I press F5. In Debug -> Exceptions, I definitely do not have the "Thrown" checkbox checked, so IMO there is absolutely no reason for the unhandled exception dialog to pop up...
I can't post the exact code, but will work on a sample soon. The basic idea behind the offending code section is that I have a thread that talks to hardware, and if I have an error talking to it, then I throw a HardwareException. The thread is launched with BeginInvoke, and the exception is caught in the callback handler when I call EndInvoke.
When the exception is thrown in the debugger, I get a messagebox that says 'HardwareException not handled by user code". But it is!!!
EDIT -- Well, this is driving me crazy. I've got sample code that is representative of the code I have in my application, and it looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Messaging;
using System.Threading;
namespace ConsoleApplication1
{
public class HardwareException : ApplicationException
{
public HardwareException( string message) : base(message) {}
}
class Program
{
delegate void HardwareTestDelegate();
static void Main(string[] args)
{
HardwareTestDelegate d = new HardwareTestDelegate( HardwareTestThread);
d.BeginInvoke( HardwareTestComplete, null);
while( true);
}
static void HardwareTestThread()
{
throw new HardwareException( "this is a test");
}
static void HardwareTestComplete( IAsyncResult iar)
{
try {
AsyncResult ar = (AsyncResult)iar;
HardwareTestDelegate caller = (HardwareTestDelegate)ar.AsyncDelegate;
caller.EndInvoke( iar);
} catch( Exception ex) {
Console.WriteLine( "Should see this line without getting an unhandled exception message in the IDE");
}
}
}
}
I throw my HardwareException from the thread, and then handle the exception when EndInvoke is called. I guess Murphy was right, because when I run this sample code, it does what I expect -- i.e. no unhandled exception error message pops up in the IDE!
Here is the response from Microsoft, case 111053102422121. Allen Weng writes the following:
Analysis:
For your information, CLR will re-throw the exception inside the callback when you call EndInvoke(). Below is a simplified version of EndInvoke():
public object EndInvoke(IAsyncResult asyncResult)
{
using (new MultithreadSafeCallScope())
{
ThreadMethodEntry entry = asyncResult as ThreadMethodEntry;
............
if (entry.exception != null)
{
throw entry.exception;
}
}
}
The exception will be handled in the call back function or in the asynchronous method if an exception handler is provided. This is how it works without a debugger attached.
When you run it in VS.NET, the debugger seems checking only the presence of the exception handler in the asynchronous method. If there is no such handler, the debugger would think the exception is not handled and pop up an error message notifying you of this.
Suggestion:
The application should work as expected when you run it stand alone. If the error message is annoying in debugging for you, you can disable it by unchecking “User unhandled” for “Common Language Runtime Exceptions”in the Exception dialog box (Debug|Exceptions or press CTRL+ATL+E). Or you can add try/catch in the asynchronous method. In the latter case, the exception is set to null and won’t be re-thrown in EndInvoke().
I'm having this same problem, so I'll post this possible workaround for posterity's sake:
In your code that throws an exception into the .NET code (HardwareTestThread() in the example above,) catch the exception that's being thrown and wrap it in some esoteric .NET exception type for which you can disable the "user-unhandled" option in the Debug>Exceptions dialog. For my case, I needed to allow an IOException to propagate through some .NET code back to my code, so I just caught the IOException and wrapped in an AppDomainUnloadedException before letting it propagate through the .NET code back to my catch block. I chose AppDomainUnloadedException because user-unhandled is unchecked for it by default and it's in the System.dll assembly, so it was already being imported in my project, though any exception should work, so long as you disable the "user-unhandled" option for it and you don't care that the debugger won't break on that type of exception in the future.
Here's my code that wraps the IOException I was needing to propagate:
public override int Read(byte[] buffer, int offset, int count)
{
try { return innerStream.Read(buffer, offset, count); }
catch (IOException ex) { throw new AppDomainUnloadedException("Exception from innerStream: " + ex.Message, ex); }
}
And here's my code where I'm catching it on the other side of the .NET code it needed to propagate through:
try { bytesRead = sslStream.Read(buffer, offset, count); }
catch (Exception ex) { /* ex handled here. */ }