前言

我们在使用ASP.NET Core进行服务端应用开发的时候,或多或少都会涉及到使用Filter的场景。Filter简单来说是Action的拦截器,它可以在Action执行之前或者之后对请求信息进行处理。我们知道.Net Core默认是提供了IOC的功能,而且IOC是.Net Core的核心,.Net Core的底层基本上是基于IOC构建起来的,但是默认情况下自带的IOC不支持属性注入功能,但是我们在定义或使用Filter的时候有时候不得不针对某个Controller或Action,这种情况下我们不得不将Filter作为Attribute标记到Controller或Action上面,但是有时候Filter是需要通过构造函数注入依赖关系的,这个时候就有了一点小小的冲突,就是我们不得不解决在Controller或Action上使用Filter的时候,想办法去构建Filter的实例。本篇文章不是一篇讲解ASP.NET Core如何使用过滤器Filter的文章,而是探究一下Filter与IOC的奇妙关系的。

简单示例

咱们上面说过了,我们所用的过滤器即Filter,无论如何都是需要去解决与IOC的关系的,特别是在当Filter作用到某些具体的Controller或Action上的时候。因为直接标记的话必须要给构造函数传递初始化参数,但是这些参数是需要通过DI注入进去的,而不是手动传递。微软给我们提供了解决方案来解决这个问题,那就是使用TypeFilterAttributeServiceFilterAttribute,关于这两个Attribute使用的方式,咱们先通过简单的示例演示一下。首先定义一个Filter,模拟一下需要注入的场景

public class MySampleActionFilter : Attribute, IActionFilter
{
private readonly IPersonService _personService;
private readonly ILogger<MySampleActionFilter> _logger;
//模拟需要注入一些依赖关系
public MySampleActionFilter(IPersonService personService, ILogger<MySampleActionFilter> logger)
{
_personService = personService;
_logger = logger;
_logger.LogInformation($"MySampleActionFilter.Ctor {DateTime.Now:yyyyMMddHHmmssffff}");
} public void OnActionExecuted(ActionExecutedContext context)
{
Person personService = _personService.GetPerson(1);
_logger.LogInformation($"TraceId=[{context.HttpContext.TraceIdentifier}] MySampleActionFilter.OnActionExecuted ");
} public void OnActionExecuting(ActionExecutingContext context)
{
_logger.LogInformation($"TraceId=[{context.HttpContext.TraceIdentifier}] MySampleActionFilter.OnActionExecuting ");
}
}

这里的日志功能ILogger在ASP.Net Core底层已经默认注入了,我们还模拟依赖了一些业务的场景,因此我们需要注入一些业务依赖,比如我们这里的PersonService。

public void ConfigureServices(IServiceCollection services)
{
//模拟注册一下业务依赖
services.AddScoped<IPersonService,PersonService>();
services.AddControllers();
}
单独使用Filter

这里我们先来演示一下单独在某些Controller或Action上使用Filter的情况,我们先来定义一个Action来模拟一下Filter的使用,由于Filter通过构造函数依赖了一下具体的服务所以我们先选择使用TypeFilterAttribute来演示,具体使用方式如下

[Route("api/[controller]/[action]")]
[ApiController]
public class PersonController : ControllerBase
{
private readonly List<Person> _persons;
public PersonController()
{
//模拟一下数据
_persons = new List<Person>
{
new Person{ Id=1,Name="张三" },
new Person{ Id=2,Name="李四" },
new Person{ Id=3,Name="王五" }
};
} [HttpGet]
//这里我们先通过TypeFilter的方式来使用定义的MySampleActionFilter
[TypeFilter(typeof(MySampleActionFilter))]
public List<Person> GetPersons()
{
return _persons;
}
}

然后我们运行起来示例,模拟请求一下GetPersons这个Action看一下效果,因为我们在定义的Filter中记录了日志信息,因此请求完成之后在控制台会打印出如下信息

info: Web5Test.MySampleActionFilter[0]
MySampleActionFilter.Ctor 202110121820482450
info: Web5Test.MySampleActionFilter[0]
TraceId=[0HMCDD7ARPKDK:00000003] MySampleActionFilter.OnActionExecuting
info: Web5Test.MySampleActionFilter[0]
TraceId=[0HMCDD7ARPKDK:00000003] MySampleActionFilter.OnActionExecuted

