与ASP.NET Core和MVC6(核心)实现统一

D4rth B4n3

更新09.08.2018这里
正在开发Unity 但我还没有时间测试它如何与ASP.NET Core框架一起使用。

更新15.03.2018
此解决方案是针对在使用.NET Framework 4.5.2而不是.NET Core框架的同时将ASP.NET Core v1与Unity结合使用的特定问题我必须使用此设置,因为我需要一些.Net 4.5.2 DLL,但是对于任何重新开始的人,我都不推荐这种方法。同样,据我所知,Unity还没有进一步开发,因此我建议对新项目使用Autofac Framework。有关如何执行此操作的更多信息,请参见此帖子

简介
我正在使用带有MVC的ASP.NET构建Web应用程序。此应用程序取决于某些服务(WCF服务,数据存储服务等)。现在,为了使事情保持良好状态和分离,我想使用DI(依赖注入)框架,特别是Unity。

初步研究
我发现了此博客文章,但不幸的是它没有用。这个想法虽然很好。
它基本上说您不应将在ServiceCollection中注册的所有服务注册到自己的容器中,而应引用默认的ServiceProvider。
所以。如果需要解决某些问题,则会调用默认的ServiceProvider,如果它没有解析度,则将使用您的自定义UnityContainer来解析类型。

问题所在
MVC始终尝试使用默认的ServiceProvider解析控制器。
另外,我注意到,即使Controller得到正确解析,我也永远无法“混合”依赖关系。现在,如果我要使用我的服务之一,也要使用ASP的IOptions接口,则该类将永远无法解析,因为这两个容器中的任何一个都不具有针对这两种类型的解析度。

我需要什么
回顾一下,我需要以下几点:

  • 我不需要将ASP.NET依赖项复制到UnityContainer中的设置
  • 一个可以解析我的MVC控制器的容器
  • 一个可以解决“混合”依赖关系的容器

编辑:
所以问题是我怎么能达到这些要点?

环境
project.json:
在此处输入图片说明

D4rth B4n3

因此,在进行了一些研究之后,我想出了以下解决问题的方法:

将Unity与ASP
结合使用为了能够将Unity与ASP结合使用,我需要一个自定义IServiceProvider(ASP文档),因此我为IUnityContainer编写了一个包装,如下所示:

public class UnityServiceProvider : IServiceProvider
{
    private IUnityContainer _container;

    public IUnityContainer UnityContainer => _container;

    public UnityServiceProvider()
    {
        _container = new UnityContainer();
    }

    #region Implementation of IServiceProvider

    /// <summary>Gets the service object of the specified type.</summary>
    /// <returns>A service object of type <paramref name="serviceType" />.-or- null if there is no service object of type <paramref name="serviceType" />.</returns>
    /// <param name="serviceType">An object that specifies the type of service object to get. </param>
    public object GetService(Type serviceType)
    {
        //Delegates the GetService to the Containers Resolve method
        return _container.Resolve(serviceType);
    }

    #endregion
}

另外,我还必须从此更改Startup类中的ConfigureServices方法的Signature:

public void ConfigureServices(IServiceCollection services)

对此:

public IServiceProvider ConfigureServices(IServiceCollection services)

现在,我可以返回自定义的IServiceProvider,它将使用它而不是默认值。
完整的ConfigureServices方法显示在底部的“连接”部分中。

解决控制器
我找到了此博客文章从中我了解到MVC使用IControllerActivator接口来处理Controller实例化。所以我写了我自己的,看起来像这样:

public class UnityControllerActivator : IControllerActivator
{
    private IUnityContainer _unityContainer;

    public UnityControllerActivator(IUnityContainer container)
    {
        _unityContainer = container;
    }

    #region Implementation of IControllerActivator

    public object Create(ControllerContext context)
    {
        return _unityContainer.Resolve(context.ActionDescriptor.ControllerTypeInfo.AsType());
    }


