本人用火狐的HttpRequester测试开发组里3个同桌发布的Web
API接口,遭受了二个意想不到的标题。
笔者测试边界情形时,第②次调用响应的结果是常规的,但当再一次及将来的呼吁时,却回到了分外“System.ObjectDisposedException:
无法访问已放出的靶子
”。
每趟重复揭橥后,都是第叁次呼吁是正规的,之后的哀求就出现那个那么些。

System.ObjectDisposedException: 无法访问已释放的对象。
对象名:“System.Net.Http.StringContent”。
   在 System.Web.Http.WebHost.HttpControllerHandler.EndProcessRequest(IAsyncResult result)
   在 System.Web.Http.WebHost.HttpControllerHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)
   在 System.Web.HttpApplication.CallHandlerExecutionStep.OnAsyncHandlerCompletion(IAsyncResult ar)

 

上面是首先次的响应平常的伏乞。

json 1

如下是raw transaction:

POST http://localhost:3102/api/Notification/SmS
Content-Type: application/json
{
“OrderNo”: “string”,的
“BusinessType”: “string”,
“SendNodeCode”: “string”
}
— response —
500 Internal Server Error
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 70
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles:
=?UTF-8?B?RDpcU291cmNlUHJvamVjdFxub3RpZmljYXRpb25cdHJ1bmtcWU0uTm90aWZpY2F0aW9uXGFwaVxOb3RpZmljYXRpb25cU21T?=
X-Powered-By: ASP.NET
Date: Mon, 06 Jun 2016 11:23:09 GMT

{ “data” : null , “status” : “103” , “message” : “数据格式不附”}

 

因为那一个API应用程序的日记记录Filter、至极处理Filter的贯彻和动用办法与另2个API项目很类似。而充裕API站点没有出现如此的题材,所以,很意外为何这里现身了这么的不行。

 

一般来说是排障进程:

由此调试程序,发现错误定位在如下代码的新民主主义革命加粗的法子上。
那块代码是用来达成记录统一的接口请求/响应日志的。

public class CustomMessageHandler : DelegatingHandler
{
        protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
        {
            if (!request.RequestUri.ToString().ToLower().Contains("swagger"))
            {
                SysLogToFile.WriteNotificationMessage(string.Format("请求url:{0}\r\n请求参数:{1}\r\n", 
                    request.RequestUri, request.Content.ReadAsStringAsync().Result));
            }
            return base.SendAsync(request, cancellationToken).ContinueWith<HttpResponseMessage>(task =>
            {
                if (!request.RequestUri.ToString().ToLower().Contains("swagger"))
                {
                    SysLogToFile.WriteNotificationMessage(string.Format("请求url:{0}\r\n请求参数:{1}\r\n响应结果:{2}",
                        request.RequestUri, request.Content.ReadAsStringAsync().Result, task.Result.Content.ReadAsStringAsync().Result));
                }
                return task.Result;
            });
        }
}

中间, task的Result是三个HttpResponseMessage对象,Content是它的3个System.Net.Http.HttpContent类型的性质,如下是老盖茨对其ReadAsStringAsync艺术的注解

#region 程序集 System.Net.Http.dll, v2.0.0.0
// D:\SourceProject\notification\trunk\packages\Microsoft.Net.Http.2.0.20710.0\lib\net40\System.Net.Http.dll
#endregion

using System;
using System.IO;
using System.Net;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

namespace System.Net.Http
{
    // 摘要: 
    //     表示 HTTP 实体正文和内容标头的基类。
    public abstract class HttpContent : IDisposable
    {
        // 摘要: 
        //     初始化 System.Net.Http.HttpContent 类的新实例。
        protected HttpContent();
        //
        // 摘要: 
        //     释放由 System.Net.Http.HttpContent 使用的非托管资源和托管资源。
        public void Dispose();
        //
        // 摘要: 
        //     释放由 System.Net.Http.HttpContent 使用的非托管资源,并可根据需要释放托管资源。
        //
        // 参数: 
        //   disposing:
        //     如果为 true,则释放托管资源和非托管资源;如果为 false,则仅释放非托管资源。
        protected virtual void Dispose(bool disposing);
        //
        // 摘要: 
        //     以异步操作将 HTTP 内容写入流。
        //
        // 返回结果: 
        //     返回 System.Threading.Tasks.Task<TResult>。 表示异步操作的任务对象。
        public Task<string> ReadAsStringAsync();
    }
}

 

由此翻看这些CustomMessageHandler类中引用的日志工具类SysLogToFile,
发现写日记文件是经过五个Queue来异步完毕的。
那猜疑,是否在异步记日志时task.Result.Content已经被销毁了啊。
所以,对下面那段记日志的代码做个改变:

                    string log = string.Format("请求url:{0}\r\n请求参数:{1}\r\n响应结果:{2}",
                        request.RequestUri, request.Content.ReadAsStringAsync().Result, task.Result.Content.ReadAsStringAsync().Result);
                    SysLogToFile.WriteNotificationMessage(log);

