WCF extension for logging and performing actions for each method. IErrorHandler has no notion of method?

StackOverflow https://stackoverflow.com/questions/10295494

  •  03-06-2021
  •  | 
  •  

Question

I have normal WCF service with few methods.

I would like to log some information and perform some actions at the beginning of method and in the end.

By implementing IParameterInspector I can easily do lot of logging. Methods BeforeCall and AfterCall give me almost everything I need.

But it doesn't work for exceptions. There is IErrorHandler, which allows me to perform some handling if exception happened. Drawback is that I don't know from which method it was thrown. All because IErrorHandler is attached to service behavior, not to operation itself.

However, I can get method name using code below:

((System.Reflection.RuntimeMethodInfo)(exception.TargetSite)).Name == "MyMethod"

This doesn't look like good idea for me.

Question: Guys, are there any other WCF extensions I can use to achieve my goal? Would you recommend to use old buddy try-catch, and maybe wrap it into some nice syntax so I can perform actions at the beginning and in the end? What would be the syntax? What do you use for similar purposes?

Thanks ahead.

Était-ce utile?

La solution

How about an IOperationInvoker?

public class NHibernateOperationInvoker : IOperationInvoker {
    private readonly IOperationInvoker _invoker;
    private readonly String _operationName;

    public NHibernateOperationInvoker(IOperationInvoker invoker, String operationName) {
        _invoker = invoker;
        _operationName = operationName;
    }

    public Object[] AllocateInputs() {
        return _invoker.AllocateInputs();
    }

    public Object Invoke(Object instance, Object[] inputs, out Object[] outputs) {
        using (var context = NHibernateContext.CreateNew()) {
            try {
                var result = _invoker.Invoke(instance, inputs, out outputs);
                context.Commit();
                return result;
            } catch(Exception ex) {
                Debug.Fail("Operation " + _operationName + " failed with " + ex.Message);
            }
        }
    }

    public IAsyncResult InvokeBegin(Object instance, Object[] inputs, AsyncCallback callback, Object state) {
        throw new NotImplementedException("NHibernateOperationInvoker.InvokeBegin");
    }

    public Object InvokeEnd(Object instance, out Object[] outputs, IAsyncResult result) {
        throw new NotImplementedException("NHibernateOperationInvoker.InvokeEnd");
    }

    public Boolean IsSynchronous {
        get { return true; }
    }
}

This is attached using an IOperationBehavior which does dispatchOperation.Invoker = new NHibernateOperationInvoker(dispatchOperation.Invoker, dispatchOperation.Name);

Autres conseils

I am not aware of any extensions that will achieve what you want and here is extensive list. IErrorHandler is fine way of handling what you need.

Don't litter your code with try/catch. Try/Catch implies that you will perform some compensation logic and logging does not fall into that category.

I am not sure why do you need cast or why are you testing for equality. Using method info is fine. Another option is using StackTrace class to get the information about every single call e.g.

 public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
            var s = new StackTrace(error);
            var faultyTowers = s.GetFrame(0);

        }

One thing to consider is something like PostSharp but it's not free ($ and performance). You could inject AOP aspect around every call that you could use for what ever you want.

You should try to have your error handler not do to much.

What you want is IDispatchMessageInspector

If anything is sent back to the client BeforeSendReply will be called. This works if you add it to the dispatchRuntime as a MessageInspector:

public class MessageLogger : IDispatchMessageInspector
{
    public object AfterReceiveRequest( ref System.ServiceModel.Channels.Message request, IClientChannel channel, InstanceContext instanceContext )
    {
        Log("Begin: " + request.Headers.Action );
        return request;
    }

    public void BeforeSendReply( ref System.ServiceModel.Channels.Message reply, object correlationState )
    {
        System.ServiceModel.Channels.Message request = (System.ServiceModel.Channels.Message)correlationState;
        Log("End: " + request.Headers.Action );
    }
}

The disadvantage is that you are looking at raw messages. They map to the operations that your service implements.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top