zoukankan      html  css  js  c++  java
  • 使用IOC内置的容器进行属性注入

    https://blog.csdn.net/LongtengGensSupreme/article/details/112525108

    ASP.NET Core MVC 控制器创建与依赖注入(*)

    https://www.cnblogs.com/tdfblog/p/controller-activation-and-dependency-injection-in-asp-net-core-mvc.html

    使用IOC内置的容器进行属性注入,新建Asp Net Core Web项目,添加以下内容
    1. 自定义特性,标记需要控制器Controoler中依赖注入的属性标记和对应服务接口

    using System;
     
    namespace WebAppTest.CustomAttrributes
    {
    /// <summary>
    /// 属性的特性标记,主要用于标记属性
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    public class CustomPropertyAttribute: Attribute
    {
    }
     
    /// <summary>
    /// 方法的特性标记,主要用于标记方法
    /// </summary>
    [AttributeUsage(AttributeTargets.Method)]
    public class CustomMethodAttribute : Attribute
    {
    }
    }

    2. 添加接口

    namespace WebAppTest.Services
    {
    public interface ITestA
    {
    void Show();
    }
    }
     
    using System;
     
    namespace WebAppTest.Services
    {
    public class TestA : ITestA
    {
    public void Show()
    {
    Console.WriteLine($"这是接口ITestA的实现。。。");
    }
    }
    }

    3.  自定义类实现IOC容器,Controller控制器 属性注入和 方法注入,CustomMethodAttribute标记需要的方法,不是所有的方法,CustomPropertyAttribute标记需要的属性,不是所有的属性

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.Controllers;
    using Microsoft.Extensions.DependencyInjection;
    using System.Collections.Generic;
    using System.Linq;
    using WebAppTest.CustomAttrributes;
     
    namespace WebAppTest.Extensions
    {
    /// <summary>
    /// 自定义的控制器创建对象,以便使用ioc创建控制器,其实IOC就是一个字典Dictionary
    /// </summary>
    public class CustomServiceBaseControllerActivator : IControllerActivator
    {
    public object Create(ControllerContext context)
    {
    var controllerType = context.ActionDescriptor.ControllerTypeInfo.AsType();
    //IOC容器完成实例化
    var controllerInstance = context.HttpContext.RequestServices.GetRequiredService(controllerType);
    //Controller控制器属性注入,CustomPropertyAttribute标记需要的属性,不是所有的属性
    foreach (var prop in controllerType.GetProperties().Where(prop => prop.IsDefined(typeof(CustomPropertyAttribute), true)))
    {
    var propValue = context.HttpContext.RequestServices.GetRequiredService(prop.PropertyType);
    prop.SetValue(controllerInstance, propValue);
    }
     
    //Controller控制器方法注入,CustomMethodAttribute标记需要的方法,不是所有的方法
    foreach (var method in controllerType.GetMethods().Where(method => method.IsDefined(typeof(CustomMethodAttribute), true)))
    {
    var methodParameters = method.GetParameters();
    List<object> listMethodParameters = new List<object>();
    foreach (var para in methodParameters)
    {
    var paraValue = context.HttpContext.RequestServices.GetRequiredService(para.ParameterType);
    listMethodParameters.Add(paraValue);
    }
     
    //调用Controller控制器方法
    method.Invoke(controllerInstance, listMethodParameters.ToArray());
    }
    return controllerInstance;
    }
     
    public void Release(ControllerContext context, object controller)
    {
    //throw new NotImplementedException();
    }
    }
    }

    4、控制器Controller中属性注入和方法注入

    using Microsoft.AspNetCore.Mvc;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using WebAppTest.CustomAttrributes;
    using WebAppTest.Extensions;
    using WebAppTest.Services;
     
    namespace WebAppTest.Controllers
    {
    public class TestController : Controller
    {
    /// <summary>
    /// 属性注入--Controller控制器属性注入,CustomPropertyAttribute标记需要的属性,不是所有的属性
    /// </summary>
    [CustomPropertyAttribute]
    public ITestA _testA { get; set; }
     
    /// <summary>
    /// 用于方法注入的字段
    /// </summary>
    private ITestB _testB;
    /// <summary>
    /// 方法注入--Controller控制器方法注入,CustomMethodAttribute标记需要的方法,不是所有的方法
    /// </summary>
    [CustomMethodAttribute]
    public void CreateInstance(ITestB testB)
    {
    _testB = testB;
    }
     
    public IActionResult Index()
    {
    _testA.Show();
    _testB.Show();
    //((ITestA)_testA.AOP(typeof(ITestA))).Show();
    return View();
    }
    }
    }

    5. Startup中添加

    //把控制器作为服务注册,然后使用它内置的ioc来替换原来的控制器的创建器,这样就可以使用IOC来依赖注入和控制反转创建对应的控制器 
    services.AddControllersWithViews().AddControllersAsServices();
    services.Replace(ServiceDescriptor.Transient<IControllerActivator, CustomServiceBaseControllerActivator>());
     
    services.AddTransient<ITestA, TestA>();
    services.AddTransient<ITestB, TestB>(); 

    _________________________________________________________________________________________________________________________________________________________________________

    ASP.NET Core MVC 控制器创建与依赖注入

     

    本文翻译自《Controller activation and dependency injection in ASP.NET Core MVC》,由于水平有限,故无法保证翻译完全准确,欢迎指出错误。谢谢!

    在我最后一篇关于 ASP.NET Core 释放IDsiposable对象的文章(中文英文原文)中,Mark Rendle 指出,MVC 控制器在请求结束时也会释放资源。乍一看,此范围内的资源在请求结束时会释放似乎是显而易见的,但是 MVC 控制器的处理方式实际上与大多数服务略有不同。

    在这篇文章中,我将介绍在ASP.NET Core MVC中IControllerActivator是如何创建控制器的,以及通过依赖注入创建控制器存在的差异。

    默认的IControllerActivator

    在 ASP.NET Core 中,当 MVC 中间件接收到请求时,通过路由选择要执行的控制器和操作方法。为了实际的执行操作, MVC 中间件必须创建所选控制器的实例。

    创建控制器的过程依赖众多不同的提供者和工厂类,但最终是由实现IControllerActivator接口的实例来决定的。实现类只需要实现两个方法:

    public interface IControllerActivator  
    {
        object Create(ControllerContext context);
        void Release(ControllerContext context, object controller);
    }
    

    如您所见,该IControllerActivator.Create方法传递了用于创建控制器的ControllerContext实例。控制器的创建方式取决于具体的实现。

    众所周知,ASP.NET Core 使用的是DefaultControllerActivator,它通过TypeActivatorCache来创建控制器。TypeActivatorCache通过调用类的构造函数,并试图从 DI 容器中解析构造函数所需参数的实例。

    有一点很重要,DefaultControllerActivator 不会试图从 DI 容器中解析控制器的实例,只会解析控制器的依赖项。


    ## DefaultControllerActivator 示例

    为了演示这个行为,我创建了一个简单的 MVC 应用程序,包括一个单一的服务和一个控制器。服务实例有一个name属性,它通过构造函数来设置。默认情况下,它使用"default"作为默认值。

    public class TestService  
    {
        public TestService(string name = "default")
        {
            Name = name;
        }
    
        public string Name { get; }
    }
    

    在应用程序中HomeController依赖于TestService,并返回Name属性的值:

    public class HomeController : Controller  
    {
        private readonly TestService _testService;
        public HomeController(TestService testService)
        {
            _testService = testService;
        }
    
        public string Index()
        {
            return "TestService.Name: " + _testService.Name;
        }
    }
    

    还有一块代码在Startup文件中。在这里我将TestService注册在 DI 容器中作为范围内服务,并设置 MVC 中间件和服务:

    public class Startup  
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
    
            services.AddScoped<TestService>();
            services.AddTransient(ctx =>
                new HomeController(new TestService("Non-default value")));
        }
    
        public void Configure(IApplicationBuilder app)
        {
            app.UseMvcWithDefaultRoute();
        }
    }
    

    您会注意到,我定义了一个工厂方法用于创建HomeController的实例。将HomeController类型注册到 DI 容器中,并且在TestService实例中传递自定义Name属性。

    如果您运行应用程序,您会看到什么结果?

    您可以看到,该TestService.Name属性使用的是默认值,表示TestService实例是直接从 DI 容器中获取的,直接忽略了创建HomeController的工厂方法。

    这很容易理解,当您通过DefaultControllerActivator创建控制器时,它不会从DI容器中创建HomeController实例,只会解析构造函数的依赖项。

    大多数情况下,使用DefaultControllerActivator是一个不错的选择,但有时您可能希望直接通过 DI 容器来创建控制器,比如您希望使用具有拦截器或装饰器等功能的第三方容器。

    幸运的是,MVC 框架包含了一个这样的IControllerActivator实现,并提供了一种非常方便的扩展方法来启用它。


    ## ServiceBasedControllerActivator

    如您所见,DefaultControllerActivator使用TypeActivatorCache来创建控制器,MVC还包括另一个实现,称为ServiceBasedControllerActivator,它是直接从 DI 容器中获取控制器。它的实现非常简单:

    public class ServiceBasedControllerActivator : IControllerActivator  
    {
        public object Create(ControllerContext actionContext)
        {
            var controllerType = actionContext.ActionDescriptor.ControllerTypeInfo.AsType();
    
            return actionContext.HttpContext.RequestServices.GetRequiredService(controllerType);
        }
    
        public virtual void Release(ControllerContext context, object controller)
        {
        }
    }
    

    当您将 MVC 服务添加到应用程序时,可以使用AddControllersAsServices()扩展方法配置基于 DI 的激活器:

    public class Startup  
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc()
                    .AddControllersAsServices();
    
            services.AddScoped<TestService>();
            services.AddTransient(ctx =>
                new HomeController(new TestService("Non-default value")));
        }
    
        public void Configure(IApplicationBuilder app)
        {
            app.UseMvcWithDefaultRoute();
        }
    }
    

    通过上面的代码,点击主页将通过 DI 容器来创建一个控制器。由于我们已经注册了一个创建HomeController的工厂方法,我们自定义TestService配置将被保留,使用替换后的Name属性:

    AddControllersAsServices方法实现了两件事情 - 它将您应用程序中的所有控制器注册到 DI 容器(如果尚未注册),并将IControllerActivator注册为ServiceBasedControllerActivator

    public static IMvcBuilder AddControllersAsServices(this IMvcBuilder builder)  
    {
        var feature = new ControllerFeature();
        builder.PartManager.PopulateFeature(feature);
    
        foreach (var controller in feature.Controllers.Select(c => c.AsType()))
        {
            builder.Services.TryAddTransient(controller, controller);
        }
    
        builder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
    
        return builder;
    }
    

    如果需要做一些更复杂的事情,您可以随时实现自己IControllerActivator;不过我找不到任何理由,这两点实现还不能满足您的需求!


    ## 总结
    • 默认情况下,在ASP.NET Core MVC 中IControllerActivator配置为DefaultControllerActivator
    • DefaultControllerActivator使用TypeActivatorCache来创建控制器。它从 DI 容器加载构造函数所需参数来创建控制器的实例。
    • 您也可以使用ServiceBasedControllerActivator作替代方法,它直接从 DI 容器加载控制器。您可以在Startup.ConfigureServices方法中使用MvcBuilderAddControllersAsServices()扩展方法来配置此激活方式。

    转载请注明出处,原文链接:http://www.cnblogs.com/tdfblog/p/controller-activation-and-dependency-injection-in-asp-net-core-mvc.html


    如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!

    欢迎各位转载,转载文章之后必须在文章页面明显位置给出作者和原文连接。

     
  • 相关阅读:
    JAVA EE获取浏览器和操作系统信息
    ANT与SVN集成
    ANT property三种使用方式
    跨机器的文件夹访问和传输方法
    yolov5网络结构分析
    点到直线距离计算及g++编译
    深拷贝与浅拷贝(c++和python)
    qt工程环境设置
    Git 篇
    PyCharm 使用的技巧
  • 原文地址:https://www.cnblogs.com/kelelipeng/p/14339659.html
Copyright © 2011-2022 走看看