天天看点

跟我一起 掌握AspNetCore底层技术和构建原理

作者:opendotnet

我打算录制一个免费的基础课程从原理、思维、实现等角度详细讲解。IOC、Options、Configuration、Logging、AOP、管道中间件、路由终结点,mvc的原理。掌握这些基础知识之后,我会基于这些技术+scoket手写一个aspnetcore。用以窥探aspnetcore的内部是如何运行的。

下面我详细解释两点基础技术IOC和AOP,大家感受一下我授课的风格。

注意基础课里讲到的知识,在整个net平台几乎都适用,及支持aspnet,winform,wpf。

这个课程学习下来你将掌握:容器技术和原理,AOP思想和各种实现手段及原理,微软常用的一些设计模式思想,配置选项,日志,管道中间件,路由终结点,aspnetcore运行机理。如果课程能够受到欢迎,我会后续会继续讲解框架设计,emit,表达式树等框架技术,我想为社区和生态做一点点贡献。

本人开发过,《Soul.IdentityServer》《Dapper.Linq》、《SqlBatis》等框架,对net掌握也算是比较深入

视频课程

【AspNetCore企业级开发《公开课》】 https://www.bilibili.com/video/BV1W14y1c7yt/?share_source=copy_web&vd_source=9caac72726a42a51e94b8d403bc6a3ac

IOC

基础知识

我们如何理解IOC?我们可以通过一个现实世界的模型来进行解释。比如有一本菜谱这个菜谱就是我们的IServiceCollection,里面记录了菜(Service)的描述信息(ServiceDescriptor)菜名(ServiceDescriptor.ServiceType)以及菜具体制作方法(ServiceDescriptor.ImplementationType),通过菜名(ServiceType)告诉厨师(IServiceProvider)制作(实列化、解析)出来我们要吃的菜。这就是IOC技术。

  • 依赖项

    Microsoft.Extensions.DependencyInjection.Abstractions:抽象包,用于扩展容器

    Microsoft.Extensions.DependencyInjection:实现包,实现IOC的基本功能

  • 核心接口

    Service:就是我们需要的服务实列(菜)

    ServiceDescriptor:用于描述服务的信息。比如服务名(ServiceType)、实现类(ImplementationType)、生命周期(Lifetime)。(某道菜的制作描述信息)

    IServiceCollection:是一个List集合,用于保存服务描述信息。(菜谱,记录了很多菜的描述信息)

    IServiceProvider:用于解析服务实列,根容器和子容器实现类不同(厨师)实现类里面有字段用于标记是否是根容器,以及记录所有解析的实列,为将来释放做准备。

    ActivatorUtilities:用于解析一个容器中不存在,但是依赖了容器中的服务的实列。

  • 关键字

    依赖:如果一个类A的构造器中有一个类B的参数,我们说A依赖B

    注入:如果A依赖B,要想实列化A,就必须先实列化B,然后把B载入A的构造器的过程

    依赖注入:IOC容器根据反射得到一个类的依赖关系,自动帮你载入依赖项的过程

