williamsandonz
williamsandonz

Reputation: 16430

Programmatically disposing of the Elmah email onMailing

I have an issue with Elmah, I've overriden the Mailing method. And I want it to dispose of the mail (not send it basically) when my App isn't in Live mode. Problem is when I do this, when my ErrorHandler (in my ASP.NET MVC app) tries to raise the exception with Elmah, i get the error: Cannot access a disposed object. Object name:'System.Net.Mail.MailMessage'. So I need to figure out a way around this. Code below:

Emailing method:

public static void ErrorMail_Mailing(object sender, ErrorMailEventArgs e)
        {
            if (!GlobalHelper.IsLiveMode)
            {

                //e.Mail.Dispose();
            }
            else
            {
                MailAddressCollection MAC = new MailAddressCollection();
                foreach (string a in EmailRecipients.Split(','))
                {
                    MAC.Add(a);
                }

                string b = "errors@" + GlobalHelper.AppName + ".com";
                e.Mail.From = new MailAddress(b);
                e.Mail.To.Clear(); // Clears existing mail addresses
                e.Mail.To.Add(MAC.ToString());
                e.Mail.Subject = GlobalHelper.AppName+ " Error: ("+e.Error.Type.Substring(0,10)+") Deployment Level:"+GlobalHelper.DeploymentMode;

            }

Errorhandler method:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
    public class CustomHandleErrorAttribute : HandleErrorAttribute
    {

        public override void OnException(ExceptionContext context)
        {
            // Bail if we can't do anything; app will crash.
            if (context == null)
                return;
            var ex = context.Exception ?? new Exception("No further information exists.");

            // Can show Data on view page /w this code
            // var data = new ErrorPresentation
            //{
            //  ErrorMessage = HttpUtility.HtmlEncode(ex.Message),
            //  TheException = ex,
            //  ShowMessage = !(filterContext.Exception == null),
            //  ShowLink = false
            //};
            //filterContext.Result = View("ErrorPage", data);

            context.ExceptionHandled = true;

            //Log to Elmah
            ErrorSignal.FromCurrentContext().Raise(ex);

            //Show Custom view page
            context.Result = new ViewResult { ViewName = "Error" };
        }
    }

Stack trace:

System.Net.Mail.SmtpException: Failure sending mail. ---> System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Mail.MailMessage'.
   at System.Net.Mail.MailMessage.get_AlternateViews()
   at System.Net.Mail.MailMessage.SetContent()
   at System.Net.Mail.SmtpClient.Send(MailMessage message)
   --- End of inner exception stack trace ---
   at System.Net.Mail.SmtpClient.Send(MailMessage message)
   at Elmah.ErrorMailModule.SendMail(MailMessage mail)
   at Elmah.ErrorMailModule.ReportError(Error error)
   at Elmah.ErrorMailModule.OnError(Exception e, HttpContext context)
   at Elmah.ErrorMailModule.OnErrorSignaled(Object sender, ErrorSignalEventArgs args)
   at Elmah.ErrorSignalEventHandler.Invoke(Object sender, ErrorSignalEventArgs args)
   at Elmah.ErrorSignal.Raise(Exception e, HttpContext context)
   at Elmah.ErrorSignal.Raise(Exception e)
   at MusingMonkey.Utilities.Filters.CustomHandleErrorAttribute.OnException(ExceptionContext context) in C:\Users\William-Business\Desktop\TWB\TWB Central\Projects\MusingMonkey\MusingMonkey\Utilities\Filters\ErrorHandler.cs:line 34
   at System.Web.Mvc.ControllerActionInvoker.InvokeExceptionFilters(ControllerContext controllerContext, IList`1 filters, Exception exception)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass25.<BeginInvokeAction>b__1e(AsyncCallback asyncCallback, Object asyncState)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.BeginInvokeAction(ControllerContext controllerContext, String actionName, AsyncCallback callback, Object state)
   at System.Web.Mvc.Controller.<>c__DisplayClass1d.<BeginExecuteCore>b__17(AsyncCallback asyncCallback, Object asyncState)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout)
   at System.Web.Mvc.Controller.BeginExecuteCore(AsyncCallback callback, Object state)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout)
   at System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state)
   at System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state)
   at System.Web.Mvc.MvcHandler.<>c__DisplayClass6.<>c__DisplayClassb.<BeginProcessRequest>b__3(AsyncCallback asyncCallback, Object asyncState)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout)
   at System.Web.Mvc.MvcHandler.<>c__DisplayClass6.<BeginProcessRequest>b__2()
   at System.Web.Mvc.SecurityUtil.<>c__DisplayClassb`1.<ProcessInApplicationTrust>b__a()
   at System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f)
   at System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action)
   at System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust[TResult](Func`1 func)
   at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state)
   at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state)
   at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

Upvotes: 0

Views: 804

Answers (1)

Atif Aziz
Atif Aziz

Reputation: 36648

The problem is that ELMAH is trying to use the MailMessage in order to send it but you have already disposed the object. The best solution for you would be to not do this via the event, but by inheriting from the ErrorMailModule and overriding it's SendMail method like this:

protected override void SendMail(MailMessage mail)
{
    if (!GlobalHelper.IsLiveMode) 
        base.SendMail(mail);
}

You can then continue to do the rest in your Mailing event handler.

Upvotes: 2

Related Questions