自信满满地以为那样就没难点了。经再测试后,发现并非如此,问题依旧留存。(ps:读书少那些啊,其实.net在调用日志工具类以前,已经把string.Format那段代码给执行并总结了,所以,事先注明个变量是对事情没有什么帮助的)

后续排障,接下去看Sms接口的贯彻代码。

 1 /// <summary>
 2     /// 通知发短信
 3     /// </summary>
 4     [HttpPost]
 5     public HttpResponseMessage SmS(InPutNotifiSmsModel inputModel)
 6     {
 7         if (inputModel == null)
 8         {
 9             return YMHttpResponseMessage.ServerDataValidateErrorMessage;
10         }
11 
12         string returnvalue = NotificationBusiness.NotificationSmS(inputModel.OrderNo, inputModel.BusinessType, inputModel.SendNodeCode);
13 
14         if (returnvalue == "1")
15         {
16             return YMHttpResponseMessage.GetMessage(CustomeHttpMessageResponseStatusCode.SUCCESS, "发送成功");
17         }
18         else if (returnvalue == "-1")
19         {
20             return YMHttpResponseMessage.GetMessage(CustomeHttpMessageResponseStatusCode.INTERNALSERVERERROR, "此订单不存在");
21         }
22         else if (returnvalue == "-2")
23         {
24             return YMHttpResponseMessage.GetMessage(CustomeHttpMessageResponseStatusCode.INTERNALSERVERERROR, "不存在通知");
25         }
26         else if (returnvalue == "-3")
27         {
28             return YMHttpResponseMessage.GetMessage(CustomeHttpMessageResponseStatusCode.INTERNALSERVERERROR, "不存在预定人");
29         }
30         else
31         {
32             return YMHttpResponseMessage.GetMessage(CustomeHttpMessageResponseStatusCode.INTERNALSERVERERROR, "发送失败");
33         }
34     }

 

因为是私下的json串,所以inputModel的值是null。经过持续调节和测试程序,小组里一个密切的同校发现,重国民党的新生活运动行品种后率先次调节和测试时,执行第⑧行;而在事后再调节和测试时,是不走第八行的。

此时就能够判定,难题或然出在第⑨行了。 

再也排查发现YMHttpResponseMessageServerDataValidateErrorMessagejson,是静态的

public class YMHttpResponseMessage
    {
        /// <summary>
        /// 服务资源未找到
        /// </summary>
        public static HttpResponseMessage ServiceNotFoundMessage;

        /// <summary>
        /// 服务器异常
        /// </summary>
        public static HttpResponseMessage ServerErrorMessage;

        /// <summary>
        /// 数据格式不附
        /// </summary>
        public static HttpResponseMessage ServerDataValidateErrorMessage;

        static YMHttpResponseMessage()
        {

            ....

            ServerDataValidateErrorMessage = new HttpResponseMessage()
            {
                Content = new StringContent(
                        new ResponseModel()
                        {
                            data = Newtonsoft.Json.JsonConvert.SerializeObject(null),
                            status = CustomeHttpMessageResponseStatusCode.INTERNALSERVERERROR,
                            message = "数据格式不附"
                        }.ToString(),
                       Encoding.UTF8,
                       "application/json"
                    ),
                StatusCode = System.Net.HttpStatusCode.InternalServerError
            };

        }

 

 再与丰富没难点的API项目源码相比,发现其内部每趟处理请求的重临值都以new一个HttpResponseMessage对象。

那般,就大约知道原因了, Http请求是无状态的,.net
CLEvoque每趟处理完请求后,会采用其自带的废品回收机制,将托管的靶子释放掉。
而static修饰的对象,其一贯保存在内部存款和储蓄器中。尽管被放走掉了,但指标还设有。
所以,就抛出了难点中涉及的可怜:System.ObjectDisposedException:
不能访问已出狱的目的

那正是说,看来,是static惹的祸了。赶紧改程序修复后,发现标题化解了。

咱俩小组那一个同学情难自禁长吁,我们用static依旧小心为好。

记得以前在电商公司做项目时,就境遇类似static导致系统难题的情况。当然,再一次强调,读书少是要吃亏的,
需弄理解static这一个用法才是王道。

最后,吐槽一下天涯论坛。  

小编初用乐乎是在二零一二年也正是自个儿入职那家用电器商公司后,认识了众多牛逼的程序猿,大家都用微博,我自然也随即用。这样显得牛逼嘛。
当时写过一篇小说,js啊,小编被open撞了一下腰
看到半钟头内很多点击量,也有比比皆是人随即来谈谈,甚是欢畅。后来的一部分小说,越来越少有那种欢娱劲儿了。
当然,跟本人力量有非常大关系。  近日温馨也不绝于耳了这样多年每月写作,在此处,给自个儿点2个赞,只为那份百折不挠。

 

相关文章

网站地图xml地图