这个时候我们将TypeFilterAttribute替换为ServiceFilterAttribute来看一下效果,替换后的Action是这个样子的

[HttpGet]
[ServiceFilter(typeof(MySampleActionFilter))]
public List<Person> GetPersons()
{
return _persons;
}

然后我们再来请求一下GetPersons这个Action,这个时候我们发现抛出了一个InvalidOperationException的异常,异常信息大致如下

System.InvalidOperationException: No service for type 'Web5Test.MySampleActionFilter' has been registered.

从这个异常信息我们可以看出我们自定义的MySampleActionFilter过滤器需要注册到IOC中去,所以我们需要注册一下

public void ConfigureServices(IServiceCollection services)
{
//模拟注册一下业务依赖
services.AddScoped<IPersonService,PersonService>();
//注册自定义的MySampleActionFilter
services.AddScoped<MySampleActionFilter>();
services.AddControllers();
}

做了如上的修改之后,我们再次启动项目请求一下GetPersons这个Action,这个时候MySampleActionFilter可以正常工作了。

这里简单的说明一下关于需要注册Filter的生命周期时,如果你不知道该注册成哪种生命周期的话那就注册成成Scope,这个是一种比较合理的方式,也就是和Controller生命周期保持一致每次请求创建一个实例即可。注册成单例的话很多时候会因为使用不当出现一些问题。

通过上面的演示我们大概了解了TypeFilterAttributeServiceFilterAttribute的使用方式和区别。

  • 使用TypeFilterAttribute的时候我们的Filter过滤器是不需要注册到IOC中去的,因为它使用Microsoft.Extensions.DependencyInjection.ObjectFactory对Filte过滤器类型进行实例化
  • 使用ServiceFilterAttribute的时候我们需要提前将我们定义的Filter注册到IOC容器中去,因为它使用容器来创建Filter的实例
全局注册的场景

很多时候呢,我们是针对全局使用Filter对所有的或者绝大多数的Action请求进行处理,这个时候我们会全局注册Filter而不需要在每个Controller或Action上一一注解。这个时候也涉及到关于Filter本身是否需要注册到IOC容器中的情况,这个地方需要注意的是Filter不是必须的需要托管到IOC容器当中去,但是一旦托管到IOC容器当中就需要注意不同注册Filter的方式,首先我们来看一下不将Filter注册到IOC的使用方式,还是那个示例

public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IPersonService,PersonService>();
services.AddControllers(options => {
options.Filters.Add<MySampleActionFilter>();
});
}

只需要把自定义的MySampleActionFilter依赖的服务提前注册到IOC容器即可不需要多余的操作,这个时候MySampleActionFilter就可以正常的工作。还有一种方式就是你想让IOC容器去托管自定义的Filter,这个时候我们需要将Filter注册到容器中去,当然声明周期我们还是选择Scope,这个时候我们需要注意一下注册全局Filter的方式了,如下所示

public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IPersonService,PersonService>();
services.AddScoped<MySampleActionFilter>();
services.AddControllers(options => {
//这里需要注意注册Filter的方法应使用AddService
options.Filters.AddService<MySampleActionFilter>();
});
}

如上面代码所示,为了能让Filter的实例来自于IOC容器,在注册全局Filter的时候我们应使用AddService方法完成注册,否则的话即使使用Add方法不会报错但是在IOC中你只能注册了个寂寞,总结一下全局注册的时候

  • 如果你不想将全局注册的Filter托管到IOC容器中,那么需要使用Add方法,这样的话Filter实例则不会通过IOC容器创建
  • 如果你想控制Filter实例的生命周期,则需要将Filter提前注册到IOC容器中去,这个时候注册全局Filter的时候就需要使用AddService方法,如果使用了AddService方法,但是你没有在IOC中注册Filter,则会抛出异常

源码探究

上面我们已经演示了将Filter托管到IOC容器和不使用IOC容器的使用方式,这方面微软考虑的也是很周到,不过就是容易让新手犯错。如果能熟练掌握,或者理解其中的工作原理的话,还是可以更好的使用这些,并且微软还为我们提供了一套灵活的扩展方式。想要更好的了解它们的工作方式,我们还得在源码下手。

