Saleh Bagheri
Saleh Bagheri

Reputation: 434

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!
}

Upvotes: 6

Views: 8642

Answers (1)

poke
poke

Reputation: 387557

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.

Upvotes: 8

Related Questions