How to avoid service locator in .net extension methods

蹲街弑〆低调 提交于 2021-01-27 05:48:41

问题


I'm looking for a clean pattern to use dependencies in .Net extension methods without explicitly newing-up or using a service locator:

public static class HttpContextExtensions
{
    public static SomeClass ExtensionMethod(this HttpContext context)
    {
        //looking to avoid this
        var dependency = ServiceLocator.GetService<DependencyType>();
        return dependency.DoSomething(context);
    }
}

Am I barking up the wrong tree here? Should I be looking for a more direct solution that passes context into a method? I'd like to continue using an extension if possible.


回答1:


In the book "Dependency Injection in .NET" by Mark Seemann, in chapter 2 he talks about 4 different patterns of injection:

  1. Constructor Injection
  2. Property Injection
  3. Method Injection
  4. Ambient Context

The 4th one, Ambient Context, is a static property, which can be of an abstract type. This property can be set in the DI Root, thread context, call context, request context, etc. .NET Security, Transactions and other stuff like that use this pattern.

Here are links that will give you more details:

  • "The Ambient Context Design Pattern in .NET" by The Wandering Glitch
  • "Ambient Context" by Mark Seemann
  • "The Ambient Context Pattern" by Tim Robert

Here is some sample code:

public interface IOutput
{
    void Print(Person person);
}

public class ConsoleOutput : IOutput
{
    public void Print(Person person)
    {
        Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
    }
}

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public static class SampleContext
{
    public static IOutput Output { get; set; }
}

public static class ExtensionMethods
{
    public static void Print(this Person person)
    {
        SampleContext.Output.Print(person);
    }
}

static class Program
{
    static void Main()
    {
        //You would use your DI framework here
        SampleContext.Output = new ConsoleOutput();

        //Then call the extension method
        var person = new Person()
        {
            FirstName = "Louis-Pierre",
            LastName = "Beaumont"
        };

        person.Print();
    }
}



回答2:


You can't use extension methods for this. Extension methods are static and this means you can't use constructor injection. Only method injection is an option, but this means you have to pass in the dependencies as method arguments and this usually sucks because dependencies should usually be an implementation detail, but method injection makes the dependencies part of the contract, which means the consumer of the extension method should know about these dependencies (and get them injected).

So the solution is: don't use extension methods for anything that has dependencies on its own: write a proper class and abstraction for this.




回答3:


A possible solution would be to instead make the extension method extend the class you're trying to inject and reference that dependency in an upstream context, such as a controller action, or any other non-static entry point that leads to this call.



来源:https://stackoverflow.com/questions/16741876/how-to-avoid-service-locator-in-net-extension-methods

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!