Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a Custom Endpoint Behavior with WCF and Autofac

I'm trying to implement a UoW like shown here: https://blog.iannelson.uk/wcf-global-exception-handling/

But I can't for the life of me figure out how to wire it up with Autofac. I have absolutely no idea where to start.

I've got WCF working fine with Autofac from using http://autofac.readthedocs.org/en/latest/integration/wcf.html

But to inject or add the IEndpointBehavior? No idea...

If there's a better way to implement a UoW I would like to hear.

Edit:

For now I've just done:

builder.RegisterType(typeof (UnitOfWork))
    .As(typeof (IUnitOfWork))
    .InstancePerLifetimeScope()
    .OnRelease(x =>
    {
        Trace.WriteLine("Comitted of UoW");
        ((IUnitOfWork) x).Commit();
        // OnRelease inhibits the default Autofac Auto-Dispose behavior so explicitly chain to it
        x.Dispose(); 
    });

Though I don't know if this is an acceptable way of doing it, seems like a hack :(

Edit2:

Doesn't seem like it's possible to run a UoW in WCF :/

Edit 3:

I've posted my solution here: http://www.philliphaydon.com/2011/11/06/unit-of-work-with-wcf-and-autofac/

like image 211
Phill Avatar asked Nov 04 '22 11:11

Phill


1 Answers

I have found a solution to this problem, where the unit of work only will be committed if no errors is thrown.

Register the unit of work as InstancePerLifetimeScope in Autofac

    builder.RegisterType(typeof (UnitOfWork))
    .As(typeof (IUnitOfWork)).InstancePerLifetimeScope();

Then i have created a combined EndpointBehavior and a ErrorHandler.

public class UnitOfWorkEndpointBehavior : BehaviorExtensionElement, IEndpointBehavior
{
    public void Validate(ServiceEndpoint endpoint)
    {
    }

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        var unitOfWorkInstanceHandler = new UnitOfWorkInstanceHandler();

        endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(unitOfWorkInstanceHandler);
        endpointDispatcher.DispatchRuntime.InstanceContextInitializers.Add(unitOfWorkInstanceHandler);
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
    }

    protected override object CreateBehavior()
    {
        return new UnitOfWorkEndpointBehavior();
    }

    public override Type BehaviorType
    {
        get { return typeof (UnitOfWorkEndpointBehavior); }
    }
}



public class UnitOfWorkInstanceHandler : IInstanceContextInitializer, IErrorHandler
{
    private bool _doCommit = true;

    public void Initialize(InstanceContext instanceContext, Message message)
    {
        instanceContext.Closing += CommitUnitOfWork;
    }

    void CommitUnitOfWork(object sender, EventArgs e)
    {
        //Only commit if no error has occured
        if (_doCommit)
        {
            //Resolve the UnitOfWork form scope in Autofac
            OperationContext.Current.InstanceContext.Extensions.Find<AutofacInstanceContext>().Resolve<IUnitOfWork>().Commit();
        }
    }

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
        _doCommit = false;
    }

    public bool HandleError(Exception error)
    {
        _doCommit = false;
        return false;
    }
}

The registration of the Endpoint Behavior in web.config

<system.serviceModel>
    ...
    <extensions>
      <behaviorExtensions>
        <add name="UnitOfWork" type="Namespace.UnitOfWorkBehavior, Namespace"/>
      </behaviorExtensions>
    </extensions>
      <behaviors>
        <endpointBehaviors>
          <behavior name="">
            <UnitOfWork/>
          </behavior>
        </endpointBehaviors>
    ...
    </behaviors>
    ...
</system.serviceModel>
like image 151
fito Avatar answered Nov 15 '22 06:11

fito