WCF Rest 服务一些问题备忘
2011-05-01 22:09
369 查看
1.如果要想让服务自动支持JSON格式,类的DataContract属性一定要加上Namespace。如果不加,则用改类作为参数的服务只能使用xml格式。
[DataContract(Namespace = "")]
public class UserProfile
{}
2. 返回的xml中,如果不希望空节点输出 i:nil="true", 需要加上[XmlSerializerFormat]属性,但是加上该属性后不能再使用json格式的请求和返回。
3.如果服务中参数用到类,则请求该类的xml中各xml节点必须按字母顺序排序,否则系统自动反序列化得到的类有些字段得不到值。
因为wcf默认的序列化方式是 DataContractSerializer,对象的所有成员以XML Element的形式而不是以XMLAttribute的形式输出,所以对象在XML的输出顺序是按照字母排序。
如果客户端生成的xml已经是按字母顺序排好的,没有问题。我们也可以在服务端把客户端请求的xml按字母顺序排序,这样客户端就不用注意节点顺序的问题了。实现方法如下:
1). 实现IServiceBehavior接口
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
IErrorHandler handler = new FaultErrorHandler();
foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
{
dispatcher.ErrorHandlers.Add(handler);
dispatcher.Endpoints.ToList().ForEach(
x => x.DispatchRuntime.MessageInspectors.Add(new MessageInspector()));
}
}
2).
public class MessageInspector:IDispatchMessageInspector
{
//int MaxMessageSize = PhoneCommon.ReceivedMaxSize;
//XmlWriterSettings xws;
public MessageInspector()
{
//this.xws = new XmlWriterSettings();
//this.xws.Indent = true;
//this.xws.Encoding = Encoding.UTF8;
}
#region IDispatchMessageInspector Members
public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
// Get the request message from the request
HttpRequestMessageProperty requestMessage = request.Properties["httpRequest"] as HttpRequestMessageProperty;
string method = string.Empty;
if (requestMessage != null)
{
// The method will be GET or POST.
method = requestMessage.Method;
if (requestMessage.Headers["Content-Type"].ToLower().Contains("xml"))
{
if (method.Equals("POST", StringComparison.InvariantCultureIgnoreCase))
{
ReOrderXmlElementAlphabetical(ref request);
}
}
}
Object correlationState = new object();
return correlationState;
}
public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
//throw new NotImplementedException();
}
#endregion
private void ReOrderXmlElementAlphabetical(ref Message message)
{
//MessageBuffer msgBuffer = message.CreateBufferedCopy(MaxMessageSize);
//Message copy = msgBuffer.CreateMessage();
//StringBuilder xmlsb = new StringBuilder();
//XmlWriter writer = XmlWriter.Create(xmlsb, this.xws);
//copy.WriteMessage(writer);
//writer.Flush();
//message = msgBuffer.CreateMessage();
//msgBuffer.Close();
try
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(message.ToString());
XmlUtils.SortXml(doc);
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(doc.OuterXml));
XmlReader bodyReader = XmlReader.Create(ms);
message = Message.CreateMessage(message.Version, null, bodyReader);
}
catch (Exception ex)
{
}
}
}
3).
public abstract class XmlUtils
{
/// <summary>
/// Alphabetical sorting of the XmlNodes
/// and their attributes in the <see cref="System.Xml.XmlDocument"/>.
/// </summary>
/// <param name="document"><see cref="System.Xml.XmlDocument"/> to be sorted</param>
public static void SortXml(XmlDocument document)
{
SortXml(document.DocumentElement);
}
/// <summary>
/// Inplace pre-order recursive alphabetical sorting of the XmlNodes child
/// elements and <see cref="System.Xml.XmlAttributeCollection" />.
/// </summary>
/// <param name="rootNode">The root to be sorted.</param>
public static void SortXml(XmlNode rootNode)
{
SortAttributes(rootNode.Attributes);
SortElements(rootNode);
foreach (XmlNode childNode in rootNode.ChildNodes)
{
SortXml(childNode);
}
}
/// <summary>
/// Sorts an attributes collection alphabetically.
/// It uses the bubble sort algorithm.
/// </summary>
/// <param name="attribCol">The attribute collection to be sorted.</param>
public static void SortAttributes(XmlAttributeCollection attribCol)
{
if (attribCol == null)
return;
bool hasChanged = true;
while (hasChanged)
{
hasChanged = false;
for (int i = 1; i < attribCol.Count; i++)
{
if (String.Compare(attribCol[i].Name, attribCol[i - 1].Name, true) < 0)
{
//Replace
attribCol.InsertBefore(attribCol[i], attribCol[i - 1]);
hasChanged = true;
}
}
}
}
/// <summary>
/// Sorts a <see cref="XmlNodeList" /> alphabetically, by the names of the elements.
/// It uses the bubble sort algorithm.
/// </summary>
/// <param name="node">The node in which its childNodes are to be sorted.</param>
public static void SortElements(XmlNode node)
{
bool changed = true;
while (changed)
{
changed = false;
for (int i = 1; i < node.ChildNodes.Count; i++)
{
if (String.Compare(node.ChildNodes[i].Name, node.ChildNodes[i - 1].Name, true) < 0)
{
//Replace:
node.InsertBefore(node.ChildNodes[i], node.ChildNodes[i - 1]);
changed = true;
}
}
}
}
}
[DataContract(Namespace = "")]
public class UserProfile
{}
2. 返回的xml中,如果不希望空节点输出 i:nil="true", 需要加上[XmlSerializerFormat]属性,但是加上该属性后不能再使用json格式的请求和返回。
3.如果服务中参数用到类,则请求该类的xml中各xml节点必须按字母顺序排序,否则系统自动反序列化得到的类有些字段得不到值。
因为wcf默认的序列化方式是 DataContractSerializer,对象的所有成员以XML Element的形式而不是以XMLAttribute的形式输出,所以对象在XML的输出顺序是按照字母排序。
如果客户端生成的xml已经是按字母顺序排好的,没有问题。我们也可以在服务端把客户端请求的xml按字母顺序排序,这样客户端就不用注意节点顺序的问题了。实现方法如下:
1). 实现IServiceBehavior接口
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
IErrorHandler handler = new FaultErrorHandler();
foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
{
dispatcher.ErrorHandlers.Add(handler);
dispatcher.Endpoints.ToList().ForEach(
x => x.DispatchRuntime.MessageInspectors.Add(new MessageInspector()));
}
}
2).
public class MessageInspector:IDispatchMessageInspector
{
//int MaxMessageSize = PhoneCommon.ReceivedMaxSize;
//XmlWriterSettings xws;
public MessageInspector()
{
//this.xws = new XmlWriterSettings();
//this.xws.Indent = true;
//this.xws.Encoding = Encoding.UTF8;
}
#region IDispatchMessageInspector Members
public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
// Get the request message from the request
HttpRequestMessageProperty requestMessage = request.Properties["httpRequest"] as HttpRequestMessageProperty;
string method = string.Empty;
if (requestMessage != null)
{
// The method will be GET or POST.
method = requestMessage.Method;
if (requestMessage.Headers["Content-Type"].ToLower().Contains("xml"))
{
if (method.Equals("POST", StringComparison.InvariantCultureIgnoreCase))
{
ReOrderXmlElementAlphabetical(ref request);
}
}
}
Object correlationState = new object();
return correlationState;
}
public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
//throw new NotImplementedException();
}
#endregion
private void ReOrderXmlElementAlphabetical(ref Message message)
{
//MessageBuffer msgBuffer = message.CreateBufferedCopy(MaxMessageSize);
//Message copy = msgBuffer.CreateMessage();
//StringBuilder xmlsb = new StringBuilder();
//XmlWriter writer = XmlWriter.Create(xmlsb, this.xws);
//copy.WriteMessage(writer);
//writer.Flush();
//message = msgBuffer.CreateMessage();
//msgBuffer.Close();
try
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(message.ToString());
XmlUtils.SortXml(doc);
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(doc.OuterXml));
XmlReader bodyReader = XmlReader.Create(ms);
message = Message.CreateMessage(message.Version, null, bodyReader);
}
catch (Exception ex)
{
}
}
}
3).
public abstract class XmlUtils
{
/// <summary>
/// Alphabetical sorting of the XmlNodes
/// and their attributes in the <see cref="System.Xml.XmlDocument"/>.
/// </summary>
/// <param name="document"><see cref="System.Xml.XmlDocument"/> to be sorted</param>
public static void SortXml(XmlDocument document)
{
SortXml(document.DocumentElement);
}
/// <summary>
/// Inplace pre-order recursive alphabetical sorting of the XmlNodes child
/// elements and <see cref="System.Xml.XmlAttributeCollection" />.
/// </summary>
/// <param name="rootNode">The root to be sorted.</param>
public static void SortXml(XmlNode rootNode)
{
SortAttributes(rootNode.Attributes);
SortElements(rootNode);
foreach (XmlNode childNode in rootNode.ChildNodes)
{
SortXml(childNode);
}
}
/// <summary>
/// Sorts an attributes collection alphabetically.
/// It uses the bubble sort algorithm.
/// </summary>
/// <param name="attribCol">The attribute collection to be sorted.</param>
public static void SortAttributes(XmlAttributeCollection attribCol)
{
if (attribCol == null)
return;
bool hasChanged = true;
while (hasChanged)
{
hasChanged = false;
for (int i = 1; i < attribCol.Count; i++)
{
if (String.Compare(attribCol[i].Name, attribCol[i - 1].Name, true) < 0)
{
//Replace
attribCol.InsertBefore(attribCol[i], attribCol[i - 1]);
hasChanged = true;
}
}
}
}
/// <summary>
/// Sorts a <see cref="XmlNodeList" /> alphabetically, by the names of the elements.
/// It uses the bubble sort algorithm.
/// </summary>
/// <param name="node">The node in which its childNodes are to be sorted.</param>
public static void SortElements(XmlNode node)
{
bool changed = true;
while (changed)
{
changed = false;
for (int i = 1; i < node.ChildNodes.Count; i++)
{
if (String.Compare(node.ChildNodes[i].Name, node.ChildNodes[i - 1].Name, true) < 0)
{
//Replace:
node.InsertBefore(node.ChildNodes[i], node.ChildNodes[i - 1]);
changed = true;
}
}
}
}
}
public
object
AfterReceiveRequest(
ref
System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
02.
{
03.
// Get the request message from the request
04.
HttpRequestMessageProperty requestMessage = request.Properties[
"httpRequest"
]
as
HttpRequestMessageProperty;
05.
string
method =
string
.Empty;
06.
if
(requestMessage !=
null
)
07.
{
08.
// The method will be GET or POST.
09.
method = requestMessage.Method;
10.
}
11.
12.
// Get the UriTemplateMatchResults from the request.
13.
// Here you can see some of the fun things that are revealed.
14.
UriTemplateMatch results = internalCopy.Properties[
"UriTemplateMatchResults"
]
as
UriTemplateMatch;
15.
if
(results !=
null
)
16.
{
17.
// Get the operation name from the request.
18.
// Here you can see what method was called in the Service.
19.
// Since we have only one method (SchemeTest), it should be this.
20.
// We can add a simple 'HelloWorld' method to see this value change.
21.
string
operationName =
string
.Empty;
22.
if
(results.RelativePathSegments.Count > 0)
23.
operationName = results.RelativePathSegments[results.RelativePathSegments.Count - 1];
24.
25.
//
26.
string
requestUri = results.RequestUri.ToString();
27.
28.
// If the request method is GET, then you can play with the query parameters, uri template, and bound variables
29.
if
(method ==
"GET"
)
30.
{
31.
32.
// Loop thru the querry parameters
33.
NameValueCollection queryParameters = results.QueryParameters;
34.
foreach
(var p
in
queryParameters)
35.
{
36.
Console.WriteLine(p);
37.
}
38.
39.
// The Uri template is the same as in the Attribute of the interface: [WebGet(UriTemplate = "SchemeTest?name={name}")]
40.
string
template = results.Template.ToString();
41.
42.
// You can loop thru the key in the variables passed in.
43.
NameValueCollection boundVariables = results.BoundVariables;
44.
foreach
(
string
key
in
boundVariables.AllKeys)
45.
{
46.
// Variable names are always in UPPER case. Don't know why.
47.
if
(key ==
"NAME"
)
48.
Console.WriteLine(
"This is the 'name' key"
);
49.
}
50.
}
51.
52.
Object correlationState =
new
object
();
53.
return
correlationState;
54.
}
相关文章推荐
- WCF+Restfull服务 提交或获取数据时数据大小限制问题解决方案
- WCF+Restfull服务 提交或获取数据时数据大小限制问题解决方案
- WCF+Restfull服务 提交或获取数据时数据大小限制问题解决方案
- WCF服务在IIS发布时遇到的一些配置问题
- 在ASP.NET MVC 中宿主WCF Rest 服务的问题及解决方法
- jQuery调用WCF需要注意的一些问题
- 关于**订单缴费windows服务项目过程中遇到的一些问题和反思
- WCF热门问题编程示例(1):WCF服务如何获得客户端IP地址信息
- VS2010 SL4解决方案前端发现不了解决方案中WCF服务问题
- wcf rest 服务用于安卓和ISO调用4-------多文件上传
- WCF热门问题编程示例(5):WCF服务如何获取客户端在线用户数量?
- WCF热门问题编程示例(5):WCF服务如何获取客户端在线用户数量?
- WCF热门问题编程示例(5):WCF服务如何获取客户端在线用户数量?
- WCF热门问题编程示例(5):WCF服务如何获取客户端在线用户数量?
- WCF热门问题编程示例(5):WCF服务如何获取客户端在线用户数量?
- WCF服务策略文件的冲突问题
- 【转载】WCF热门问题编程示例(4):WCF客户端如何异步调用WCF服务?
- WCF热门问题编程示例(2)多个实例调用一个WCF服务操作,需要等待服务响应吗
- WCF热门问题编程示例(4):WCF客户端如何异步调用WCF服务?
- Angular客户端请求Rest服务跨域问题的解决方法