.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 //else 139 //{ 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 }
一个简单的异常过滤器
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 }
现在存在的问题是如果Action内部有异常被过滤器捕获, CorsMessageHandler就卡死在
var tmp = base.SendAsync(request, cancellationToken); response = tmp.Result;//卡死在这里, 用tmp.Wait();也是一样卡死
调试看task的State是WaitingForActivation, 但是用Wait/Result无限期卡死无法得到结果, 但是用await(Microsoft.Bcl.Async引入)就不存在问题, 能正常执行出结果
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。