    public void Release(ControllerContext context, object controller)
    {
        //ignored
    }

    #endregion
}

现在,如果激活了Controller类,它将被我的UnityContainer实例化。因此,我的UnityContainer必须知道如何解析任何控制器!

下一个问题:使用默认的IServiceProvider
现在,如果我在ASP.NET中注册诸如Mvc之类的服务,通常我会这样做:

services.AddMvc();

现在,如果我使用UnityContainer,则由于未注册,因此无法解析所有MVC依赖关系。因此,我可以注册它们(例如AutoFac),也可以创建UnityContainerExtension。我选择了扩展,并提出了以下两个方面:
UnityFallbackProviderExtension

public class UnityFallbackProviderExtension : UnityContainerExtension
{
    #region Const

    ///Used for Resolving the Default Container inside the UnityFallbackProviderStrategy class
    public const string FALLBACK_PROVIDER_NAME = "UnityFallbackProvider";

    #endregion

    #region Vars

    // The default Service Provider so I can Register it to the IUnityContainer
    private IServiceProvider _defaultServiceProvider;

    #endregion

    #region Constructors

    /// <summary>
    /// Creates a new instance of the UnityFallbackProviderExtension class
    /// </summary>
    /// <param name="defaultServiceProvider">The default Provider used to fall back to</param>
    public UnityFallbackProviderExtension(IServiceProvider defaultServiceProvider)
    {
        _defaultServiceProvider = defaultServiceProvider;
    }

    #endregion

    #region Overrides of UnityContainerExtension

    /// <summary>
    /// Initializes the container with this extension's functionality.
    /// </summary>
    /// <remarks>
    /// When overridden in a derived class, this method will modify the given
    /// <see cref="T:Microsoft.Practices.Unity.ExtensionContext" /> by adding strategies, policies, etc. to
    /// install it's functions into the container.</remarks>
    protected override void Initialize()
    {
        // Register the default IServiceProvider with a name.
        // Now the UnityFallbackProviderStrategy can Resolve the default Provider if needed
        Context.Container.RegisterInstance(FALLBACK_PROVIDER_NAME, _defaultServiceProvider);

        // Create the UnityFallbackProviderStrategy with our UnityContainer
        var strategy = new UnityFallbackProviderStrategy(Context.Container);

        // Adding the UnityFallbackProviderStrategy to be executed with the PreCreation LifeCycleHook
        // PreCreation because if it isnt registerd with the IUnityContainer there will be an Exception
        // Now if the IUnityContainer "magically" gets a Instance of a Type it will accept it and move on
        Context.Strategies.Add(strategy, UnityBuildStage.PreCreation);
    }

    #endregion
}


UnityFallbackProviderStrategy

public class UnityFallbackProviderStrategy : BuilderStrategy
{
    private IUnityContainer _container;

    public UnityFallbackProviderStrategy(IUnityContainer container)
    {
        _container = container;
    }

    #region Overrides of BuilderStrategy

    /// <summary>
    /// Called during the chain of responsibility for a build operation. The
    /// PreBuildUp method is called when the chain is being executed in the
    /// forward direction.
    /// </summary>
    /// <param name="context">Context of the build operation.</param>
    public override void PreBuildUp(IBuilderContext context)
    {
        NamedTypeBuildKey key = context.OriginalBuildKey;

        // Checking if the Type we are resolving is registered with the Container
        if (!_container.IsRegistered(key.Type))
        {
            // If not we first get our default IServiceProvider and then try to resolve the type with it
            // Then we save the Type in the Existing Property of IBuilderContext to tell Unity
            // that it doesnt need to resolve the Type
            context.Existing = _container.Resolve<IServiceProvider>(UnityFallbackProviderExtension.FALLBACK_PROVIDER_NAME).GetService(key.Type);
        }

        // Otherwise we do the default stuff
        base.PreBuildUp(context);
    }

    #endregion
}