TypeFilterAttribute

首先我们来看一下TypeFilterAttribute的源码,我们知道在某个Action上使用TypeFilterAttribute的时候是不要求将Filter注册到IOC中去的,因为这个时候Filter的实例是通过ObjectFactory创建出来的。在开始之前我们需要知道一个常识那就是在ASP.NET Core上我们所使用的Filter都必须要实现IFilterMetadata接口,这是ASP.NET Core底层知道Filter的唯一凭证,比如我们上面自定义的MySampleActionFilter是实现了IActionFilter接口,那么IActionFilter肯定是直接或间接的实现了IFilterMetadata接口,我们可以看一下IActionFilter接口的定义[点击查看源码]

public interface IActionFilter : IFilterMetadata
{
void OnActionExecuting(ActionExecutingContext context);
void OnActionExecuted(ActionExecutedContext context);
}

通过上面的代码我们可以看到Filter本身肯定是要实现自IFilterMetadata接口的,这个是Filter的身份标识。接下来我们就来看一下TypeFilterAttribute源码的定义[点击查看源码]

public class TypeFilterAttribute : Attribute, IFilterFactory, IOrderedFilter
{
//创建Filter实例的工厂
private ObjectFactory? _factory; public TypeFilterAttribute(Type type)
{
ImplementationType = type ?? throw new ArgumentNullException(nameof(type));
} /// <summary>
/// 创建Filter时需要的构造参数
/// </summary>
public object[]? Arguments { get; set; } /// <summary>
/// Filter实例的类型
/// </summary>
public Type ImplementationType { get; } /// <summary>
/// Filter的优先级顺序
/// </summary>
public int Order { get; set; } /// <summary>
/// 是否跨请求使用
/// </summary>
public bool IsReusable { get; set; } /// <summary>
/// 创建Filter实例的实现方法
/// </summary>
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
if (serviceProvider == null)
{
throw new ArgumentNullException(nameof(serviceProvider));
} if (_factory == null)
{
//获取自定义传递的初始化Filter实例的参数类型以创建ObjectFactory
var argumentTypes = Arguments?.Select(a => a.GetType())?.ToArray();
//通过ActivatorUtilities创建ObjectFactory
_factory = ActivatorUtilities.CreateFactory(ImplementationType, argumentTypes ?? Type.EmptyTypes);
}
//通过IServiceProvider实例和传递的初始换参数得到IFilterMetadata实例即Filter实例
var filter = (IFilterMetadata)_factory(serviceProvider, Arguments);
//可以是嵌套的IFilterFactory实例
if (filter is IFilterFactory filterFactory)
{
filter = filterFactory.CreateInstance(serviceProvider);
}
//返回创建的IFilterMetadata实例
return filter;
}
}

通过上面的代码我们可以得知TypeFilterAttribute中包含一个CreateInstance方法,而这个方法正是创建返回了一个IFilterMetadata实例即Filter实例,而创建IFilterMetadata实例则是通过ActivatorUtilities这个类创建的。在之前的文章中我们曾大致提到过这个类,ActivatorUtilities类可以借助IServiceProvider来创建一个具体的对象实例,所以当你不想使用DI的方式获取一个类的实例,但是这个类的依赖需要通过IOC容器去获得,那么可以借助ActivatorUtilities类来实现。需要注意的是虽然Filter实例是通过ActivatorUtilities创建出来的,而且它的依赖项来自IOC容器,但是FIlter实例本身并不受IOC容器托管。所以我们在使用的时候并没有将Filter注册到IOC容器中去。

ServiceFilterAttribute

上面我们看到了TypeFilterAttribute的实现方式,接下来我们来看一下和它类似的ServiceFilterAttribute的实现。我们知道ServiceFilterAttribute创建Filter实例必须要依赖IOC容器,即我们需要自行将Filter提前注册到IOC容器中去,这样才能通过ServiceFilterAttribute来正确的获取到Filter的实例,接下来我们就来通过源码来一探究竟[点击查看源码]

