我们的框架结构如下:
- webapi 项目
- 基本 CQRS 项目
- Nhibnerate 配置项目
该解决方案使用 Autofac 连接所有类。该 api 将加载所有程序集并在这些程序集中注册所有模块。
大多数模块只是查找所有接口和实现,并且效果很好,每个请求都使用实例。
CQRS 是命令和查询处理程序的一个非常基本的示例。由于将来会有很多并且它们可能具有各种依赖项,我不想手动编写工厂来获取所有处理程序(或在 API 中添加对每个处理程序的引用)。
为了解决上述问题,我有一个命令/查询处理程序工厂,它接受它想要运行的命令或查询。使用反射它找到它的处理程序类型并使用基本 handlerResolver 以便它可以获得处理程序的新实例。为此,我将传递ILifetimeScope
给解析器,因此它只在一个地方完成。(我知道引用生命周期范围通常是一种反模式,但我的感觉是,如果我最终得到数百个命令和查询,我最终会得到一个可怕的工厂,它需要所有可能的依赖项,并使用 autofac把它连起来更干净)。
如果每个请求都将所有内容都保留为实例,那么这一切都可以正常工作,则所有类都已解析并且命令和查询将运行。问题是对于每个 API 请求,NHibnernate 配置都会重建,这在我的机器上大约需要 1.5 秒。这意味着几乎每个请求都需要 2 秒才能响应。
我想做的是能够将 NHibnerate 配置和 sessionFactory 注册为单例(因为它不会有任何敏感/用户数据相关信息),以便尽可能少地创建它。还要根据要求保留所有处理程序和其他类,以便它们独立并尽快处理。
连接 web api 的主类:
public static class AutoFacSetup
{
public static IContainer Create()
{
var builder = new ContainerBuilder();
// this is to insist we use hbm config rather than fluent as there are two implentations of IConfigurationFactory
builder.RegisterType<OurHbmConfigurationFactory>().SingleInstance();
var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray();
// Register your Web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).InstancePerRequest();
builder.RegisterAssemblyModules(assemblies);
builder.RegisterSelf();
var container = builder.Build();
return container;
}
public static void RegisterSelf(this ContainerBuilder builder)
{
IContainer container = null;
builder.Register(c => container).AsSelf().SingleInstance();
builder.RegisterBuildCallback(c => container = c);
}
}
模块类之一的示例:
public class AutoFacInstallerModule : Module
{
protected override void Load(ContainerBuilder builder)
{
var assembly = GetType().Assembly;
builder
.RegisterAssemblyTypes(assembly)
.Except<NhibernateDbConnectionFactory>(x => x.SingleInstance())
.Except<MySessionFactory>(x => x.SingleInstance())
.AsImplementedInterfaces()
.InstancePerRequest();
}
}