Matt W
Matt W

Reputation: 12424

How to replace a dependency in ASP.NET core?

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

Answers (1)

Ali Doustkani
Ali Doustkani

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

Related Questions