IStringLocalizer with third party DI
I am trying to set up localization following this documentation
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization
I guess if you are using inline DI it just works, but I am using Simple Injector instead of assembling in DI, so it complains that I haven't registered the IStringLocalizer. How do I go about registering the IStringLocalizer as I obviously cannot do this
container.Register<IStringLocalizer, StringLocalizer>(Lifestyle.Scoped);
thank
source to share
To get localization in ASP.NET Core you will have to call AddLocalization()
from your method ConfigureServices
and enable automatic cross-layout:
public void ConfigureServices(IServiceCollection services)
{
// ** Add localization to ASP.NET Core **
services.AddLocalization();
// 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)
{
// ** Enable auto cross-wiring ***
// This call allows Simple Injector to resolve anything from ASP.NET Core.
container.AutoCrossWireAspNetComponents(app);
// Your usual startup stuff here
}
The call services.AddLocalization()
adds the appropriate registrations to the ASP.NET Core config system, but by itself prevents Simple Injector from reaching it. However, Simple Injector v4.1 contains an extension method AutoCrossWireAspNetComponents
that allows the container to look for missing dependencies in the ASP.NET core configuration system.
That's all you need to get things working out, but we can do better ...
Due to limitations in the built-in Core Core.NET container, you are forced to introduce generic abstractions such as ILogger<T>
and IStringLocalizer<T>
where T
will always be the most consuming type. This means that when such a dependency is required in HomeController
, you need to enter ILogger<HomeController>
and IStringLocalizer<HomeController>
. It would be much cleaner, more maintainable, and more secure to be able to introduce abstractions without generating ILogger
and IStringLocalizer
, and let the DI container automatically find the correct generic implementation to implement.
Unfortunately, the built-in DI container does not support this. But most mature DI libraries do support this, as does Simple Injector.
The following registration allows any application component to depend on non-generic IStringLocalizer
and Simple Injector will inject a generic StringLocalizer<T>
where T
it becomes a consuming type, thus still getting a localizer for that particular class.
container.RegisterConditional(
typeof(IStringLocalizer),
c => typeof(StringLocalizer<>).MakeGenericType(c.Consumer.ImplementationType),
Lifestyle.Singleton,
c => true);
With this registration yours HomeController
cannot depend on IStringLocalizer
as shown below:
public class HomeController : Controller
{
private readonly IStringLocalizer localizer;
public HomeController(IStringLocalizer localizer)
{
this.localizer = localizer;
}
}
source to share
I know this is old, but I came across this post looking to do the same, but I took a different approach based on the ILogger registration I was using. So here is what I do to get strongly typed IStringLocalizers in my controllers and services.
Traverse StringLocalizerFactory
container.CrossWire<IStringLocalizerFactory>(app);
Then use RegisterConditional
container.RegisterConditional(
typeof(IStringLocalizer),
c => typeof(StringLocalizer<>).MakeGenericType(c.Consumer.ImplementationType),
Lifestyle.Singleton,
c => true);
And then I can insert a non-original IStringLocalizer into my controllers etc. and it will be of the correct type. For example, if I use the following constructor
public MyController(IStringLocalizer localiser)...
Then the localizer will have the type
IStringLocalizer<MyController>
This is with ASP.NET Core MVC 2 and Simple Injector 4.1. I wonder if steven has a comment on this approach?
source to share