Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency Injection in abstract class, ASP.NET Core

In my ASP.NET Core 2 project, I create new class that inherits the RazorPage class to add some additional property in views.

public abstract class WebViewPage<TModel> : Microsoft.AspNetCore.Mvc.Razor.RazorPage<TModel>
{
    public string Version
    {
        get
        {
            return "1.00.100";
        }
    }
    public User CurrentUser
    {
        get
        {
            //challenge is here:
            //return _services.GetRequiredService<IUserService>().GetCurrentUser();
        }
    }
}

public abstract class WebViewPage : WebViewPage<dynamic>
{

}

and _ViewImport.cshtml file changed to this:

@inherits MyProject.WebViewPage<TModel>
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

The project works fine till challenge codes are marked as comment. but, how can I inject dependencies to the abstract class? or how to Resolve services in abstract class?

This is my StartUp.cs file:

public void ConfigureServices(IServiceCollection services)
{
        services.AddMemoryCache();
        services.AddMvc();
        services.AddTransient<IUserService, UserService>();
        //services.AddScoped<IRazorPage<?>, WebViewPage<?>(); // ?: challenge!
}
like image 821
Saleh Bagheri Avatar asked Apr 03 '18 17:04

Saleh Bagheri


People also ask

Can we use dependency injection in abstract class?

Any concrete class inheriting the abstract class should be instantiable with a constructor (if not abstract itself of course). But use of constructor is prohibited by Spring because any class that we instantiate this way cannot be taken in charge by Spring's automated dependency injection.

Does ASP.NET Core support dependency injection?

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.

Can we use abstract class instead of interface in dependency injection?

As always, the answer is: "It depends." You can't do these approaches with interfaces as interfaces only specify the contract and don't have implementation. If the contract is all you need, then go with an interface. If you need code to be shared by the subclasses, then go with an abstract class.


1 Answers

If you need access to the service provider inside of your razor page, you could access the HttpContext through the Context property, e.g.:

var userService = Context.RequestServices.GetRequiredService<IUserService>();

A possibly better alternative would be to have a constructor that takes the IUserService as a dependency. So implementations of your type would have to pass that dependency on, essentially requiring them to have a constructor dependency on their own (which makes a good explicit design).


As for that dependency registration part, note that you generally cannot register abstract classes because they cannot be instantiated.

But in general, in order to register a generic type, you have to use the more verbose overload of AddScoped which takes actual Type arguments:

services.AddScoped(typeof(IRazorPage<>), typeof(WebViewPage<>)); 

Making a generic method call requires a real type as a generic type argument, so you would have to specify a concrete type for the type argument T inside IRazorPage<T> and WebViewPage<T>. Since you explicitly do not want to use a concrete type there but instead want to tell the dependency injection container to support any type, you cannot use this syntax there.

Since the typeof operator can determine the actual generic type, you can use it without having to use a specific type argument which would limit the registration to a single type.

like image 102
poke Avatar answered Oct 04 '22 13:10

poke