C# 停止自托管owin服务器时完成当前请求

C# 停止自托管owin服务器时完成当前请求,c#,.net,owin,self-hosting,katana,C#,.net,Owin,Self Hosting,Katana,我把OWIN服务器作为控制台应用程序的一部分。您可以在此处看到主要方法: class Program { public static ManualResetEventSlim StopSwitch = new ManualResetEventSlim(); static void Main(string[] args) { Console.CancelKeyPress += (s, a) => { a.Can

我把OWIN服务器作为控制台应用程序的一部分。您可以在此处看到主要方法:

class Program
{
    public static ManualResetEventSlim StopSwitch = new ManualResetEventSlim();

    static void Main(string[] args)
    {
        Console.CancelKeyPress += (s, a) =>
        {
            a.Cancel = true;
            StopSwitch.Set();
        };

        using (WebApp.Start<Startup>("http://+:8080/"))
        {
            Console.WriteLine("Server is running...");
            Console.WriteLine("Press CTRL+C to stop it.");
            StopSwitch.Wait();
            Console.WriteLine("Server is stopping...");
        }

        Console.ReadKey();
        Console.WriteLine("Server stopped. Press any key to close app...");
    }
}
类程序
{
公共静态手动ResetEventSlim停止开关=新的手动ResetEventSlim();
静态void Main(字符串[]参数)
{
Console.CancelKeyPress+=(s,a)=>
{
a、 取消=真;
StopSwitch.Set();
};
使用(WebApp.Start(“http://+:8080/”)
{
WriteLine(“服务器正在运行…”);
控制台。WriteLine(“按CTRL+C停止它”);
停止开关。等待();
WriteLine(“服务器正在停止…”);
}
Console.ReadKey();
Console.WriteLine(“服务器已停止。按任意键关闭应用程序…”);
}
}
当处理请求的时间稍微长一点,同时用户按下CTRL+C停止应用程序时,请求处理立即停止,不发送响应。有可能改变这种行为吗?我想拒绝所有新请求,但要等到当前正在处理的请求完成,然后停止服务器


我最初的想法是创建OWIN中间件,它将跟踪当前正在处理的请求,并将停止操作推迟到所有事情完成为止。中间件还将在停止阶段使所有请求短路。但是这个解决方案对我来说不太好。

我以建议的中间件方法结束:

public class ShutDownMiddleware
{
    private readonly Func<IDictionary<string, object>, Task> next;
    private static int requestCount = 0;
    private static bool shutDownStateOn = false;

    public static void ShutDown()
    {
        shutDownStateOn = true;
    }

    public static int GetRequestCount()
    {
        return requestCount;
    }

    public ShutDownMiddleware(Func<IDictionary<string, object>, Task> next)
    {
        this.next = next;
    }

    public async Task Invoke(IDictionary<string, object> environment)
    {
        if (shutDownStateOn)
        {
            environment["owin.ResponseStatusCode"] = HttpStatusCode.ServiceUnavailable;
            return;
        }

        Interlocked.Increment(ref requestCount);
        try
        {
            await next.Invoke(environment);
        }
        finally
        {
            Interlocked.Decrement(ref requestCount);
        }
    }
}
公共类关闭中间件
{
私有只读Func next;
私有静态int requestCount=0;
私有静态bool shutDownStateOn=false;
公共静态无效关机()
{
shutDownStateOn=true;
}
公共静态int GetRequestCount()
{
返回请求计数;
}
公共关闭中间件(Func next)
{
this.next=next;
}
公共异步任务调用(IDictionary环境)
{
如果(关闭状态)
{
环境[“owin.ResponseStatusCode”]=HttpStatusCode.ServiceUnavailable;
返回;
}
联锁增量(参考请求计数);
尝试
{
等待下一步。调用(环境);
}
最后
{
联锁。减量(参考请求计数);
}
}
}
这是作为管道中的第一个中间件注册的,在程序的主要方法中,我可以这样使用它:

public class Program
{
    public static ManualResetEventSlim StopSwitch = new ManualResetEventSlim();

    static void Main(string[] args)
    {
        Console.CancelKeyPress += (s, a) =>
        {
            a.Cancel = true;
            StopSwitch.Set();
        };

        using (WebApp.Start<Startup>("http://+:8080/"))
        {
            Console.WriteLine("Server is running...");
            Console.WriteLine("Press CTRL+C to stop it.");
            StopSwitch.Wait();
            Console.WriteLine("Server is stopping...");
            ShutDownMiddleware.ShutDown();
            while (ShutDownMiddleware.GetRequestCount() != 0)
            {
                Thread.Sleep(TimeSpan.FromSeconds(1));
            }
        }
    }
}
公共类程序
{
公共静态手动ResetEventSlim停止开关=新的手动ResetEventSlim();
静态void Main(字符串[]参数)
{
Console.CancelKeyPress+=(s,a)=>
{
a、 取消=真;
StopSwitch.Set();
};
使用(WebApp.Start(“http://+:8080/”)
{
WriteLine(“服务器正在运行…”);
控制台。WriteLine(“按CTRL+C停止它”);
停止开关。等待();
WriteLine(“服务器正在停止…”);
ShutDownMiddleware.ShutDown();
while(ShutDownMiddleware.GetRequestCount()!=0)
{
线程睡眠(TimeSpan.FromSeconds(1));
}
}
}
}
我还发现:
他们正在讨论类似的方法。

听起来是个不错的主意。我认为你需要一些东西来缩短新的请求,而将一些东西放入管道似乎是正确的做法。对于跟踪请求,您可以在请求开始和结束时使用基本的/
减量
计数器,以便知道最后一个请求何时完成。您的代码不是完全线程安全的。考虑这个场景:RealestCube是0,调用StutDutter(),但同时一个新的请求到达,并且仍然将SutnStuteOn评估为false。ShutDown()继续,返回,主线程将GetRequestCount()计算为0,以便应用程序停止。但是,上面描述的请求仍然在运行,我发现了另一个问题:When
wait next.Invoke(环境)您只知道此中间件和可能所有后续中间件都已完成,但在完成之后,将需要一些时间通过网络传输生成的响应。因此,如果在GetRequestCount()获取0后立即终止应用程序,则传输响应可能会中断。