现在,如果我的UnityContainer没有注册任何内容,则只需询问默认提供者即可。
我从几篇不同的文章中学到了所有这些

这种方法的好处是,我现在也可以“混合”依赖项。如果我需要任何服务以及来自ASP的IOptions接口,我的UnityContainer都将解决所有这些依赖关系并将其注入到我的控制器中!!!
唯一要记住的是,如果我使用自己的任何依赖关系,都必须向Unity注册我的Controller类,因为默认的IServiceProvider无法再解析我的Controllers依赖关系。

最后:连线
现在,在我的项目中,我使用不同的服务(ASP选项,带有选项的MVC)。为了使其全部正常工作,我的ConfigureServices方法现在看起来像这样:

public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        // Add all the ASP services here
        // #region ASP
        services.AddOptions();
        services.Configure<WcfOptions>(Configuration.GetSection("wcfOptions"));

        var globalAuthFilter = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .Build();

        services.AddMvc(options => { options.Filters.Add(new AuthorizeFilter(globalAuthFilter)); })
                .AddJsonOptions
            (
                options => options.SerializerSettings.ContractResolver = new DefaultContractResolver()
            );
        // #endregion ASP

        // Creating the UnityServiceProvider
        var unityServiceProvider = new UnityServiceProvider();

        IUnityContainer container = unityServiceProvider.UnityContainer;

        // Adding the Controller Activator
        // Caution!!! Do this before you Build the ServiceProvider !!!
        services.AddSingleton<IControllerActivator>(new UnityControllerActivator(container));

        //Now build the Service Provider
        var defaultProvider = services.BuildServiceProvider();

        // Configure UnityContainer
        // #region Unity

        //Add the Fallback extension with the default provider
        container.AddExtension(new UnityFallbackProviderExtension(defaultProvider));

        // Register custom Types here

        container.RegisterType<ITest, Test>();

        container.RegisterType<HomeController>();
        container.RegisterType<AuthController>();

        // #endregion Unity

        return unityServiceProvider;
    }

由于我在过去的一周中了解了大部分关于DI的知识,所以我希望我不会破坏任何大的Pricipal / Pattern,如果有的话,请告诉我!

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

配置核心以允许使用ASP.NET Core(Asp.net 5,MVC6,VNext)的所有子域

来自分类Dev

ASP.NET 4.6 WebForms和ASP.NET Core MVC 1.0(aka MVC6)可以在同一应用程序中运行吗?

来自分类Dev

ASP.NET Core / MVC6中的WebTelemetryInitializerBase

来自分类Dev

ASP.NET MVC:统一和HierarchicalLifeTimemanager

来自分类Dev

Asp.Net核心MVC6如何在Identity 3中初始添加角色

来自分类Dev

在ASP.NET Core MVC6中将文件和模型发布到控制器

来自分类Dev

在ASP.NET Core 1.0 MVC6中使用内置的IoC配置AutoMapper 4.2

来自分类Dev

如何将输入元素集中在Asp.Net Core(MVC6)视图上

来自分类Dev

ASP.NET 5 MVC6自定义CSS和Javascript放置约定

来自分类Dev

ASP.NET 5和MVC6中的project.json

来自分类Dev

ASP.NET MVC6:以编程方式设置webroot

来自分类Dev

在ASP.NET 5(MVC6)中请求BinaryRead

来自分类Dev

ASP.NET MVC 6和ASP.NET Core 1.0之间有什么区别以及核心框架背后的原因?

来自分类Dev

将类实现从 asp.net mvc 移植到 asp.net mvc 核心

来自分类Dev

ASP.NET MVC 6(ASP.NET Core或ASP.NET5)中的友好URL

来自分类Dev

ASP.NET-Core MVC6 foreach语句无法对类型为'System.Threading.Tasks.Task <..>的变量进行操作

来自分类Dev

从web.config到Asp.net 5.0 Core vnext MVC6的企业库数据库连接

