sol*_*ish 8 .net c# rest wcf json
我想实现这样的服务方法:
[OperationContract]
[WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat=WebMessageFormat.Json)]
public void MakeShape(string shape, string color, IDictionary<string, object> moreArgs)
{
if (shape == "circle")
{
MakeCircle(color, moreArgs);
}
}
Run Code Online (Sandbox Code Playgroud)
我的客户POST对象如下:
{
"shape":"circle",
"color": "blue",
"radius": 42,
"filled":true,
"annotation": {"date":"1/1/2012", "owner":"George"}
}
Run Code Online (Sandbox Code Playgroud)
在调用MakeCircle时,moreArgs将有3个条目("radius","filled"和一个名为"annotation"的字典,其中包含2个键值对.)
我到目前为止最好的是:
//Step 1: get the raw JSON by accepting a Stream with BodyStyle=WebMessageBodyStyle.Bare
[OperationContract]
[WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle=WebMessageBodyStyle.Bare)]
public void MakeShape(Stream jsonStream)
{
//Step 2: parse it into a Dictionary with JavaScriptSerializer or JSON.net
StreamReader reader = new StreamReader(jsonStream);
JavaScriptSerializer jsSerializer = new JavaScriptSerializer();
Dictionary<string, object> args = jsSerializer.Deserialize<Dictionary<string,object>>(reader.ReadToEnd());
//Step 3: manually lookup and cast the "standard" arguments, and remove them from the Dictionary
string shape = (string)args["shape"];
string color = (string)args["color"];
//Step 4: make the original call, passing the remaining Dictionary as moreArgs
MakeShape(shape,color,args);
}
Run Code Online (Sandbox Code Playgroud)
我可以忍受这样的解决方案,除了第3步将是一个很难与几十种方法保持同步.显然有些东西必须打开字典并使用额外的参数,但我宁愿将代码保留在我的通信层之外.IMO它进入了解参数的业务逻辑(在本例中由MakeCircle表示).
我非常喜欢WCF的自动绑定,因为它消除了这些容易出错的手动翻译.我希望有一种方法可以将它用于几乎所有的东西,除了为它不知道如何映射的参数指定一些额外的逻辑.也许有某种服务行为表示"将它们传递给[此代码]并且我会处理它"?
我已经考虑过IExtensibleDataObject提供的"往返"支持,但它似乎没有让我的代码访问未知属性 - 它们仅仅是为了发送回客户端的唯一目的.http://msdn.microsoft.com/en-us/library/ms731083.aspx
另一个选择是使用包含IDictionary的自定义类,并以某种方式自己接管反序列化.所以服务方法是:[OperationContract] [WebInvoke(RequestFormat = WebMessageFormat.Json,ResponseFormat = WebMessageFormat.Json,BodyStyle = WebMessageBodyStyle.WrappedRequest)] public void MakeShape(字符串形状,字符串颜色,MoreArgs moreArgs)
而且我必须强迫客户进入更严格的结构:
{
"shape":"circle",
"color": "blue",
"moreArgs":{
"radius": 42,
"filled":true
"annotation": {"date":"1/1/2012", "owner":"George"}
}
}
Run Code Online (Sandbox Code Playgroud)
那不太理想,但我可以忍受它.问题变成了如何定义MoreArgs并正确填充一个.我的下一次尝试:
[DataContract]
public class MoreArgs : ISerializable
{
public Dictionary<string, object> Properties;
public MoreArgs(SerializationInfo info, StreamingContext context)
{
Properties = new Dictionary<string, object>();
foreach (var entry in info)
{
Properties.Add(entry.Name, entry.Value);
}
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
foreach (string key in Properties.Keys)
{
info.AddValue(key, Properties[key]);
}
}
}
Run Code Online (Sandbox Code Playgroud)
这会在服务启动时抛出InvalidDataContractException(... MoreArgs'不能是ISerializable并且具有DataContractAttribute属性.)
删除[DataContract]属性会抛出我期望的InvalidDataContractException(... MoreArgs'无法序列化.请考虑使用DataContractAttribute属性标记它...).
同样如预期的那样,删除ISerializable继承会清除异常,但会在调用MakeCircle时导致moreArgs.Properties为null.
我也想知道是否有一些我可以使用的混合解决方案?也许:
然后,MoreArgs也将包含原始参数,但这可能不是灾难.我想我可以使用反射来调用我需要的调用,但是当WCF必须在内部调试并调试并优化引导时,这感觉很愚蠢.
@梅丽莎·艾弗里·威尔
我对我的“解决方案”不满意,但我必须继续前进。
在应用程序启动时,对于我想要调用的每个方法,我都会将 MethodInfo 填充到查找表中。它由接口和方法名称作为键。我使用反射和自定义属性来查找它们,但是任何数量的技术都可以在这里使用。
我的一个 WCF 服务方法接受接口名称、方法名称和 Stream 作为参数。我使用 JSON.NET 将参数反序列化为字典并将其传递给我的调度程序。
调度程序通过接口和方法名称查找 MethodInfo。然后,将字典中的参数与 MethodInfo 中的参数进行匹配,填充参数数组。如果目标方法实际上有一个 Dictionary moreArgs 参数,它会获取任何不匹配的参数。最后,我调用 MethodInfo.Invoke,传递新填充的参数数组。
这是很多繁琐的代码来完成 WCF几乎为我做的一些事情,但我没有找到更好的解决方案。
自己控制这一切有一些好处。我最喜欢的是能够使用保存的 MethodInfos 以我想要的任何语言自动生成客户端调用存根。
如果后期绑定被证明是一个性能问题,我会考虑将所有调用手动放入一个大开关(methodName)中。如果我的界面仍然经常更改,我可能会尝试生成样板绑定代码作为构建步骤。也许我永远不会打扰,因为我将在数据库访问方面遇到瓶颈。
归档时间: |
|
查看次数: |
3204 次 |
最近记录: |