阅读源码探索实现NetCore中间件
1.在Core2.2 Startup 中,Configure 方法写入中间件,app.Use
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
#region Middleware
app.Use(next =>
{
Console.WriteLine("this is Middleware1");
return new RequestDelegate(async context =>
{
context.Response.ContentType = "text/html; charset=utf-8";
await context.Response.WriteAsync("<span><h3>This is Middleware1 start</h3></span>");
await next.Invoke(context);
await context.Response.WriteAsync("<span><h3>This is Middleware1 end</h3></span>");
});
});
app.Use(next =>
{
return new RequestDelegate(async context =>
{
await context.Response.WriteAsync("<span><h3>This is Middleware2 start</h3></span>");
await next.Invoke(context);
await context.Response.WriteAsync("<span><h3>This is Middleware2 end</h3></span>");
});
});
app.Use(next =>
{
Console.WriteLine("this is Middleware3");
return new RequestDelegate(async context =>
{
await context.Response.WriteAsync("<span><h3>This is Middleware3 start</h3></span>");
await next.Invoke(context);
await context.Response.WriteAsync("<span><h3>This is Middleware3 end</h3></span>");
});
});
app.Run(async context => await context.Response.WriteAsync("跑完了.")); //这一句得加上,才能看出
#endregion
if (env.IsDevelopment()) app.UseDeveloperExceptionPage();
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
3.通过查看源码,得知app.Use方法其实去添加了一个Func委托到 IList<Func<RequestDelegate, RequestDelegate>>,
public IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
{
//_components 就是这个 private readonly IList<Func<RequestDelegate, RequestDelegate>> _components
//= new List<Func<RequestDelegate, RequestDelegate>>();
_components.Add(middleware);// _components
return this;
}
接着看处理中间件的逻辑看这段代码
public RequestDelegate Build()
{
RequestDelegate app = context =>
{
// If we reach the end of the pipeline, but we have an endpoint, then something unexpected has happened.
// This could happen if user code sets an endpoint, but they forgot to add the UseEndpoint middleware.
var endpoint = context.GetEndpoint();
var endpointRequestDelegate = endpoint?.RequestDelegate;
if (endpointRequestDelegate != null)
{
var message =
$"The request reached the end of the pipeline without executing the endpoint: '{endpoint.DisplayName}'. " +
$"Please register the EndpointMiddleware using '{nameof(IApplicationBuilder)}.UseEndpoints(...)' if using " +
$"routing.";
throw new InvalidOperationException(message);
}
context.Response.StatusCode = 404;
return Task.CompletedTask;
};
foreach (var component in _components.Reverse())
{
app = component(app);
}
return app;
}
透过这段源码可以发现,处理整个中间件逻辑是,所有的中间件 被存入到 集合 _components ,核心就是把这个集合,转换成单个委托 RequestDelege 。方便调用者调用,执行委托里面的 方法。
借助于这个想法和思路,自己来写个demo
新建一个Core测试程序:
namespace Test
{
/// <summary>
/// 给入字符串,返回 Task
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public delegate Task Conduit(string str);
public class MiddlewareDemo
{
[Test]
public void Implement()
{
CustomMiddleware middle = new CustomMiddleware();
#region C
middle.Add(next =>
{
return zfc =>
{
Console.WriteLine("第一阶段开始");
System.Diagnostics.Debug.WriteLine("第一阶段开始");
return next(zfc);
};
});
middle.Add(next =>
{
return zfc =>
{
Console.WriteLine("第二阶段开始");
System.Diagnostics.Debug.WriteLine("第二阶段开始");
return next(zfc);
};
});
middle.Add(next =>
{
return zfc =>
{
Console.WriteLine("第三阶段开始");
System.Diagnostics.Debug.WriteLine("第三阶段开始");
return next(zfc);
};
});
#endregion
#region D
//middle.Add(next =>
//{
// return async zfc =>
// {
// Console.WriteLine("第一阶段开始");
// System.Diagnostics.Debug.WriteLine("第一阶段开始");
// await next(zfc);
// Console.WriteLine("第一阶段结束");
// System.Diagnostics.Debug.WriteLine("第一阶段结束");
// };
//});
//middle.Add(next =>
//{
// return async zfc =>
// {
// Console.WriteLine("第二阶段开始");
// System.Diagnostics.Debug.WriteLine("第二阶段开始");
// await next(zfc);
// System.Diagnostics.Debug.WriteLine("第二阶段结束");
// Console.WriteLine("第二阶段结束");
// };
//});
//middle.Add(next =>
//{
// return async zfc =>
// {
// Console.WriteLine("第三阶段开始");
// System.Diagnostics.Debug.WriteLine("第三阶段开始");
// await next(zfc);
// System.Diagnostics.Debug.WriteLine("第三阶段结束");
// Console.WriteLine("第三阶段结束");
// };
//});
#endregion
var ak = middle.GetDelegate();
ak.Invoke("正序执行中间件");
System.Diagnostics.Debug.WriteLine("**********分界线**********");
var ff = middle.Reverse();
ff.Invoke("开始执行中间件!");
System.Diagnostics.Debug.WriteLine("跑完了ddd");
Console.WriteLine("跑完了ddd");
}
}
/// <summary>
/// 模拟中间件
/// </summary>
public class CustomMiddleware
{
public IList<Func<Conduit, Conduit>> _middlelist = new List<Func<Conduit, Conduit>>();
// Add也就是NetCore中StartUp中的 app.Use ,同理
public void Add(Func<Conduit, Conduit> func)
{
_middlelist.Add(func);
}
//为了方便理解做比较,这个没有集合倒序
//把集合整合成一个 Conduit委托
public Conduit GetDelegate()
{
Conduit conduit = str =>
{
str = "初始化!";
return Task.CompletedTask;
};
foreach (Func<Conduit, Conduit> item in _middlelist)//正序
//核心在这里,看似在赋新值,其实是在一层又一层包裹这一个执行方法实例,
//给人感觉就像在叠加一样,如果这个地方没有倒序,那么执行方法顺序就是反的
conduit = item(conduit);
return conduit;
}
/// <summary>
/// 把集合进行倒叙,然后整合成一个 Conduit委托
/// </summary>
/// <returns></returns>
public Conduit Reverse()
{
Conduit app = str =>
{
str = "初始化!";
return Task.CompletedTask;
};
foreach (var component in _middlelist.Reverse())//倒序
app = component(app);
return app;
}
/*
public RequestDelegate Build()
{
IList<Func<RequestDelegate, RequestDelegate>> _components = new List<Func<RequestDelegate, RequestDelegate>>();
RequestDelegate app = context =>
{
// If we reach the end of the pipeline, but we have an endpoint, then something unexpected has happened.
// This could happen if user code sets an endpoint, but they forgot to add the UseEndpoint middleware.
var endpoint = context.GetEndpoint();
var endpointRequestDelegate = endpoint?.RequestDelegate;
if (endpointRequestDelegate != null)
{
var message =
$"The request reached the end of the pipeline without executing the endpoint: '{endpoint.DisplayName}'. " +
$"Please register the EndpointMiddleware using '{nameof(IApplicationBuilder)}.UseEndpoints(...)' if using " +
$"routing.";
throw new InvalidOperationException(message);
}
context.Response.StatusCode = 404;
return Task.CompletedTask;
};
foreach (var component in _components.Reverse())
{
app = component(app);
}
return app;
}
*/
}
}
至此,模仿Core中间件的执行已经完成,感兴趣的小伙伴,可以新建一个测试程序,测试一下,你会发现很多不同的东西哦
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具