mhinze / ShortBus

In-process mediator with low-friction API
MIT License
210 stars 41 forks source link

Example Autofac usage in ASP.NET MVC5 application #41

Closed rebeccapowell closed 9 years ago

rebeccapowell commented 9 years ago

I've had some troubles with StructureMap, so I decided to try Autofac instead:

Global.ascx.cs

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        IoCConfig.RegisterDependencies();
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
}

IoCConfig.cs

public class IoCConfig
{
    public static void RegisterDependencies()
    {
        var builder = new ContainerBuilder();

        builder.RegisterSource(new ContravariantRegistrationSource());
        builder.RegisterAssemblyTypes(typeof(IMediator).Assembly)
            .AsClosedTypesOf(typeof(IQueryHandler<,>))
            .AsImplementedInterfaces();

        //builder.RegisterType<Mediator>().As<IMediator>().InstancePerRequest();

        builder.RegisterType<Mediator>().AsImplementedInterfaces().InstancePerLifetimeScope();

        builder.RegisterType<AutofacDependencyResolver>()
            .AsImplementedInterfaces()
            .InstancePerLifetimeScope();

        builder.RegisterControllers(typeof(MvcApplication).Assembly)
                .InstancePerHttpRequest();
        builder.RegisterAssemblyModules(typeof(MvcApplication).Assembly);
        builder.RegisterModule<AutofacWebTypesModule>();

        var container = builder.Build();
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    }
}

In my controller I then have:

public class HomeController : Controller
{
    private readonly IMediator Mediator;

    public HomeController(IMediator mediator)
    {
        Mediator = mediator;
    }

    public ActionResult Index()
    {
        var result = Mediator.Request(new Framework.Queries.ListCustomers { Name = "test", Skip = 0, Take = 10 });
        return View(result);
    }
}

And the error returned by index is:

None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'ShortBus.Mediator' can be invoked with the available services and parameters:
Cannot resolve parameter 'StructureMap.IContainer container' of constructor 'Void .ctor(StructureMap.IContainer)'.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: Autofac.Core.DependencyResolutionException: None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'ShortBus.Mediator' can be invoked with the available services and parameters:
Cannot resolve parameter 'StructureMap.IContainer container' of constructor 'Void .ctor(StructureMap.IContainer)'.

[DependencyResolutionException: None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'ShortBus.Mediator' can be invoked with the available services and parameters:
Cannot resolve parameter 'StructureMap.IContainer container' of constructor 'Void .ctor(StructureMap.IContainer)'.]
   Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters) +528
   Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters) +109
   Autofac.Core.Resolving.InstanceLookup.<Execute>b__0() +61
   Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func`1 creator) +201
   Autofac.Core.Resolving.InstanceLookup.Execute() +262
   Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters) +282
   Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters) +72
   Autofac.Core.Activators.Reflection.<>c__DisplayClass2.<CanSupplyValue>b__0() +82
   Autofac.Core.Activators.Reflection.ConstructorParameterBinding.Instantiate() +233
   Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters) +563
   Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters) +109
   Autofac.Core.Resolving.InstanceLookup.<Execute>b__0() +61
   Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func`1 creator) +201
   Autofac.Core.Resolving.InstanceLookup.Execute() +262
   Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters) +282
   Autofac.Core.Resolving.ResolveOperation.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters) +60
   Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters) +111
   Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters) +279
   Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance) +175
   Autofac.ResolutionExtensions.ResolveOptionalService(IComponentContext context, Service service, IEnumerable`1 parameters) +242
   Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, Type serviceType, IEnumerable`1 parameters) +72
   Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, Type serviceType) +48
   Autofac.Integration.Mvc.AutofacDependencyResolver.GetService(Type serviceType) +57
   System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +87

[InvalidOperationException: An error occurred when trying to create a controller of type 'Website.Controllers.HomeController'. Make sure that the controller has a parameterless public constructor.]
   System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +247
   System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType) +437
   System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName) +257
   System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory) +326
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +157
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +88
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +50
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +103
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

