Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid service locator in .net extension methods

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.

like image 215
Eric Avatar asked May 24 '13 18:05

Eric


People also ask

What's the difference between the dependency injection and service locator patterns?

The main difference is how the dependencies are located, in Service Locator, client code request the dependencies, in DI Container we use a container to create all of objects and it injects dependency as constructor parameters (or properties). Dependency Injection doesn't require the use of a DI Container though.

Why Service Locator is an anti pattern?

Service Locator is a dangerous pattern because it almost works. You can locate Dependencies from consuming classes, and you can replace those Dependencies with different implementations — even with Test Doubles from unit tests.

How does DI work in .NET core?

ASP.NET Core supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies. For more information specific to dependency injection within MVC controllers, see Dependency injection into controllers in ASP.NET Core.


1 Answers

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();
    }
}
like image 197
Loupi Avatar answered Sep 21 '22 13:09

Loupi