从这篇博客文章中,我能够创建一个IDispatchMessageFormatter
使用JSON.NET序列化的自定义WCF
。需要注意的是,它的效果很好:与一起使用UriTemplate
并不一定能按预期工作。
这是博客文章提供的实现:
class NewtonsoftJsonDispatchFormatter : IDispatchMessageFormatter
{
private readonly OperationDescription od;
private readonly ServiceEndpoint ep;
private readonly Dictionary<string, int> parameterNames = new Dictionary<string, int>();
public NewtonsoftJsonDispatchFormatter(OperationDescription od, ServiceEndpoint ep, bool isRequest)
{
this.od = od;
this.ep = ep;
if (isRequest)
{
int operationParameterCount = od.Messages[0].Body.Parts.Count;
if (operationParameterCount > 1)
{
this.parameterNames = new Dictionary<string, int>();
for (int i = 0; i < operationParameterCount; i++)
{
this.parameterNames.Add(od.Messages[0].Body.Parts[i].Name, i);
}
}
}
}
public void DeserializeRequest(Message message, object[] parameters)
{
if (message.IsEmpty)
return;
object bodyFormatProperty;
if (!message.Properties.TryGetValue(WebBodyFormatMessageProperty.Name, out bodyFormatProperty) ||
(bodyFormatProperty as WebBodyFormatMessageProperty).Format != WebContentFormat.Raw)
{
throw new InvalidOperationException("Incoming messages must have a body format of Raw. Is a ContentTypeMapper set on the WebHttpBinding?");
}
XmlDictionaryReader bodyReader = message.GetReaderAtBodyContents();
bodyReader.ReadStartElement("Binary");
byte[] rawBody = bodyReader.ReadContentAsBase64();
using (MemoryStream ms = new MemoryStream(rawBody))
using (StreamReader sr = new StreamReader(ms))
{
if (parameters.Length == 1)
parameters[0] = Helper.serializer.Deserialize(sr, od.Messages[0].Body.Parts[0].Type);
else
{
// multiple parameter, needs to be wrapped
using (Newtonsoft.Json.JsonReader reader = new Newtonsoft.Json.JsonTextReader(sr))
{
reader.Read();
if (reader.TokenType != Newtonsoft.Json.JsonToken.StartObject)
throw new InvalidOperationException("Input needs to be wrapped in an object");
reader.Read();
while (reader.TokenType == Newtonsoft.Json.JsonToken.PropertyName)
{
string parameterName = reader.Value as string;
reader.Read();
if (this.parameterNames.ContainsKey(parameterName))
{
int parameterIndex = this.parameterNames[parameterName];
parameters[parameterIndex] = Helper.serializer.Deserialize(reader, this.od.Messages[0].Body.Parts[parameterIndex].Type);
}
else
reader.Skip();
reader.Read();
}
}
}
}
}
public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result) { ... }
}
基本上,object[] parameters
在DeserializeMethod
签名是out
参数,该方法需要实例化。
因此,这在处理REST端点方面做得非常好:
[WebInvoke(Method="POST", UriTemplate="foo/")]
public Foo MakeFoo(Foo foo) { ... }
或像这样:
[WebInvoke(Method="POST", UriTemplate="FooBar/")]
public FooBar FooBar(Foo foo, Bar bar) { .. }
但是它当前不将URI模板参数映射到方法参数,例如:
[WebGet(UriTemplate="Foo/{id}")]
public Foo GetFoo(string id) { ... }
微软写在重写GetRequestDispatchFormatter
:
这是一个扩展点,派生的行为可以用来提供自己的IDispatchMessageFormatter实现,该实现被调用以从请求消息中反序列化服务操作的输入参数。必须从请求消息的To
URI中反序列化服务操作的UriTemplate中指定的参数,并且必须从请求消息的主体中反序列化其他参数。
很好。我更新了消息正文中参数的反序列化。但是我不想重写。中的反序列化参数UriTemplate
。是否可以使用现有代码以默认方式UriTemplate
处理传入的URI请求到参数的方法?
似乎我需要使用类似的东西,UriTemplateDispatchFormatter
但是我不确定如何实现它,并且它是非公开的。
好吧,这也许是我要做的最荒谬的事情,但是复制的源代码UriTemplateDispatchFormatter
,您可以简单地返回一个UriTemplateDispatchFormatter
带有“
inner” IDispatchFormatter
(与IDispatchFormatter
我在此处提供的代码相对应)的a
。不确定为什么将此类设为内部> _>
下面的类定义:
class UriTemplateDispatchFormatter : IDispatchMessageFormatter
{
internal Dictionary<int, string> pathMapping;
internal Dictionary<int, KeyValuePair<string, Type>> queryMapping;
Uri baseAddress;
IDispatchMessageFormatter bodyFormatter;
string operationName;
QueryStringConverter qsc;
int totalNumUTVars;
UriTemplate uriTemplate;
public UriTemplateDispatchFormatter(OperationDescription operationDescription, IDispatchMessageFormatter bodyFormatter, QueryStringConverter qsc, string contractName, Uri baseAddress)
{
this.bodyFormatter = bodyFormatter;
this.qsc = qsc;
this.baseAddress = baseAddress;
this.operationName = operationDescription.Name;
Populate(
out this.pathMapping,
out this.queryMapping,
out this.totalNumUTVars,
out this.uriTemplate,
operationDescription,
qsc,
contractName);
}
public void DeserializeRequest(Message message, object[] parameters)
{
object[] bodyParameters = new object[parameters.Length - this.totalNumUTVars];
if (bodyParameters.Length != 0)
{
this.bodyFormatter.DeserializeRequest(message, bodyParameters);
}
int j = 0;
UriTemplateMatch utmr = null;
string UTMRName = "UriTemplateMatchResults";
if (message.Properties.ContainsKey(UTMRName))
{
utmr = message.Properties[UTMRName] as UriTemplateMatch;
}
else
{
if (message.Headers.To != null && message.Headers.To.IsAbsoluteUri)
{
utmr = this.uriTemplate.Match(this.baseAddress, message.Headers.To);
}
}
NameValueCollection nvc = (utmr == null) ? new NameValueCollection() : utmr.BoundVariables;
for (int i = 0; i < parameters.Length; ++i)
{
if (this.pathMapping.ContainsKey(i) && utmr != null)
{
parameters[i] = nvc[this.pathMapping[i]];
}
else if (this.queryMapping.ContainsKey(i) && utmr != null)
{
string queryVal = nvc[this.queryMapping[i].Key];
parameters[i] = this.qsc.ConvertStringToValue(queryVal, this.queryMapping[i].Value);
}
else
{
parameters[i] = bodyParameters[j];
++j;
}
}
}
public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
{
throw new NotImplementedException();
}
private static void Populate(out Dictionary<int, string> pathMapping,
out Dictionary<int, KeyValuePair<string, Type>> queryMapping,
out int totalNumUTVars,
out UriTemplate uriTemplate,
OperationDescription operationDescription,
QueryStringConverter qsc,
string contractName)
{
pathMapping = new Dictionary<int, string>();
queryMapping = new Dictionary<int, KeyValuePair<string, Type>>();
string utString = GetUTStringOrDefault(operationDescription);
uriTemplate = new UriTemplate(utString);
List<string> neededPathVars = new List<string>(uriTemplate.PathSegmentVariableNames);
List<string> neededQueryVars = new List<string>(uriTemplate.QueryValueVariableNames);
Dictionary<string, byte> alreadyGotVars = new Dictionary<string, byte>(StringComparer.OrdinalIgnoreCase);
totalNumUTVars = neededPathVars.Count + neededQueryVars.Count;
for (int i = 0; i < operationDescription.Messages[0].Body.Parts.Count; ++i)
{
MessagePartDescription mpd = operationDescription.Messages[0].Body.Parts[i];
string parameterName = XmlConvert.DecodeName(mpd.Name);
if (alreadyGotVars.ContainsKey(parameterName))
{
throw new InvalidOperationException();
}
List<string> neededPathCopy = new List<string>(neededPathVars);
foreach (string pathVar in neededPathCopy)
{
if (string.Compare(parameterName, pathVar, StringComparison.OrdinalIgnoreCase) == 0)
{
if (mpd.Type != typeof(string))
{
throw new InvalidOperationException();
}
pathMapping.Add(i, parameterName);
alreadyGotVars.Add(parameterName, 0);
neededPathVars.Remove(pathVar);
}
}
List<string> neededQueryCopy = new List<string>(neededQueryVars);
foreach (string queryVar in neededQueryCopy)
{
if (string.Compare(parameterName, queryVar, StringComparison.OrdinalIgnoreCase) == 0)
{
if (!qsc.CanConvert(mpd.Type))
{
throw new InvalidOperationException();
}
queryMapping.Add(i, new KeyValuePair<string, Type>(parameterName, mpd.Type));
alreadyGotVars.Add(parameterName, 0);
neededQueryVars.Remove(queryVar);
}
}
}
if (neededPathVars.Count != 0)
{
throw new InvalidOperationException();
}
if (neededQueryVars.Count != 0)
{
throw new InvalidOperationException();
}
}
private static string GetUTStringOrDefault(OperationDescription operationDescription)
{
string utString = GetWebUriTemplate(operationDescription);
if (utString == null && GetWebMethod(operationDescription) == "GET")
{
utString = MakeDefaultGetUTString(operationDescription);
}
if (utString == null)
{
utString = operationDescription.Name;
}
return utString;
}
private static string MakeDefaultGetUTString(OperationDescription od)
{
StringBuilder sb = new StringBuilder(XmlConvert.DecodeName(od.Name));
//sb.Append("/*"); // note: not + "/*", see 8988 and 9653
if (!IsUntypedMessage(od.Messages[0]))
{
sb.Append("?");
foreach (MessagePartDescription mpd in od.Messages[0].Body.Parts)
{
string parameterName = XmlConvert.DecodeName(mpd.Name);
sb.Append(parameterName);
sb.Append("={");
sb.Append(parameterName);
sb.Append("}&");
}
sb.Remove(sb.Length - 1, 1);
}
return sb.ToString();
}
private static bool IsUntypedMessage(MessageDescription message)
{
if (message == null)
{
return false;
}
return (message.Body.ReturnValue != null && message.Body.Parts.Count == 0 && message.Body.ReturnValue.Type == typeof(Message)) ||
(message.Body.ReturnValue == null && message.Body.Parts.Count == 1 && message.Body.Parts[0].Type == typeof(Message));
}
private static void EnsureOk(WebGetAttribute wga, WebInvokeAttribute wia, OperationDescription od)
{
if (wga != null && wia != null)
{
throw new InvalidOperationException();
}
}
private static string GetWebUriTemplate(OperationDescription od)
{
// return exactly what is on the attribute
WebGetAttribute wga = od.Behaviors.Find<WebGetAttribute>();
WebInvokeAttribute wia = od.Behaviors.Find<WebInvokeAttribute>();
EnsureOk(wga, wia, od);
if (wga != null)
{
return wga.UriTemplate;
}
else if (wia != null)
{
return wia.UriTemplate;
}
else
{
return null;
}
}
private static string GetWebMethod(OperationDescription od)
{
WebGetAttribute wga = od.Behaviors.Find<WebGetAttribute>();
WebInvokeAttribute wia = od.Behaviors.Find<WebInvokeAttribute>();
EnsureOk(wga, wia, od);
if (wga != null)
{
return "GET";
}
else if (wia != null)
{
return wia.Method ?? "POST";
}
else
{
return "POST";
}
}
}
以及以下行为:
class NewtonsoftJsonBehavior : WebHttpBehavior
{
protected override IDispatchMessageFormatter GetRequestDispatchFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
{
return new UriTemplateDispatchFormatter(
operationDescription,
new NewtonsoftJsonDispatchFormatter(operationDescription, endpoint, true),
GetQueryStringConverter(operationDescription),
endpoint.Contract.Name,
endpoint.Address.Uri);
}
protected override IDispatchMessageFormatter GetReplyDispatchFormatter(OperationDescription od, ServiceEndpoint ep)
{
return new NewtonsoftJsonDispatchFormatter(od, ep, false);
}
}
作品
我想反序列化表单中的类: 其中文本是加密的,反序列化应该在重建TestFieldEncryptedMessage实例之前取消对值的加密。 我采用的方法非常类似于:https://github.com/codesqueak/jackson-json-crypto 也就是说,我正在构建一个扩展SimpleModule的模块: 如您所见,设置了两个修饰符:EncryptedSerializerModif
问题内容: 我有一堂课 我想将下面的JSON数据反序列化到上面的类/对象中 我的想法是在JSON中是一个对象,但我只想获取(在JSON中)在反序列化期间将像在类中那样传递。 如何使用Json.NET实现该目标? 我相信我可以使用CustomJsonConverter完成它。但是我很困惑。docs中的示例仅用于,但不适用。 问题答案: 我只是使用上面在问题中提到的方法解决了我的问题。在我完整的代码下
我想通过扩展默认的反序列化器来创建自己的反序列化器,在其后面设置更多的值: 如您所见,我还想将此DTO母类重用于其他DTO。 我没有找到任何这样的例子。我真的是世界上第一个 反序列化的“AsUsual”(p,ctxt)应该是什么 我应该使用什么motherclass?JsonDeserializer/StdDeserializer/UntypedObjectDeserializer 反序列化程序会
问题内容: 我对WCF有点陌生,将尝试清楚地描述我要做什么。 我有一个使用JSON请求的WCF Web服务。我在大多数情况下都可以很好地发送/接收JSON。例如,以下代码可以正常运行,并且符合预期。 JSON已发送: WCF: 这将按预期返回带有“ Dave”的JSON对象。问题是我无法始终保证我收到的JSON与我的DataContract中的成员完全匹配。例如,JSON: 由于大小写不匹配,将无
问题内容: 我正在使用Flickr API 。调用该方法时,默认的JSON结果为: 我想将此响应解析为Java对象: JSON属性应按以下方式映射: 不幸的是,我无法找到一种使用Annotations做到这一点的好方法。到目前为止,我的方法是将JSON字符串读入a 并从中获取值。 但是我认为,这是有史以来最不优雅的方式。有没有简单的方法,可以使用注释还是自定义反序列化器? 这对我来说将是很明显的,
I'va是一个OID接口,可以由许多具体类型实现: 现在我有一个具有两个字段的对象,一个使用抽象接口类型(OID)定义,另一个使用具体类型(MyOID)定义 我想使用jackson以不同的方式序列化/反序列化字段,无论它们是使用抽象接口类型还是具体类型定义的: 注意,被序列化,包括类型信息(多态序列化),而被序列化为文本 为此,我将OID接口注释为: 并为每个具体类型分配了类型id: 最后,对容器