zoukankan      html  css  js  c++  java
  • .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     }
    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引入)就不存在问题, 能正常执行出结果

      

  • 相关阅读:
    Js中的正则表达式
    js内存泄露的几种情况
    JavaScript的setTimeout与setInterval执行时机
    IE模拟addDOMLoadEvent和jQuery的ready实现
    谈谈JavaScript的异步实现
    在iOS7中修改状态栏字体的颜色
    IOS 疯狂基础之 页面间跳转
    ATL2.1版的CString分析
    翻译: 如何改变MFC应用程序主窗口的类名
    VC5.0中的ATL的一个有趣的bug
  • 原文地址:https://www.cnblogs.com/yyjdelete/p/3957651.html
Copyright © 2011-2022 走看看