给Asp.Net Core写一个结束进程的中间件

起因

在Asp.Net Core中,更新dll无法像原先在Asp.Net中直接覆盖dll的方法,更新项目.这里是通过在中间件中,监视dll变化.简单粗暴的结束dotnet进程来实现.至于为什么使用结束进程的来实现.是因为还没发现更好的方法. 其实用中间件实现非常不好,只是学习使用中间件.

在正常项目中一般会通过IIS/Jexus将请求转发到Kestrel(Asp.Net Core宿主),这样即使Asp.Net Core项目在使用过程出现进程崩溃.也可以在很短的时间内由IIS/Jexus重新拉起.达到守护进程的效果. 下面要实现的中间件结束进程,在由IIS/Jexus拉起,实现覆盖dll时,更新项目的效果.

实现中间件有两种方法:
1. 通过中间件构造函数获取RequestDelegate 类型参数, 实现Invoke函数,参数为HttpContext类型,返回Task
2. 中间件实现IMiddleware接口,实现InvokeAsync函数,参数为HttpContext和RequestDelegate

第一种代码实现

public static class UpdateFileMiddlewareExtensions
{
    /// <summary>
    /// 监视dll文件变化的时候,结束当前进程
    /// </summary>
    /// <param name="builder"></param>
    /// <returns></returns>
    public static IApplicationBuilder UseUpdateFile(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<UpdateFileMiddleware>();
    }
}

public class UpdateFileMiddleware
{
    private readonly RequestDelegate _next;

    /// <summary>
    /// 监测文件变化
    /// </summary>
    private static FileSystemWatcher fileSystemWatcher = null;

    public UpdateFileMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public Task Invoke(HttpContext context)
    {
        string dir = Directory.GetCurrentDirectory();   //获取项目所在的根目录
        if (fileSystemWatcher == null)
        {
            fileSystemWatcher = new FileSystemWatcher(dir, "*.dll");
            fileSystemWatcher.Changed += FileSystemWatcher_Changed;
            fileSystemWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size;
            fileSystemWatcher.EnableRaisingEvents = true;
            fileSystemWatcher.IncludeSubdirectories = true;
        }
        return this._next(context);
    }

    private void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
    {
        fileSystemWatcher.EnableRaisingEvents = false;
        if (e.ChangeType == WatcherChangeTypes.Changed)
        {
            Process.GetCurrentProcess().Kill();  //结束当前进程
        }
        fileSystemWatcher.EnableRaisingEvents = true;
    }
}

使用

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseUpdateFile();  //使用该中间件
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseCookiePolicy();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
        endpoints.MapRazorPages();
    });
}

第二种 代码实现

public class CustomMiddleware : IMiddleware
{
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        //请求处理
        //.....

        await next(context);
    }
}
public static class CustomMiddlewareExtensions
{
    /// <summary>
    /// UseCustomMiddleware 实现xxxx功能
    /// </summary>
    /// <param name="app"></param>
    /// <returns></returns>
    public static IApplicationBuilder UseCustomMiddleware(this IApplicationBuilder app)
    {
        return app.UseMiddleware<CustomMiddleware>();
    }
}


在Configure方法中,调用UseCustomMiddleware

秋风 2019-04-27