Background:
I've used Castle Windsor with Installers and Facilities according to the Castle Windsor tutorial with earlier versions of MVC (pre-6) and WebAPI.
根据温莎城堡的教程,我使用了早期版本的MVC (pre-6)和WebAPI。
ASP.NET (5) Core has included some Dependency Injection support but I still haven't figured out exactly how to wire it up, and the few samples I have found look a lot different than how I've used it before (with the installers/facilities). Most examples predate ASP.NET (5) cores recent release and some seem to have outdated information.
ASP。NET(5)核心包含了一些依赖注入支持,但是我还没有弄清楚如何将它连接起来,我发现的几个示例看起来与我以前使用它(安装程序/设备)的方式有很大的不同。大多数例子之前ASP。NET(5)核心最近发布,有些似乎有过时的信息。
It seems to have changed quite radically from the previous versions composition root setup, and not even Microsoft.Framework.DependencyInjection.ServiceProvider
can resolve all of the dependencies when I set it as the Castle Windsor DI fallback. I'm still digging into the details but there isn't much up to date information.
它似乎与以前的版本组合根设置完全不同,甚至不是Microsoft.Framework.DependencyInjection。ServiceProvider可以解决所有的依赖关系,当我将它设置为Castle Windsor DI fallback时。我还在钻研细节,但没有太多的最新信息。
My attempt to use Castle Windsor for DI
I've found an adapter like this: Github Castle.Windsor DI container.
我找到了一个这样的适配器:Github城堡。温莎DI容器。
Startup.cs
Startup.cs
private static IWindsorContainer container;
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory)
{
container = new WindsorContainer();
app.UseServices(services =>
{
// ADDED app.ApplicationServices FOR FALLBACK DI
container.Populate(services, app.ApplicationServices);
container.BeginScope();
return container.Resolve<IServiceProvider>();
});
// ... default stuff
WindsorRegistration.cs I added a few lines to add a Castle Windsor ILazyComponentLoader
fallback.
WindsorRegistration。我添加了几行代码来添加一个Castle Windsor ILazyComponentLoader回退。
using Castle.MicroKernel.Lifestyle;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.Resolvers.SpecializedResolvers;
using Castle.Windsor;
using Microsoft.Framework.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Notes.Infrastructure
{
/// <summary>
/// An adapted current autofac code to work with Castle.Windsor container.
/// https://github.com/aspnet/Home/issues/263
/// </summary>
public static class WindsorRegistration
{
public static void Populate(
this IWindsorContainer container,
IEnumerable<IServiceDescriptor> descriptors,
IServiceProvider fallbackProvider // ADDED FOR FALLBACK DI
)
{
// ADDED FOR FALLBACK DI
// http://davidzych.com/2014/08/27/building-the-castle-windsor-dependency-injection-populator-for-asp-net-vnext/
// Trying to add a fallback if Castle Windsor doesn't find the .NET stuff
var fallbackComponentLoader = new FallbackLazyComponentLoader(fallbackProvider);
container.Register(Component.For<ILazyComponentLoader>().Instance(fallbackComponentLoader));
// Rest as usual from the Github link
container.Register(Component.For<IWindsorContainer>().Instance(container));
container.Register(Component.For<IServiceProvider>().ImplementedBy<WindsorServiceProvider>());
container.Register(Component.For<IServiceScopeFactory>().ImplementedBy<WindsorServiceScopeFactory>());
container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel));
Register(container, descriptors);
}
private static void Register(
IWindsorContainer container,
IEnumerable<IServiceDescriptor> descriptors)
{
foreach (var descriptor in descriptors)
{
if (descriptor.ImplementationType != null)
{
// Test if the an open generic type is being registered
var serviceTypeInfo = descriptor.ServiceType.GetTypeInfo();
if (serviceTypeInfo.IsGenericTypeDefinition)
{
container.Register(Component.For(descriptor.ServiceType)
.ImplementedBy(descriptor.ImplementationType)
.ConfigureLifecycle(descriptor.Lifecycle)
.OnlyNewServices());
}
else
{
container.Register(Component.For(descriptor.ServiceType)
.ImplementedBy(descriptor.ImplementationType)
.ConfigureLifecycle(descriptor.Lifecycle)
.OnlyNewServices());
}
}
else if (descriptor.ImplementationFactory != null)
{
var service1 = descriptor;
container.Register(Component.For(descriptor.ServiceType)
.UsingFactoryMethod<object>(c =>
{
var builderProvider = container.Resolve<IServiceProvider>();
return
service1.ImplementationFactory(builderProvider);
})
.ConfigureLifecycle(descriptor.Lifecycle)
.OnlyNewServices());
}
else
{
container.Register(Component.For(descriptor.ServiceType)
.Instance(descriptor.ImplementationInstance)
.ConfigureLifecycle(descriptor.Lifecycle)
.OnlyNewServices());
}
}
}
private static ComponentRegistration<object> ConfigureLifecycle(
this ComponentRegistration<object> registrationBuilder,
LifecycleKind lifecycleKind)
{
switch (lifecycleKind)
{
case LifecycleKind.Singleton:
registrationBuilder.LifestyleSingleton();
break;
case LifecycleKind.Scoped:
registrationBuilder.LifestyleScoped();
break;
case LifecycleKind.Transient:
registrationBuilder.LifestyleTransient();
break;
}
return registrationBuilder;
}
private class WindsorServiceProvider : IServiceProvider
{
private readonly IWindsorContainer _container;
public WindsorServiceProvider(IWindsorContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
return _container.Resolve(serviceType);
}
}
private class WindsorServiceScopeFactory : IServiceScopeFactory
{
private readonly IWindsorContainer _container;
public WindsorServiceScopeFactory(IWindsorContainer container)
{
_container = container;
}
public IServiceScope CreateScope()
{
return new WindsorServiceScope(_container);
}
}
private class WindsorServiceScope : IServiceScope
{
private readonly IServiceProvider _serviceProvider;
private readonly IDisposable _scope;
public WindsorServiceScope(IWindsorContainer container)
{
_scope = container.BeginScope();
_serviceProvider = container.Resolve<IServiceProvider>();
}
public IServiceProvider ServiceProvider
{
get { return _serviceProvider; }
}
public void Dispose()
{
_scope.Dispose();
}
}
}
}
First hiccup and resolution attempt
From that example I was getting:
从这个例子中,我得到了:
An exception of type 'Castle.MicroKernel.ComponentNotFoundException' occurred in Castle.Windsor.dll but was not handled in user code Additional information: No component for supporting the service Microsoft.Framework.Runtime.IAssemblyLoaderEngine was found
类型“Castle.MicroKernel”的例外。发生在Castle.Windsor ComponentNotFoundException”。但是没有在用户代码中处理额外的信息:没有用于支持服务Microsoft.Framework.Runtime的组件。IAssemblyLoaderEngine被发现
It wasn't available looking in the debugger at the Castle Fallback - Microsoft.Framework.DependencyInjection.ServiceProvider
(table of services).
无法在城堡的回退- Microsoft.Framework.DependencyInjection中查看调试器。ServiceProvider服务(表)。
From http://davidzych.com/tag/castle-windsor/ I have tried to add a Fallback since Windsor couldn't resolve all of the ASP.NET dependencies.
从http://davidzych.com/tag/castle-windsor/我尝试添加一个回退,因为温莎无法解决所有的ASP。净依赖性。
FallbackLazyComponentLoader.cs
FallbackLazyComponentLoader.cs
/// <summary>
/// https://github.com/davezych/DependencyInjection/blob/windsor/src/Microsoft.Framework.DependencyInjection.Windsor/FallbackLazyComponentLoader.cs
/// </summary>
public class FallbackLazyComponentLoader : ILazyComponentLoader
{
private IServiceProvider _fallbackProvider;
public FallbackLazyComponentLoader(IServiceProvider provider)
{
_fallbackProvider = provider;
}
public IRegistration Load(string name, Type service, IDictionary arguments)
{
var serviceFromFallback = _fallbackProvider.GetService(service);
if (serviceFromFallback != null)
{
return Component.For(service).Instance(serviceFromFallback);
}
return null;
}
}
It was seemingly necessary (to inject all the .NET dependencies)
I could comment out startup.cs app.UseBrowserLink(); to get rid of the IAssemblyLoaderEngine exception.
我可以评论启动。cs app.UseBrowserLink();要除去iassembly - loaderengine异常。
if (string.Equals(env.EnvironmentName, "Development", StringComparison.OrdinalIgnoreCase))
{
//app.UseBrowserLink(); //
Now I run into an exception:
An exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll but was not handled in user code
类型“System.Reflection”的例外。发生在mscorlib TargetInvocationException”。dll,但没有在用户代码中处理。
Trying to get the service: {Name = "IUrlHelper" FullName = "Microsoft.AspNet.Mvc.IUrlHelper"}
试图获得服务:{Name = "IUrlHelper" FullName = "Microsoft.AspNet.Mvc.IUrlHelper"}
public IRegistration Load(string name, Type service, IDictionary arguments)
{
var serviceFromFallback = _fallbackProvider.GetService(service);
How to move forward?
What is wrong with this attempt to wire up Castle Windsor DI into ASP.NET (5) Core?
这种试图将温莎城堡连接成ASP的尝试是错误的。净(5)核心?
3 个解决方案
#1
5
For now I don't think you can use Castle Windsor Container as the DI container because Windsor doesn't support the new DNVM. But AutoFac does and they follow the same rule.
现在我认为你不能用城堡温莎集装箱作为DI容器,因为温莎不支持新的DNVM。但AutoFac也遵循同样的规则。
In the Startup.cs there is a ConfigureServices
method whose return type is void. You can change the return type to ISerivceProvider
and return a concrete IServiceProvider
, the system will use the new IServiceProvider
as the default DI container. Below is the AutoFac example.
在启动。有一个配置服务方法,其返回类型为void。您可以将返回类型更改为ISerivceProvider并返回一个具体的IServiceProvider,系统将使用新的IServiceProvider作为默认的DI容器。下面是AutoFac示例。
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.Configure<AppSettings>(Configuration.GetSubKey("AppSettings"));
services.AddMvc();
var builder = new ContainerBuilder();
AutofacRegistration.Populate(builder, services);
var container = builder.Build();
return container.Resolve<IServiceProvider>();
}
The other DI adapters also implemented the similar interfaces. You can try yourself, but note AutoFac is in beta5 now so you need to make some adjustment to make your application run.
其他的DI适配器也实现了类似的接口。您可以尝试一下,但是注意AutoFac现在在beta5中,所以您需要进行一些调整以使您的应用程序运行。
Hope this helps
希望这有助于
#2
2
There is a lot going on in your question, and to be honest I don't understand all of it.
你的问题有很多,老实说,我并不完全理解。
However, there is a working Castle Windsor composition root in MvcSiteMapProvider that you are welcome reverse-engineer. Follow these steps to get a working composition root demo project for Windsor:
然而,在MvcSiteMapProvider中有一个工作的温莎组合根,您是受欢迎的逆向工程。按照以下步骤,为Windsor找到一个工作组合根演示项目:
- Create a new MVC 5 project.
- 创建一个新的MVC 5项目。
- Install MvcSiteMapProvider.MVC5.DI.Windsor.
- 安装MvcSiteMapProvider.MVC5.DI.Windsor。
- Analyze the following files for the basic structure:
/App_Start/DIConfig.cs
- / App_Start DIConfig.cs
/App_Start/CompositionRoot.cs
- / App_Start CompositionRoot.cs
/DI/InjectableControllerFactory.cs
- DI / InjectableControllerFactory.cs
/DI/Windsor/WindsorDependencyInjectionContainer.cs
- / DI /温莎/ WindsorDependencyInjectionContainer.cs
/DI/Windsor/Installers/MvcInstaller.cs
- DI /温莎/安装/ MvcInstaller.cs
/DI/Windsor/Installers/MvcSiteMapProviderInstaller.cs
- DI /温莎/安装/ MvcSiteMapProviderInstaller.cs
- 为基本结构分析下列文件:/App_Start/DIConfig。cs / App_Start / CompositionRoot。cs / DI / InjectableControllerFactory。cs / DI /温莎/ WindsorDependencyInjectionContainer。cs / DI /温莎/安装/ MvcInstaller。cs / DI /温莎/安装/ MvcSiteMapProviderInstaller.cs
Once you have this working configuration, you can then refactor it and add to it to suit your application's needs.
一旦您有了这个工作配置,您就可以重构它并添加到它以满足您的应用程序的需要。
As I recall, there weren't any changes required to make the MVC 4 DI configuration work with MVC 5. So, the problem you are running into is most likely one of the following:
正如我所记得的,没有任何更改需要使MVC 4 DI配置与MVC 5一起工作。所以,你遇到的问题很可能是以下几个问题之一:
- You are using a 3rd party DI component that is not compatible with MVC 5.
- 您使用的是与MVC 5不兼容的第三方DI组件。
- You are using DependencyResolver, and your configuration doesn't include the necessary code to resolve the dependencies of MVC 5.
- 您使用的是DependencyResolver,而您的配置不包含解决MVC 5依赖关系的必要代码。
- You are using advanced features of Castle Windsor that we are not using, and have them misconfigured in some way.
- 您正在使用我们不使用的高级功能的城堡温莎,并在某些方面配置错误。
ControllerFactory vs DependencyResolver
Do note that according to Dependency Injection in .NET by Mark Seemann (which I highly recommend), it is ill-advised to use IDependencyResolver
with Castle Windsor because it guarantees resource leaks. In fact, this is probably the most compelling argument that he makes for his reasoning for declaring service locator as anti-pattern.
请注意,根据Mark Seemann(我强烈推荐的)在。net中的依赖注入,使用IDependencyResolver与Castle Windsor是不明智的,因为它保证了资源的泄漏。事实上,这可能是他为其将服务定位器声明为反模式的理由所做的最令人信服的论证。
The recommended approach is to use IControllerFactory
as the integration point into MVC, which implements a ReleaseController
method to solve this issue.
推荐的方法是将IControllerFactory作为集成点到MVC,它实现了一个发布控制方法来解决这个问题。
#3
0
So looking at your code, literally all of it can be replaced by Castle.Windsor.MsDependencyInjection
library.
看看你的代码,所有的代码都可以被Castle.Windsor取代。MsDependencyInjection图书馆。
Add Castle.Windsor.MsDependencyInjection
to your project then use like so:
添加Castle.Windsor。对您的项目进行MsDependencyInjection,然后使用如下:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// Normal component registration can go here...
return WindsorRegistrationHelper.CreateServiceProvider(yourWindsorContainer, services);
}
#1
5
For now I don't think you can use Castle Windsor Container as the DI container because Windsor doesn't support the new DNVM. But AutoFac does and they follow the same rule.
现在我认为你不能用城堡温莎集装箱作为DI容器,因为温莎不支持新的DNVM。但AutoFac也遵循同样的规则。
In the Startup.cs there is a ConfigureServices
method whose return type is void. You can change the return type to ISerivceProvider
and return a concrete IServiceProvider
, the system will use the new IServiceProvider
as the default DI container. Below is the AutoFac example.
在启动。有一个配置服务方法,其返回类型为void。您可以将返回类型更改为ISerivceProvider并返回一个具体的IServiceProvider,系统将使用新的IServiceProvider作为默认的DI容器。下面是AutoFac示例。
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.Configure<AppSettings>(Configuration.GetSubKey("AppSettings"));
services.AddMvc();
var builder = new ContainerBuilder();
AutofacRegistration.Populate(builder, services);
var container = builder.Build();
return container.Resolve<IServiceProvider>();
}
The other DI adapters also implemented the similar interfaces. You can try yourself, but note AutoFac is in beta5 now so you need to make some adjustment to make your application run.
其他的DI适配器也实现了类似的接口。您可以尝试一下,但是注意AutoFac现在在beta5中,所以您需要进行一些调整以使您的应用程序运行。
Hope this helps
希望这有助于
#2
2
There is a lot going on in your question, and to be honest I don't understand all of it.
你的问题有很多,老实说,我并不完全理解。
However, there is a working Castle Windsor composition root in MvcSiteMapProvider that you are welcome reverse-engineer. Follow these steps to get a working composition root demo project for Windsor:
然而,在MvcSiteMapProvider中有一个工作的温莎组合根,您是受欢迎的逆向工程。按照以下步骤,为Windsor找到一个工作组合根演示项目:
- Create a new MVC 5 project.
- 创建一个新的MVC 5项目。
- Install MvcSiteMapProvider.MVC5.DI.Windsor.
- 安装MvcSiteMapProvider.MVC5.DI.Windsor。
- Analyze the following files for the basic structure:
/App_Start/DIConfig.cs
- / App_Start DIConfig.cs
/App_Start/CompositionRoot.cs
- / App_Start CompositionRoot.cs
/DI/InjectableControllerFactory.cs
- DI / InjectableControllerFactory.cs
/DI/Windsor/WindsorDependencyInjectionContainer.cs
- / DI /温莎/ WindsorDependencyInjectionContainer.cs
/DI/Windsor/Installers/MvcInstaller.cs
- DI /温莎/安装/ MvcInstaller.cs
/DI/Windsor/Installers/MvcSiteMapProviderInstaller.cs
- DI /温莎/安装/ MvcSiteMapProviderInstaller.cs
- 为基本结构分析下列文件:/App_Start/DIConfig。cs / App_Start / CompositionRoot。cs / DI / InjectableControllerFactory。cs / DI /温莎/ WindsorDependencyInjectionContainer。cs / DI /温莎/安装/ MvcInstaller。cs / DI /温莎/安装/ MvcSiteMapProviderInstaller.cs
Once you have this working configuration, you can then refactor it and add to it to suit your application's needs.
一旦您有了这个工作配置,您就可以重构它并添加到它以满足您的应用程序的需要。
As I recall, there weren't any changes required to make the MVC 4 DI configuration work with MVC 5. So, the problem you are running into is most likely one of the following:
正如我所记得的,没有任何更改需要使MVC 4 DI配置与MVC 5一起工作。所以,你遇到的问题很可能是以下几个问题之一:
- You are using a 3rd party DI component that is not compatible with MVC 5.
- 您使用的是与MVC 5不兼容的第三方DI组件。
- You are using DependencyResolver, and your configuration doesn't include the necessary code to resolve the dependencies of MVC 5.
- 您使用的是DependencyResolver,而您的配置不包含解决MVC 5依赖关系的必要代码。
- You are using advanced features of Castle Windsor that we are not using, and have them misconfigured in some way.
- 您正在使用我们不使用的高级功能的城堡温莎,并在某些方面配置错误。
ControllerFactory vs DependencyResolver
Do note that according to Dependency Injection in .NET by Mark Seemann (which I highly recommend), it is ill-advised to use IDependencyResolver
with Castle Windsor because it guarantees resource leaks. In fact, this is probably the most compelling argument that he makes for his reasoning for declaring service locator as anti-pattern.
请注意,根据Mark Seemann(我强烈推荐的)在。net中的依赖注入,使用IDependencyResolver与Castle Windsor是不明智的,因为它保证了资源的泄漏。事实上,这可能是他为其将服务定位器声明为反模式的理由所做的最令人信服的论证。
The recommended approach is to use IControllerFactory
as the integration point into MVC, which implements a ReleaseController
method to solve this issue.
推荐的方法是将IControllerFactory作为集成点到MVC,它实现了一个发布控制方法来解决这个问题。
#3
0
So looking at your code, literally all of it can be replaced by Castle.Windsor.MsDependencyInjection
library.
看看你的代码,所有的代码都可以被Castle.Windsor取代。MsDependencyInjection图书馆。
Add Castle.Windsor.MsDependencyInjection
to your project then use like so:
添加Castle.Windsor。对您的项目进行MsDependencyInjection,然后使用如下:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// Normal component registration can go here...
return WindsorRegistrationHelper.CreateServiceProvider(yourWindsorContainer, services);
}