public class ServiceFilterAttribute : Attribute, IFilterFactory, IOrderedFilter
{
/// <summary>
/// 要实例化Filter的类型
/// </summary>
public ServiceFilterAttribute(Type type)
{
ServiceType = type ?? throw new ArgumentNullException(nameof(type));
} /// <summary>
/// Filter执行的优先级顺序
/// </summary>
public int Order { get; set; } /// <summary>
/// 要实例化Filter的类型
/// </summary>
public Type ServiceType { get; } /// <summary>
/// 是否跨请求使用
/// </summary>
public bool IsReusable { get; set; } /// <summary>
/// 创建Filter实例的实现方法
/// </summary>
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
if (serviceProvider == null)
{
throw new ArgumentNullException(nameof(serviceProvider));
}
//直接在IServiceProvider实例中获取IFilterMetadata实例
var filter = (IFilterMetadata)serviceProvider.GetRequiredService(ServiceType);
//支持IFilterFactory自身的嵌套执行
if (filter is IFilterFactory filterFactory)
{
filter = filterFactory.CreateInstance(serviceProvider);
}
return filter;
}
}

通过上面的代码我们可以看到ServiceFilterAttribute与TypeFilterAttribute的不同之处。首先ServiceFilterAttribute不支持手动传递初始化参数,因为它初始化的依赖全部来自于IOC容器。其次IFilterMetadata实例本身也是直接在IOC容器中获取的,而并不是仅仅只是依赖关系使用IOC容器。这也就是为何我们在使用ServiceFilterAttribute的时候需要自行先将Filter注册到IOC容器中去。

IFilterFactory

我们上面看到了无论是ServiceFilterAttribute还是TypeFilterAttribute,它们都是实现了IFilterFactory接口,它们之所以可以定义创建Filter实例的实现方法也完全是实现了CreateInstance方法,所以本质都是IFilterFactory。通过这个名字我们可以看出它是创建Filter的工厂,ServiceFilterAttribute和TypeFilterAttribute只是通过这个接口实现了自己创建IFilterFactory的逻辑。这是微软给我们提供的一个灵活之处,通过它我们可以在请求管道的任意位置创建Filter实例。接下来我们就来看一下IFilterFactory的定义[点击查看源码]

public interface IFilterFactory : IFilterMetadata
{
/// <summary>
/// 是否跨请求使用
/// </summary>
bool IsReusable { get; } /// <summary>
/// 创建Filter实例
/// </summary>
/// <param name="serviceProvider">IServiceProvider实例</param>
/// <returns>返回Filter实例</returns>
IFilterMetadata CreateInstance(IServiceProvider serviceProvider);
}

通过代码可知IFilterFactory也是实现了IFilterMetadata接口,所以它本身也是一个Filter,只是它比较特殊一些。既然它是一个Filter,但是它也很特殊,那么ASP.NET Core在使用的时候是如何区分是一个Filter实例,还是一个IFilterFactory实例呢?这两者存在一个本质的区别,Filter实例是可以直接在Action请求的时候拿来执行一些类似OnActionExecutingOnActionExecuted的操作的,但是IFilterFactory实例需要先调用CreateInstance方法得到一个真正可以执行的Filter实例的。

这个我们可以在FilterProvider中得到答案。IFilterProvider是用来定义提供Filter实现的操作,通过它我们可以得到可执行的Filter实例,在它的默认实现DefaultFilterProvider类中的OnProvidersExecuting方法里调用了它自身的ProvideFilter方法,看到方法的名字我们可以知道这是提供Filter实例之前的操作,在这里我们可以准备好Filter实例,我们来看一下OnProvidersExecuting方法的实现[点击查看源码]

public void OnProvidersExecuting(FilterProviderContext context)
{
//如果Action描述里的Filter描述存在,即存在Filter定义
if (context.ActionContext.ActionDescriptor.FilterDescriptors != null)
{
var results = context.Results;
var resultsCount = results.Count;
for (var i = 0; i < resultsCount; i++)
{
//循环调用了ProvideFilter方法
ProvideFilter(context, results[i]);
}
}
}

这个方法通过判断执行的Action是否存在需要执行的Filter,如果存在则获取可执行的Filter实例,因为每个Action上可能存在许多个可执行的Filter,所以这里采用了循环操作,那么核心就在ProvideFilter方法[点击查看源码]

