当自托管OWIN服务器关闭时,如何向Web API操作发出取消信号?

Dav*_*bin 4 c# asp.net owin asp.net-web-api2

我有一个在Windows服务中托管的基于OWIN的ASP.NET Web API.我的大多数ApiController操作都是异步的,并接受CancellationToken参数:

[Route("data/{id}")]
public async Task<IHttpActionResult> GetSomeDataAsync(int id, CancellationToken token)
{
    try
    {
        using (var _dataSource = ...)
        {
            return Ok(await _dataSource.GetDataAsync(id, token));
        }
    }
    catch (OperationCanceledException ex)
    {
        return StatusCode(HttpStatusCode.NoContent);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用Web API的内置请求取消功能,如果客户端取消请求,token则发出信号并_dataSource适当地处理它并抛出OperationCanceledException.

到目前为止,太棒了.

但是当我的主机进程终止时(即Windows服务停止),token没有发出信号,并且取消和纾困过程不优雅.

我知道OWIN环境字典的host.onAppDisposing属性,我已经挖掘了Microsoft.Owin [.*]Microsoft.AspNet.WebApi.*包的源代码,试图弄清楚其中GetSomeDataAsynctoken参数是什么来自,但我不知道如何将各个部分连接在一起.

我想做点什么

class WebServiceInAWindowsService : ServiceBase
{
    private readonly CancellationTokenSource _cts = new CancellationTokenSource();
    ...
    protected override void OnStop()
    {
        _cts.Cancel();
    }
}
Run Code Online (Sandbox Code Playgroud)

但我不确定如何_cts成为CancellationTokens我的行动的源头,同时不打破运行良好的请求取消功能.

我认为这CancellationTokenSource.CreateLinkedTokenSource()可能有用,但我没有看到如何将各个部分组合在一起.

你能帮我吗?谢谢!

Tra*_*her 6

host.onAppDisposing当你调用Dispose返回的值时触发WebApp.Start.

https://github.com/aspnet/AspNetKatana/blob/9f6e09af6bf203744feb5347121fe25f6eec06d8/src/Microsoft.Owin.Hosting/Engine/HostingEngine.cs#L302-L308

https://github.com/aspnet/AspNetKatana/blob/9f6e09af6bf203744feb5347121fe25f6eec06d8/src/Microsoft.Owin.Hosting/Engine/HostingEngine.cs#L112

GetSomeDataAsync默认情况下,它仅与请求断开连接令牌相关联(例如owin.CallCancelled).通过中间件或其他方式,您可以将其替换为也连接到的链接TCS host.onAppDisposing.

就像是:

app.Use(async (env, next) =>
{
  var reqAbt = env.Get<CancellationToken>("owin.CallCancelled");
  var appAbt = env.Get<CancellationToken>("host.onAppDisposing"); 
  using (linked = CancellationTokenSource.CreateLinkedTokenSource(reqAbt, appAbt))
  {
    env["owin.CallCancelled"] = linked.Token;
    await next();
    env["owin.CallCancelled"] = reqAbt;
  }
});
Run Code Online (Sandbox Code Playgroud)