Silverlight_Rest_WCF系列之四:Rest调用者,RestInvoker.
还记得上篇文章中的PUT调用Rest服务的代码吗?不记得没关系,下面就是它的代码。
WebRequest webRequest =WebRequestCreator.ClientHttp.Create(
new Uri("http://localhost:19598/ProductService.svc/Product"));
webRequest.ContentType = "application/json";
webRequest.Method = "PUT";
webRequest.BeginGetRequestStream(requestAsyncCallback =>
{
Stream requestStream = webRequest.EndGetRequestStream(requestAsyncCallback);
JsonObject jo = new JsonObject();
jo["Id"] = Guid.NewGuid().ToString();
jo["Name"] = "test";
string jsonString = jo.ToString();
byte[] buffer = System.Text.Encoding.Unicode.GetBytes(jsonString);
requestStream.Write(buffer, 0, buffer.Length);
requestStream.Close();
webRequest.BeginGetResponse(responseAsyncCallback =>
{
WebResponse webResponse = webRequest.EndGetResponse(responseAsyncCallback);
using (StreamReader reader = new StreamReader(webResponse.GetResponseStream()))
{
string result = reader.ReadToEnd();
//MessageBox.Show(result);
this.Dispatcher.BeginInvoke(() =>
{
MessageBox.Show(result);
});
}
}, null);
}, null);
#endregion
如果说每次调用服务都需要写这么多代码的话,那估计程序员会疯的。所以我决定对他进行包装。
在这段代码中有几个地方可以封装。
1:创建WebRequest的代码可以封装。
new Uri("http://localhost:19598/ProductService.svc/Product"));
webRequest.ContentType = "application/json";
webRequest.Method = "PUT";
2:序列化数据到requestStream对象中可以封装。
JsonObject jo = new JsonObject();
jo["Id"] = Guid.NewGuid().ToString();
jo["Name"] = "test";
string jsonString = jo.ToString();
byte[] buffer = System.Text.Encoding.Unicode.GetBytes(jsonString);
requestStream.Write(buffer, 0, buffer.Length);
requestStream.Close();
3:对返回结果执行的操作可以封装。
using (StreamReader reader = new StreamReader(webResponse.GetResponseStream()))
{
string result = reader.ReadToEnd();
//MessageBox.Show(result);
this.Dispatcher.BeginInvoke(() =>
{
MessageBox.Show(result);
});
}
按照1,2,3的方式我们先从1开始。代码如下:
1:使用GetWebRequest函数获取WebRequest对象,当然了你也可以用factory,但是在目前而言,一个函数就足够了。
/// 获取WebRequest对象
/// </summary>
/// <param name="requestUriString">请求的地址</param>
/// <param name="httpMethod">请求的方法:GET,PUT,POST,DELETE</param>
/// <param name="contentType">请求的类型,json:"application/json"</param>
/// <returns></returns>
public static HttpWebRequest GetWebRequest(string requestUriString,
string httpMethod,
string contentType)
{
HttpWebRequest request = (HttpWebRequest)WebRequestCreator.ClientHttp.Create(new Uri(requestUriString));
request.Method = httpMethod;
if (!string.IsNullOrWhiteSpace(contentType))
{
request.ContentType = contentType;
}
return request;
}
2:封装序列化到RequestStream的过程。
SerializeDataToRequestStream(data,requestStream);
requestStream.Close();
SerializeDataToRequestStream方法可以对JsonObject,匿名类,DataContract修饰的类进行序列化。
{
if (data.GetType() == typeof(System.Json.JsonObject))
{
string jsonString = data.ToString();
byte[] buffer = System.Text.Encoding.Unicode.GetBytes(jsonString);
requestStream.Write(buffer, 0, buffer.Length);
}
else if(data.GetType().FullName.Contains("AnonymousType")) //如果是匿名类
{
#region 使用反射获取属性和值,可以使用FastInvoker来优化。
PropertyInfo[] pis = data.GetType().GetProperties();
System.Json.JsonObject jo = new System.Json.JsonObject();
foreach(PropertyInfo pi in pis)
{
jo[pi.Name] = pi.GetValue(data, null).ToString();
}
#endregion
string jsonString = jo.ToString();
byte[] buffer = System.Text.Encoding.Unicode.GetBytes(jsonString);
requestStream.Write(buffer, 0, buffer.Length);
}
else
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
serializer.WriteObject(requestStream, data);
}
}
3:处理WebResponse。如果T是String类型则直接返回Json的string,否则使用DataContractJsonSerializer 反序列化成对象进行操作。
/// 处理WebResponse
/// </summary>
/// <typeparam name="T">WebResponse返回结果的类型</typeparam>
/// <param name="webResponse">webResponse对象</param>
/// <param name="action">对结果的操作</param>
private static void HandleWebResponse<T>(WebResponse webResponse, Action<T> action)
{
using (Stream responseStream = webResponse.GetResponseStream())
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
if (typeof(T) == typeof(string))
{
T responseObject = (T)(object)GetStringFromStream(responseStream);
action(responseObject);
}
else
{
T responseObject = (T)serializer.ReadObject(responseStream);
action(responseObject);
}
}
}
好了,基本框架已经搭建好了,尝试下调用GET服务吧。
/// 调用GET方法
/// </summary>
/// <typeparam name="T">结果的类型</typeparam>
/// <param name="requestUriString">请求的地址</param>
/// <param name="action">对结果的操作</param>
public static void InvokeGet<T>(string requestUriString, Action<T> action)
{
HttpWebRequest webRequest = GetWebRequest(requestUriString, "GET", string.Empty);
webRequest.BeginGetResponse((asyncResult) =>
{
WebResponse response = webRequest.EndGetResponse(asyncResult);
HandleWebResponse(response, action);
}, null);
}
调用GET服务比较简单,使用GET从指定的URL下载数据就可以了,那么调用POST,PUT,DELETE呢?
其实原理都比较简单,就是GetRequestStream--->写数据到RequestStream--->GetResponse。
所以可以写一个通用方法来调用PUT,POST,DELETE。
/// 调用PUT/POST/DELETE方法
/// </summary>
/// <typeparam name="TData">请求数据的类型</typeparam>
/// <typeparam name="TResult">结果的类型</typeparam>
/// <param name="requestUriString">请求的地址</param>
/// <param name="data">请求的数据</param>
/// <param name="action">对结果的操作</param>
/// <param name="httpMethod">请求的具体方法,PUT/POST/DELETE</param>
public static void InvokePutPostDelete<TData, TResult>(string requestUriString, TData data, Action<TResult> action, string httpMethod)
{
HttpWebRequest webRequest = GetWebRequest(requestUriString, httpMethod, "application/json");
webRequest.BeginGetRequestStream((requestAsyncResult) =>
{
Stream requestStream = webRequest.EndGetRequestStream(requestAsyncResult);
SerializeDataToRequestStream(data,requestStream);
requestStream.Close();
webRequest.BeginGetResponse((responseAsyncResult) =>
{
WebResponse response = webRequest.EndGetResponse(responseAsyncResult);
HandleWebResponse(response, action);
}, null);
}, null);
}
RestInvoker的完整代码如下:
{
/// <summary>
/// 获取WebRequest对象
/// </summary>
/// <param name="requestUriString">请求的地址</param>
/// <param name="httpMethod">请求的方法:GET,PUT,POST,DELETE</param>
/// <param name="contentType">请求的类型,json:"application/json"</param>
/// <returns></returns>
public static HttpWebRequest GetWebRequest(string requestUriString,
string httpMethod,
string contentType)
{
HttpWebRequest request = (HttpWebRequest)WebRequestCreator.ClientHttp.Create(new Uri(requestUriString));
request.Method = httpMethod;
if (!string.IsNullOrWhiteSpace(contentType))
{
request.ContentType = contentType;
}
return request;
}
/// <summary>
/// 调用GET方法
/// </summary>
/// <typeparam name="T">结果的类型</typeparam>
/// <param name="requestUriString">请求的地址</param>
/// <param name="action">对结果的操作</param>
public static void InvokeGet<T>(string requestUriString, Action<T> action)
{
HttpWebRequest webRequest = GetWebRequest(requestUriString, "GET", string.Empty);
webRequest.BeginGetResponse((asyncResult) =>
{
WebResponse response = webRequest.EndGetResponse(asyncResult);
HandleWebResponse(response, action);
}, null);
}
/// <summary>
/// 调用PUT方法
/// </summary>
/// <typeparam name="TData">请求数据的类型</typeparam>
/// <typeparam name="TResult">结果的类型</typeparam>
/// <param name="requestUriString">请求的地址</param>
/// <param name="data">请求的数据</param>
/// <param name="action">对结果的操作</param>
public static void InvokePut<TData,TResult>(string requestUriString, TData data, Action<TResult> action)
{
InvokePutPostDelete(requestUriString, data, action, "PUT");
}
/// <summary>
/// 调用POST方法
/// </summary>
/// <typeparam name="TData">请求数据的类型</typeparam>
/// <typeparam name="TResult">结果的类型</typeparam>
/// <param name="requestUriString">请求的地址</param>
/// <param name="data">请求的数据</param>
/// <param name="action">对结果的操作</param>
public static void InvokePost<TData, TResult>(string requestUriString, TData data, Action<TResult> action)
{
InvokePutPostDelete(requestUriString, data, action, "POST");
}
/// <summary>
/// 调用DELETE方法
/// </summary>
/// <typeparam name="TData">请求数据的类型</typeparam>
/// <typeparam name="TResult">结果的类型</typeparam>
/// <param name="requestUriString">请求的地址</param>
/// <param name="data">请求的数据</param>
/// <param name="action">对结果的操作</param>
public static void InvokeDelete<TData, TResult>(string requestUriString, TData data, Action<TResult> action)
{
InvokePutPostDelete(requestUriString, data, action, "DELETE");
}
/// <summary>
/// 调用PUT/POST/DELETE方法
/// </summary>
/// <typeparam name="TData">请求数据的类型</typeparam>
/// <typeparam name="TResult">结果的类型</typeparam>
/// <param name="requestUriString">请求的地址</param>
/// <param name="data">请求的数据</param>
/// <param name="action">对结果的操作</param>
/// <param name="httpMethod">请求的具体方法,PUT/POST/DELETE</param>
public static void InvokePutPostDelete<TData, TResult>(string requestUriString, TData data, Action<TResult> action, string httpMethod)
{
HttpWebRequest webRequest = GetWebRequest(requestUriString, httpMethod, "application/json");
webRequest.BeginGetRequestStream((requestAsyncResult) =>
{
Stream requestStream = webRequest.EndGetRequestStream(requestAsyncResult);
SerializeDataToRequestStream(data,requestStream);
requestStream.Close();
webRequest.BeginGetResponse((responseAsyncResult) =>
{
WebResponse response = webRequest.EndGetResponse(responseAsyncResult);
HandleWebResponse(response, action);
}, null);
}, null);
}
/// <summary>
/// 序列化对象到RequestStream中
/// </summary>
/// <typeparam name="T">请求数据的类型</typeparam>
/// <param name="data">请求的数据</param>
/// <param name="requestStream">RequestStream</param>
private static void SerializeDataToRequestStream<T>(T data, Stream requestStream)
{
if (data.GetType() == typeof(System.Json.JsonObject))
{
string jsonString = data.ToString();
byte[] buffer = System.Text.Encoding.Unicode.GetBytes(jsonString);
requestStream.Write(buffer, 0, buffer.Length);
}
else if(data.GetType().FullName.Contains("AnonymousType")) //如果是匿名类
{
#region 使用反射获取属性和值,可以使用FastInvoker来优化。
PropertyInfo[] pis = data.GetType().GetProperties();
System.Json.JsonObject jo = new System.Json.JsonObject();
foreach(PropertyInfo pi in pis)
{
jo[pi.Name] = pi.GetValue(data, null).ToString();
}
#endregion
string jsonString = jo.ToString();
byte[] buffer = System.Text.Encoding.Unicode.GetBytes(jsonString);
requestStream.Write(buffer, 0, buffer.Length);
}
else
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
serializer.WriteObject(requestStream, data);
}
}
/// <summary>
/// 处理WebResponse
/// </summary>
/// <typeparam name="T">WebResponse返回结果的类型</typeparam>
/// <param name="webResponse">webResponse对象</param>
/// <param name="action">对结果的操作</param>
private static void HandleWebResponse<T>(WebResponse webResponse, Action<T> action)
{
using (Stream responseStream = webResponse.GetResponseStream())
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
if (typeof(T) == typeof(string))
{
T responseObject = (T)(object)GetStringFromStream(responseStream);
action(responseObject);
}
else
{
T responseObject = (T)serializer.ReadObject(responseStream);
action(responseObject);
}
}
}
/// <summary>
/// 从Stream中获取String
/// </summary>
/// <param name="stream"></param>
/// <returns></returns>
public static string GetStringFromStream(Stream stream)
{
byte[] buffer = new byte[32768];
stream.Position = 0; //重置读取位置
while (true)
{
int read = stream.Read(buffer, 0, buffer.Length);
if (read <= 0)
break;
}
return System.Text.Encoding.UTF8.GetString(buffer, 0, (int)stream.Length);
}
/// <summary>
/// 复制流
/// </summary>
/// <param name="input">输入流</param>
/// <param name="output">输出流</param>
private static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[32768];
input.Position = 0; //重置读取位置
while (true)
{
int read = input.Read(buffer, 0, buffer.Length);
if (read <= 0)
return;
output.Write(buffer, 0, read);
}
}
}
但是我们还没有解决跨线程问题,还记得上篇文章中的this.Dispatcher.BeginInvoker吗?
但是在某些特定情况下,客户端不想调用BeginInvoker。
我们下回要修改RestInvoker,让它可以跨线程。 下回分解。。。