ASP.NET Core Controller与IOC结合问题整理

前言

看到标题可能大家会有所疑问Controller和IOC能有啥羁绊,但是我还是拒绝当一个标题党的。相信有很大一部分人已经知道了这么一个结论,默认情况下ASP.NET Core的Controller并不会托管到IOC容器中,注意关键字我说的是"默认",首先咱们不先说为什么,如果还有不知道这个结论的同学们可以自己验证一下,验证方式也很简单,大概可以通过以下几种方式。

验证Controller不在IOC中

首先,我们可以尝试在ServiceProvider中获取某个Controller实例,比如

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
  var productController = app.ApplicationServices.GetService<ProductController>();
}

这是最直接的方式,可以在IOC容器中获取注册过的类型实例,很显然结果会为null。另一种方式,也是利用它的另一个特征,那就是通过构造注入的方式,如下所示我们在OrderController中注入ProductController,显然这种方式是不合理的,但是为了求证一个结果,我们这里仅做演示,强烈不建议实际开发中这么写,这是不规范也是不合理的写法

public class OrderController : Controller
{
  private readonly ProductController _productController;
  public OrderController(ProductController productController)
  {
    _productController = productController;
  }

  public IActionResult Index()
  {
    return View();
  }
}

结果显然是会报一个错InvalidOperationException: Unable to resolve service for type 'ProductController' while attempting to activate 'OrderController'。原因就是因为ProductController并不在IOC容器中,所以通过注入的方式会报错。还有一种方式,可能不太常用,这个是利用注入的一个特征,可能有些同学已经了解过了,那就是通过自带的DI,即使一个类中包含多个构造函数,它也会选择最优的一个,也就是说自带的DI允许类包含多个构造函数。利用这个特征,我们可以在Controller中验证一下

public class OrderController : Controller
{
  private readonly IOrderService _orderService;
  private readonly IPersonService _personService;

  public OrderController(IOrderService orderService)
  {
    _orderService = orderService;
  }

  public OrderController(IOrderService orderService, IPersonService personService)
  {
    _orderService = orderService;
    _personService = personService;
  }

  public IActionResult Index()
  {
    return View();
  }
}

我们在Controller中编写了两个构造函数,理论上来说这是符合DI特征的,运行起来测试一下,依然会报错InvalidOperationException: Multiple constructors accepting all given argument types have been found in type 'OrderController'. There should only be one applicable constructor。以上种种都是为了证实一个结论,默认情况下Controller并不会托管到IOC当中。

DefaultControllerFactory源码探究

上面虽然我们看到了一些现象,能说明Controller默认情况下并不在IOC中托管,但是还没有足够的说服力,接下来我们就来查看源码,这是最有说服力的。我们找到Controller工厂注册的地方,在MvcCoreServiceCollectionExtensions扩展类中[点击查看源码]的AddMvcCoreServices方法里

//给IControllerFactory注册默认的Controller工厂类DefaultControllerFactory
//也是Controller创建的入口
services.TryAddSingleton<IControllerFactory, DefaultControllerFactory>();
//真正创建Controller的工作类DefaultControllerActivator
services.TryAddTransient<IControllerActivator, DefaultControllerActivator>();

由此我们可以得出,默认的Controller创建工厂类为DefaultControllerFactory,那么我们直接找到源码位置[点击查看源码],
为了方便阅读,精简一下源码如下所示

internal class DefaultControllerFactory : IControllerFactory
{
  //真正创建Controller的工作者
  private readonly IControllerActivator _controllerActivator;
  private readonly IControllerPropertyActivator[] _propertyActivators;

  public DefaultControllerFactory(
    IControllerActivator controllerActivator,
    IEnumerable<IControllerPropertyActivator> propertyActivators)
  {
    _controllerActivator = controllerActivator;
    _propertyActivators = propertyActivators.ToArray();
  }

  /// <summary>
  /// 创建Controller实例的方法
  /// </summary>
  public object CreateController(ControllerContext context)
  {
    //创建Controller实例的具体方法(这是关键方法)
    var controller = _controllerActivator.Create(context);
    foreach (var propertyActivator in _propertyActivators)
    {
      propertyActivator.Activate(context, controller);
    }
    return controller;
  }

  /// <summary>
  /// 释放Controller实例的方法
  /// </summary>
  public void ReleaseController(ControllerContext context, object controller)
  {
    _controllerActivator.Release(context, controller);
  }
}

