eFeature.Headers;
public Stream Body => _httpResponseFeature.Body;
}
public static partial class Extensions
{
public static Task WriteAsync(this HttpResponse response,string content)
{
var buffer = Encoding.UTF8.GetBytes(content);
return response.Body.WriteAsync(buffer, 0, buffer.Length);
}
}
定义处理器
封装好了HttpContext,终于可以回过头来看看处理器。
处理器的处理方法现在应该是这样:
Task Handle(HttpContext context);
接下来就是怎么定义这个处理器了。
起码有两种方式:
1、定义一个接口:
public interface IHttpHandler
{
Task Handle(HttpContext context);
}
2、定义一个委托类型
public delegate Task RequestDelegate(HttpContext context);
两种方式,本质上没啥区别,委托代码方式更灵活,不用实现一个接口,还符合鸭子模型。
处理器就选用委托类型。
定义了处理器,接下来看看服务器
四 服务器的抽象
服务器应该有一个开始方法,传入处理器,并执行。
服务器抽象如下:
public interface IServer
{
Task StartAsync(RequestDelegate handler);
}
定义一个HttpListener的服务器来实现IServer,由于HttpListener的服务器需要提供HttpContext所需的数据,所以先定义HttpListenerFeature
public class HttpListenerFeature : IHttpRequestFeature, IHttpResponseFeature
{
private readonly HttpListenerContext _context;
public HttpListenerFeature(HttpListenerContext context) => _context = context;
Uri IHttpRequestFeature.Url => _context.Request.Url;
Nameva lueCollection IHttpRequestFeature.Headers => _context.Request.Headers;
Nameva lueCollection IHttpResponseFeature.Headers => _context.Response.Headers;
Stream IHttpRequestFeature.Body => _context.Request.InputStream;
Stream IHttpResponseFeature.Body => _context.Response.OutputStream;
int IHttpResponseFeature.StatusCode
{
get => _context.Response.StatusCode;
set => _context.Response.StatusCode = value;
}
}
定义HttpListener服务器
public class HttpListenerServer : IServer
{
private readonly HttpListener _httpListener;
private readonly string[] _urls;
public HttpListenerServer(params string[] urls)
{
_httpListener = new HttpListener();
_urls = urls.Any() ? urls : new string[] { "http://localhost:5000/" };
}
public async Task StartAsync(RequestDelegate handler)
{
Array.ForEach(_urls, url => _httpListener.Prefixes.Add(url));
_httpListener.Start();
Console.WriteLine($"服务器{typeof(HttpListenerServer).Name} 开启,开始监听:{string.Join(";", _urls)}");
while (true)
{
var listtenerContext = await _httpListener.GetContextAsync();
var feature = new HttpListenerFeature(listtenerContext);
var features = new FeatureCollection()
.Set<IHttpRequestFeature>(feature)
.Set<IHttpResponseFeature>(feature);
var httpContext = new HttpContext(features);
await handler(httpContext);
listtenerContext.Response.Close();
}
}
}
修改Main方法运行测试
static async Task Main(string[] args)
{
IServer server = new HttpListenerServer();
async Task FooBar(HttpContext httpContext)
{
await httpContext.Response.WriteAsync("fooBar");
}
await server.StartAsync(FooBar);
}
运行结果如下:
至此,完成了服务器和处理器的抽象。
接下来单看处理器,所有的处理逻辑都集合在一个方法中,理想的方式是有多个处理器进行处理,比如处理器A处理完,则接着B处理器进行处理……
那么就要管理多个处理器之间的连接方式。
五 中间件
中间件的定义
假设有三个处理器A,B,C
框架要实现:A处理器开始处理,A处理完成之后,B处理器开始处理,B处理完成之后,C处理器开始处理。
引入中间件来完成处理器的连接。
中间件的要实现的功能很简单:
- 传入下一个要执行的处理器;
- 在中间件中的处理器里,记住下一个要执行的处理器;
- 返回中间件中的处理器,供其他中间件使用。
所以中间件应该是这样的:
//伪代码
处理器 Middleware(传入下一个要执行的处理器)
{
return 处理器
{
//处理器的逻辑
下一个要执行的处理器在这里执行
}
}
举个例子,现在有三个中间件FooMiddleware,BarMiddleware,BazMiddlewa