ASP.NET Core DependencyResolver
Asked Answered
C

7

26

In ASP.NET MVC 5 is possible to obtain some dependency through DependencyResolver.Current.GetService<T>(). Is there something similar in ASP.NET Core?

Cherice answered 14/6, 2016 at 13:38 Comment(3)
The DependencyResolver.Current has been replaced with the IServiceProvider abstraction.Womanly
OK. But is there something like ServiceProvider.Current.GetService<T>()? I want to be able to obtain a service without the need to inject it.Cherice
There isn't, and that's actually a good thing. What you are trying to do is a bad practice.Womanly
D
25

Yes, there is. In ASP.NET Core 1.0.0, the services available within a request from HttpContext are exposed through the RequestServices collection[1]:

this.HttpContext.RequestServices

You can use the GetService method to retrieve the dependencies by specifying the type of the dependency:

this.HttpContext.RequestServices.GetService(typeof(ISomeService));

Generally, you shouldn’t use these properties directly, preferring instead to request the types your classes you require via your class’s constructor, and letting the framework inject these dependencies. This yields classes that are easier to test and are more loosely coupled.

[1] https://docs.asp.net/en/latest/fundamentals/dependency-injection.html#request-services

Desmonddesmoulins answered 15/7, 2016 at 9:3 Comment(2)
It was removed in RC2 github.com/aspnet/Announcements/issues/118Ankara
Correct, it was made available on ASP.NET Core 1.0.0. I should have mentioned the version in the reply to make it clearer. Thank you for pointing it out.Desmonddesmoulins
S
15

If you really need it, you can write own one. First - create AppDependencyResolver class.

public class AppDependencyResolver
{
    private static AppDependencyResolver _resolver;

    public static AppDependencyResolver Current
    {
        get
        {
            if (_resolver == null)
                throw new Exception("AppDependencyResolver not initialized. You should initialize it in Startup class");
            return _resolver;
        }
    }

    public static void Init(IServiceProvider services)
    {
        _resolver = new AppDependencyResolver(services);
    }

    private readonly IServiceProvider _serviceProvider;

    public object GetService(Type serviceType)
    {
        return _serviceProvider.GetService(serviceType);
    }

    public T GetService<T>()
    {
        return _serviceProvider.GetService<T>();
    }

    private AppDependencyResolver(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }
} 

Please note that _serviceProvider.GetService<T>(); only available if you add using Microsoft.Extensions.DependencyInjection;. That namespace will be available if you add "Microsoft.Extensions.DependencyInjection": "1.0.0" to your project.json. Than you should call Init method in your startup class. For example

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        AppDependencyResolver.Init(app.ApplicationServices);
        //all other code

After that you can use it anywhere, same as DependencyResolver.Current. But my suggestion - use it only if no other choice left.

Sholom answered 26/9, 2016 at 13:48 Comment(3)
One of the major things about Dependency injection is avoid using static (singleton) instances.Sikorski
As I said, use it only if no other choice left. If you can inject it in controller or filter - it is better choise. If you need some background task it is better to create new scope and use it to resolve dependency. But sometimes in legacy code you need to resolve some singeleton service and you have no time to rewrite such code - this method may be used.Sholom
"If you really need it" -- how are you mocking tests that might require DI without it?Stagnant
F
8

Here is the way that worked for me in .Net core 2.0

public ViewResult IndexWithServiceLocatorPattern([FromServices]ProductTotalizer totalizer)
{
    var repository = (IRepository)HttpContext.RequestServices.GetService(typeof(IRepository));
    ViewBag.HomeController = repository.ToString();
    ViewBag.Totalizer = totalizer.repository.ToString();
    return View("Index", repository.Products);
}

If I have to do it with classical way, It would be like below.

public class HomeController : Controller
{
    private readonly IRepository repo;

    /// <summary>
    /// MVC receives an incoming request to an action method on the Home controller. 
    /// MVC asks the ASP.NET service provider component for a new instance of the HomeController class.
    /// The service provider inspects the HomeController constructor and discovers that it has a dependency on the IRepository interface. 
    /// The service provider consults its mappings to find the implementation class it has been told to use for dependencies on the IRepository interface. 
    /// The service provider creates a new instance of the implementation class. 
    /// The service provider creates a new HomeController object, using the implementation object as a constructor argument.
    /// The service provider returns the newly created HomeController object to MVC, which uses it to handle the incoming HTTP request.
    /// </summary>
    /// <param name="repo"></param>
    public HomeController(IRepository repo)
    {
        this.repo = repo;
    }

    /// <summary>
    ///  Using Action Injection
    ///  MVC uses the service provider to get an instance of the ProductTotalizer class and provides it as an
    ///  argument when the Index action method is invoked.Using action injection is less common than standard
    ///  constructor injection, but it can be useful when you have a dependency on an object that is expensive to
    ///  create and that is required in only one of the action methods defined by a controller
    /// </summary>
    /// <param name="totalizer"></param>
    /// <returns></returns>
    public ViewResult Index([FromServices]ProductTotalizer totalizer)
    {
        ViewBag.Total = totalizer.repository.ToString();
        ViewBag.HomeCotroller = repo.ToString();
        return View(repo.Products);
    }
}
Floatation answered 16/4, 2018 at 13:38 Comment(0)
I
4

Service available in Asp.net core, its within HttpContext

this.HttpContext.RequestServices

By using this service, it is possible to get service. and also you can use GetService method to retrieve the dependencies by specifying the type of the dependency:

this.HttpContext.RequestServices.GetService(typeof(ISomeService));
Illyria answered 7/11, 2016 at 18:9 Comment(0)
A
2

There are extension methods for IServiceProvider: GetService, GetRequiredService and GetServices. All have generic and non-generic versions. In Asp.Net Core web project you can obtain reference to IServiceProvider via DI or from IApplicationBuilder. In Console app you should create your own instance of IServiceProvider and store reference somewhere

var services = new ServiceCollection();
...
ServiceProvider = services.BuildServiceProvider();
Ankara answered 15/7, 2016 at 17:44 Comment(0)
D
0

I think this could be a good start:

That's official documentation for dependency injection for asp.net 5.

Dependency injection is now built into asp.net 5 but you are free to use other libraries like autofac. The default one is working fine for me.

In your starup class, you have a method like this

public void ConfigureServices(IServiceCollection services)
{

    //IServiceCollection acts like a container and you 
    //can register your classes like this:

    services.AddTransient<IEmailSender, AuthMessageSender>();
    services.Singleton<ISmsSender, AuthMessageSender>();
    services.AddScoped<ICharacterRepository, CharacterRepository>();

}

From:

DependencyResolver Asp.net 5.0

Dowdell answered 14/6, 2016 at 13:44 Comment(0)
E
0

I also want to add to the main answer, In razor view pages we can use @inject directive for DI. It will retrieve the targeted services to view pages on Asp.Net core, like this

@inject XYZ.Web.Services.CurrencyService currencyService;
Etui answered 5/5, 2020 at 21:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.