autoface -如何从Singleton中解析issomething的函数,其中issomething是Instan



我试图使用autofacc注入依赖到一个MVC 4应用程序中的FluentValidation。我想我已经制定了策略,但我被卡在解决我的每请求issomething从一个单例。

场景如下:我有一个派生自FluentValidation的AbstractValidator的验证器。我读到过FluentValidation验证器作为单例执行得最好,所以我的构造函数需要一个Func并存储该Factory以供以后使用。当使用验证器时,它应该向存储工厂请求IDataStore,获取为该请求创建的实例并使用它。这就是理论。我要感谢https://github.com/robdmoore/UnobtrusiveMVCTechniques,它帮助我找到了这个解决方案。这是验证器…

public class SiteAdminViewModelValidator : AbstractValidator<SiteAdminViewModel> {
    private readonly Func<IDataStore> _dbFactory;
    public SiteAdminViewModelValidator(Func<IDataStore> dbFactory) {
        _dbFactory = dbFactory;
        RuleFor(model => model.SiteCode).Length(1, 40).Must(BeSpecial);
    }
    public bool BeSpecial(string siteCode) {
        var db = _dbFactory();
        List<Stuff> stuffs = db.All<Stuff>().ToList();
        return true;
    }
}

如果有人能给我指一个我正在努力完成的工作示例,那就太好了,但我也想知道解决autofacc这个特殊问题的方法。

这是我的验证器注册…

public class FluentValidatorModule : Module {
    protected override void Load(ContainerBuilder builder) {
        base.Load(builder);
        builder.RegisterType<AutofacValidatorFactory>().As<IValidatorFactory>().SingleInstance();
    var validators = AssemblyScanner.FindValidatorsInAssembly(System.Reflection.Assembly.GetExecutingAssembly());
    validators.ToList().ForEach(v => builder.RegisterType(v.ValidatorType).As(v.InterfaceType).SingleInstance());
    }
}

这是我注册的IDataStore工厂…

builder.RegisterType<SuperDB>().As<IDataStore>().InstancePerHttpRequest();
builder.Register<Func<IDataStore>>(c => {
                                       var context = c.Resolve<IComponentContext>();
                                       return context.Resolve<IDataStore>;
                                   });

这是我得到的错误,当我的验证器要求一个IDataStore在线-var db = _dbFactory();

标签匹配'AutofacWebRequest'的作用域在请求实例所在的范围。这通常表明一个按http请求注册的组件正在被请求SingleInstance()组件(或类似的场景)。在网上集成总是从DependencyResolver。当前或ILifetimeScopeProvider。RequestLifetime,

…这正是我在编写自己的工厂注册- Func注册之前尝试时得到的结果。从阅读对类似问题的各种答案来看,看起来我上面的内容应该可以工作,因为我认为我现在正在解析Func以获得当前解析器。

我同意这应该工作- Func<IDataStore>定义了一个工厂,将根据需要在每个方法中产生依赖项。

我绕过这个方法的方法是使用DependencyResolver.Current,如错误消息所建议的。主要原因是我已经用Autofac设置好了。Mvc4 nuget包…

DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

要设置这个方法,我输入下面的func

public Func<T> PerHttpSafeResolve<T>()
{
    return () => DependencyResolver.Current.GetService<T>();
} 

构造容器

builder.RegisterType<SuperDB>().As<IDataStore>().InstancePerHttpRequest();
builder.RegisterInstance(PerHttpSafeResolve<IDataStore>());

编辑:注册实例的第二行是说-如果你需要一个Func<IDataStore>,然后使用传递到方法的值。PerHttpSafeResolve<IDataStore>的结果只是一个函数(工厂),因此它可以作为单个实例存在。

问题在于验证器的作用域。autofacc总是从应用程序容器中解析SingleInstance依赖项,这意味着验证器的依赖项也来自应用程序容器。

Autofac从那里的请求Func<IDataStore>实例,而不是从请求容器。当您解析IComponentContext时,您将获得验证器被解析的容器:应用程序容器。由于Func<IDataStore>的作用域是一个请求,autofacc无法在应用程序级别提供它,因此出现了错误。

正确的方法是将验证器注册为InstancePerHttpRequest。组件的生命周期由其最长的依赖项决定;当验证器没有依赖关系时,它们作为单例器工作得最好。但是,在这种情况下,依赖于IDataStore的验证器被限制最多只能存活IDataStore实例的生命周期。(好的一面是,你可以摆脱Func。)

把它想象成去参加一个聚会:如果你搭了主人的车,你必须呆在那里直到聚会结束。如果你想早点离开,你就不能和主人一起坐车。

最新更新