如何开始使用ASP.NET(5)Core和Castle Windsor进行依赖注入? [英] How can I get started with ASP.NET (5) Core and Castle Windsor for Dependency Injection?

查看:102
本文介绍了如何开始使用ASP.NET(5)Core和Castle Windsor进行依赖注入?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据Castle Windsor教程以及较早版本的MVC(6之前的版本)和WebAPI,我已将Castle Windsor与安装程序和设施一起使用.

I've used Castle Windsor with Installers and Facilities according to the Castle Windsor tutorial with earlier versions of MVC (pre-6) and WebAPI.

ASP.NET(5)核心包括一些依赖注入支持,但是我仍然没有弄清楚如何连接它,而我发现的一些示例看起来与以前使用时有很大不同. (以及安装程序/设施).大多数示例早于ASP.NET(5)内核的最新版本,而某些示例似乎已过时.

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.

与以前的版本组合根目录设置相比,它似乎发生了很大变化,并且当我将其设置为Castle Windsor DI后备时,甚至Microsoft.Framework.DependencyInjection.ServiceProvider都无法解决所有依赖关系.我仍在研究细节,但没有太多最新信息.

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.

我找到了这样的适配器: Github Castle.Windsor DI容器 .

I've found an adapter like this: 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 我添加了几行以添加Castle Windsor ILazyComponentLoader后备广告.

WindsorRegistration.cs I added a few lines to add a Castle Windsor ILazyComponentLoader fallback.

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


第一次打cup和解决尝试

从该示例中我得到:


First hiccup and resolution attempt

From that example I was getting:

Castle.Windsor.dll中发生了类型'Castle.MicroKernel.ComponentNotFoundException'的异常,但未在用户代码中处理 附加信息:找不到支持服务Microsoft.Framework.Runtime.IAssemblyLoaderEngine的组件

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 Fallback-Microsoft.Framework.DependencyInjection.ServiceProvider(服务表).

It wasn't available looking in the debugger at the Castle Fallback - Microsoft.Framework.DependencyInjection.ServiceProvider (table of services).

来自 http://davidzych.com/tag/castle-windsor/由于Windsor无法解决所有ASP.NET依赖关系,因此尝试添加回退.

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.

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异常.

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.

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

现在我遇到一个异常:

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

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

Trying to get the service: {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)Core的尝试有什么问题?

How to move forward?

What is wrong with this attempt to wire up Castle Windsor DI into ASP.NET (5) Core?

推荐答案

目前我不认为您可以将Castle Windsor Container用作DI容器,因为Windsor不支持新的DNVM .但是AutoFac确实这样做,并且它们遵循相同的规则.

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.

在Startup.cs中,有一个ConfigureServices方法,其返回类型为void.您可以将返回类型更改为ISerivceProvider并返回具体的IServiceProvider,系统将使用新的IServiceProvider作为默认的DI容器.下面是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.

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中,因此您需要进行一些调整才能使您的应用程序运行.

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.

希望这会有所帮助

这篇关于如何开始使用ASP.NET(5)Core和Castle Windsor进行依赖注入?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