2012-03-18 81 views
11

有沒有辦法在ASP.NET Web API beta中找出HTTP請求是否被取消(由於任何其他原因被用戶中止)?我正在尋找機會獲得一種即取即用的取消標記,表示請求已中止,因此長時間運行的操作也應中止。ASP.NET Web API +長時間運行操作取消

可能的相關問題 - CancellationTokenModelBinder類的用例。爲取消令牌設置單獨的綁定程序的原因是什麼?

回答

7

您可以不時查看Response.IsClientConnected以查看瀏覽器是否仍連接到服務器。

+0

這似乎是從ASP.NET MVC堆棧,而不是從ASP.NET MVC Web API。如果錯了,請糾正我。 – 2012-03-19 09:02:13

+2

這是來自核心ASP.Net引擎。只適用於IIS集成管道(不是VS調試模式)。 MSDN涵蓋了一個很好的文檔: http://msdn.microsoft.com/en-us/library/system.web.httpresponse.isclientconnected.aspx – 2012-03-19 09:22:10

+0

謝謝你的建議。這似乎是唯一的選擇,我可能會基於此構建解決方案。 – 2012-03-19 15:31:53

8

我想總結一下。似乎工作的唯一方法是檢查Response.IsClientConnected。 關於到底是怎麼回事幕後走向臺前這裏是一些技術細節: herehere 這種方法有一定的缺陷:只能在IIS(沒有自託管,沒有開發服務器)

  • 作品;
  • 根據一些SO的答案可能會很慢(客戶端斷開連接後不立即響應):here;
  • 有關於這個通話費用方面的考慮:here

最後我想出了基於IsClientConnected到Web API控制器下面這段代碼注入的CancellationToken:

public class ConnectionAbortTokenAttribute : System.Web.Http.Filters.ActionFilterAttribute 
{ 
    private readonly string _paramName; 
    private Timer _timer; 
    private CancellationTokenSource _tokenSource; 
    private CancellationToken _token; 

    public ConnectionAbortTokenAttribute(string paramName) 
    { 
     _paramName = paramName; 
    } 

    public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext) 
    { 
     object value; 
     if (!actionContext.ActionArguments.TryGetValue(_paramName, out value)) 
     { 
      // no args with defined name found 
      base.OnActionExecuting(actionContext); 
      return; 
     } 

     var context = HttpContext.Current; 
     if (context == null) 
     { 
      // consider the self-hosting case (?) 
      base.OnActionExecuting(actionContext); 
      return; 
     } 

     _tokenSource = new CancellationTokenSource(); 
     _token = _tokenSource.Token; 
     // inject 
     actionContext.ActionArguments[_paramName] = _token; 
     // stop timer on client disconnect 
     _token.Register(() => _timer.Dispose()); 

     _timer = new Timer 
     (
      state => 
      { 
       if (!context.Response.IsClientConnected) 
       { 
        _tokenSource.Cancel(); 
       } 
      }, null, 0, 1000 // check each second. Opts: make configurable; increase/decrease. 
     ); 

     base.OnActionExecuting(actionContext); 
    } 

    /* 
    * Is this guaranteed to be called? 
    * 
    * 
    */ 
    public override void OnActionExecuted(System.Web.Http.Filters.HttpActionExecutedContext actionExecutedContext) 
    { 
     if(_timer != null) 
      _timer.Dispose(); 

     if(_tokenSource != null) 
      _tokenSource.Dispose(); 

     base.OnActionExecuted(actionExecutedContext); 
    } 
} 
+0

也有一個選項可以使用SignalR和類似的解決方案,但它們對我來說有點超出範圍。 – 2012-03-19 15:51:52

0

如果您將CancellationToken添加到控制器方法中,它將被框架自動注入,並且當客戶端調用xhr.abort()時,令牌將自動取消

類似的東西來

public Task<string> Get(CancellationToken cancellationToken = default(CancellationToken)) 

對於MVC,你也可以參考

HttpContext.Current.Response.IsClientConnected 
HttpContext.Response.ClientDisconnectedToken 

對於.NetCore

services.AddTransient<ICustomInterface>(provider => { 
    var accessor = provider.GetService<IHttpContextAccessor>); 
    accessor.HttpContext.RequestAborted; 
    });