首页 > 代码库 > .Net Task<T>的一种比较神奇的卡死情况(Wait/Result卡死, await能得到结果)

.Net Task<T>的一种比较神奇的卡死情况(Wait/Result卡死, await能得到结果)

出现的环境.Net4.0 + WebApi1(4.0.30506.0) + Microsoft.Bcl.Async.1.0.168

自己死活看不出原因, 分享出来给大家看看,希望有人能找到问题的关键

 

出现错误的是下面这两个模块

下面的CorsMessageHandler,抄的http://www.cnblogs.com/artech/p/cors-4-asp-net-web-api-04.html, 做了部分修改

  1     public class CorsMessageHandler : DelegatingHandler  2     {  3         private static readonly CorsAttribute DEFAULT_CORS = new CorsAttribute("*");//默认支持所有  4   5         protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)  6         {  7             cancellationToken.ThrowIfCancellationRequested();  8             try  9             { 10                 //得到描述目标Action的HttpActionDescriptor 11                 HttpMethod originalMethod = request.Method; 12                 bool isPreflightRequest = request.IsPreflightRequest(); 13                 if (isPreflightRequest) 14                 { 15                     string method = request.Headers.GetValues("Access-Control-Request-Method").First(); 16                     request.Method = new HttpMethod(method); 17                 } 18                 HttpConfiguration configuration = request.GetConfiguration(); 19                 HttpControllerDescriptor controllerDescriptor = configuration.Services.GetHttpControllerSelector().SelectController(request); 20                 HttpControllerContext controllerContext = new HttpControllerContext(request.GetConfiguration(), request.GetRouteData(), request) 21                 { 22                     ControllerDescriptor = controllerDescriptor 23                 }; 24                 //避免权限错误 25                 //HttpActionDescriptor actionDescriptor = configuration.Services.GetActionSelector().SelectAction(controllerContext); 26  27                 //根据HttpActionDescriptor得到应用的CorsAttribute特性 28                 CorsAttribute corsAttribute = null; 29                 //corsAttribute = actionDescriptor.GetCustomAttributes<CorsAttribute>().FirstOrDefault(); 30                 corsAttribute = corsAttribute?? controllerDescriptor.GetCustomAttributes<CorsAttribute>().FirstOrDefault(); 31                 if (null == corsAttribute) 32                 { 33                     corsAttribute = DEFAULT_CORS; 34                     //return base.SendAsync(request, cancellationToken); 35                 } 36  37                 //利用CorsAttribute实施授权并生成响应报头 38                 IDictionary<string, string> headers; 39                 request.Method = originalMethod; 40                 bool authorized = corsAttribute.TryEvaluate(request, out headers); 41                 HttpResponseMessage response; 42                 if (isPreflightRequest) 43                 { 44                     if (authorized) 45                     { 46                         response = new HttpResponseMessage(HttpStatusCode.OK); 47                     } 48                     else 49                     { 50                         response = request.CreateErrorResponse(HttpStatusCode.BadRequest, corsAttribute.ErrorMessage); 51                     } 52                 } 53                 else 54                 { 55                     var tmp = base.SendAsync(request, cancellationToken); 56                     tmp.Wait(); 57                     response = tmp.Result; 58                 } 59  60                 if (headers != null) 61                 { 62                     foreach (var item in headers) 63                     { 64                         response.Headers.Add(item.Key, item.Value); 65                     } 66                 } 67                 return response; 68             } 69             catch 70             { 71             } 72             //catch -> fallback 73             return await base.SendAsync(request, cancellationToken); 74         } 75     } 76     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] 77     public class CorsAttribute : Attribute 78     { 79         public Uri[] AllowOrigins { get; private set; } 80         public string ErrorMessage { get; private set; } 81  82         public CorsAttribute(params string[] allowOrigins) 83         { 84             var tmp = (allowOrigins ?? new string[0]); 85             if (tmp.Length == 1 && "*" == tmp[0]) 86             { 87                 this.AllowOrigins = null; 88             } 89             else 90             { 91                 this.AllowOrigins = tmp.Select(origin => new Uri(origin)).ToArray(); 92             } 93         } 94  95         public bool TryEvaluate(HttpRequestMessage request, out IDictionary<string, string> headers) 96         { 97             headers = null; 98  99             //bugfix: GetValues在找不到时会报错100             IEnumerable<string> origins;101             if (request.Headers.TryGetValues("Origin", out origins))102             {103                 string origin = origins.FirstOrDefault();104                 if (!String.IsNullOrEmpty(origin))105                 {106                     Uri originUri = new Uri(origin);107                     if (this.AllowOrigins == null || this.AllowOrigins.Contains(originUri))//支持"*"108                     {109                         headers = this.GenerateResponseHeaders(request);110                         return true;111                     }112                 }113             }114             this.ErrorMessage = "Cross-origin request denied";115             return false;116         }117 118         private IDictionary<string, string> GenerateResponseHeaders(HttpRequestMessage request)119         {120             //设置响应报头"Access-Control-Allow-Methods"121             string origin = request.Headers.GetValues("Origin").First();122             Dictionary<string, string> headers = new Dictionary<string, string>();123             headers.Add("Access-Control-Allow-Origin", origin);124             if (request.IsPreflightRequest())125             {126                 //设置响应报头"Access-Control-Request-Headers"127                 //和"Access-Control-Allow-Headers"128                 string requestHeaders = request.Headers.GetValues("Access-Control-Request-Headers").FirstOrDefault();129                 if (!string.IsNullOrEmpty(requestHeaders))130                 {131                     headers.Add("Access-Control-Allow-Headers", requestHeaders);132                 }133                 //string requestMethods = request.Headers.GetValues("Access-Control-Request-Method").FirstOrDefault();134                 //if (!string.IsNullOrEmpty(requestHeaders))135                 //{136                 //    headers.Add("Access-Control-Allow-Methods", requestMethods + ", OPTIONS");137                 //}138                 //else139                 //{140                     headers.Add("Access-Control-Allow-Methods", "*");141                 //}142             }143             headers.Add("Access-Control-Allow-Credentials", "true");//true, 允许跨域传cookie, 要在POST的返回值中也存在144             return headers;145         }146     }
View Code

一个简单的异常过滤器

 1     public class JsonExceptionFilter : FilterAttribute, IExceptionFilter//, IActionFilter 2     { 3  4         public Task ExecuteExceptionFilterAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken) 5         { 6             return Task.Factory.StartNew((obj) => 7             { 8                 CancellationToken ct = (CancellationToken)obj; 9                 if (actionExecutedContext.Exception != null)10                 {11                     var res = new ResultModel<String>(false, actionExecutedContext.Exception.GetType().ToString());12                     var resText = JsonConvert.SerializeObject(res);13                     if (actionExecutedContext.Response == null)14                     {15                         actionExecutedContext.Response = new HttpResponseMessage();16                     }17                     actionExecutedContext.Response.Content = new StringContent("{\"State\":-255}", Encoding.UTF8, "application/json");18                 }19             }, cancellationToken, cancellationToken);20         }21     }
View Code

现在存在的问题是如果Action内部有异常被过滤器捕获, CorsMessageHandler就卡死在

var tmp = base.SendAsync(request, cancellationToken);response = tmp.Result;//卡死在这里, 用tmp.Wait();也是一样卡死

调试看task的State是WaitingForActivation, 但是用Wait/Result无限期卡死无法得到结果, 但是用await(Microsoft.Bcl.Async引入)就不存在问题, 能正常执行出结果

  

.Net Task<T>的一种比较神奇的卡死情况(Wait/Result卡死, await能得到结果)