Autofac RegisterGeneric 适用于单元测试但不适用于应用程序
Autofac RegisterGeneric works in unit test but not in application
我有一个 ASP.NET MVC 6 (Framework 4.6.1) 应用程序,Autofac 版本为 4.0.0-rc1-177。
在我的 Startup.cs 中,我调用了我制作的 AutofacLoader:
var container = Core.DI.AutofacLoader.Configure(services).Build();
AutofacLoader class:
public class AutofacLoader
{
public static IContainer Container { get; set; }
/// <summary>
/// Register the DI modules through AutoFac
/// </summary>
/// <param name="services">IServiceCollection to register the modules on</param>
/// <returns></returns>
public static ContainerBuilder Configure(IServiceCollection services)
{
var builder = new ContainerBuilder();
builder.RegisterModule<LogRequestsModule>();
//Core
builder.RegisterModule(new Core.ServiceModules.AutoMapperModule());
builder.RegisterModule(new Core.ServiceModules.ServicesModule());
builder.RegisterModule(new DAL.ServicesModules.IBSRepositoriesModule());
//Dieet
builder.RegisterModule(new Dieet.Core.ServiceModules.AutoMapperModule());
builder.RegisterModule(new Dieet.Core.ServiceModules.ServicesModule());
builder.RegisterModule(new Dieet.DAL.ServicesModules.DieetRepositoriesModule());
//builder.RegisterAssemblyModules(Assembly.GetExecutingAssembly());
if (services == null)
{
Container = builder.Build();
}
else
{
builder.Populate(services);
}
return builder;
}
}
我的 IBS.Core.ServicesModules.ServiceModule class(当我在此 class 中放置一个断点时,在启动我的应用程序时被调用,所以由 AutofacLoader class):
namespace IBS.Core.ServiceModules
{
public class ServicesModule : Module
{
protected override void Load(ContainerBuilder builder)
{
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces();
builder.RegisterGeneric(typeof(PaginatedSearchViewModel<>)).As(typeof(IPaginatedSearchViewModel<>)).InstancePerLifetimeScope();
}
}
}
我的 xunit 测试(使用 FluentAssertions)通过了:
public class ServiceModulesTest
{
[Fact]
public void ShouldBeInstantiatable()
{
AutofacLoader.Configure(null);
var container = AutofacLoader.Container;
var instance = container.Resolve<IPaginatedSearchViewModel<PatientViewModel>>();
instance.Should().BeOfType<PaginatedSearchViewModel<PatientViewModel>>();
}
}
但是当我 运行 应用程序时,在我的一个 API 控制器中,我有例如这个方法:
[HttpGet("patienten")]
public async Task<PagedResult<PatientViewModel>> GetPatientsAsync(IPaginatedSearchViewModel<PatientFilters> vm)
{
return await _infohosService.GetAllPatientsWithDossiersAndVerpleegperiodesAsync(vm);
}
这在浏览器中失败并响应:无法解析接口。
当我自己将 IPaginatedSearchViewModel 更改为参数中的具体 class 时:
[HttpGet("patienten")]
public async Task<PagedResult<PatientViewModel>> GetPatientsAsync(PaginatedSearchViewModel<PatientFilters> vm)
{
return await _infohosService.GetAllPatientsWithDossiersAndVerpleegperiodesAsync(vm);
}
API 有效。
所以我的问题是:
为什么我的单元测试通过了? (我是单元测试的新手,所以也许我在这里做错了什么?)
我怎样才能让 Autofac 也解析这个接口,因为它适用于我所有的服务、存储库、IDbContext,...?
I'm not sure if asp.net mvc 6 uses DI container on model binding stage
确实是这个问题。我已经 Google 多了一些,但没有发现 MVC 6 在模型绑定阶段使用 DI 容器。
使用方法中的具体class解决
我有一个 ASP.NET MVC 6 (Framework 4.6.1) 应用程序,Autofac 版本为 4.0.0-rc1-177。
在我的 Startup.cs 中,我调用了我制作的 AutofacLoader:
var container = Core.DI.AutofacLoader.Configure(services).Build();
AutofacLoader class:
public class AutofacLoader
{
public static IContainer Container { get; set; }
/// <summary>
/// Register the DI modules through AutoFac
/// </summary>
/// <param name="services">IServiceCollection to register the modules on</param>
/// <returns></returns>
public static ContainerBuilder Configure(IServiceCollection services)
{
var builder = new ContainerBuilder();
builder.RegisterModule<LogRequestsModule>();
//Core
builder.RegisterModule(new Core.ServiceModules.AutoMapperModule());
builder.RegisterModule(new Core.ServiceModules.ServicesModule());
builder.RegisterModule(new DAL.ServicesModules.IBSRepositoriesModule());
//Dieet
builder.RegisterModule(new Dieet.Core.ServiceModules.AutoMapperModule());
builder.RegisterModule(new Dieet.Core.ServiceModules.ServicesModule());
builder.RegisterModule(new Dieet.DAL.ServicesModules.DieetRepositoriesModule());
//builder.RegisterAssemblyModules(Assembly.GetExecutingAssembly());
if (services == null)
{
Container = builder.Build();
}
else
{
builder.Populate(services);
}
return builder;
}
}
我的 IBS.Core.ServicesModules.ServiceModule class(当我在此 class 中放置一个断点时,在启动我的应用程序时被调用,所以由 AutofacLoader class):
namespace IBS.Core.ServiceModules
{
public class ServicesModule : Module
{
protected override void Load(ContainerBuilder builder)
{
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces();
builder.RegisterGeneric(typeof(PaginatedSearchViewModel<>)).As(typeof(IPaginatedSearchViewModel<>)).InstancePerLifetimeScope();
}
}
}
我的 xunit 测试(使用 FluentAssertions)通过了:
public class ServiceModulesTest
{
[Fact]
public void ShouldBeInstantiatable()
{
AutofacLoader.Configure(null);
var container = AutofacLoader.Container;
var instance = container.Resolve<IPaginatedSearchViewModel<PatientViewModel>>();
instance.Should().BeOfType<PaginatedSearchViewModel<PatientViewModel>>();
}
}
但是当我 运行 应用程序时,在我的一个 API 控制器中,我有例如这个方法:
[HttpGet("patienten")]
public async Task<PagedResult<PatientViewModel>> GetPatientsAsync(IPaginatedSearchViewModel<PatientFilters> vm)
{
return await _infohosService.GetAllPatientsWithDossiersAndVerpleegperiodesAsync(vm);
}
这在浏览器中失败并响应:无法解析接口。
当我自己将 IPaginatedSearchViewModel 更改为参数中的具体 class 时:
[HttpGet("patienten")]
public async Task<PagedResult<PatientViewModel>> GetPatientsAsync(PaginatedSearchViewModel<PatientFilters> vm)
{
return await _infohosService.GetAllPatientsWithDossiersAndVerpleegperiodesAsync(vm);
}
API 有效。
所以我的问题是:
为什么我的单元测试通过了? (我是单元测试的新手,所以也许我在这里做错了什么?)
我怎样才能让 Autofac 也解析这个接口,因为它适用于我所有的服务、存储库、IDbContext,...?
I'm not sure if asp.net mvc 6 uses DI container on model binding stage
确实是这个问题。我已经 Google 多了一些,但没有发现 MVC 6 在模型绑定阶段使用 DI 容器。
使用方法中的具体class解决