在StartUp中使用Autofac解决每用户/每请求的依赖性

时间:2016-09-26 08:26:24

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

我试图解决ASP.Net WebApi 2项目的StartUp类中的依赖项。 Autofac用于配置依赖注入。方案如下:

  • 不同的用户会看到不同的数据。每个用户都拥有某些权限,允许该用户查看某些数据。
  • 正在使用包含多个边界的域驱动架构。不允许在域和数据访问层中进行跨境调用。这很重要,因为为了获取用户所允许数据的所有代码,我们需要进行一些跨境调用。
  • 我们想要过滤数据访问层内的数据,只检索每个用户的允许数据。这里不允许跨境通话。
  • 为了达到这个目的,我想从用户可以看到的记录中注入所有代码的列表。
  • 为此,我尝试使用Autofac注册工厂,该工厂根据用户创建此列表。我们将工厂称为StuffFactory,将列表称为StuffModel

现在的问题是所有这些都需要注册为InstancePerRequest。抛出一个InvalidOperatonException,这听起来很合理,因为StartUp无法访问请求生命周期范围?

  

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

允许的东西在容器中注册的代码:

private IContainer RegisterAllowedStuff(IContainer container)
{
    var builder = new ContainerBuilder();

    builder.Register(x => GetAllowedStuffForUser(container))
        .As<StuffModel>()
        .InstancePerRequest();

    builder.Update(container);
    return container;
}

private static StuffModel GetAllowedStuffForUser(IContainer container)
{
    var stuffFactory = container.Resolve<IStuffFactory>();
    return stuffFactory.CreateStuffModel(Helper.GetParsedUserName());
}

我有点被困在如何从这里前进。对于我完全监督的Autofac问题,是否有一个简单的解决方案?有人可能更清楚我是如何实现这一点的吗?提前谢谢!

2 个答案:

答案 0 :(得分:6)

您的启动类中不应该有任何业务逻辑。 Autofac 允许您注册将在解析时调用的lambda方法。目前,HttpRequest可用,因此您可以将这些lambda注册为InstancePerRequest

在您的情况下,如果您想将StuffModel注册为InstancePerRequest,您可以这样做:

builder.RegisterType<ConcreteStuffFactory>()
       .As<IStuffFactory>();
builder.Register(c => c.Resolve<IStuffFactory>()
                       .CreateStuffModel(Helper.GetParsedUserName()))
       .As<IStuffModel>()
       .InstancePerRequest();

顺便说一下,我也没有使用看起来像反模式的Helper类,你可以创建一个服务来获取当前用户的用户名,例如IUserContextProvider。您还可以在IUserContextProvider

上添加ConcreteStuffFactory依赖项
public class ConcreteStuffFactory
{
    public ConcreteStuffFactory(IUserContextProvider userContextProvider)
    {
         this._userContextProvider = userContextProvider; 
    }

    private readonly IUserContextProvider _userContextProvider; 


    public IStuffModel CreateStuffModel()
    {
        String userName = this._userContextProvider.UserName; 
        // do things with userName
    }
}

和注册:

builder.RegisterType<ConcreteStuffFactory>()
       .As<IStuffFactory>();
builder.RegisterType<HttpContextUserContextProvider>()
       .As<IUserContextProvider>()
       .InstancePerRequest();
builder.Register(c => c.Resolve<IStuffFactory>().CreateStuffModel())
       .As<IStuffModel>()
       .InstancePerRequest();

答案 1 :(得分:0)

在我看来,您提供的异常文本解释了您的代码无法运行的原因。

对我而言,听起来非常明显,无法访问Startup方法中的每个请求实例,该方法本身仅在应用程序的生命周期内被调用一次。

我会考虑将您的代码移动到可以基于每个请求调用的位置。你是否想过写一个custom action filter