2012-03-18 21 views
11

Có cách nào để tìm ra trong ASP.NET Web API beta cho dù yêu cầu HTTP đã bị hủy bỏ (bị hủy bỏ bởi người dùng vì bất kỳ lý do nào khác)? Tôi đang tìm kiếm cơ hội để có một loại mã thông báo hủy bỏ out-of-the-box sẽ báo hiệu rằng yêu cầu bị hủy bỏ và do đó các ops dài hạn cũng nên bị hủy bỏ.ASP.NET Web API + Hủy hoạt động dài hạn

Câu hỏi có liên quan - trường hợp sử dụng cho lớp CancellationTokenModelBinder. Lý do để có một chất kết dính riêng biệt cho mã thông báo hủy là gì?

Trả lời

7

Bạn có thể kiểm tra Response.IsClientConnected theo thời gian để xem liệu trình duyệt có còn kết nối với máy chủ hay không.

+0

này có vẻ là từ ASP.NET MVC chồng, chứ không phải từ ASP.NET API web MVC. Hãy sửa tôi nếu sai. –

+2

Đây là từ động cơ lõi ASP.Net. Chỉ hoạt động với đường dẫn tích hợp IIS (không phải chế độ gỡ lỗi VS). MSDN bao gồm tài liệu tốt: http://msdn.microsoft.com/en-us/library/system.web.httpresponse.isclientconnected.aspx –

+0

cảm ơn bạn đã đề xuất. Điều này có vẻ là lựa chọn duy nhất, tôi có lẽ sẽ xây dựng giải pháp dựa trên điều này. –

8

Tôi muốn tóm tắt một chút. Cách tiếp cận duy nhất dường như hoạt động là kiểm tra Response.IsClientConnected. chi tiết Dưới đây một số kỹ thuật liên quan đến những gì đang xảy ra đằng sau sân khấu: herehere Cách tiếp cận này có một số sai sót:

  • trình chỉ dưới IIS (không tự lưu trữ, không có Dev Server);
  • Theo một số câu trả lời SO có thể chậm (không phản ứng ngay sau khi khách hàng bị ngắt kết nối): here;
  • Có những cân nhắc về chi phí cuộc gọi này: here

Cuối cùng tôi đã đưa ra những đoạn mã sau đây để tiêm CancellationToken dựa trên IsClientConnected vào bộ điều khiển Web API:

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

Ngoài ra còn có một tùy chọn để sử dụng SignalR và các giải pháp tương tự, nhưng chúng có một chút phạm vi đối với tôi. –

0

Nếu bạn đã thêm CancellationToken vào phương thức điều khiển, nó sẽ tự động được tiêm bởi khung và khi khách hàng gọi xhr.abort() mã thông báo sẽ tự động bị hủy

Một cái gì đó tương tự như

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

Đối với MVC bạn cũng có thể tham khảo

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

Đối .NetCore

services.AddTransient<ICustomInterface>(provider => { 
    var accessor = provider.GetService<IHttpContextAccessor>); 
    accessor.HttpContext.RequestAborted; 
    }); 
Các vấn đề liên quan