还记得上篇文章中的PUT调用Rest服务的代码吗?不记得没关系,下面就是它的代码。
View Code
#region
使用WebRequest
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的代码可以封装。
WebRequest webRequest
=
WebRequestCreator.ClientHttp.Create(
new
Uri(
"
http://localhost:19598/ProductService.svc/Product
"
));
webRequest.ContentType
=
"
application/json
"
;
webRequest.Method
=
"
PUT
"
;
2:序列化数据到requestStream对象中可以封装。
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();
3:对返回结果执行的操作可以封装。
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);
});
}
按照1,2,3的方式我们先从1开始。代码如下:
1:使用GetWebRequest函数获取WebRequest对象,当然了你也可以用factory,但是在目前而言,一个函数就足够了。
///
<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;
}
2:封装序列化到RequestStream的过程。
Stream requestStream
=
webRequest.EndGetRequestStream(requestAsyncResult);
SerializeDataToRequestStream(data,requestStream);
requestStream.Close();
SerializeDataToRequestStream方法可以对JsonObject,匿名类,DataContract修饰的类进行序列化。
View Code
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);
}
}
3:处理WebResponse。如果T是String类型则直接返回Json的string,否则使用DataContractJsonSerializer 反序列化成对象进行操作。
///
<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);
}
}
}
好了,基本框架已经搭建好了,尝试下调用GET服务吧。
///
<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
);
}
调用GET服务比较简单,使用GET从指定的URL下载数据就可以了,那么调用POST,PUT,DELETE呢?
其实原理都比较简单,就是GetRequestStream--->写数据到RequestStream--->GetResponse。
所以可以写一个通用方法来调用PUT,POST,DELETE。
View Code
///
<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
);
}
RestInvoker的完整代码如下:
View Code
public
class
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,让它可以跨线程。 下回分解。。。