目的其实很简单,是想要封装一个发送http的post请求的函数。
函数参数填url地址、请求参数、以及得到后台相应的回调函数、访问超时时间
形如:
public void HttpPost(string url, Dictionary<string, string> dic , Action<IAsyncResult> callback,int timeout)
网上找了之后发现HttpWebRequest 这个类可以实现这个功能
于是网上查到可以这么写
/// <summary>
/// 异步post
/// </summary>
public void HttpPost(string url, Dictionary<string, string> dic , Action<string> callback)
{
Uri uri = new Uri(url);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
HttpReqPack pack = new HttpReqPack(request, dic, callback);
request.BeginGetRequestStream(new AsyncCallback(RequestProceed), pack);
}
这里的pack是自己封装的,目的是为了在BeginGetRequestStream这个函数第二个参数传入一些请求相关信息的数据,因为这个函数的第一个参数是一个委托,第二个参数是带入这个委托的参数其实主要的工作是在RequestProceed这个函数里完成的。以下是HttpReqPack类以及RequestProceed函数的定义。
HttpReqPack类:
class HttpReqPack
{
public HttpWebRequest request;
public Dictionary<string, string> dic;
public Action<string> responesProceed;
public HttpReqPack(HttpWebRequest request, Dictionary<string, string> dic, Action<string> responseProceed)
{
this.request = request;
this.dic = dic;
this.responesProceed = responseProceed;
}
}
private void RequestProceed(IAsyncResult asyncResult)
{
HttpReqPack pack = (HttpReqPack)asyncResult.AsyncState;
Dictionary<string, string> dic = pack.dic;
HttpWebRequest request = pack.request;//(HttpWebRequest)asyncResult.AsyncState;
StreamWriter postDataWriter = new StreamWriter(request.EndGetRequestStream(asyncResult));
int i = 0;
foreach (var item in dic)
{
if(i==0)
postDataWriter.Write(item.Key+"="+item.Value);
else
postDataWriter.Write("&"+item.Key + "=" + item.Value);
i++;
}
postDataWriter.Close();
request.BeginGetResponse(t=> {
String responseString;
try
{
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(t);
StreamReader responseReader = new StreamReader(response.GetResponseStream());
responseString = responseReader.ReadToEnd();
}
catch(Exception e)
{
responseString = JsonConvert.SerializeObject(new ReturnMsg(PublicVar.SVR_UNKNOW_ERROR, e.Message));
}
//调用一下委托
pack.responesProceed.Invoke(responseString);
}, request);
}
在这函数中,就用到了刚才封装的那个HttpReqPack类,把发送参数、url地址还有最重要的是刚才构造的HttpWebRequest对象取出来使用。这个HttpWebRequest对象把他保存在一个名为request的对象,他有个BeginGetResponse方法,这个方法才是发起网络请求的核心方法(经过后期打印日志发现,最耗时的方法也是这个),第一个参数仍然是一个带一个参数无返回值的委托,为了简洁代码,我使用了一个lambda表达式来写,BeginGetResponse的第二个参数是request对象本身就不多说了。
这个委托带的一个参数是HttpWebRequest类型的request对象本身,委托的方法体内使用了另一个重要的方法EndGetResponse,这个方法作用是等待刚才发起的网络请求的结束,当然也可能抛异常,比如网络地址不存在等等,所以用了try..catch..去捕获。EndGetResponse函数的返回值是HttpWebResponse
类型的,把结果保存在response变量,就可以得到最终的后台返回的数据。
最后,调用事先保存在pack中的responesProceed方法,去回调到外层最初调用HttpPost函数的地方。
调用地方的代码可以这样:
new HttpClient().HttpPost(url, dic, t=> {
String responseString = t;
MessageBox.Show(responseString);
});
到目前为止,差不多已经完成了,可是还差一个超时时间设置,我希望自己设置http请求的超时时间,这个如何解决?
尝试了设置request的
request.Timeout = timeout;
request.ReadWriteTimeout = 1;
这两个属性都不管用。
查看了msdn里HttpWebRequest.BeginGetResponse函数,参考里面的例子代码。完成了异步类型超时的设置方式,以下是完整的代码:
using Charge.Public;
using Charge.Record;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
namespace Charge
{
class HttpSender
{
class HttpReqPack
{
public RequestState requestState;
public Dictionary<string, string> dic;
public Action<string> responesProceed;
public int timeout;
public HttpReqPack(RequestState requestState, Dictionary<string, string> dic, Action<string> responseProceed,int timeout)
{
this.requestState = requestState;
this.dic = dic;
this.responesProceed = responseProceed;
this.timeout = timeout;
}
}
/// <summary>
/// 异步post
/// </summary>
public void HttpPost(string url, Dictionary<string, string> dic , int timeout, Action<string> callback)
{
Uri uri = new Uri(url);
RequestState myRequestState = new RequestState();
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
myRequestState.request = request;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
HttpReqPack pack = new HttpReqPack(myRequestState, dic, callback, timeout);
request.BeginGetRequestStream(new AsyncCallback(RequestProceed), pack);
}
// Abort the request if the timer fires.
private static void TimeoutCallback(object state, bool timedOut)
{
if (timedOut)
{
HttpWebRequest request = state as HttpWebRequest;
if (request != null)
{
request.Abort();
}
}
}
public static ManualResetEvent allDone = new ManualResetEvent(false);
private void RequestProceed(IAsyncResult asyncResult)
{
HttpReqPack pack = (HttpReqPack)asyncResult.AsyncState;
Dictionary<string, string> dic = pack.dic;
HttpWebRequest request = pack.requestState.request;
StreamWriter postDataWriter = new StreamWriter(request.EndGetRequestStream(asyncResult));
int i = 0;
foreach (var item in dic)
{
if(i==0)
postDataWriter.Write(item.Key+"="+item.Value);
else
postDataWriter.Write("&"+item.Key + "=" + item.Value);
i++;
}
postDataWriter.Close();
LogHelper.WriteDebug("http计时程序", " request.BeginGetResponse");
try
{
IAsyncResult result = request.BeginGetResponse(t=> {
String responseString;
try
{
LogHelper.WriteDebug("http计时程序", " request.EndGetResponse");
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(t);
LogHelper.WriteDebug("http计时程序", " response.GetResponseStream()");
StreamReader responseReader = new StreamReader(response.GetResponseStream());
LogHelper.WriteDebug("http计时程序", "responseReader.ReadToEnd()");
responseString = responseReader.ReadToEnd();
LogHelper.WriteDebug("http计时程序", " 完成");
}
catch(Exception e)
{
responseString = JsonConvert.SerializeObject(new ReturnMsg(PublicVar.SVR_UNKNOW_ERROR, e.Message));
}
//调用一下委托
pack.responesProceed.Invoke(responseString);
}, request);
// this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), request, pack.timeout, true);
// The response came in the allowed time. The work processing will happen in the
// callback function.
allDone.WaitOne();
// Release the HttpWebResponse resource.
pack.requestState.response.Close();
}
catch (Exception e)
{
LogHelper.WriteDebug("报错", e.Message);
}
}
}
}