public void ProvideFilter(FilterProviderContext context, FilterItem filterItem)
{
if (filterItem.Filter != null)
{
return;
} var filter = filterItem.Descriptor.Filter;
//如果Filter不是IFilterFactory实例则是可以直接使用的Filter
if (filter is not IFilterFactory filterFactory)
{
//直接赋值Filter
filterItem.Filter = filter;
filterItem.IsReusable = true;
}
else
{
//如果是IFilterFactory实例
//获取IOC容器实例即IServiceProvider实例
var services = context.ActionContext.HttpContext.RequestServices;
//调用IFilterFactory的CreateInstance得到Filter实例
filterItem.Filter = filterFactory.CreateInstance(services);
filterItem.IsReusable = filterFactory.IsReusable; if (filterItem.Filter == null)
{
throw new InvalidOperationException();
}
ApplyFilterToContainer(filterItem.Filter, filterFactory);
}
}

通过这个代码我们就可以看出,这里会判断Filter是常规的IFilterMetadata实例还是IFilterFactory实例,如果是IFilterFactory则需要调用它的CreateInstance方法得到一个可以直接使用的Filter实例,否则就可以直接使用这个Filter了。所以我们注册Filter的时候可以是任何IFilterMetadata实例,但是真正执行的时候需要转换成统一的可直接执行的类似ActionFilter的实例。

既然ServiceFilterAttribute和TypeFilterAttribute可以实现自IFilterFactory接口,那么我们完全可以自己通过IFilterFactory接口来实现一个Filter创建的工厂,这样的话为我们创建Filter提供了另一种思路,我们以我们上面自定义的MySampleActionFilter为例,为它创建一个MySampleActionFilterFactory工厂,实现代码如下

public class MySampleActionFilterFactory : Attribute, IFilterFactory
{
public bool IsReusable => false; public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
//我们这里模拟通过IServiceProvider获取依赖的实例
IPersonService personService = serviceProvider.GetService<IPersonService>();
ILogger<MySampleActionFilter> logger = serviceProvider.GetService<ILogger<MySampleActionFilter>>();
//通过依赖构造MySampleActionFilter实例并返回
return new MySampleActionFilter(personService,logger);
}
}

这样的话我们可以把MySampleActionFilterFactory同样作用于上面的示例代码中去,如下所示,执行效果是一样的

[HttpGet]
//[ServiceFilter(typeof(MySampleActionFilter))]
[MySampleActionFilterFactory]
public List<Person> GetPersons()
{
return _persons;
}
全局注册

之前我们通过示例看到,全局注册Filter的时候也存在是否将Filter注册到IOC容器的这种情况。既可以注册到IOC容器,也可以不注册到IOC容器,只不过添加过滤器的方法不一样,看着也挺神奇的,但是一旦用错IOC就容易注册了个寂寞。我们知道全局注册Filter的时候承载Filter的本质是一个集合,这个集合的名字叫FilterCollection,这里我们只关注它的Add方法和AddService方法即可。FilterCollection继承自Collection<IFilterMetadata>。在.Net Core中微软的代码风格是用特定的类继承自已有的泛型操作,这样的话可以让开发者更关注类功能的本身,而且还可以防止书写泛型出错,是个不错的思路。Add存在好几个重载方法但是本质都是调用最全的哪一个方法,接下来我们就来先看一下最本质的Add方法[点击查看源码]

public IFilterMetadata Add(Type filterType, int order)
{
if (filterType == null)
{
throw new ArgumentNullException(nameof(filterType));
} //不是IFilterMetadata类型添加会报错
if (!typeof(IFilterMetadata).IsAssignableFrom(filterType))
{
throw new ArgumentException();
} //最终还是将注册的Filter类型包装成TypeFilterAttribute
var filter = new TypeFilterAttribute(filterType) { Order = order };
Add(filter);
return filter;
}

有点意思,豁然开朗了,通过Add方法全局添加的Filter本质还是包装成了TypeFilterAttribute,这也就解释了为啥我们可以不用再IOC容器中注册Filter而之前使用Filter了原因就是TypeFilterAttribute帮我们创建了。那接下来我们再来看看AddService方法的实现[点击查看源码]

