Domain Services - DomainService Factory

May 28, 2010 at 2:30 PM

I've found an issue when using a custom domain service factory while using the MvcExtensions.  If I call a boot strapper at application_start everything is fine.  But when I flip to using a StructureMapMvcApplication, the DomainService factory fails.

I couldn't nail down the issue exactly, but basically I used something like:

using System;
using System.ServiceModel.DomainServices.Server;
using StructureMap;

namespace Udm.Infrastructure.IoC
{
    public class StructureMapDomainServiceFactory : IDomainServiceFactory
    {
        #region IDomainServiceFactory Members

        public DomainService CreateDomainService(Type domainServiceType, DomainServiceContext context)
        {
            var service = ObjectFactory.GetInstance(domainServiceType) as DomainService;
            if (service != null)
                service.Initialize(context);
            return service;
        }

        public void ReleaseDomainService(DomainService domainService)
        {
            domainService.Dispose();
        }

        #endregion
    }
}

Whenever ObjectFactory.GetInstance(domainServiceType) was called, the method would fail due to one of the constructors not being present in the container.  I set break points, and the registry was being called when the Mvc application started, but it wasn't being called if the domain service was hit directly.  The application_start does fire if you hit the domain service directly though, therefore calling the Bootstrapper directly works, but using the StructureMapMvcApplication does not.  Hope that's descriptive enough.

Coordinator
May 28, 2010 at 2:59 PM

Would you Please post some code of the SM Registry, so that I can see how the DomainServiceFactory and DomainService is mapped.

Coordinator
May 28, 2010 at 3:43 PM

Ok I just played with the DomainService and I think the following would solve the Issue:

Lets assume that your custom DomainService has some dependency, over here I am just passing a single dependency:

 

public class CustomDomainService : DomainService
{
    private IRepository repository;

    public CustomDomainService(IRepository repository)
    {
        this.repository = repository;
    }
}

 


Next, we will create the custom domain service factory

 

public class CustomDomainServiceFactory : IDomainServiceFactory
{
    private readonly IContainer container;

    public CustomDomainServiceFactory(IContainer container)
    {
        this.container = container;
    }

    public DomainService CreateDomainService(Type domainServiceType, DomainServiceContext context)
    {
        DomainService service = (DomainService) container.GetInstance(domainServiceType);

        service.Initialize(context);

        return service;
    }

    public void ReleaseDomainService(DomainService domainService)
    {
        domainService.Dispose();
    }
}

Check that we are passing the SM Container in the ctor instead of the ObjectFactory.

 

Next, we will create the SM Registry:

    public class CustomServiceRegistrty : Registry
    {
        public CustomServiceRegistrty()
        {
            For<IRepository>().Use<Repository>();
            For<DomainService>().Use<CustomDomainService>();
            For<IDomainServiceFactory>().Singleton().Use<CustomDomainServiceFactory>();
        }
    }

And at last we have to tell the DomainService which factory it would use, in this case we will create a custom BootstrapperTask:

public class RegisterDomainServiceFactory : BootstrapperTask
{
    protected override TaskContinuation ExecuteCore(IServiceLocator serviceLocator)
    {
        DomainService.Factory = serviceLocator.GetInstance<IDomainServiceFactory>();

        return TaskContinuation.Continue;
    }
}

 


And this is the global.asax:

public class MvcApplication : StructureMapMvcApplication
{
}

And that's it.

Do let me know if you find any issue.

Jul 12, 2010 at 1:17 PM

Sorry for the late late late reply, but my priorities have shifted and I'm just now revisiting this.   I wanted to reply back to let you know of only one difference.   I do like the idea of passing in the IContainer into the  DomainServiceRegistry, that worked great.  But my SM Registry does not include the line:

For<DomainService>().Use<CustomDomainService>();

There isn't a need for it.

Everything else works very well, it's almost exactly the code I had to begin with, minus the passing in of the IContainer, and adding the DomainServiceRegistry to my SM registry.   (Had it in a boostrapper task, but was instantiating it manually)

Thanks again, this library is a huge help.