用过上面的源码可知,真正创建Controller的地方在_controllerActivator.Create方法中,通过上面的源码可知为IControllerActivator默认注册的是DefaultControllerActivator类,直接找到源码位置[点击查看源码],我们继续简化一下源码如下所示

internal class DefaultControllerActivator : IControllerActivator
{
  private readonly ITypeActivatorCache _typeActivatorCache;

  public DefaultControllerActivator(ITypeActivatorCache typeActivatorCache)
  {
    _typeActivatorCache = typeActivatorCache;
  }

  /// <summary>
  /// Controller实例的创建方法
  /// </summary>
  public object Create(ControllerContext controllerContext)
  {
    //获取Controller类型信息
    var controllerTypeInfo = controllerContext.ActionDescriptor.ControllerTypeInfo;
    //获取ServiceProvider
    var serviceProvider = controllerContext.HttpContext.RequestServices;
    //创建controller实例
    return _typeActivatorCache.CreateInstance<object>(serviceProvider, controllerTypeInfo.AsType());
  }

  /// <summary>
  /// 释放Controller实例
  /// </summary>
  public void Release(ControllerContext context, object controller)
  {
    //如果controller实现了IDisposable接口,那么Release的时候会自动调用Controller的Dispose方法
    //如果我们在Controller中存在需要释放或者关闭的操作,可以再Controller的Dispose方法中统一释放
    if (controller is IDisposable disposable)
    {
      disposable.Dispose();
    }
  }
}

通过上面的代码我们依然要继续深入到ITypeActivatorCache实现中去寻找答案,通过查看MvcCoreServiceCollectionExtensions类的AddMvcCoreServices方法源码我们可以找到如下信息

services.TryAddSingleton<ITypeActivatorCache, TypeActivatorCache>();

有了这个信息,我们可以直接找到TypeActivatorCache类的源码[点击查看源码]代码并不多,大致如下所示

internal class TypeActivatorCache : ITypeActivatorCache
{
  //创建ObjectFactory的委托
  private readonly Func<Type, ObjectFactory> _createFactory =
    (type) => ActivatorUtilities.CreateFactory(type, Type.EmptyTypes);
  //Controller类型和对应创建Controller实例的ObjectFactory实例的缓存
  private readonly ConcurrentDictionary<Type, ObjectFactory> _typeActivatorCache =
      new ConcurrentDictionary<Type, ObjectFactory>();

  /// <summary>
  /// 真正创建实例的地方
  /// </summary>
  public TInstance CreateInstance<TInstance>(
    IServiceProvider serviceProvider,
    Type implementationType)
  {
    //真正创建的操作是createFactory
    //通过Controller类型在ConcurrentDictionary缓存中获得ObjectFactory
    //而ObjectFactory实例由ActivatorUtilities.CreateFactory方法创建的
    var createFactory = _typeActivatorCache.GetOrAdd(implementationType, _createFactory);
    //返回创建实例
    return (TInstance)createFactory(serviceProvider, arguments: null);
  }
}

通过上面类的代码我们可以清晰的得出一个结论,默认情况下Controller实例是由ObjectFactory创建出来的,而ObjectFactory实例是由ActivatorUtilities的CreateFactory创建出来,所以Controller实例每次都是由ObjectFactory创建而来,并非注册到IOC容器中。并且我们还可以得到一个结论ObjectFactory应该是一个委托,我们找到ObjectFactory定义的地方[点击查看源码]

delegate object ObjectFactory(IServiceProvider serviceProvider, object[] arguments);

这个确实如我们猜想的那般,这个委托会通过IServiceProvider实例去构建类型的实例,通过上述源码相关的描述我们会产生一个疑问,既然Controller实例并非由IOC容器托管,它由ObjectFactory创建而来,但是ObjectFactory实例又是由ActivatorUtilities构建的,那么生产对象的核心也就在ActivatorUtilities类中,接下来我们就来探究一下ActivatorUtilities的神秘面纱。

ActivatorUtilities类的探究

书接上面,我们知道了ActivatorUtilities类是创建Controller实例最底层的地方,那么ActivatorUtilities到底和容器是啥关系,因为我们看到了ActivatorUtilities创建实例需要依赖ServiceProvider,一切都要从找到ActivatorUtilities类的源码开始。我们最初接触这个类的地方在于它通过CreateFactory方法创建了ObjectFactory实例,那么我们就从这个地方开始,找到源码位置[点击查看源码]实现如下

