10+ 剃须刀页面代码背后通过依赖注入获取 dbcontexts
10+ razor page code behind get dbcontexts via dependency injection
我开发了一个 C# ASP.NET Core MVC
应用程序,其中包含很多 razor pages
。
我的大部分剃须刀页面都使用 日志记录 、 发送电子邮件 并使用 多个 dbcontextes.
很多 class 看起来像这样:
class A : PageModel
{
private readonly ADbContext _context;
private readonly UserManager<ApplicationUser> _userManager;
private readonly IEmailSender _emailSender;
private readonly ILogger<MyModel> _logger;
public UpdateModel(ADbContext context,
UserManager<ApplicationUser> userManager,
IEmailSender emailSender,
ILogger<MyModel> logger)
{
_context = context;
_userManager = userManager;
_emailSender = emailSender;
_logger = logger;
}
}
我有 10 多页这样的内容。
当我创建页面时,我必须添加这些字段。所以很多时候。
摆脱大量字段声明的理想方法是什么?一个 base class
继承了我开发的每一个页面模型?但是这个基础 class 将是一个非常通用的基础 class,带有日志记录、电子邮件和上下文,它们实际上彼此并不相似。
每次我声明一个使用它们的 class 时声明这些字段是一个好的架构选择吗?
总的来说,是的,这就是您所做的。您的依赖项正在被注入,这意味着您需要 ivars 来保存它们,并需要一个构造函数来接受它们。它可以感觉并且看起来是重复的,但这实际上是一件好事。它使您的 class 一目了然:您可以一目了然地快速查看 class 具有哪些依赖项。
如果您愿意,可以创建一个基地 class。但是,您应该注意只在基础 class 中包含真正适用于每个推导的内容。危险在于添加并非在所有情况下都实际需要的依赖项,然后现在您有一堆页面加载它们不需要且不使用的依赖项。
在这里你也可以在一定程度上使用抽象。例如,如果每个页面都依赖于一个上下文,但在不同的场景中可能是不同的上下文,你可以将ivar类型设置为DbContext
,而不是你的具体上下文类型,然后你可以将其设置为任何有效的DbContext
的推导。您的记录器也是如此。你实际上想要注入 ILogger<MyPageModel>
,但你可以在基础 class 上制作 ivar 只是 ILogger
,然后它将接受任何记录器。
不过,当您开始这样做时,您会更难确定 classes 的依赖关系,因此这是一个让步。就个人而言,如果存在共享逻辑,我只会使用基 class。如果 base class 的唯一目的是定义一组特定的依赖项,那么它就不值得拥有。
是否适合改用过滤器?您的过滤器依赖项可以通过 DI 注入吗?
https://www.learnrazorpages.com/razor-pages/filters
您还可以通过在需要服务的函数级别直接注入来简化某些 DI 的情况,而不是通过在参数上方添加“[FromService]”在构造函数级别注入:
[HttpGet]
public ActionResult OnGetDoSomething([FromServices] IEmailSender emailService)
{
// Do something
}
这样,如果不需要,您就不必实例化这些服务。
这样的事情怎么样?
class A : BasePage {
public UpdateModel(IServiceProvider provider) : base(provider) {
// here you can access the base properties
}
}
class BasePage : PageModel {
public ADbContext _context { get; set; }
public UserManager<ApplicationUser> _userManager; { get; set; }
public IEmailSender _emailSender; { get; set; }
public ILogger<MyModel> _logger; { get; set; }
public UpdateModel(IServiceProvider provider) : base(provider) {
Context = (ADbContext)provider.GetRequiredService(typeof(ADbContext));
UserManager = (UserManager)provider.GetRequiredService(typeof(UserManager));
EmailSender = (IEmailSender)provider.GetRequiredService(typeof(IEmailSender));
Logger = (ILogger)provider.GetRequiredService(typeof(ILogger));
}
}
我开发了一个 C# ASP.NET Core MVC
应用程序,其中包含很多 razor pages
。
我的大部分剃须刀页面都使用 日志记录 、 发送电子邮件 并使用 多个 dbcontextes.
很多 class 看起来像这样:
class A : PageModel
{
private readonly ADbContext _context;
private readonly UserManager<ApplicationUser> _userManager;
private readonly IEmailSender _emailSender;
private readonly ILogger<MyModel> _logger;
public UpdateModel(ADbContext context,
UserManager<ApplicationUser> userManager,
IEmailSender emailSender,
ILogger<MyModel> logger)
{
_context = context;
_userManager = userManager;
_emailSender = emailSender;
_logger = logger;
}
}
我有 10 多页这样的内容。 当我创建页面时,我必须添加这些字段。所以很多时候。
摆脱大量字段声明的理想方法是什么?一个 base class
继承了我开发的每一个页面模型?但是这个基础 class 将是一个非常通用的基础 class,带有日志记录、电子邮件和上下文,它们实际上彼此并不相似。
每次我声明一个使用它们的 class 时声明这些字段是一个好的架构选择吗?
总的来说,是的,这就是您所做的。您的依赖项正在被注入,这意味着您需要 ivars 来保存它们,并需要一个构造函数来接受它们。它可以感觉并且看起来是重复的,但这实际上是一件好事。它使您的 class 一目了然:您可以一目了然地快速查看 class 具有哪些依赖项。
如果您愿意,可以创建一个基地 class。但是,您应该注意只在基础 class 中包含真正适用于每个推导的内容。危险在于添加并非在所有情况下都实际需要的依赖项,然后现在您有一堆页面加载它们不需要且不使用的依赖项。
在这里你也可以在一定程度上使用抽象。例如,如果每个页面都依赖于一个上下文,但在不同的场景中可能是不同的上下文,你可以将ivar类型设置为DbContext
,而不是你的具体上下文类型,然后你可以将其设置为任何有效的DbContext
的推导。您的记录器也是如此。你实际上想要注入 ILogger<MyPageModel>
,但你可以在基础 class 上制作 ivar 只是 ILogger
,然后它将接受任何记录器。
不过,当您开始这样做时,您会更难确定 classes 的依赖关系,因此这是一个让步。就个人而言,如果存在共享逻辑,我只会使用基 class。如果 base class 的唯一目的是定义一组特定的依赖项,那么它就不值得拥有。
是否适合改用过滤器?您的过滤器依赖项可以通过 DI 注入吗?
https://www.learnrazorpages.com/razor-pages/filters
您还可以通过在需要服务的函数级别直接注入来简化某些 DI 的情况,而不是通过在参数上方添加“[FromService]”在构造函数级别注入:
[HttpGet]
public ActionResult OnGetDoSomething([FromServices] IEmailSender emailService)
{
// Do something
}
这样,如果不需要,您就不必实例化这些服务。
这样的事情怎么样?
class A : BasePage {
public UpdateModel(IServiceProvider provider) : base(provider) {
// here you can access the base properties
}
}
class BasePage : PageModel {
public ADbContext _context { get; set; }
public UserManager<ApplicationUser> _userManager; { get; set; }
public IEmailSender _emailSender; { get; set; }
public ILogger<MyModel> _logger; { get; set; }
public UpdateModel(IServiceProvider provider) : base(provider) {
Context = (ADbContext)provider.GetRequiredService(typeof(ADbContext));
UserManager = (UserManager)provider.GetRequiredService(typeof(UserManager));
EmailSender = (IEmailSender)provider.GetRequiredService(typeof(IEmailSender));
Logger = (ILogger)provider.GetRequiredService(typeof(ILogger));
}
}