Pure DI 如何使用 Razor Pages 实现
How is Pure DI implemented with Razor Pages
这个问题类似于,但是这个问题是关于Razor Pages的,它需要一个不同的截取点。
我正在使用 Dependency Injection Principles, Practices, and Patterns (DIPP&P). Part of my application has a web API controller. To implement Pure DI with my controller, I was easily able to follow section 7.3.1 "Creating a custom controller activator" from DIPP&P to create a controller activator class, similar to the example found in DIPP&P 书中解释的纯 DI 方法制作一个 ASP.NET 核心应用程序。这是通过实施 IControllerActivator
并在 create
方法中组合我的组合根来完成的。
我的应用程序还将包含 Razor Pages。我想继续使用 Pure DI 方法,但我找不到任何有关如何执行此操作的示例。我的假设是我需要创建一个 RazorPageActivator
class,它实现 ASP.NET 核心 GitHub 中的 IRazorPageActivator
and add my composition root to the Activate
method. However, after reviewing the RazorPageActivator
class,它看起来非常复杂我担心如果我通过制作自己的 class 来实现 IRazorPageActivator
来拦截它(或覆盖它?),事情将会中断,我会一团糟。
我的问题是,如果可能的话,如何使用 Razor Pages 实现纯 DI?
使用 Razor Pages,IPageModelActivatorProvider
充当您的 Composition Root 的 Composer。这是一个基于默认 Visual Studio (2019) Razor Pages 项目模板的示例。
让我们从自定义 IPageModelActivatorProvider
开始,它作为您的 Composer,是您的 Composition Root 的一部分:
public class CommercePageModelActivatorProvider
: IPageModelActivatorProvider, IDisposable
{
// Singletons
private readonly ILoggerFactory loggerFactory;
public CommercePageModelActivatorProvider(ILoggerFactory loggerFactory) =>
this.loggerFactory = loggerFactory;
public Func<PageContext, object> CreateActivator(
CompiledPageActionDescriptor desc) =>
c => this.CreatePageModelType(c, desc.ModelTypeInfo.AsType());
public Action<PageContext, object> CreateReleaser(
CompiledPageActionDescriptor desc) =>
(c, pm) => (pm as IDisposable)?.Dispose();
private object CreatePageModelType(PageContext c, Type pageModelType)
{
// Create Scoped components
var context = new CommerceContext().TrackDisposable(c);
// Create Transient components
switch (pageModelType.Name)
{
case nameof(IndexModel):
return new IndexModel(this.Logger<IndexModel>(), context);
case nameof(PrivacyModel):
return new PrivacyModel(this.Logger<PrivacyModel>());
default: throw new NotImplementedException(pageModelType.FullName);
}
}
public void Dispose() { /* Release Singletons here, if needed */ }
private ILogger<T> Logger<T>() => this.loggerFactory.CreateLogger<T>();
}
注意此实现的一些事项:
- 此 class 的结构与 book's code samples 中给出的非常相似。
- 它实现了
IDisposable
以允许处理它自己创建的单例。在这种情况下,在它的构造函数中没有创建单例,所以不需要处理任何东西。 ILoggerFactory
是“外部所有”;它由框架创建,并将由框架处理(如果需要)。
- class 使用自定义
TrackDisposable
扩展方法(稍后显示),该方法允许跟踪作用域和瞬态依赖项。 TrackDisposable
方法会将这些实例添加到请求中,并允许框架在请求结束时处理它们。
- 这就是
CreateReleaser
方法仅处置页面本身的原因。当您跟踪它们以进行处置时,所有其他创建的组件的处置由框架完成。您也可以选择跟踪页面本身;在这种情况下,您可以将 CreateReleaser
委托留空。
- 有一个方便的
Logger<T>()
方法可以简化 ILogger<T>
实现的创建。这些来自框架并由 ILoggerFactory
. 创建
这是 TrackDisposable
扩展方法:
public static class DisposableExtensions
{
public static T TrackDisposable<T>(this T instance, PageContext c)
where T : IDisposable
{
c.HttpContext.Response.RegisterForDispose(instance);
return instance;
}
}
最后缺少的基础设施是将 CommercePageModelActivatorProvider
注册到框架的 DI 容器中。这是在 Startup class:
内部完成的
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
// Register your custom component activator here
services.AddSingleton<
IPageModelActivatorProvider, CommercePageModelActivatorProvider>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
}
}
这个问题类似于
我正在使用 Dependency Injection Principles, Practices, and Patterns (DIPP&P). Part of my application has a web API controller. To implement Pure DI with my controller, I was easily able to follow section 7.3.1 "Creating a custom controller activator" from DIPP&P to create a controller activator class, similar to the example found in DIPP&P 书中解释的纯 DI 方法制作一个 ASP.NET 核心应用程序。这是通过实施 IControllerActivator
并在 create
方法中组合我的组合根来完成的。
我的应用程序还将包含 Razor Pages。我想继续使用 Pure DI 方法,但我找不到任何有关如何执行此操作的示例。我的假设是我需要创建一个 RazorPageActivator
class,它实现 ASP.NET 核心 GitHub 中的 IRazorPageActivator
and add my composition root to the Activate
method. However, after reviewing the RazorPageActivator
class,它看起来非常复杂我担心如果我通过制作自己的 class 来实现 IRazorPageActivator
来拦截它(或覆盖它?),事情将会中断,我会一团糟。
我的问题是,如果可能的话,如何使用 Razor Pages 实现纯 DI?
使用 Razor Pages,IPageModelActivatorProvider
充当您的 Composition Root 的 Composer。这是一个基于默认 Visual Studio (2019) Razor Pages 项目模板的示例。
让我们从自定义 IPageModelActivatorProvider
开始,它作为您的 Composer,是您的 Composition Root 的一部分:
public class CommercePageModelActivatorProvider
: IPageModelActivatorProvider, IDisposable
{
// Singletons
private readonly ILoggerFactory loggerFactory;
public CommercePageModelActivatorProvider(ILoggerFactory loggerFactory) =>
this.loggerFactory = loggerFactory;
public Func<PageContext, object> CreateActivator(
CompiledPageActionDescriptor desc) =>
c => this.CreatePageModelType(c, desc.ModelTypeInfo.AsType());
public Action<PageContext, object> CreateReleaser(
CompiledPageActionDescriptor desc) =>
(c, pm) => (pm as IDisposable)?.Dispose();
private object CreatePageModelType(PageContext c, Type pageModelType)
{
// Create Scoped components
var context = new CommerceContext().TrackDisposable(c);
// Create Transient components
switch (pageModelType.Name)
{
case nameof(IndexModel):
return new IndexModel(this.Logger<IndexModel>(), context);
case nameof(PrivacyModel):
return new PrivacyModel(this.Logger<PrivacyModel>());
default: throw new NotImplementedException(pageModelType.FullName);
}
}
public void Dispose() { /* Release Singletons here, if needed */ }
private ILogger<T> Logger<T>() => this.loggerFactory.CreateLogger<T>();
}
注意此实现的一些事项:
- 此 class 的结构与 book's code samples 中给出的非常相似。
- 它实现了
IDisposable
以允许处理它自己创建的单例。在这种情况下,在它的构造函数中没有创建单例,所以不需要处理任何东西。ILoggerFactory
是“外部所有”;它由框架创建,并将由框架处理(如果需要)。 - class 使用自定义
TrackDisposable
扩展方法(稍后显示),该方法允许跟踪作用域和瞬态依赖项。TrackDisposable
方法会将这些实例添加到请求中,并允许框架在请求结束时处理它们。 - 这就是
CreateReleaser
方法仅处置页面本身的原因。当您跟踪它们以进行处置时,所有其他创建的组件的处置由框架完成。您也可以选择跟踪页面本身;在这种情况下,您可以将CreateReleaser
委托留空。 - 有一个方便的
Logger<T>()
方法可以简化ILogger<T>
实现的创建。这些来自框架并由ILoggerFactory
. 创建
这是 TrackDisposable
扩展方法:
public static class DisposableExtensions
{
public static T TrackDisposable<T>(this T instance, PageContext c)
where T : IDisposable
{
c.HttpContext.Response.RegisterForDispose(instance);
return instance;
}
}
最后缺少的基础设施是将 CommercePageModelActivatorProvider
注册到框架的 DI 容器中。这是在 Startup class:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
// Register your custom component activator here
services.AddSingleton<
IPageModelActivatorProvider, CommercePageModelActivatorProvider>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
}
}