依赖注入 – 如何开始使用ASP.NET(5)Core和Castle Windsor进行依赖注入?

背景:

根据Castle Windsor教程,我已经使用Castle Windsor与安装程序和设施,早期版本的MVC(pre-6)和WebAPI.

ASP.NET(5)Core已经包括了一些依赖注入支持,但是我仍然没有弄清楚如何连线,我发现的几个示例与以前使用的样本有很大的不同(与安装/设施).大多数例子早于ASP.NET(5)核心最新版本,有些似乎有过时的信息.

它似乎已经从以前的版本组合根设置发生了很大变化,甚至没有Microsoft.Framework.DependencyInjection.ServiceProvider可以解决所有的依赖项,当我将其设置为城堡温莎DI后备.我仍然在挖掘细节,但并不是最新的信息.

我试图使用城堡温莎DI

我找到一个这样的适配器:Github Castle.Windsor DI container.

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
我添加了几行来添加城堡温莎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();
            }
        }
    }
}

首先打嗝和解决尝试

从这个例子我得到:

Castle.Windsor.dll中出现了“Castle.MicroKernel.ComponentNotFoundException”类型的异常,但未在用户代码中处理
附加信息:没有用于支持服务的组件Microsoft.Framework.Runtime.IAssemblyLoaderEngine被发现

它在城堡后背 – Microsoft.Framework.DependencyInjection.ServiceProvider(服务表)中无法查找调试器.

http://davidzych.com/tag/castle-windsor/起,我尝试添加一个Fallback,因为Windsor无法解析所有的ASP.NET依赖关系.

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;
    }
}

似乎有必要(注入所有的.NET依赖项)

我可以注释掉startup.cs app.UseBrowserLink();以摆脱IAssemblyLoaderEngine异常.

        if (string.Equals(env.EnvironmentName, "Development", StringComparison.OrdinalIgnoreCase))
        {
            //app.UseBrowserLink(); // 

现在我遇到一个例外:

在mscorlib.dll中发生了类型“System.Reflection.TargetInvocationException”的异常,但在用户代码中未处理

尝试获取服务:{Name =“IUrlHelper”FullName =“Microsoft.AspNet.Mvc.IUrlHelper”}

    public IRegistration Load(string name, Type service, IDictionary arguments)
    {
        var serviceFromFallback = _fallbackProvider.GetService(service);

如何前进?

这个尝试将Castle Windsor DI连接到ASP.NET(5)核心中有什么问题?

最佳答案
现在我不认为你可以使用Castle Windsor Container作为DI容器,因为Windsor不支持新的DNVM.但是AutoFac也遵循同样的规则.

在Startup.cs中有一个ConfigureServices方法,其返回类型为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>();
}

其他DI适配器也实现了类似的接口.您可以尝试自己,但是注意AutoFac现在在beta5中,因此您需要进行一些调整,使您的应用程序运行.

希望这可以帮助

转载注明原文:依赖注入 – 如何开始使用ASP.NET(5)Core和Castle Windsor进行依赖注入? - 代码日志