出现的环境.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 classCorsMessageHandler : 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 = newHttpMethod(method); 17 } 18 HttpConfiguration configuration =request.GetConfiguration(); 19 HttpControllerDescriptor controllerDescriptor =configuration.Services.GetHttpControllerSelector().SelectController(request); 20 HttpControllerContext controllerContext = newHttpControllerContext(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, outheaders); 41 HttpResponseMessage response; 42 if(isPreflightRequest) 43 { 44 if(authorized) 45 { 46 response = newHttpResponseMessage(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 inheaders) 63 { 64 response.Headers.Add(item.Key, item.Value); 65 } 66 } 67 returnresponse; 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 classCorsAttribute : 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 => newUri(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", outorigins)) 102 { 103 string origin =origins.FirstOrDefault(); 104 if (!String.IsNullOrEmpty(origin)) 105 { 106 Uri originUri = newUri(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 returnheaders; 145 } 146 }
一个简单的异常过滤器
1 public class JsonExceptionFilter : FilterAttribute, IExceptionFilter//, IActionFilter 2 { 3 4 publicTask 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 = newHttpResponseMessage(); 16 } 17 actionExecutedContext.Response.Content = new StringContent("{"State":-255}", Encoding.UTF8, "application/json"); 18 } 19 }, cancellationToken, cancellationToken); 20 } 21 }
现在存在的问题是如果Action内部有异常被过滤器捕获,CorsMessageHandler就卡死在
vartmp=base.SendAsync(request,cancellationToken); response=tmp.Result;//卡死在这里, 用tmp.Wait();也是一样卡死
调试看task的State是WaitingForActivation, 但是用Wait/Result无限期卡死无法得到结果, 但是用await(Microsoft.Bcl.Async引入)就不存在问题, 能正常执行出结果