带有第三方 DI 的 IStringLocalizer

IStringLocalizer with third party DI

我正在尝试按照此文档设置本地化

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization

我假设如果您使用内置 DI,它就可以正常工作,但是我使用的是 Simple Injector 而不是内置 DI,所以它抱怨我没有注册 IStringLocalizer。我该如何注册 IStringLocalizer,因为我显然不能这样做

container.Register<IStringLocalizer, StringLocalizer>(Lifestyle.Scoped);

谢谢

要在 ASP.NET Core 中进行本地化,您必须从 ConfigureServices 方法中调用 AddLocalization() 并启用 自动交叉连接:

public void ConfigureServices(IServiceCollection services) {

    services.AddLocalization(); // ** Add localization to ASP.NET Core **

    // Normal MVC stuff
    services.AddMvc();

    // Simple Injector integration
    IntegrationSimpleInjector(services);
}

private void IntegrationSimpleInjector(IServiceCollection services) {
    container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

    services.AddSingleton<IControllerActivator>(
        new SimpleInjectorControllerActivator(container));

    services.EnableSimpleInjectorCrossWiring(container);
    services.UseSimpleInjectorAspNetRequestScoping(container);
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env) {

    // This call allows Simple Injector to resolve anything from ASP.NET Core.
    container.AutoCrossWireAspNetComponents(app); // ** Enable auto cross-wiring ***

    // NOTE: If you're still running .NET Core v1.x, auto cross-wiring will not be
    // available. In that case, you can make the following call to CrossWire<T>
    // to register StringLocalizer<T>'s dependency explicitly.
    // container.CrossWire<IStringLocalizerFactory>(app);

    // Your usual startup stuff here
}

services.AddLocalization() 的调用添加了对 ASP.NET 核心配置系统的适当注册,但它本身并不允许 Simple Injector 访问它。然而,Simple Injector v4.1 包含一个 AutoCrossWireAspNetComponents 扩展方法,允许容器在 ASP.NET 核心配置系统中寻找缺失的依赖项。

这就是你需要的一切,运行,但我们可以做得更好...

由于内置 ASP.NET 核心 DI 容器的限制,您被迫注入通用抽象,例如 ILogger<T>IStringLocalizer<T>,其中 T总是 是消费类型本身。这意味着当 HomeController 中需要这种依赖时,你需要注入一个 ILogger<HomeController>IStringLocalizer<HomeController>。能够注入非泛型 ILoggerIStringLocalizer 抽象,并让 DI 容器自动找到正确的泛型实现来实现,这将更加清洁、更易于维护和更安全。

不幸的是,内置的 DI 容器支持这个。但是大多数成熟的 DI 库实际上 确实 支持这一点,Simple Injector 也是如此。

以下注册,允许任何应用程序组件依赖于非泛型 IStringLocalizer 并且 Simple Injector 将注入泛型 StringLocalizer<T>,其中 T 成为消费类型,因此仍然获取 那个特定 class.

的定位器
container.RegisterConditional(
    typeof(IStringLocalizer),
    c => typeof(StringLocalizer<>).MakeGenericType(c.Consumer.ImplementationType),
    Lifestyle.Singleton,
    c => true);

通过此注册,您的 HomeController 将不再依赖 IStringLocalizer,如下所示:

public class HomeController : Controller
{
    private readonly IStringLocalizer localizer;

    public HomeController(IStringLocalizer localizer)
    {
        this.localizer = localizer;
    }
}

我知道这是旧的,但我遇到了这个 post 想做同样的事情,但我根据我使用的 ILogger 注册采取了不同的方法。所以这就是我在我的控制器和服务中获得强类型 IStringLocalizers 的方法。

Cross-wire StringLocalizerFactory

container.CrossWire<IStringLocalizerFactory>(app);

然后使用RegisterConditional

container.RegisterConditional(
    typeof(IStringLocalizer),
    c => typeof(StringLocalizer<>).MakeGenericType(c.Consumer.ImplementationType),
    Lifestyle.Singleton,
    c => true);

然后我可以将 non-generic IStringLocalizer 注入我的控制器等,它将是正确的类型。例如,如果我使用以下构造函数

public MyController(IStringLocalizer localiser)...

那么 localiser 的类型将是

IStringLocalizer<MyController>

这是 ASP.NET Core MVC 2 & Simple Injector 4.1。不知steven对这种做法有何评论?