public static ObjectFactory CreateFactory(Type instanceType, Type[] argumentTypes)
{
  //查找instanceType的构造函数
  //找到构造信息ConstructorInfo
  //得到给定类型与查找类型instanceType构造函数的映射关系
  FindApplicableConstructor(instanceType, argumentTypes, out ConstructorInfo constructor, out int?[] parameterMap);
  //构建IServiceProvider类型参数
  var provider = Expression.Parameter(typeof(IServiceProvider), "provider");
  //构建给定类型参数数组参数
  var argumentArray = Expression.Parameter(typeof(object[]), "argumentArray");
  //通过构造信息、构造参数对应关系、容器和给定类型构建表达式树Body
  var factoryExpressionBody = BuildFactoryExpression(constructor, parameterMap, provider, argumentArray);
  //构建lambda
  var factoryLamda = Expression.Lambda<Func<IServiceProvider, object[], object>>(
    factoryExpressionBody, provider, argumentArray);
  var result = factoryLamda.Compile();
  //返回执行结果
  return result.Invoke;
}

ActivatorUtilities类的CreateFactory方法代码虽然比较简单,但是它涉及到调用了其他方法,由于嵌套的比较深代码比较多,而且不是本文讲述的重点,我们就不再这里细说了,我们可以大概的描述一下它的工作流程。

  • 首先在给定的类型里查找到合适的构造函数,这里我们可以理解为查找Controller的构造函数。
  • 然后得到构造信息,并得到构造函数的参数与给定类型参数的对应关系
  • 通过构造信息和构造参数的对应关系,在IServiceProvider得到对应类型的实例为构造函数赋值
  • 最后经过上面的操作通过初始化指定的构造函数来创建给定Controller类型的实例

综上述的相关步骤,我们可以得到一个结论,Controller实例的初始化是通过遍历Controller类型构造函数里的参数,然后根据构造函数每个参数的类型在IServiceProvider查找已经注册到容器中相关的类型实例,最终初始化得到的Controller实例。这就是在IServiceProvider得到需要的依赖关系,然后创建自己的实例,它内部是使用的表达式树来完成的这一切,可以理解为更高效的反射方式。

关于ActivatorUtilities类还包含了其他比较实用的方法,比如CreateInstance方法

public static T CreateInstance<T>(IServiceProvider provider, params object[] parameters)

它可以通过构造注入的方式创建指定类型T的实例,其中构造函数里具体的参数实例是通过在IServiceProvider实例里获取到的,比如我们我们有这么一个类

public class OrderController
{
  private readonly IOrderService _orderService;
  private readonly IPersonService _personService;

  public OrderController(IOrderService orderService, IPersonService personService)
  {
    _orderService = orderService;
    _personService = personService;
  }
}

其中它所依赖的IOrderService和IPersonService实例是注册到IOC容器中的

IServiceCollection services = new ServiceCollection()
 .AddScoped<IPersonService, PersonService>()
 .AddScoped<IOrderService, OrderService>();

然后你想获取到OrderController的实例,但是它只包含一个有参构造函数,但是构造函数的参数都以注册到IOC容器中。当存在这种场景你便可以通过以下方式得到你想要的类型实例,如下所示

IServiceProvider serviceProvider = services.BuildServiceProvider();
OrderController orderController = ActivatorUtilities.CreateInstance<OrderController>(serviceProvider);

即使你的类型OrderController并没有注册到IOC容器中,但是它的依赖都在容器中,你也可以通过构造注入的方式得到你想要的实例。总的来说ActivatorUtilities里的方法还是比较实用的,有兴趣的同学可以自行尝试一下,也可以通过查看ActivatorUtilities源码的方式了解它的工作原理。

AddControllersAsServices方法

上面我们主要是讲解了默认情况下Controller并不是托管到IOC容器中的,它只是表现出来的让你以为它是在IOC容器中,因为它可以通过构造函数注入相关实例,这主要是ActivatorUtilities类的功劳。说了这么多Controller实例到底可不可以注册到IOC容器中,让它成为真正受到IOC容器的托管者。要解决这个,必须要满足两点条件

  • 首先,需要将Controller注册到IOC容器中,但是仅仅这样还不够,因为Controller是由ControllerFactory创建而来
  • 其次,我们要改造ControllerFactory类中创建Controller实例的地方让它从容器中获取Controller实例,这样就解决了所有的问题

