自我所以火狐的HttpRequester测试出组里一个校友发布的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的实现同运用办法以及其他一个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是它的一个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。经过不断调试程序,小组里一个缜密之同校发现,重新运行项目后首先不行调试时,执行第9执行;而当此后再也调试时,是无移动第9实践之。

此时便得看清,问题也许发生在第9尽了。 

再次排查发现YMHttpResponseMessageServerDataValidateErrorMessage凡是静态的

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
CLR每次处理完要后,会以该从带的污物回收机制,将托管的目标释放掉。
而static修饰的靶子,其一直保存在内存中。虽然受放飞掉了,但目标还存。
所以,就丢弃来了问题中提到的怪:System.ObjectDisposedException:
无法访问已放出的对象

这就是说,看来,是static惹的侵害了。赶紧转程序修复后,发现问题迎刃而解了。

咱小组那个同学情不自禁长吁,大家用static还是小心吧好。

记得以前当电商企业召开项目时,就碰到类似static导致系统问题之景象。当然,再次强调,读书少是设吃亏的,
需弄明白static这些用法才是王道。

末段,吐槽一下博客园。  

自身初用博客园是当2011年为尽管是自个儿入职那小电商公司后,认识了众多牛逼的程序猿,大家都为此博客园,我当也就用。这样显得牛逼嘛。
当时描绘过相同首随笔,js啊,我被open撞了一下腰,
看到半钟头外非常多接触击量,也发生很多人数随着来谈谈,甚是兴奋。后来底有的随笔,越来越少有那种热闹劲儿了。
当然,跟自己能力来老可怜关系。  如今协调吗不断了如此长年累月每月写作,在这边,给自己沾一个褒奖,只吧就卖坚持。

 

相关文章

网站地图xml地图