来自分类Dev

Asp.NEt核心和MVC 6有什么区别?

来自分类Dev

在asp.net 5 MVC6中,标记帮助器和Route属性之间的奇怪行为

来自分类Dev

ASP.NET 5 MVC6中数据模型注释的本地化和国际化

来自分类Dev

VB.NET对ASP.NET 5(MVC6)的支持

来自分类Dev

与ASP.NET MVC BeginExecuteCore等效的ASP.NET Core

来自分类Dev

asp .net 和 asp .net core 有什么区别?

来自分类Dev

MVC 5和ASP.NET标识-实现混乱

来自分类Dev

ASP.NET Core MVC 和 EF Core 1.1

来自分类Dev

如何在ASP.NET MVC 6(ASP.NET Core)中获取returnUrl AccessDeniedPath

来自分类Dev

在asp.net MVC6中获取Angular Ajax数据

来自分类Dev

ASP.NET 5 MVC6 Angular 2(Beta 0)-重复承诺

来自分类Dev

如何自托管ASP.NET 5 MVC6应用程序

Related 相关文章

  1. 1

    配置核心以允许使用ASP.NET Core(Asp.net 5,MVC6,VNext)的所有子域

  2. 2

    ASP.NET 4.6 WebForms和ASP.NET Core MVC 1.0(aka MVC6)可以在同一应用程序中运行吗?

  3. 3

    ASP.NET Core / MVC6中的WebTelemetryInitializerBase

  4. 4

    ASP.NET MVC:统一和HierarchicalLifeTimemanager

  5. 5

    Asp.Net核心MVC6如何在Identity 3中初始添加角色

  6. 6

    在ASP.NET Core MVC6中将文件和模型发布到控制器

  7. 7

    在ASP.NET Core 1.0 MVC6中使用内置的IoC配置AutoMapper 4.2

  8. 8

    如何将输入元素集中在Asp.Net Core(MVC6)视图上

  9. 9

    ASP.NET 5 MVC6自定义CSS和Javascript放置约定

  10. 10

    ASP.NET 5和MVC6中的project.json

  11. 11

    ASP.NET MVC6:以编程方式设置webroot

  12. 12

    在ASP.NET 5(MVC6)中请求BinaryRead

  13. 13

    ASP.NET MVC 6和ASP.NET Core 1.0之间有什么区别以及核心框架背后的原因?

  14. 14

    将类实现从 asp.net mvc 移植到 asp.net mvc 核心

  15. 15

    ASP.NET MVC 6(ASP.NET Core或ASP.NET5)中的友好URL

  16. 16

    ASP.NET-Core MVC6 foreach语句无法对类型为'System.Threading.Tasks.Task <..>的变量进行操作

  17. 17

    从web.config到Asp.net 5.0 Core vnext MVC6的企业库数据库连接

  18. 18

    Asp.NEt核心和MVC 6有什么区别?

  19. 19

    在asp.net 5 MVC6中,标记帮助器和Route属性之间的奇怪行为

  20. 20

    ASP.NET 5 MVC6中数据模型注释的本地化和国际化

  21. 21

    VB.NET对ASP.NET 5(MVC6)的支持

  22. 22

    与ASP.NET MVC BeginExecuteCore等效的ASP.NET Core

  23. 23

    asp .net 和 asp .net core 有什么区别?

  24. 24

    MVC 5和ASP.NET标识-实现混乱

  25. 25

    ASP.NET Core MVC 和 EF Core 1.1

  26. 26

    如何在ASP.NET MVC 6(ASP.NET Core)中获取returnUrl AccessDeniedPath

  27. 27

    在asp.net MVC6中获取Angular Ajax数据

  28. 28

    ASP.NET 5 MVC6 Angular 2(Beta 0)-重复承诺

  29. 29

    如何自托管ASP.NET 5 MVC6应用程序

热门标签

归档