如果我们自己去实现将Controller托管到IOC容器中,就需要满足以上两个操作一个是要将Controller放入容器,然后让创建Controller的地方从IOC容器中直接获取Controller实例。庆幸的是,微软帮我们封装了一个相关的方法,它可以帮我们解决将Controller托管到IOC容器的问题,它的使用方法如下所示

services.AddMvc().AddControllersAsServices();
//或其他方式,这取决于你构建的Web项目的用途可以是WebApi、Mvc、RazorPage等
//services.AddMvcCore().AddControllersAsServices();

相信大家都看到了,玄机就在AddControllersAsServices方法中,但是它存在于MvcCoreMvcBuilderExtensions类和MvcCoreMvcCoreBuilderExtensions类中,不过问题不大,因为它们的代码是完全一样的。只是因为你可以通过多种方式构建Web项目比如AddMvc或者AddMvcCore,废话不多说直接上代码[点击查看源码]

public static IMvcBuilder AddControllersAsServices(this IMvcBuilder builder)
{
  if (builder == null)
  {
    throw new ArgumentNullException(nameof(builder));
  }
  var feature = new ControllerFeature();
  builder.PartManager.PopulateFeature(feature);
  //第一将Controller实例添加到IOC容器中
  foreach (var controller in feature.Controllers.Select(c => c.AsType()))
  {
    //注册的声明周期是Transient
    builder.Services.TryAddTransient(controller, controller);
  }
  //第二替换掉原本DefaultControllerActivator的为ServiceBasedControllerActivator
  builder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
  return builder;
}

第一点没问题那就是将Controller实例添加到IOC容器中,第二点它替换掉了DefaultControllerActivator为为ServiceBasedControllerActivator。通过上面我们讲述的源码了解到DefaultControllerActivator是默认提供Controller实例的地方是获取Controller实例的核心所在,那么我们看看ServiceBasedControllerActivator与DefaultControllerActivator到底有何不同,直接贴出代码[点击查看源码]

public class ServiceBasedControllerActivator : IControllerActivator
{
  public object Create(ControllerContext actionContext)
  {
    if (actionContext == null)
    {
      throw new ArgumentNullException(nameof(actionContext));
    }
    //获取Controller类型
    var controllerType = actionContext.ActionDescriptor.ControllerTypeInfo.AsType();
    //通过Controller类型在容器中获取实例
    return actionContext.HttpContext.RequestServices.GetRequiredService(controllerType);
  }

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

相信大家对上面的代码一目了然了,和我们上面描述的一样,将创建Controller实例的地方改造了在容器中获取的方式。不知道大家有没有注意到ServiceBasedControllerActivator的Release的方法居然没有实现,这并不是我没有粘贴出来,确实是没有代码,之前我们看到的DefaultControllerActivator可是有调用Controller的Disposed的方法,这里却啥也没有。相信聪明的你已经想到了,因为Controller已经托管到了IOC容器中,所以他的生命及其相关释放都是由IOC容器完成的,所以这里不需要任何操作。

我们上面还看到了注册Controller实例的时候使用的是TryAddTransient方法,也就是说每次都会创建Controller实例,至于为什么,我想大概是因为每次请求都其实只会需要一个Controller实例,况且EFCore的注册方式官方建议也是Scope的,而这里的Scope正是对应的一次Controller请求。在加上自带的IOC会提升依赖类型的声明周期,如果将Controller注册为单例的话如果使用了EFCore那么它也会被提升为单例,这样会存在很大的问题。也许正是基于这个原因默认才将Controller注册为Transient类型的,当然这并不代表只能注册为Transient类型的,如果你不使用类似EFCore这种需要作用域为Scope的服务的时候,而且保证使用的主键都可以使用单例的话,完全可以将Controller注册为别的生命周期,当然这种方式个人不是很建议。

Controller结合Autofac

有时候大家可能会结合Autofac一起使用,Autofac确实是一款非常优秀的IOC框架,它它支持属性和构造两种方式注入,关于Autofac托管自带IOC的原理咱们在之前的文章浅谈.Net Core DependencyInjection源码探究中曾详细的讲解过,这里咱们就不过多的描述了,咱们今天要说的是Autofac和Controller的结合。如果你想保持和原有的IOC一致的使用习惯,即只使用构造注入的话,你只需要完成两步即可

首先将默认的IOC容器替换为Autofac,具体操作也非常简单,如下所示

public static IHostBuilder CreateHostBuilder(string[] args) =>
      Host.CreateDefaultBuilder(args)
       .ConfigureWebHostDefaults(webBuilder =>
       {
         webBuilder.UseStartup<Startup>();
       })
       //只需要在这里设置ServiceProviderFactory为AutofacServiceProviderFactory即可
       .UseServiceProviderFactory(new AutofacServiceProviderFactory());

然后就是咱们之前说的,要将Controller放入容器中,然后修改生产Controller实例的ControllerFactory的操作为在容器中获取,当然这一步微软已经为我们封装了便捷的方法

services.AddMvc().AddControllersAsServices();

只需要通过上面简单得两步,既可以将Controller托管到Autofac容器中。但是,我们说过了Autofac还支持属性注入,但是默认的方式只支持构造注入的方式,那么怎么让Controller支持属性注入呢?我们还得从最根本的出发,那就是解决Controller实例存和取的问题

首先为了让Controller托管到Autofac中并且支持属性注入,那么就只能使用Autofac的方式去注册Controller实例,具体操作是在Startup类中添加ConfigureContainer方法,然后注册Controller并声明支持属性注入

public void ConfigureContainer(ContainerBuilder builder)
{
  var controllerBaseType = typeof(ControllerBase);
  //扫描Controller类
  builder.RegisterAssemblyTypes(typeof(Program).Assembly)
  .Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType)
  //属性注入
  .PropertiesAutowired();
}