It appears to be trying to resolve StructureMap.IContainer, but I have set the DependencyResolver to use Autofac.

Does anyone have any ideas on how to solve this? I love the idea of Shortbus, but I'm having a lot of problems getting up and running. Does anyone have an example Github ASP.NET MVC project they can direct me to?

mhinze commented 9 years ago

You should check out MediatR.. ShortBus works fine, but MediatR is actively maintained

rebeccapowell commented 9 years ago

Thanks. I've made the realisation that the Shortbus Nuget package is way out of date with the current source.

I did actually figure this out, if anyone else asks. The IoC config looks likes this:

public static void RegisterDependencies()
{
    IContainer container = BuildContainer();

    // set MVC resolver
    System.Web.Mvc.DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    // set Shortbus resolver! Important :-)
    ShortBus.DependencyResolver.SetResolver(new ShortBus.Autofac.AutofacDependencyResolver(container));
}

public static IContainer BuildContainer()
{
    var builder = new ContainerBuilder();

    // MVC registrations
    builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
    builder.RegisterModelBinderProvider();
    builder.RegisterControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired();
    builder.RegisterFilterProvider();

    builder.RegisterSource(new ContravariantRegistrationSource());

    builder.RegisterAssemblyTypes(typeof(IMediator).Assembly, typeof(IMyHandler).Assembly)
        .AsClosedTypesOf(typeof(IRequestHandler<,>))
        .AsImplementedInterfaces();

    builder.RegisterType<Mediator>().AsImplementedInterfaces().InstancePerLifetimeScope();
    builder.RegisterType<ShortBus.Autofac.AutofacDependencyResolver>()
        .AsImplementedInterfaces()
        .InstancePerLifetimeScope();

    builder.RegisterType<MyDbContext>().As<IMyDbContext>().InstancePerRequest();

    return builder.Build();
}

If was simply that I hadn't twigged that there were two AutofacDependencyResolvers,. one in the Autofac.MVC5 package and one in the Shortbus package. Once that clicked, it all fell into place.

I'll take a look at that other project. Would be nice to have a nuget source instead of a local build.

mhinze commented 9 years ago

You can do install-package shortbus -pre for the latest

On Fri, Jul 3, 2015 at 9:32 AM, Ben Powell notifications@github.com wrote:

Thanks. I've made the realisation that the Shortbus Nuget package is way out of date with the current source.

I did actually figure this out, if anyone else asks. The IoC config looks likes this:

public static void RegisterDependencies() { IContainer container = BuildContainer();

// set MVC resolver
System.Web.Mvc.DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
// set Shortbus resolver! Important :-)
ShortBus.DependencyResolver.SetResolver(new ShortBus.Autofac.AutofacDependencyResolver(container));

}

public static IContainer BuildContainer() { var builder = new ContainerBuilder();

// MVC registrations
builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
builder.RegisterModelBinderProvider();
builder.RegisterControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired();
builder.RegisterFilterProvider();

builder.RegisterSource(new ContravariantRegistrationSource());

builder.RegisterAssemblyTypes(typeof(IMediator).Assembly, typeof(IMyHandler).Assembly)
    .AsClosedTypesOf(typeof(IRequestHandler<,>))
    .AsImplementedInterfaces();

builder.RegisterType<Mediator>().AsImplementedInterfaces().InstancePerLifetimeScope();
builder.RegisterType<ShortBus.Autofac.AutofacDependencyResolver>()
    .AsImplementedInterfaces()
    .InstancePerLifetimeScope();

builder.RegisterType<MyDbContext>().As<IMyDbContext>().InstancePerRequest();

return builder.Build();

}

If was simply that I hadn't twigged that there were two AutofacDependencyResolvers,. one in the Autofac.MVC5 package and one in the Shortbus package. Once that clicked, it all fell into place.

I'll take a look at that other project. Would be nice to have a nuget source instead of a local build.

— Reply to this email directly or view it on GitHub https://github.com/mhinze/ShortBus/issues/41#issuecomment-118364300.