Reputation: 12424
In the startup.cs we have this:
public void ConfigureServices(IServiceCollection services)
{
services.AddLocalization(options => options.ResourcesPath = "Resources");
}
And so our Index Razor page can have this:
public IndexModel(IStringLocalizer<Strings> localizer) {
I want to wrap the localizer
in another class and replace it's presence in the IoC container with a singleton of the wrapper.
The problem is that it does not appear possible to retrieve or remove entries from the container while in the COnfigureServices
method.
Essentially, I want to replace the registered instance provided by the AddLocalization
call so that I don't need to replace every instance of the wrapper class's injection in the solution.
Is this possible?
Upvotes: 1
Views: 4446
Reputation: 808
You can solve this problem with Decorator pattern.
First of all configure the services so that you can access the StringLocalizer<>
directly. This is for the MyLocalizer<>
class, because it needs a direct instance of StringLocalizer<>
type, not the interface (IStringLocalizer<>
). If you don't register it MyLocalizer<>
would not get resolved.
services.AddTransient(typeof(StringLocalizer<>));
Then register the decorator (the dependency that you want to be replaced). Note that I assumed AddLocalization()
is called before this line of code. This is the rule of the DI container; it always resolves the last registered type. So, after this line of code all dependents of IStringLocalizer<>
will get MyLocalizer<>
instead of the standard StringLocalizer<>
.
// be careful about using Singleton scope
services.AddSingleton(typeof(IStringLocalizer<>), typeof(MyLocalizer<>));
Decorator Implementation:
Decorator pattern allows you to add extra features to an existing object. Suppose the IStringLocalizer<T>
object returns a simple string that I need to just make it upper-case.
public class MyLocalizer<T> : IStringLocalizer<T>
{
public MyLocalizer(StringLocalizer<T> original)
{
_original = original;
}
private readonly StringLocalizer<T> _original;
// the decorator behavior is the same for all other methods.
// But for this particular method it adds a little feature to the original one! Beautiful :)
public LocalizedString this[string name] =>
new LocalizedString(name, _original[name].Value.ToUpper());
public LocalizedString this[string name, params object[] arguments] =>
_original[name, arguments];
public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures) =>
_original.GetAllStrings(includeParentCultures);
public IStringLocalizer WithCulture(CultureInfo culture) =>
_original.WithCulture(culture);
}
Now, nothing in your dependent classes will change. They just use MyLocalizer<T>
instead of MVC's StingLocalizer<T>
.
Wish that helps!
Upvotes: 4