其次是解决取的问题,这里我们就不需要AddControllersAsServices方法了,因为AddControllersAsServices解决了Controller实例在IOC中存和取的问题,但是这里我们只需要解决Controller取得问题说只需要使用ServiceBasedControllerActivator即可,具体操作是

services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());

仅需要在默认的状态下完成这两步,既可以解决Controller托管到Autofac中并支持属性注入的问题,这也是最合理的方式。当然如果你使用AddControllersAsServices可是可以实现相同的效果了,只不过是没必要将容器重复的放入容器中了。

总结

本文我们讲述了关于ASP.NET Core Controller与IOC结合的问题,我觉得这是有必要让每个人都有所了解的知识点,因为在日常的Web开发中Controller太常用了,知道这个问题可能会让大家在开发中少走一点弯路,接下来我们来总结一下本文大致讲解的内容

  1. 首先说明了一个现象,那就是默认情况下Controller并不在IOC容器中,我们也通过几个示例验证了一下。
  2. 其次讲解了默认情况下创造Controller实例真正的类ActivatorUtilities,并大致讲解了ActivatorUtilities的用途。
  3. 然后我们找到了将Controller托管到IOC容器中的办法AddControllersAsServices,并探究了它的源码,了解了它的工作方式。
  4. 最后我们又演示了如何使用最合理的方式将Controller结合Autofac一起使用,并且支持属性注入。