服务注册

  • 万能公式
    //需要安装:Microsoft.Extensions.DependencyInjection
    //创建IServiceCollection实列
    IServiceCollection services = new ServiceCollection();
    //由于IServiceCollection实现了IList<ServiceDescriptor>接口
    //因此下面是一个万能公式,其它的都是扩展方法,本质调用的还是这个万能公式,包括委托的方式(他的实现类型是一个委托)
    services.Add(new ServiceDescriptor(typeof(IConnection),typeof(SqlConnection),ServiceLifetime.Singleton));
               
  • 泛型接口
    //泛型接口需要提前知道类型
    services.AddSingleton<IDbConnection, SqlConnection>();
               
  • 反射接口
    //反射的方式在编写框架时十分有用,无反射无框架
    services.AddSingleton(typeof(IDbConnection), typeof(SqlConnection);
               
  • 委托方式
    //当我们构建的对象需要编写逻辑时,委托方式十分有用
    services.AddSingleton<IDbConnection, SqlConnection>();
    //低级用法
    //假设DbContext依赖IDbConnection,并且需要一个name
    services.AddSingleton(sp =>
    {
     var connection = sp.GetRequiredService<IDbConnection>();
    return new DbContext(connection, "c1");
    }); 
    //高级用法
    //sp是一个IServiceProvider的实列
    //委托方式在注册的同时还能进行预解析
    //sp到底是根容器还是子容器由解析时的IServiceProvider
    services.AddSingleton(sp =>
    { 
    return ActivatorUtilities.CreateInstance<DbContext>(sp,"c1");
    });
               
  • 泛型注册
    //注册泛型时,只能使用反射接口,并且泛型参数不要写入,解析时来确立,如果有多个泛型参数使用逗号隔开
    services.AddSingleton(typeof(ILogger<>), typeof(ConsoleLogger<>);
               

构建容器

IServiceProvider container = services.BuildServiceProvider(new ServiceProviderOptions 
{
 ValidateOnBuild = true,//构建时检查是否有依赖没有注册的服务
 ValidateScopes = true,//在解析服务时检查是否通过根容器来解析Scoped类型的实列
});
           

服务解析

//如果同一个服务类型,注册多个实现,那么默认获取最后一个实现。
services.AddSingleton<IDbConnection, SqlConnection>();
services.AddSingleton<IDbConnection, MySqlConnection>();
IServiceProvider container = services.BuildServiceProvider();
//如果服务未注册,返回
IDbConnection? connection = container.GetService<IDbConnection>();
//服务不存在讲引发异常
IDbConnection connection = container.GetRequiredService<IDbConnection>();
//获取IDbConnection所有实现
IEnumerable<IDbConnection> connections = container.GetRequiredServices<IDbConnection>();
//假设DbContext依赖IDbConnection,并且需要一个name,但是容器没有注册DbContext
var context = ActivatorUtilities.CreateInstance<DbContext>(container,"c1");
           

生命周期

我们需要会搭建测试案例,来验证是否是同一个实列,以及释放问题。

public class A : IDisposable
{
 public string ID { get; }

 public A()
 {
 ID = Guid.NewGuid().ToString();
 }

 public void Dispose()
 {
 Console.WriteLine(ID + ":已释放...");
 }
}
//你可以测试其他生命周期
services.AddScoped<A>();//替换其他生命周期
//根容器:通过Debug模式查看container可以看到一个属性IsRootScope用来标记它是否是根容器
IServiceProvider container = services.BuildServiceProvider(new ServiceProviderOptions 
{ 
 ValidateOnBuild = true,//构建时检查是否有依赖没有注册的服务
 ValidateScopes = false,//在解析服务时检查是否通过根容器来解析Scoped类型的实列
});
//a1:通过根容器创建,需要设ValidateScopes为false(危险)
var a1 = container.GetRequiredService<A>();
var a2 = container.GetRequiredService<A>();
using(var scope = rootContainer.CreateScope())
{
//a2:通过子容器创建(合法)
 var a3 = scope.ServiceProvider.GetRequiredService<A>();
 var a4 = scope.ServiceProvider.GetRequiredService<A>();
 Console.WriteLine(a1.ID);
 Console.WriteLine(a2.ID);
 Console.WriteLine(a3.ID);
 Console.WriteLine(a4.ID);
}
Console.ReadLine();
           

通过修改A服务注册的生命周期我们可以得到一下结论。

测试Singleton发现:a1,a2,a3,a4的Id都相同

测试Scope发现:a1和a2的Id相同,a3和a4的Id相同,a1和a3的Id不相同

测试Transient发现:a1,a2,a3,a4的Id都不同

Singleton:无论通过根容器还是子容器,获取的都是同一实列,而且不会执行释放(除非释放根容器)。

Scoped:同一scope获取的都是同一实列,不同的scope获取的实列不同。scope释放会释放由它解析出来的所有实列(除了单实例以外),如果并执行Dispose方法(前提实现了IDisposable)。

Transient:无论是否同一scope获取的实列都不同,每次获取都是一个新的实列,scope释放会释放所有的实列。

注意:ServiceProvider会记录由它创建的所有实列,如果释放IServiceScope的实列,则会释放(ServiceProvider)和所有(单实列除外)由它创建的实列。

Scope范围:scope的范围有多大取决于你何时创建何时释放。从创建到释放就是他的生命周期。

//按时间5s之后释放
public class A : IDisposable
{
 public string ID { get; } = Guid.NewGuid().ToString();
 public void Dispose()
 {
 Console.WriteLine(ID + ":已释放...");
 }
}
IServiceProvider container = services.BuildServiceProvider();
var scope = rootContainer.CreateScope();
var a1 = container.GetRequiredService<A>();
Thread.Sleep(5 * 1000);
scope.Dispose();
           

组件扫描

这里我们演示如何通过注解来扫描,大家也可以根据接口的方式来扫描

[AttributeUsage(AttributeTargets.Class)]
public class InjectionAttribute : Attribute
{
 public Type? ServiceType { get; set; }
 public ServiceLifetime Lifetime { get; set; } = ServiceLifetime.Transient;
}
public static class InjectionIServiceCollectionExtensions
{
 public static IServiceCollection AddServicesByInjection<T>(this IServiceCollection services)
 {
 var serviceTypes = typeof(T).Assembly.GetTypes()
 .Where(a => a.IsClass)
 .Where(a => a.GetCustomAttribute<InjectionAttribute>() != )//扫描注解
 .Where(a => !a.IsAbstract);
 foreach (var item in serviceTypes)
 {
 var injection = item.GetCustomAttribute<InjectionAttribute>();
if (injection!.ServiceType == )
 {
 services.Add(new ServiceDescriptor(item, item, injection.Lifetime));
 }
else
 {
 services.Add(new ServiceDescriptor(injection!.ServiceType, item, injection.Lifetime));
 }
 }
return services;
 }
}

public interface IDbConnection
{

}

[Injection(ServiceType = typeof(IDbConnection), Lifetime = ServiceLifetime.Scoped)]
public class DbConnection : IDbConnection
{

}
//测试
var services = new ServiceCollection();
//传入需要扫描的程序集
services.AddServicesByInjection<Program>();
var sp = services.BuildServiceProvider();
var connection = sp.GetService<IDbConnection>();
           

构造模式

  • 构造模式用于简化被构造对象的创建,通过提供一大堆的api来丰富简化构造过程,增加调用者的体验。
  • 构造者需要提供一个Build方法用于构建和返回将要构造的对象实列。
  • 在容器中一般需要提供一个公开的IServiceCollection类型的属性,用于注册服务。
public enum ServiceLifetime
{
 Transient,
 Scoped,
}
public class ServiceDescriptor
{
 public Type ServiceType { get; }

 public ServiceLifetime Lifetime { get; }

 public ServiceDescriptor(Type serviceType, ServiceLifetime lifetime)
 {
 ServiceType = serviceType;
 Lifetime = lifetime;
 }
}
//目标对象
public interface IContainer
{

}
//如果直接创建成本很高,体验很差
public class Container: IContainer
{
 private List<ServiceDescriptor> _services = new();

 public Container(List<ServiceDescriptor> services)
 {
 _services = services;
 }
}
//目标对象的构造者
public interface IContainerBuilder
{
//接口只提供一个通用方法,降低实现成本
void Add(ServiceDescriptor descriptor);
//构造目标对象
 IContainer Build();
}
//实现构造者
public class ContainerBuilder : IContainerBuilder
{
 private List<ServiceDescriptor> _services = new();

 public void Add(ServiceDescriptor descriptor)
 {
 _services.Add(descriptor);
 }

 public IContainer Build()
 {
return new Container(_services);
 }
}
//扩展构造者,提供更加便捷的api
public static class IContainerBuilderExtensions
{
 public static void AddTransient<T>(this IContainerBuilder builder)
 {
 builder.Add(new ServiceDescriptor(typeof(T), ServiceLifetime.Transient));
 }
 public static void AddScoped<T>(this IContainerBuilder builder)
 {
 builder.Add(new ServiceDescriptor(typeof(T), ServiceLifetime.Scoped));
 }
}

//测试
var containerBuilder = new ContainerBuilder();
containerBuilder.AddScoped<DbContext>();
var container = containerBuilder.Build();
           

工厂模式

  • 工厂模式侧重于对象的管理,一般提供一个Create方法,支持命名创建。
  • 通过上面的学习我们发现IOC有一个弊端,就是他是通过服务类型的解析服务的。有些情况下我们需要通过命名的方式来解析服务。此时可以使用工厂模式
public interface IDbConnection
{

}
public class MySqlDbConnection : IDbConnection
{

}
public class SqlDbConnection : IDbConnection
{

}

public class DbConnectionFactory
{
 private IServiceProvider _serviceProvider;

 private Dictionary<string, Type> _connections;

 public DbConnectionFactory(IServiceProvider provider, Dictionary<string, Type> connections)
 {
 _serviceProvider = provider;
 _connections = connections;
 }

 public IDbConnection? Create(string name)
 {
if (_connections.TryGetValue(name, out Type? connectionType))
 {
return _serviceProvider.GetRequiredService(connectionType) as IDbConnection;
 }
return default;
 }
}

//测试
var services = new ServiceCollection();
services.AddScoped<MySqlDbConnection>();
services.AddScoped<SqlDbConnection>();
services.AddSingleton(sp => 
{
 var connections = new Dictionary<string, Type>
 {
 { "s1", typeof(SqlDbConnection) },
 { "s2", typeof(MySqlDbConnection) }
 };
return new DbConnectionFactory(connections);
});
var sp = services.BuildServiceProvider();
var factory = sp.GetRequiredService<DbConnectionFactory>();
var s1 = factory.Create(sp, "s1");
var s2 = factory.Create(sp, "s2");
           

提供模式

  • 如果看到提供者模式,说明我们可以提供多个方案,支持多实现
  • 一般通过工厂来管理提供者,用以支持命名实列
public interface ILogger
{
void Info(string message);
}

public interface ILoggerProvider
{
 ILogger CreateLogger(string name);
}

public class ConsoleLoggerProvider : ILoggerProvider
{
 public ILogger CreateLogger(string name)
 {
return new ConsoleLogger(name);
 }
class ConsoleLogger : ILogger
 {
 private string _name;
 public ConsoleLogger(string name)
 {
 _name = name;
 }
 public void Info(string message)
 {
 Console.WriteLine($"{_name}:{message}");
 }
 }
}

public class DebugLoggerProvider : ILoggerProvider
{
 public ILogger CreateLogger(string name)
 {
return new DebugLogger(name);
 }

class DebugLogger : ILogger
 {
 private string _name;
 public DebugLogger(string name)
 {
 _name = name;
 }
 public void Info(string message)
 {
 Debug.WriteLine($"{_name}:{message}");
 }
 }
}

public class LoggerFactory
{
 private IEnumerable<ILoggerProvider> _providers;

 public LoggerFactory(IEnumerable<ILoggerProvider> providers)
 {
 _providers = providers;
 }

 public ILogger Create(string name)
 {
 var loggers = _providers.Select(s=>s.CreateLogger(name));
return new LoggerCollection(loggers);
 }
class LoggerCollection : ILogger
 {
 private IEnumerable<ILogger> _loggers;
 public LoggerCollection(IEnumerable<ILogger> loggers)
 {
 _loggers = loggers;
 }

 public void Info(string message)
 {
 foreach (var logger in _loggers)
 {
 logger.Info(message);
 }
 }
 }
}
           

代理模式

  • 代理模式侧重于对目标对象进行加强,通过实现目标对象的接口具备目标对象的能力。
  • 一般通过实现和目标对象相同的接口来获得目标对象的能力
  • 代理可以通过目标对象来简化实现成本,代理只负责编写加强逻辑
  • 一般代理器只代理单个目标对象,我们把下面这个模式也可以归纳到代理模式,因为它能满足代理的许多特点比如加强、拥有目标对象的能力
  • 思考我们需要一个LoggerCollection,需要实现ICollection

    接口,如何降低实现成本?

public interface ILogger
{
void Info(string message);
}

public class LoggerCollection : ILogger
{
 private IEnumerable<ILogger> _loggers;
 public LoggerCollection(IEnumerable<ILogger> loggers)
 {
 _loggers = loggers;
 }

 public void Info(string message)
 { //加强逻辑
 foreach (var logger in _loggers)
 {
//具体实现由目标对象实现
 logger.Info(message);
 }
 }
}

           

容器实现

实现容器有三个重要的对象,通过IContainerBuilder来构建Container实列。Container负责根据服务描述来找到服务实现,通过服务实现的依赖来进行注入。下面我们写一个简化版本的容器。

  • ServiceDescriptor:负责描述服务信息
  • IContainerBuilder:负责构建容器
  • IContainer:负责根据服务描述信息解析服务
public class DbConnection
{
}

public class DbContext
{
 public DbConnection Connection { get; }

 public DbContext(DbConnection connection)
 {
 Connection = connection;
 }
}

public class ServiceDescriptor
{
 public Type ServiceType { get; }
 public Type ImplementionType { get; }
 public object? Instance { get; }

 public ServiceDescriptor(Type serviceType, Type implementionType, object? instance = )
 {
 ServiceType = serviceType;
 ImplementionType = implementionType;
 Instance = instance;
 }
}

public interface IContainer
{
 object? GetService(Type serviceType);
}

public interface IContainerBuilder
{
void Add(ServiceDescriptor descriptor);
 IContainer Build();
}

public class Container : IContainer
{
 private IEnumerable<ServiceDescriptor> _services;

 public Container(IEnumerable<ServiceDescriptor> services)
 {
 _services = services;
 }

 public object? GetService(Type serviceType)
 {
 var descriptor = _services
 .FirstOrDefault(a => a.ServiceType == serviceType);
if (descriptor == )
 {
 throw new InvalidOperationException("服务未注册");
 }
//判断是否是委托(涉及到了协变)
 var invokerType = typeof(Func<IContainer, object>);
if (typeof(Func<IContainer, object>).IsInstanceOfType(descriptor.Instance))
 {
 var func = descriptor.Instance as Func<IContainer, object> ?? throw new ArgumentException();
return func(this);
 }
 var constructor = serviceType.GetConstructors()
 .OrderByDescending(a => a.GetParameters().Length)
 .FirstOrDefault() ?? throw new ArgumentException();
//递归解析依赖
 var parameters = constructor.GetParameters()
 .Select(s => GetService(s.ParameterType));
return Activator.CreateInstance(descriptor.ImplementionType, parameters.ToArray());
 }
}

public class ContainerBuilder : IContainerBuilder
{
 private List<ServiceDescriptor> _services = new();

 public void Add(ServiceDescriptor descriptor)
 {
 _services.Add(descriptor);
 }

 public IContainer Build()
 {
return new Container(_services);
 }
}

public static class IContainerBuilderExtensions
{
 public static void Add<TService>(this IContainerBuilder builder)
 where TService : class
 {
 builder.Add(new ServiceDescriptor(typeof(TService), typeof(TService)));
 }
 public static void Add<TService, TImplement>(this IContainerBuilder builder)
 {
 builder.Add(new ServiceDescriptor(typeof(TService), typeof(TImplement)));
 }

 public static void Add<TService>(this IContainerBuilder builder, Func<IContainer, TService> func)
 {
 builder.Add(new ServiceDescriptor(typeof(TService), typeof(Action<IContainer, TService>), func));
 }
}
//测试
IContainerBuilder builder = new ContainerBuilder();
builder.Add(c => new DbConnection());
builder.Add<DbContext>();
var container = builder.Build();
var context = container.GetService(typeof(DbContext));
           

AOP

跟我一起 掌握AspNetCore底层技术和构建原理

基础知识

假设这是一个U型管道,污水水从一端流入,另一端流出。

现在我们要对污水进行过滤,A负责过滤B负责消毒。显然有四个处理点,他们的顺序分别是:1->2->3->4。其中1,4是A过滤器的处理点,2,3是B过滤器的处理点。显然3个过滤器就有6个处理点。我们可以随意调整A,B过滤器的顺序,可随意插拔。这就是AOP的思想。

执行顺序:先进后出(栈)

执行点数:过滤器数 * 2

AOP是对OOP的一种补充,即面向切面编程,一种编程思想。我们管A,B为切面。1~4为切入点。AOP的优势是面向切面编程,每个切面负责独立的系统逻辑,降低代码的复杂度,提高代码的复用率。可以随意调整顺序,随意插拔。用于对业务逻辑进行增强。面向切面编程可以使得系统逻辑和业务逻辑进行分离。

系统逻辑:比如身份认证,异常处理,参数校验

业务逻辑:就是我们真正关心不得不写的业务逻辑。

public class Demo
{
 public void A()
 {
 Console.WriteLine(1);
 B();
 Console.WriteLine(4);
 }
 public void B()
 {
 Console.WriteLine(2);
 Console.WriteLine(3);
 }
}
//这段代码没有实际意义,但是它展示了函数调用的执行过程。(先进后出)
           

静态代理

假设我们需要实现一个IList接口,我们知道IList接口有很多方法,实现成本非常高。我们可以通过代理模式来实现

代理模式可以降低实现的成本,还可以对目标对象进行加强。代理者不需要实现具体的业务逻辑,只需要编写加强逻辑即可。

//实现IEnumerable接口只能加强两个方法,但是实现IList接口可以加强很多方法
class MyCollection : IEnumerable<object>
{
 private IEnumerable<object> _target;

 public MyCollection(IEnumerable<object> target)
 {
 _target = target;
 }

 public IEnumerator<object> GetEnumerator()
 {
//编写加强逻辑比如打印
 Console.WriteLine("调用迭代器了");
//通过target来实现,代理类之关系加强逻辑,不关心接口实现
return _target.GetEnumerator();
 }

 IEnumerator IEnumerable.GetEnumerator()
 {
return ((IEnumerable)_target).GetEnumerator();
 }
}

//测试
var target= new List<object>();
//可以看到MyCollection对target进行了代理,加强了GetEnumerator函数(可以打印消息)
var collection = new MyCollection(target);
//此时GetEnumerator就会被加强,返回target的迭代器。
var it = collection.GetEnumerator();
           

我们可以通过静态代理来实现链式调用,完成污水处理问题。

public interface IWater
{
void Invoke();
}
public class Water : IWater
{
 public void Invoke()
 {
//业务逻辑
 Console.WriteLine("水已经净化了");
 }
}
//实现目标对象的接口IWater
public class WaterProxy1 : IWater
{
 private readonly IWater _target;

 public WaterProxy1(IWater target)
 {
 _target = target;
 }

 public void Invoke()
 {
 Console.WriteLine("开始消毒杀菌");//系统逻辑
 _target = target;
 Console.WriteLine("完成消毒杀菌");//系统逻辑
 }
}
public class WaterProxy2 : IWater
{
 private readonly IWater _target;

 public WaterProxy2(IWater target)
 {
 _target = target;
 }

 public void Invoke()
 {
 Console.WriteLine("开始去除杂质");//系统逻辑
 _target = target;
 Console.WriteLine("完成去除杂质");//系统逻辑
 }
}
//此时是先去除杂质后在消毒
//p1的target是Water,p2的target是p1
var target = new Water();
var p1 = new WaterProxy1(target);
var p2 = new WaterProxy2(p1);
p2.Invoke();
//此时是先消毒后在去除杂质
//p2的target是Water,p1的target是p2
var target = new Water();
var p2 = new WaterProxy2(target);
var p1 = new WaterProxy1(p2);
p2.Invoke();
           

可以看到系统逻辑和业务逻辑进行了分离,系统逻辑写到了不同的切面。切面之间何以随意组合,增减。这就是AOP思想的一种呈现方式。代码服用度很高,可以代理所有的IWater的实现。(假设Mercury也实现了IWater接口,那么WaterProxy1和WaterProxy2也能对他进行增强)

静态代理的本质是子类继承父类,或者实现接口,对目标对象进行增强。

静态代理的弊端是只能实现一个接口(标准),无法代理其他类型的实列。他的切面的可复用率有限,限定在它实现的接口。

注意:如果是通过实现的方式,那么无论静态代理还是动态代理,都只能代理父类中的虚函数(virtual),因为子类只能重写父类中的虚函数。所以建议使用接口的方式。

动态代理

动态代理可以通过Castle.Core来实现。我们说静态代理和动态代理的区别是,静态代理在代码编译之前就已经确立的代理关系。而动态代理的原理是,在编译之后,运行时通过Emit来动态创建目标对象的子类,或者实现目标对象的接口。把拦截器织入到动态生成的类中,这里的拦截器可以织入到任意的实现类中。(Emit技术可以在运行时生成一个class,大家可以通过打印castle.core返回的实列的类名来进行验证)

动态代理和静态代理的本质都是继承或者实现,但是静态代理是需要手动编写代理类,而动态代理由框架动态生成代理类。

public interface IWater
{
void Invoke()
}
public class Water()
{
 public void Invoke()
 {
//业务逻辑
 Console.WriteLine("水已经净化了");
 } 
}
//拦截器-切面
public Interceptor1 : IInterceptor
{
void Intercept(IInvocation invocation)
 {
 Console.WriteLine("开始去除杂质");//系统逻辑
 invocation.Proceed();
 Console.WriteLine("完成去除杂质");//系统逻辑
 }
}
var generator = new ProxyGenerator();
var target = new Water();
//通过框架生成代理类
var proxy = generator.CreateInterfaceProxyWithTarget<IWater>(target,new Interceptor1());
Console.WriteLine(proxy.GetType().FullName);//可以看到这个类并不是我们生成的
proxy.Invoke();
           

委托方式

这是aspnetcore管道的核心代码

public interface IWater
{
void Invoke();
}

public class Water : IWater
{
 public void Invoke()
 {
//业务逻辑
 Console.WriteLine("水已经净化了");
 }
}
//定义一个委托
public delegate void WaterDelegate(IWater water);

public class ApplicationBuilder
{
 private readonly List<Func<WaterDelegate, WaterDelegate>> _components = n

 public void Use(Func<WaterDelegate, WaterDelegate> middleware)
 {
 _components.Add(middleware);
 }

 public WaterDelegate Build()
 {
//负责兜底
 WaterDelegate app = c =>
 {
 throw new InvalidOperationException("无效的管道");
 };
for (int i = _components.Count - 1; i > -1; i--)
 {
 app = _components[i](app);//完成嵌套
 }
return app;
 } 
}
           

测试

var builder = new ApplicationBuilder();
//过滤器1
builder.Use(next => 
{
return water =>
 {
 Console.WriteLine("开始去污");
 next(water);
 Console.WriteLine("完成去污");
 };
});
//过滤器2
builder.Use(next =>
{
return water =>
 {
 Console.WriteLine("开始消毒");
 next(water);
 Console.WriteLine("完成消毒");
 };
});
builder.Use(next =>
{
return water =>
 {
 Console.WriteLine("开始消毒");
//next(water);最后一个委托不能执行next,因为此时next是兜底的那个会抛出异常
water.Invoke();
 Console.WriteLine("完成消毒");
 };
});
//构建管道
var app = builder.Build();
var target = new Water();
//开始处理
app.Invoke(target);
           

接口方式

public class HttpContext
{

}
//链路器
public interface IChain
{
 Task NextAsync();
}
//用于执行filter
public class FilterChain : IChain
{
 private readonly IFilter _filter;
 private readonly HttpContext _context;
 private readonly IChain _next;
 public FilterChain(IFilter filter, HttpContext context, IChain next)
 {
 _filter = filter;
 _context = context;
 _next = next;
 }
 public async Task NextAsync()
 {
 await _filter.InvokeAsync(_context, _next);
 }
}
//用于执行servlet
public class ServletChain : IChain
{
 private readonly IServlet _servlet;
 private readonly HttpContext _context;

 public ServletChain(IServlet servlet, HttpContext context)
 {
 _servlet = servlet;
 _context = context;
 }

 public async Task NextAsync()
 {
 await _servlet.DoPostAsync(_context);
 }
}
public interface IFilter
{
 Task InvokeAsync(HttpContext context, IChain chain);
}
public class Filter1 : IFilter
{
 public async Task InvokeAsync(HttpContext context, IChain chain)
 {
 Console.WriteLine("身份认证开始");
 await chain.NextAsync();
 Console.WriteLine("身份认证结束");
 }
}
public class Filter2 : IFilter
{
 public async Task InvokeAsync(HttpContext context, IChain chain)
 {
 Console.WriteLine("授权认证开始");
 await chain.NextAsync();
 Console.WriteLine("授权认证结束");
 }
}
public interface IServlet
{
 Task DoPostAsync(HttpContext context);
}
public class HelloServlet : IServlet
{
 public Task DoPostAsync(HttpContext context)
 {
 Console.WriteLine("Hello World");
return Task.CompletedTask;
 }
}
public class WebHost
{
 private readonly List<IFilter> _filters = new List<IFilter>();

 public void AddFilter(IFilter filter)
 {
 _filters.Add(filter);
 }

 public void Execute(HttpContext context, IServlet servlet)
 {
//自行处理filter为空的情况,就是直接执行serlvet就好了
 var stack = new Stack<IFilter>(_filters);
 var filter = stack.Pop();
 var chain = GetFilterChain(context, servlet, stack);
 filter.InvokeAsync(context, chain);
 }
//构建链路器(递归算法)
 private IChain GetFilterChain(HttpContext context, IServlet servlet, Stack<IFilter> filters)
 {
if (filters.Any())
 {
 var filter = filters.Pop();
 var next = GetFilterChain(context, servlet, filters);
return new FilterChain(filter, context, next);
 }
else
 {
return new ServletChain(servlet, context);
 }
 }
}
           

测试

var host = new WebHost();
host.AddFilter(new Filter1());
host.AddFilter(new Filter2());
var context = new HttpContext();
host.Execute(context);           

继续阅读