15

我正在尝试使用 Autofac 将依赖项注入到 MVC 4 应用程序中的 FluentValidation 中。我想我已经制定了策略,但是我一直无法解决我的单例请求 ISomething。

这是场景:我有一个从 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;
    }
}

如果有人可以为我指出我正在尝试完成的工作示例,那就太好了,但我也想知道解决这个特殊的 Autofac 技巧的方法。

这是我的验证人注册...

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”匹配的标记的范围。这通常表明注册为 per-HTTP 请求的组件正在由 SingleInstance() 组件(或类似场景)请求。在 Web 集成下,始终从 DependencyResolver.Current 或 ILifetimeScopeProvider.RequestLifetime 请求依赖项,而不是从容器本身.

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

任何帮助将不胜感激。

4

2 回答 2

18

我同意这应该可行 -Func<IDataStore>正在定义一个工厂,它将根据需要在每种方法中产生依赖关系。

我解决此方法的方法是使用DependencyResolver.Current错误消息建议的方法。主要原因是我已经使用 Autofac.Mvc4 nuget 包进行了设置...

DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

所以要实际设置方法,我有以下功能

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

并且在构建容器时

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

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

于 2013-03-21T08:18:53.080 回答
9

问题是验证器的范围。Autofac 总是SingleInstance从应用程序容器中解析依赖关系,这意味着验证器的依赖关系也来自应用程序容器。

Autofac 是从那里Func<IDataStore>请求实例,而不是从请求容器。当您解析时,您将获得正在解析验证器的容器:应用程序容器。由于范围仅限于请求,Autofac 无法在应用程序级别提供它,因此会出现错误。IComponentContextFunc<IDataStore>

正确的方法是将验证器注册为InstancePerHttpRequest. 组件的生命周期取决于其最长生命周期的依赖关系;当验证器没有依赖关系时,它们作为单例的效果最好。但是,在这种情况下,依赖的验证器IDataStore最多只能在 IDataStore实例的生命周期内存活。(从好的方面来说,你可以摆脱Func.)

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

于 2013-03-21T04:49:50.297 回答