ASP.NET Core抽象类中的依赖注入

Dependency Injection in abstract class, ASP.NET Core

在我的 ASP.NET Core 2 项目中,我创建了继承 RazorPage 类的新类,以在视图中添加一些额外的属性。

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>
{

}

_ViewImport.cshtml 文件更改为:

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

该项目工作正常,直到挑战代码被标记为评论。 但是,我怎样才能将依赖项注入抽象类呢? 或者如何解决抽象类中的服务?

这是我的 StartUp.cs 文件:

public void ConfigureServices(IServiceCollection services)
{
        services.AddMemoryCache();
        services.AddMvc();
        services.AddTransient<IUserService, UserService>();
        //services.AddScoped<IRazorPage<?>, WebViewPage<?>(); // ?: challenge!
}

答案

如果您需要访问razor 页面内的 service provider,您可以通过 Context 属性访问 HttpContext,例如:

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

一个可能更好的选择是拥有一个将 IUserService 作为依赖项的构造函数。 因此,您的类型的实现必须传递该依赖性,本质上要求它们具有自己的构造函数依赖性(这是一个很好的显式设计)。

至于那个依赖注册部分,注意你一般不能注册抽象类,因为它们不能被实例化。

但一般来说,为了注册泛型类型,您必须使用更详细的 AddScoped 重载,它采用实际Type参数:

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

进行泛型方法调用需要一个真实类型作为泛型类型参数,因此您必须在 IRazorPage<T>WebViewPage<T> 中为类型参数 T 指定一个具体类型。 由于您明确不想在那里使用具体类型,而是想告诉依赖注入容器支持任何类型,因此您不能在那里使用此语法。

由于 typeof 运算符可以确定实际的泛型类型,因此您可以使用它而不必使用将注册限制为单一类型的特定类型参数。


How to resolve parent class instance from registered child class in Asp.net core dependency injection

假设我有一个类

abstract class CustomContext: IdentityDbContext<AppUser, Role>{}
class TContext: CustomContext{}

在服务注册中

services.AddDbContext<TContext>();

在上面,我可以像下面这样解析 TContext 的实例

var context = ServicesCollector.Container.GetService(typeof(TContext));

但是在程序的某处,我想解析 CustomContext 的实例。

答案

向解析实现的委托工厂注册抽象。

services.AddScoped<CusomContext>(sp => sp.GetRequiredService<TContext>());

这样,当请求抽象时,尝试解析它的容器就会知道它。


ASP.Net Core MVC: Dependency Injection by Base Type

在转向 ASP.Net Core 之前,我使用了 Ninject,它允许我以通用方式注入我的实体框架数据库上下文。 例如:

Bind<DbContext>().To<MyActualDbContext>();

在 ASP.Net Core MVC 中,当使用 AddDbContext 时,如果我执行以下操作,将导致服务无法解析。

AddDbContext<MyActualDbContext>(x=> x.UseSqlServer("..."));
---
public class TestController: Controller {
    public DbContext Db {get; private set;}
    public TestController(DbContext Db){
        this.Db = Db;
    }
}

我知道我可以通过使用 AddSingletonAddScoped 来解决这个问题,但是,由于 AddDbContext 是专门开发用于处理 EF 数据上下文的,我想知道是否有任何方法可以使用该方法实现此目的。

如果 AddDbContext 不支持此行为,那么 AddSingletonAddScoped 哪个替代方法更好? 我知道 AddScoped 每次请求都会实例化服务一次,但我想知道 Singleton 是否会导致任何潜在问题。 我想确保在 ED DbContext 的情况下使用这两种方法不会有任何可能的缺点。

答案

您可以使用

// Or use AddTransient, makes no difference as it only wraps around the
// container resolve method
services.AddScoped<DbContext>(provider => provider.GetRequiredService<MyActualDbContext>());

但老实说,我看不出这样做有什么好处,因为基类不会有任何 DbSet,所以如果不将它转换为原始代码就不能使用它,但这在某种程度上打败了这个想法 完全有IoC。

是的,单例 DbContext 是有问题的。 它可能会导致内存泄漏(跟踪缓存会不断增长),如果您将其放置在某个地方,DI系统将始终返回已放置的单例上下文实例。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值