如何重用InstancePerRequest实例使用Autofac在组合根中创建

时间:2016-01-30 02:00:01

标签: c# asp.net-mvc dependency-injection autofac

我有一个Asp.NET MVC5应用程序,我用这种方式在Startup类中使用Autofac注册我的类型:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        IContainer container = null;
        var builder = new ContainerBuilder();

        // Register Services
        builder.RegisterType<SalesRepository>().As<ISalesRepository>().InstancePerRequest();
        builder.RegisterType<SalesService>().As<ISalesService>().InstancePerRequest();
        builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
           .AsClosedTypesOf(typeof(IHandle<>))
           .AsImplementedInterfaces()
           .InstancePerRequest();
        builder.Register<IAppEvents>(_ => new AppEvents(container)).InstancePerRequest();

        // Register MVC Controllers
        builder.RegisterControllers(Assembly.GetExecutingAssembly());

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

        app.UseAutofacMiddleware(container);
        app.UseAutofacMvc();
    }
}

这些是我的服务(这是一个简化的场景,仅用于演示)。 SalesService类接收ISalesRepository接口作为依赖项。另外我有一个AppEvents类,我想解决IHandle类型:

public interface ISalesRepository { }
public class SalesRepository : ISalesRepository
{
    public SalesRepository() { }
}

public interface ISalesService { }
public class SalesService : ISalesService
{
    ISalesRepository _repo;
    public SalesService(ISalesRepository repo)
    {
        _repo = repo;
    }
}

public interface IHandle<T>
{
    void Handle();
}

public class SalesActionHandle : IHandle<string>
{
    ISalesRepository _repo;
    public SalesActionHandle(ISalesRepository repo)
    {
        _repo = repo;
    }

    public void Handle() { }
}

public interface IAppEvents
{
    void Raise<T>();
}

public class AppEvents : IAppEvents
{
    private readonly IContainer _container;

    public AppEvents(IContainer container)
    {
        if (container == null)
            throw new ArgumentNullException("container");
        _container = container;
    }

    public void Raise<T>()
    {
        var handlers = _container.Resolve<IEnumerable<IHandle<T>>>(); // Runtime error here
        foreach (var handler in handlers)
            handler.Handle();
    }
}

这是我唯一的(简化)控制器:

public class HomeController : Controller
{
    ISalesService _service;
    IAppEvents _events;

    public HomeController(ISalesService service, IAppEvents events)
    {
        _service = service;
        _events= events;
    }

    public ActionResult Index()
    {
        _events.Raise<string>();
        return View();
    }
}

我遇到的问题是,执行该行时会出现错误:

var handlers = _container.Resolve<IEnumerable<IHandle<T>>>();
  

没有标记匹配的范围&#39; AutofacWebRequest&#39;从请求实例的范围中可见。这通常表示SingleInstance()组件(或类似场景)正在请求注册为每HTTP请求的组件。在Web集成下,始终从DependencyResolver.Current或ILifetimeScopeProvider.RequestLifetime请求依赖项,从不从容器本身请求

我通过这样做来解决它:

public void Raise<T>()
{
    using (var scope = _container.BeginLifetimeScope("AutofacWebRequest"))
    {
        var handlers = scope.Resolve<IEnumerable<IHandle<T>>>();
        foreach (var handler in handlers)
            handler.Handle();
    }
}

但在这种情况下,当解决IHandle(使用SalesActionHandle实例)时,SalesRepository的新实例将作为SalesActionHandle构造函数中的参数传递。我想要的是&#34;重用&#34; SalesService正在使用的相同实例(它是在解析ISalesService时创建的。我希望请求具有相同的SalesRepository实例)

有没有办法实现这种行为? 示例代码可在Github中使用:https://github.com/josmonver/AutofacTest

1 个答案:

答案 0 :(得分:1)

您可能想要使用     AutofacDependencyResolver.Current.RequestLifetimeScope 匹配您当前的请求范围,但不创建新的请求范围。