public IFilterMetadata AddService(Type filterType, int order)
{
if (filterType == null)
{
throw new ArgumentNullException(nameof(filterType));
} //不是IFilterMetadata类型添加会报错
if (!typeof(IFilterMetadata).IsAssignableFrom(filterType))
{
throw new ArgumentException();
} //最终还是将注册的Filter类型包装成ServiceFilterAttribute
var filter = new ServiceFilterAttribute(filterType) { Order = order };
Add(filter);
return filter;
}

同理AddService本质是将注册的Filter类型包装成了ServiceFilterAttribute,所以我们如果已经提前在IOC中注册了Filter,那么我们只需要直接使用AddService注册Filter即可。当然如果你不知道这个方法而是使用了Add方法也不会报错,只是IOC容器可能有点寂寞。不过微软的这思路确实值得我们学习,这种情况下处理逻辑是统一的,最终都是来自IFilterFactory这个接口。

总结

通过本篇文章我们了解了在ASP.NET Core使用Filter的时候,Filter有构建实例的方式,即可以将Filter注册到IOC容器中去,也可以不用注册。区别就是你是否可以自行控制Filter实例的生命周期,整体来说微软的设计思路还是非常合理的,有助于我们统一处理Filter实例的生成。我们都知道自带的IOC只支持构造注入这样的话就给特定的Action构建Filter的时候带来了不便,微软给出了TypeFilterAttributeServiceFilterAttribute解决方案,接下来我们就总结一下它们俩

  • TypeFilterAttribute和ServiceFilterAttribute都实现了IFilterFactory接口,只是创建Filter实例的方式不同。
  • TypeFilterAttribute通过ActivatorUtilities创建Filter实例,虽然它的依赖模块来自IOC容器,但是Filter实例本身并不受IOC容器管理。
  • ServiceFilterAttribute则是通过IServiceProvider获取了Filter实例,这样整个Filter是受到IOC容器管理的,注入当然是基础操作了。
  • 全局注册Filter的时候如果没有将Filter注册到IOC容器中,则使用Add方法添加过滤器,Add方法的本质是将注册的Filter包装成TypeFilterAttribute
  • 如果全局注册Filter的时候Filter已经提前注册到IOC容器中,则使用AddService方法添加过滤器,AddService方法的本质是将注册的Filter包装成ServiceFilterAttribute

通过上面的描述相信大家能更好的理解Filter本身与IOC容器的关系,这样的话也能帮助大家在具体使用的时候知道如何去用,如何更合理的使用。这里我们是用的IActionFilter作为示例,不过没有没关系,只要是实现了IFilterMetadata接口的都是一样的,即所有的操作都是针对接口的,这也是面向对象编程的本质。如果有更多疑问,或作者描述不正确,欢迎大家评论区讨论。

欢迎扫码关注我的公众号

ASP.NET Core Filter与IOC的羁绊的更多相关文章

  1. ASP.NET Core Controller与IOC的羁绊

    前言 看到标题可能大家会有所疑问Controller和IOC能有啥羁绊,但是我还是拒绝当一个标题党的.相信有很大一部分人已经知道了这么一个结论,默认情况下ASP.NET Core的Controller ...

  2. ASP.NET Core中使用IOC三部曲(一.使用ASP.NET Core自带的IOC容器)

    前言 本文主要是详解一下在ASP.NET Core中,自带的IOC容器相关的使用方式和注入类型的生命周期. 这里就不详细的赘述IOC是什么 以及DI是什么了.. emm..不懂的可以自行百度. 目录 ...

  3. ASP.NET Core中使用IOC三部曲(二.采用Autofac来替换IOC容器,并实现属性注入)

    前言 本文主要是详解一下在ASP.NET Core中,自带的IOC容器相关的使用方式和注入类型的生命周期. 这里就不详细的赘述IOC是什么 以及DI是什么了.. emm..不懂的可以自行百度. 目录 ...

  4. ASP.NET Core中使用IOC三部曲(三.采用替换后的Autofac来实现AOP拦截)

    前言 本文主要是详解一下在ASP.NET Core中,采用替换后的Autofac来实现AOP拦截 觉得有帮助的朋友~可以左上角点个关注,右下角点个推荐 这里就不详细的赘述IOC是什么 以及DI是什么了 ...

  5. Asp.Net Core 内置IOC容器的理解

    Asp.Net Core 内置IOC容器的理解 01.使用IOC容器的好处 对接口和实现类由原来的零散式管理,到现在的集中式管理. 对类和接口之间的关系,有多种注入模式(构造函数注入.属性注入等). ...

  6. Asp.Net Core Filter 深入浅出的那些事-AOP

    一.前言 在分享ASP.NET Core Filter 使用之前,先来谈谈AOP,什么是AOP 呢? AOP全称Aspect Oriented Programming意为面向切面编程,也叫做面向方法编 ...

  7. 简单讲解Asp.Net Core自带IOC容器ServiceCollection

    一.  理解ServiceCollection之前先要熟悉几个概念:DIP.IOC.DI.Ioc容器: 二.  接下来先简单说一下几个概念问题: 1.DIP(依赖倒置原则):六大设计原则里面一种设计原 ...

  8. ASP.NET Core 3.1 IOC容器以及默认DI以及替换Autofac生命周期

    IOC 就是我们需要一个对象 以前我们是去 new 现在我们是直接向 IOC容器 要我们需要的那个对象. 使用一个IOC容器(autofac)通过依赖注入控制各个组件的耦合.也就是说你写好了组件,不需 ...

  9. Asp.net Core Filter过滤器异常处理

    本文旨在: 1 继承ExceptionFilterAttribute,重写Override OnException(ExceptionContext context)处理异常 2 在.netCore中 ...