到此这篇关于ASP.NET Core Controller与IOC结合问题整理的文章就介绍到这了,更多相关ASP.NET Core Controller与IOC结合问题内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • ASP.NET Core MVC如何实现运行时动态定义Controller类型

    昨天有个朋友在微信上问我一个问题:他希望通过动态脚本的形式实现对ASP.NET Core MVC应用的扩展,比如在程序运行过程中上传一段C#脚本将其中定义的Controller类型注册到应用中,问我是否有好解决方案.我当时在外边,回复不太方便,所以只给他说了两个接口/类型:IActionDescriptorProvider和ApplicationPartManager.这是一个挺有意思的问题,所以回家后通过两种方案实现了这个需求.源代码从这里下载. 一.实现的效果 我们先来看看实现的效果.如下所

  • ASP.NET Core中的Controller使用示例

    ASP.NET CORE出现之前我们实现的Controller,MVC都继承自Controller基类,WebApi的话继承自ApiController.现在ASP.NET CORE把MVC跟WebApi合并了,已经不再区分MVC或者WebApi.ASP.NET CORE的Controller继承结构也发生了变化.我们看其他示例的时候会发现有些继承自Controller有些继承自ControllerBase.事实上ControllerBase是Controller的基类.也就是说如果你继承自Co

  • ASP.NET Core对Controller进行单元测试的完整步骤

    前言 单元测试对我们的代码质量非常重要.很多同学都会对业务逻辑或者工具方法写测试用例,但是往往忽略了对Controller层写单元测试.我所在的公司没见过一个对Controller写过测试的.今天来演示下如果对Controller进行单元测试.以下内容默认您对单元测试有所了解,比如如何mock一个接口.在这里多叨叨一句,面向接口的好处,除了能够快速的替换实现类(其实大部分接口不会有多个实现),最大的好处就是可以进行mock,可以进行单元测试. 测试Action 下面的Action非常简单,非常常

  • ASP.NET Core Controller与IOC结合问题整理

    前言 看到标题可能大家会有所疑问Controller和IOC能有啥羁绊,但是我还是拒绝当一个标题党的.相信有很大一部分人已经知道了这么一个结论,默认情况下ASP.NET Core的Controller并不会托管到IOC容器中,注意关键字我说的是"默认",首先咱们不先说为什么,如果还有不知道这个结论的同学们可以自己验证一下,验证方式也很简单,大概可以通过以下几种方式. 验证Controller不在IOC中 首先,我们可以尝试在ServiceProvider中获取某个Controller实

  • ASP.NET Core依赖注入系列教程之控制反转(IoC)

    前言 ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制,ASP.NET通过定义接口的方式对它们进行了"标准化",我们将这些标准化的组件称为服务,ASP.NET在内部专门维护了一个DI容器来提供所需的服务.要了解这个DI容器以及现实其中的服务提供机制,我们先得知道什么是DI(Dependence Injection),而一旦我们提到DI,又不得不说IoC(Inverse of Control). 一.流程控

  • ASP.NET Core MVC 依赖注入View与Controller

    目录 一.ASP.NET Core MVC 之依赖注入 View 1.填充查找数据 2.重写服务 二. ASP.NET Core MVC 之依赖注入 Controller 1.构造函数注入 2.使用 FromServices 操作注入 3.在控制器中访问设置 一.ASP.NET Core MVC 之依赖注入 View ASP.NET Core 支持在试图中使用依赖注入.这将有助于提供视图专用的服务,比如本地化或者仅用于填充视图元素的数据.应尽量保持控制器和视图之间的关注点分离.视图所显示的大部分

  • ASP.NET Core MVC中的控制器(Controller)介绍

    操作(action)和操作结果(action result)是 ASP.NET MVC 构建应用程序的一个基础部分.在 ASP.NET MVC 中,控制器用于定义和聚合一组操作.操作是控制器中处理传入请求的一种方法.控制器提供了一种逻辑方式,将相似的操作组织起来,允许一些通用的规则(例如路由,缓存,授权)使用共同的应用.传入的请求通过 路由 映射到操作.ASP.NET Core MVC 中,控制器可以是任何以 “Controller” 结尾或继承自以 “Controller” 结尾的可实例化类.

  • ASP.NET Core应用中与第三方IoC/DI框架的整合

    一.ConfigureServices方法返回的ServiceProvider没有用! 我们可以通过一个简单的实例来说明这个问题.我们先定义了如下这个一个MyServiceProvider,它实际上是对另一个ServiceProvider的封装.简单起见,我们利用一个字典来保存服务接口与实现类型的映射关系,这个关系可以通过调用Registe方法来注册.在提供服务实例的GetService方法中,如果提供的服务类型已经被注册,我们会创建并返回对应的实例对象,否则我们将利用封装的这个ServiceP

  • 浅谈ASP.NET Core中间件实现分布式 Session

    1.1. 中间件原理 1.1.1. 什么是中间件 中间件是段代码用于处理请求和响应,通常多个中间件链接起来形成管道,由每个中间件自己来决定是否要调用下一个中间件. 1.1.2. 中间件执行过程 举一个示例来演示中间件的执行过程(分别有三个中间件:日志记录.权限验证和路由):当请求进入应用程序时,执行执行日志记录的中间件,它记录请求属性并调用链中的下一个中间件权限验证,如果权限验证通过则将控制权传递给下一个中间件,不通过则设置401 HTTP代码并返回响应,响应传递给日志中间件进行返回. 1.1.

  • ASP.NET Core中调整HTTP请求大小的几种方法详解

    一.前言 之所以称ASP.NET Core是一个Web开发平台,源于它具有一个极具扩展性的请求处理管道,我们可以通过这个管道的定制来满足各种场景下的HTTP处理需求.ASP. NET Core应用的很多特性,比如路由.认证.会话.缓存等,也同时定制消息处理管道来实现的.我们甚至可以通过管道定制在ASP.NET Core平台上创建我们自己的Web框架,实际上MVC和SingalR这两个重要的Web框架也是采用这样的方式创建的. HTTP协议自身的特性决定了任何一个Web应用的工作方式都是监听.接收

随机推荐