我使用castle.windsor和owin在webapi2中使用了一些DI。这是相关的代码:
[assembly: OwinStartup(typeof(Bla.Startup))]
namespace Bla
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
//...
var container = new WindsorContainer().Install(new ControllerInstaller());
var httpDependencyResolver = new WindsorHttpDependencyResolver(container);
config.DependencyResolver = httpDependencyResolver;
//...
}
}
public class ControllerInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(AllTypes.FromThisAssembly()
.Pick().If(t => t.Name.EndsWith("Controller"))
.Configure(configurer => configurer.Named(configurer.Implementation.Name))
.LifestylePerWebRequest());
//...
}
}
internal class WindsorDependencyScope : IDependencyScope
{
private readonly IWindsorContainer _container;
private readonly IDisposable _scope;
public WindsorDependencyScope(IWindsorContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
_container = container;
_scope = container.BeginScope();
}
public object GetService(Type t)
{
return _container.Kernel.HasComponent(t)
? _container.Resolve(t) : null;
}
public IEnumerable<object> GetServices(Type t)
{
return _container.ResolveAll(t)
.Cast<object>().ToArray();
}
public void Dispose()
{
_scope.Dispose();
}
}
internal sealed class WindsorHttpDependencyResolver : IDependencyResolver
{
private readonly IWindsorContainer _container;
public WindsorHttpDependencyResolver(IWindsorContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
_container = container;
}
public object GetService(Type t)
{
return _container.Kernel.HasComponent(t)
? _container.Resolve(t) : null;
}
public IEnumerable<object> GetServices(Type t)
{
return _container.ResolveAll(t)
.Cast<object>().ToArray();
}
public IDependencyScope BeginScope()
{
return new WindsorDependencyScope(_container);
}
public void Dispose()
{
}
}
owin的一个很大的优点是它删除了依赖形式system.web。这允许从其他事物中实现相当有效(在内存中?)集成测试。我面临的问题是:
config.DependencyResolver = httpDependencyResolver;
引入了对系统的依赖。所以当我尝试运行这样一个简单的测试时:
private TestServer _server;
[TestFixtureSetUp]
public void FixtureInit()
{
_server = TestServer.Create<Startup>();
}
[Test]
public voidSomeTest()
{
using (var server = TestServer.Create<Startup>())
{
HttpResponseMessage response = server.HttpClient.GetAsync("/api/bladibla/test").Result;
// ...
}
}
我明白了:
{"Looks like you forgot to register the http module Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule\r\nTo fix this add\r\n<add name=\"PerRequestLifestyle\" type=\"Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.Windsor\" />\r\nto the <httpModules> section on your web.config.\...
我可以在测试项目的app.config中注册一些东西吗?任何反馈都会非常受欢迎。
PS:
我尝试添加:
<system.web>
<httpModules>
<add name="PerRequestLifestyle" type="Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.Windsor" />
</httpModules>
</system.web>
<system.webServer>
<modules>
<add name="PerRequestLifestyle" type="Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.Windsor" />
</modules>
</system.webServer>
到app.config但没有成功。
PPS:
好的,如果我改变了:
container.Register(AllTypes.FromThisAssembly()
.Pick().If(t => t.Name.EndsWith("Controller"))
.Configure(configurer => configurer.Named(configurer.Implementation.Name))
.LifestylePerWebRequest());
为:
container.Register(AllTypes.FromThisAssembly()
.Pick().If(t => t.Name.EndsWith("Controller"))
.Configure(configurer => configurer.Named(configurer.Implementation.Name))
.LifestyleTransient());
它有效,这是有道理的。最大的问题是,我如何动态更改它,具体取决于它是在部署/适当的Web环境还是测试环境中。
答案 0 :(得分:4)
{&#34;看起来您忘记注册http模块Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule \ r \ n要修复此添加\ r \ n \ r \ n \ n \ n在web.config上的部分....
但你试图注册:
PerRequestLifestyle
看到区别? PerWebRequestLifestyle不是PerRequestLifeStyle。
看一下Mauricio Scheffer`s HybridLifeStyles,它可以非常容易地设置容器进行测试。
答案 1 :(得分:0)
在使用OWIN进行内存测试时,我使用以下扩展方法来覆盖行为:
private static void OverridePerWebRequestLifestyle(this IWindsorContainer container)
{
container.Kernel.ComponentModelCreated += model =>
{
if (model.LifestyleType == LifestyleType.PerWebRequest)
{
model.LifestyleType = LifestyleType.Transient;
}
};
}