34

Is there a way to globally handle exceptions in regular ASP.NET Web Service (asmx) using ELMAH like we do it in ASP.NET web site ?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
mberube.Net
  • 2,120
  • 2
  • 29
  • 39

3 Answers3

25

ASP.NET web services never fire Application_Error event and exceptions cannot be handled globally by ELMAH like in ASP.NET apps. But we can "manually" log exceptions using ELMAH:


public int WebServiceMethod() {
  try {
   ...
  }
  catch (Exception ex) {
    Elmah.ErrorLog.GetDefault(
      HttpContext.Current).Log(new Elmah.Error(ex, HttpContext.Current));
  }
}

bkaid
  • 51,465
  • 22
  • 112
  • 128
Tadas Šukys
  • 4,140
  • 4
  • 27
  • 32
  • That's what I thought but I was checking if there was a "cleaner" solution. Thanks – mberube.Net Feb 02 '10 at 18:17
  • Yep, cleaner solution or practice would be interesting for me too. And this is good question (+1). – Tadas Šukys Feb 02 '10 at 19:03
  • I finally used your solution, I didn't find a better way to do it. Thanks for the hint. – mberube.Net Mar 23 '10 at 12:57
  • 3
    Use Elmah.ErrorSignal.FromCurrentContext().Raise(ex); instead to trigger all subscribed/configured log types/filters – Steven Quick Oct 11 '13 at 02:22
  • FromCurrentContext() is the better solution and I posted an answer to that affect on 22 Feb 2012. For some reason it was deleted the same day. if any high rep users happen to visit please check my answer and vote for un-deletion if you see fit. – Stephen Kennedy Sep 13 '16 at 09:45
23

You can use a SoapExtension to do this :

using System;
using System.Web.Services.Protocols;

namespace MyNamespace
{
    class ELMAHExtension : SoapExtension
    {
        public override object GetInitializer(Type serviceType)
        { return null; }

        public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
        { return null; }

        public override void Initialize(object initializer)
        { }

        public override void ProcessMessage(SoapMessage message)
        {
            if (message.Stage == SoapMessageStage.AfterSerialize &&
                message.Exception != null)
            {
                // Log exception here
            }
        }
    }
}

You register this in the web.config with the following lines :

<system.web>
  <webServices>
    <soapExtensionTypes>
      <add type="MyNamespace.ELMAHExtension, MyDLL" priority="1" group="1" />
    </soapExtensionTypes>
  </webServices>
</system.web>

This will give you access to the HttpContext and SoapMessage objects which should give you all of the details you need about what was being called. I think the exception you retrieve at this stage will always be a SoapException and that the bit you are interested in is probably the inner exception.

Liam Corner
  • 345
  • 2
  • 2
  • 1
    havent had a chance to try this yet, but it _looks_ like it should work. Where it says 'log exception here' the code `Elmah.ErrorLog.GetDefault( HttpContext.Current).Log(new Elmah.Error(ex, HttpContext.Current));` might do the trick. – codeulike Jan 12 '11 at 13:57
  • @DavidRobbins Nope, but I don't see any reason it wouldn't work the same. – avesse Jan 29 '13 at 13:27
  • Unfortunately this approach doesn't work with the ScriptService/JSON (http://stackoverflow.com/a/9585721/198065) – Regin Larsen Jan 20 '14 at 14:56
  • Is `group="1"` valid? Intellisense suggests you need "Low" or "High". – NickG Aug 03 '15 at 10:28
  • This indeed works! I managed to make it work by adding this line to `ProcessMessage` function: `Elmah.ErrorSignal.FromCurrentContext().Raise(message.Exception);` But keep in mind that it won't work when using the default test interface of asmx service. (The one with the invoke button) I have read somewhere that the reason it wont work is that the interface uses HTTP, not SOAP, so soapExtensions are not loaded when the method is invoked from the interface. But I am not exactly sure. – emregon Dec 07 '15 at 19:48
  • 1
    Maybe I've missed the point but I think this works **only for calls to another web services, not for my internal not handled errors**. – fabriciorissetto Jan 18 '16 at 13:40
0

You can use this code

 try{
// your code in here
}
     catch (Exception ert)
            {
                Elmah.ErrorSignal.FromCurrentContext().Raise(ert);

            }