随机推荐

  1. Web安全-CDN相关技术

    CDN介绍 CDN的全称是Content Delivery Network,即内容分发网络.CDN是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡.内容分发. ...

  2. linux centos7 df命令

    2021-08-04 1. df 命令简介 linux 中 df 命令的功能是用来检查 linux 服务器的文件系统的磁盘空间占用情况.可以利用该命令来获取硬盘被占用了多少空间,目前还剩下多少空间等信 ...

  3. 假期作业03:使用IDE开发你的Java程序

    假期作业03:使用IDE开发你的Java程序 一.使用Eclipse创建一个Java项目HelloWorldPrj,编写一个Java程序并运行. 首先要下载eclipse. (注意这里要选一个中国的, ...

  4. 一、部署sqlserver

    1.下载并挂载sqlserver镜像 2.填写秘钥:6GPYM-VHN83-PHDM2-Q9T2R-KBV83 3.默认下一步 4.勾选需要的功能 5.默认下一步 6.默认下一步 等待安装完成即可. ...

  5. Docker | 入门 & 基础操作

    Dcoker 入门 确保docker 已经安装好了,如没有装好的可以参考:Docker | 安装 运行第一个容器 docker run -it ubuntu /bin/bash docker run ...

  6. python3 爬虫五大模块之五:信息采集器

    Python的爬虫框架主要可以分为以下五个部分: 爬虫调度器:用于各个模块之间的通信,可以理解为爬虫的入口与核心(main函数),爬虫的执行策略在此模块进行定义: URL管理器:负责URL的管理,包括 ...

  7. Element UI:级联选择器Cascader_动态加载_多级请求不同接口(已知第一级调取第二级)

    ELEMENT UI_CASCADER 使用过饿了么级联动态加载的小伙伴应该都知道,lazyLoad本身是一个无差别返回渲染结点的函数. 当我们存在一个需求:已知级联选择器的第一级结点,现在需要通过第 ...

  8. 【第九篇】- Git 标签之Spring Cloud直播商城 b2b2c电子商务技术总结

    Git 标签 如果你达到一个重要的阶段,并希望永远记住那个特别的提交快照,你可以使用 git tag 给它打上标签. 比如说,我们想为我们的 xxx 项目发布一个"1.0"版本. ...

  9. 【第十四篇】- Maven 自动化构建之Spring Cloud直播商城 b2b2c电子商务技术总结

    Maven 自动化构建 自动化构建定义了这样一种场景: 在一个项目成功构建完成后,其相关的依赖工程即开始构建,这样可以保证其依赖项目的稳定. 比如一个团队正在开发一个项目 bus-core-api, ...

  10. 使用tasker定时打开一耳光应用

    比如现在要做一个:到9点钟自动打开"酷狗音乐"1.任务→点击"+"→填写"打开酷狗音乐"→点击"√"2.任务编辑→点击& ...