Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/323.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 与ASP.NET核心和MVC6(核心)的统一_C#_Asp.net Core Mvc_Unity Container - Fatal编程技术网

C# 与ASP.NET核心和MVC6(核心)的统一

C# 与ASP.NET核心和MVC6(核心)的统一,c#,asp.net-core-mvc,unity-container,C#,Asp.net Core Mvc,Unity Container,更新日期:2018年8月9日 Unity正在开发中,但我还没有时间测试它如何与ASP.NET核心框架配合使用 更新日期:2018年3月15日 此解决方案针对的是使用带Unity的ASP.NET Core v1而使用.NET Framework 4.5.2而不是.NET Core Framework的特定问题。我不得不使用这种设置,因为我需要一些.NET4.5.2DLL,但对于任何重新开始的人,我不推荐这种方法。此外,据我所知,Unity没有进一步开发,因此我建议在新项目中使用Autofac框架。

更新日期:2018年8月9日 Unity正在开发中,但我还没有时间测试它如何与ASP.NET核心框架配合使用

更新日期:2018年3月15日 此解决方案针对的是使用带Unity的ASP.NET Core v1而使用.NET Framework 4.5.2而不是.NET Core Framework的特定问题。我不得不使用这种设置,因为我需要一些.NET4.5.2DLL,但对于任何重新开始的人,我不推荐这种方法。此外,据我所知,Unity没有进一步开发,因此我建议在新项目中使用Autofac框架。有关如何执行此操作的更多信息,请参见此

简介
我正在使用ASP.NET和MVC构建一个Web应用程序。此应用程序依赖于某些服务(WCF服务、数据存储服务等)。现在,为了保持良好和解耦,我想使用DI(依赖注入)框架,特别是Unity 初步研究
我发现了这一点,但遗憾的是它不起作用。不过,这个想法很好。
它基本上说,您不应该将ServiceCollection中注册的所有服务注册到您自己的容器中,而应该引用默认的ServiceProvider。
因此。如果需要解析某些内容,将调用默认的ServiceProvider,如果没有解析,则将使用自定义UnityContainer解析该类型。

问题
MVC总是尝试使用默认的ServiceProvider解析控制器
此外,我注意到,即使控制器能够正确解析,我也无法“混合”依赖项。现在,如果我想使用我的一个服务,但同时使用ASP的IOptions接口,则该类永远无法解析,因为这两个容器中没有一个对这两种类型都有解析。

我需要什么
因此,概括一下,我需要以下几点:

  • 不需要将ASP.NET依赖项复制到UnityContainer中的设置
  • 可以解析我的MVC控制器的容器
  • 可以解析“混合”依赖项的容器
编辑:
所以问题是我怎样才能达到这些点

环境
project.json:

因此,经过一些研究,我提出了以下解决问题的方法:

与ASP一起使用Unity
为了能够将Unity与ASP结合使用,我需要一个定制的IServiceProvider(),因此我为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
}
为此:

public IServiceProvider ConfigureServices(IServiceCollection services)
现在我可以返回我的自定义iSeries Provider,它将被使用,而不是默认的。
完整的ConfigureServices方法显示在底部的连线部分。

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

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
}
services.AddMvc();
现在,如果一个控制器类被激活,它将与我的UnityContainer一起安装。因此,我的UnityContainer必须知道如何解析任何控制器!

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

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
}
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
}
公共类UnityFallbackProviderExtension:UnityContainerExtension
{
#区域常数
///用于解析UnityFallbackProviderStrategy类内的默认容器
public const string FALLBACK\u PROVIDER\u NAME=“UnityFallbackProvider”;
#端区
#区域变量
//默认服务提供程序,以便我可以将其注册到IUnityContainer
私人IServiceProvider\u defaultServiceProvider;
#端区
#区域构造函数
/// 
///创建UnityFallbackProviderExtension类的新实例
/// 
///用于回退到的默认提供程序
public UnityFallbackProviderExtension(IServiceProvider defaultServiceProvider)
{
_defaultServiceProvider=defaultServiceProvider;
}
#端区
#UnityContainerExtension的区域覆盖
/// 
///使用此扩展的功能初始化容器。
/// 
/// 
///在派生类中重写时,此方法将修改给定的
///通过增加战略、政策等
///将其功能安装到容器中。
受保护的覆盖无效初始化()
{
//使用名称注册默认的IServiceProvider。
//现在,如果需要,UnityFallbackProviderStrategy可以解析默认提供程序
Context.Container.RegisterInstance(回退\u提供程序\u名称,\u defaultServiceProvider);
//使用我们的UnityContainer创建UnityFallbackProvider策略
var strategy=newunityFallbackProviderStrategy(Context.Container);
//添加要与PreCreation LifeCycleHook一起执行的UnityFallbackProviderStrategy
//预创建,因为如果未向IUnityContainer注册,则会出现异常
//现在,如果IUnityContainer“神奇地”获得一个类型的实例,它将接受它并继续
Context.Strategies.Add(strategy,UnityBuildStage.PreCreation);
}
#端区
}

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
}
公共类UnityFallbackProviderStrategy:BuilderStrategy
{
专用IUnityContainer\u容器;
public UnityFallbackProviderStrategy(IUnityContainer容器)
{
_容器=容器;
}
#BuilderStrategy的区域覆盖
/// 
///在构建操作的责任链期间调用
///P
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
       .UseUnityServiceProvider()   <---- Add this line
       .UseStartup<Startup>()
       .Build();