C# 如何在REST WCF服务中接受任意JSON对象?

C# 如何在REST WCF服务中接受任意JSON对象?,c#,.net,json,wcf,rest,C#,.net,Json,Wcf,Rest,我想实现如下服务方法: [OperationContract] [WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat=WebMessageFormat.Json)] public void MakeShape(string shape, string color, IDictionary<string, object> moreArgs) { if (shape == "circle") {

我想实现如下服务方法:

[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);
    }
}
在调用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);
}
这并不理想,但我可以接受。问题变成了如何定义更多参数并正确填充一个参数。我的下一次尝试:

[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]);
        }  
    }
}
[DataContract]
公共类MoreArgs:ISerializable
{
公共字典属性;
public MoreArgs(SerializationInfo信息、StreamingContext上下文)
{
属性=新字典();
foreach(信息中的var条目)
{                      
添加(entry.Name、entry.Value);
}
}  
public void GetObjectData(SerializationInfo信息、StreamingContext上下文)
{
foreach(Properties.Keys中的字符串键)
{
info.AddValue(key,Properties[key]);
}  
}
}
这会在服务启动时引发InvalidDataContractException(…MoreArgs'无法ISerializable且具有DataContractAttribute属性。)

移除[DATACONTROR]属性抛出ValudDATAcNoTractExtExchange,我预期(……MyErgS)不能被序列化。考虑用DATACONTROTTABLE属性……标记它)。< /P> 正如预期的那样,删除ISerializable继承会清除异常,但会导致调用MakeCycle时moreArgs.Properties为null


我还想知道是否有一些混合解决方案我可以使用?也许:

  • 接受一个流并像我第一次尝试那样构造参数字典
  • 像我稍后的尝试一样,使用MoreArgs参数定义方法
  • 从从流中提取的字典中填充MoreArgs对象
  • 以某种方式重新调用WCF,说“调用如果有这些参数将被调用的方法”(指定原始参数字典,加上新的正确填充的MoreArgs)
MoreArgs也将包含原始参数,但这可能不是灾难。我想我可能可以使用反射来完成我需要的调用,但是当WCF必须在内部拥有这个函数,并且经过调试和优化才能启动时,这感觉很傻。

@Melissa Avery Weir

我对我的“解决方案”不满意,但我必须向前迈进

在应用程序启动时,对于我要调用的每个方法,我都会在查找表中填充MethodInfo。它由接口和方法名设置键。我使用反射和一个自定义属性来查找它们,但这里可以使用多种技术

我的one WCF服务方法接受接口名、方法名和流作为参数。我使用JSON.NET将参数反序列化到字典,并将其传递给我的调度程序

dispatcher按接口和方法名称查找MethodInfo。然后,将字典中的参数与MethodInfo中的参数进行匹配,填充参数数组。如果目标方法实际上有一个Dictionary moreArgs参数,那么它将获得任何不匹配的参数。最后我调用MethodInfo.Invoke,传递新填充的参数数组

做一些WCF几乎为我做的事情需要很多复杂的代码,但我没有找到更好的解决方案

我自己控制这一切有一些好处。我最喜欢的功能是使用保存的MethodInfos以我想要的任何语言自动生成客户端调用存根


如果后期绑定是一个性能问题,我会考虑把所有的调用手动放在一个大交换机(MultDead)中。如果我的接口仍在频繁更改,我可能会尝试生成样板绑定代码作为构建步骤。也许我再也不会麻烦了,因为我在DB访问方面会遇到瓶颈。

你有没有想过解决这个问题的办法?这是我遇到的一个用例,我也遇到过同样的情况。我最终接受了一个流作为请求参数,并使用JSON.NET解析流中包含的JSON对象。谢谢你跟进你自己的问题+1.
{
    "shape":"circle",
    "color": "blue",
    "moreArgs":{
        "radius": 42,
        "filled":true
        "annotation": {"date":"1/1/2012", "owner":"George"}
        }
}
[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]);
        }  
    }
}