Hosting WCF service in Orchard + AutoFac IoC

Developer
Jan 9, 2011 at 10:05 PM
Edited Jan 9, 2011 at 10:09 PM

Hi!

What is the best way to host WCF service inside custom module using underlying IoC controller? I want to inject some object into service constructor and don't really know how to make it work without altering the OrchardStarter.CreateHostContainer method.

Normally, I'd register service factory (or the service itself) in AutoFac container, but it involves changes in CreateHostContainer. Take a look at this: http://code.google.com/p/autofac/wiki/WcfIntegration

I thought about being able to add/remove those registrations to the container in module Enable/Disable event. Unfortunately, it seems like there is no object exposing underlying container I could inject into my module bootstrapper:// Maybe I'm just missing something? Is it possible to modify underlying IoC container from custom modules (add/remove registrations and so on) at all?

Cheers, Piotr

Developer
Jan 11, 2011 at 5:30 PM

Maybe I should rephrase question in more generic way:) Is it possible to modify AutoFac registrations from custom modules (eg. during module lifetime events)?

- Piotr

Jan 11, 2011 at 8:20 PM
Edited Jan 11, 2011 at 8:37 PM

For me it is also interesting if there is any standard way of doing this. While writing custom Account Management Module we've found following way of doing this:

    //orchard will register this module automatically
    public class OurMegaAuthenticationModule2 : Module
    {
        protected override void Load(ContainerBuilder builder)
        {

            //registering service you are going to inject
            builder.RegisterType<CommunityFormsAuthenticationService>();
        }
        protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
        {            
            // inject IAuthenticationService serivce
            //this code will replace IAuthenticationService with our own realization
            if (NeedsComponent(registration, typeof(IAuthenticationService)))
            {
                registration.Preparing += (sender, e) =>
                {
                    var parameter = new TypedParameter(
                        typeof(IAuthenticationService), e.Context.Resolve<CommunityFormsAuthenticationService>());
                    e.Parameters = e.Parameters.Concat(new[] { parameter });
                };
            }
        }         
       
        protected virtual bool NeedsComponent(IComponentRegistration registration, Type componentType)
        {
            return registration.Activator.LimitType.GetConstructors()
                .Any(x => x.GetParameters()
                    .Any(xx => xx.ParameterType == componentType));
        }
    }

Sorry, code higlightning doest work :(

Developer
Jan 11, 2011 at 8:28 PM

Cool, thanks, I'll try this.

It seems like there's a possibility to use ContainerBuilder in custom modules - if it works, as you said, WCF services can be registered as shown in AutoFac wiki (only needs to reference AutoFac's WcfIntegration dll).

- Piotr

Jan 11, 2011 at 8:42 PM

You are right. You can use in the method above:

protected override void Load(ContainerBuilder builder)
{
     //your autofac wcf integration registrations
 }

And that's all, it will work like a charm =)

Developer
Jan 12, 2011 at 9:38 AM

I almost got it working. The only problem is registering WCF services in AutoFac needs also setting AutoFacServiceHostFactory.Container to the current container.

Normally, you'd just add your registrations to the builder, and call AutoFacServiceHostFactory.Container = builder.Build(). When i do call builder.Build in my Module.Load method, Orchard throws lots of errors. I assume that building container at this moment prevents further builder modifications in other parts of a system (eg. adding type registrations).

So the question is - how to access the current instance of AutoFac.IContainer that Orchard is using? ContainerBuilder seems to be the only thing available in Module.Load method, but it lacks any reference to the current IContainer (besides the Build() method).

Guys, maybe the AutoFacServiceHostFactory should be setup at the Orchard startup (AFAIK GetHostContainer method in OrchardStarter)? It would make adding WCF services as easy as implementing IDependency + adding appropriate service routes...

- Piotr