- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
来自 this blog post ,我能够创建一个使用 JSON.NET 序列化的自定义 WCF IDispatchMessageFormatter
。它工作得很好,但有一个警告:将它与 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) { ... }
}
基本上,DeserializeMethod
签名中的object[] 参数
是该方法需要实例化的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) { ... }
Microsoft 在覆盖的 GetRequestDispatchFormatter
上写入:
This is an extensibility point that derived behaviors can use to supply their own implementation of IDispatchMessageFormatter that is called to deserialize the input parameters of the service operation from the request message. Parameters specified in the UriTemplate of the service operation must be deserialized from the To URI of the request message and other parameters must be deserialized from the body of the request message.
太棒了。我更新了消息正文中参数的反序列化。但我不想覆盖 UriTemplate
中参数的反序列化。有什么方法可以使用现有代码将传入的 URI 请求映射到默认处理 UriTemplate
的参数?
看来我需要使用类似 UriTemplateDispatchFormatter
的东西但我不确定如何实现它,而且它是非公开的。
最佳答案
好吧,这可能是我不得不做的最荒谬的事情,但是复制 UriTemplateDispatchFormatter
的源代码,您可以简单地返回一个带有“inner"IDispatchFormatter
对应于我在此处提供的 IDispatchFormatter
。不知道为什么这个类是内部的 >_>
下面的类定义:
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);
}
}
作品
关于c# - 在不更改 URI 模板反序列化的情况下使用自定义 WCF 正文反序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33554997/
我正在阅读 Python 文档以真正深入了解 Python 语言,并遇到了 filter 和 map 函数。我以前使用过过滤器,但从未使用过映射,尽管我在 SO 上的各种 Python 问题中都见过这
当我尝试打印 BST 的级别顺序时,这个问题提示了我。 这是一个 Pre-Order Sequence: 4, 1, 2, 3, 5, 6, 7, 8 In_order Sequence : 1, 2
我的代码在 main(序列测试;)的第一行出现错误,指出它是对 sequence::sequence() 的 undefined reference 。我无法更改 main 中的代码。有谁知道我该如何
这可能很简单,但我在通常的 latex 指南中找不到任何相关内容。在这句话中: {\em hello\/} “\/”的目的是什么? 最佳答案 这就是所谓的斜体校正。其目的是确保斜体文本后有适当的间距。
当我从 Postgresql 表中删除所有记录,然后尝试重置序列以在插入时开始一个编号为 1 的新记录时,我得到不同的结果: SELECT setval('tblname_id_seq', (SELE
在版本10.0.3中,MariaDB引入了一种称为序列的存储引擎。 其ad hoc为操作生成整数序列,然后终止。 该序列包含正整数,以降序或升序排列,并使用起始,结束和递增值。 它不允许在多个查询中
如何在 Groovy 中获取给定数字的序列,例如: def number = 169 // need a method in groovy to find the consecutive number
基本上,如果这是 .NET,它看起来像这样: ISomething { string A { get; } int B { get; } } var somethings = new List
说以下代码部分(同一块): A <= 1 A <= 2 变量 A 总是被赋值为 2 吗?还是会出现竞争条件并分配 1 或 2? 我对非阻塞赋值的理解是,由硬件在 future 分配变量 A,因此它可能
在运行 WiX 设置时,我正在寻找操作列表及其顺序。不知何故,官方网站似乎没有提供任何信息。 基本问题是我想正确安排我的自定义操作。通常我需要使用 regsvr32.exe 注册一个 DLL,而这只能
F#初学者在这里 我想创建一个类型,它是具有至少一个元素的另一种具体类型(事件)的序列。任何其他元素都可以在以后随时添加。通常在 C# 中,我会创建一个具有私有(private) List 和公共(p
作为构建过程和不断发展的数据库的一部分,我试图创建一个脚本,该脚本将删除用户的所有表和序列。我不想重新创建用户,因为这将需要比所允许的更多的权限。 我的脚本创建了一个过程来删除表/序列,执行该过程,然
我想恢复两个向量的第一个日期和相同向量的第二个日期之间的日期序列,.... 这是一个例子: dates1 = as.Date(c('2015-10-01', '2015-03-27', '2015-0
这个问题已经有答案了: sql ORDER BY multiple values in specific order? (12 个回答) 已关闭 9 年前。 我有一个 sql 语句,我想要ORDER
我想恢复两个向量的第一个日期和相同向量的第二个日期之间的日期序列,.... 这是一个例子: dates1 = as.Date(c('2015-10-01', '2015-03-27', '2015-0
在用java编写代码时,我需要用“],[”分割字符串。下面是我的代码。 try (BufferedReader reader = new BufferedReader(new InputStreamR
这个问题已经有答案了: Project Euler Question 14 (Collatz Problem) (8 个回答) 已关闭 9 年前。 我正在尝试查找数字的 Collatz 序列。以下
我有一个例程函数process_letter_location(const char& c, string &word)。 在我的 main 中,我声明了一系列字符串变量,如下所示: string s
我需要找到最长的多米诺骨牌链,给定一组 12 个随机挑选的多米诺骨牌。我已经递归地生成了多米诺骨牌的所有可能性(使用 0 到 12 的面值有 91 种可能性)。多米诺骨牌由一 block “砖 blo
我有这个数据结构 Seq,它继承了类 vector 但有一些额外的功能。使用这个数据结构 Seq 我有这个预定义的数据结构: typedef Seq > MxInt2d; 我现在想要一个包含多个 Mx
我是一名优秀的程序员,十分优秀!