使用 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>();
}
请注意此实现的一些事项:
- 这个类的结构与book's code samples中给出的非常相似。
- 它实现了
IDisposable 以允许处理它自己创建的单例。在这种情况下,它的构造函数中没有创建单例,因此不需要处理任何内容。 ILoggerFactory 是“外部所有”;它由框架创建,并将由框架处置(如果需要)。
- 该类使用自定义
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 类中完成的:
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)
{
...
}
}