您的位置:首页 > 其它

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;

}

}

}

}

}

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.
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: