在webmethod中使用json.net序列化程序

我将从我的问题开始:

我有一个webmethod,我通过AJAX / JSON调用.
我们称之为“GlobalMethod”,它用于管理“容器”对象,该对象具有从相同“基类”派生的项列表.
这是我的情况的代码示例:

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[System.Web.Script.Services.ScriptService]
public class MyService : System.Web.Services.WebService
{

    [WebMethod]
    public string GlobalMethod(Container data)
    {
        string result = "";
        foreach (var item in data.Items)
        {
            result += item.BaseProperty;
            if (item is FirstDerivedClass)
                result += ((FirstDerivedClass)item).FirstDerivedProperty;
            else if (item is SecondDerivedClass)
                result += ((SecondDerivedClass)item).SecondDerivedProperty;
        }
        return result;
    }
}


public class Container
{
    public List<BaseClass> Items;
}

public abstract class BaseClass
{
    public string BaseProperty;
}

public class FirstDerivedClass : BaseClass
{
    public string FirstDerivedProperty;
}

public class SecondDerivedClass : BaseClass
{
    public string SecondDerivedProperty;
}

这种方法根本无法解决.我将无法使用默认的JavascriptSerializer调用此方法,因为序列化程序无法解析容器将具有的对象类型:它们可以是FirstDerivedClass或SecondDerivedClass类型.

所以,浏览网页寻找我的问题的解决方案,我遇到了Json.NET,其方法JsonConvert.DeserializeObject能够检索使用JsonConvert.SerializeObject序列化的原始对象类型,因为它添加了一个名为“$type”的属性”.

我现在的问题是:如何使用此序列化程序而不是ASMX使用的默认方法制作web方法?
如果方法签名仍然存在

[WebMethod]
public string GlobalMethod(Container data)

然后我将获得一个完全空的Container对象,因为框架正在进行反序列化工作,并且不知道要实例化哪些项目,并且我无法告诉框架它应该使用Json.NET来完成工作,能够完全反序列化数据.

如果我尝试这种方式修改方法

[WebMethod]
    public string GlobalMethod(string data)
    {
        string result = "";
        Container container = JsonConvert.DeserializeObject<Container>(data,new JsonSerializerSettings
                                        {
                                            TypeNameHandling = TypeNameHandling.Objects
                                        });
        foreach (var item in container.Items) {
   ...

然后我会得到另一个服务器错误500,因为“没有为u0027system.string u0027的类型定义无参数构造函数”

好吧,希望我的问题很清楚……我一整天都花在它上面,我似乎找不到解决方案.重新审视我的方法的体系结构,以避免使用派生类是不是一个选项(要注意实际的代码要复杂得多,我只是简化它以达到目的!).

顺便说一句,我将添加调用webmethod的ajax方法以这种方式完成:

$.ajax({
        type: "POST",url: wsUrl + method,data: JSON.stringify(data),contentType: "application/json; charset=utf-8",dataType: "json",processData: false,success: function(msg)
        {
            try{
                success(JSON.parse(msg.d));
            } finally {

            }   

        },error: error
    });

感谢任何与我分享知识的人!

我想分享一下我是如何解决我的问题的.正如我已经说过的,我用这种方式修改了我的方法:

[WebMethod]
public string GlobalMethod(string data)
{
    string result = "";
    Container container = JsonConvert.DeserializeObject<Container>(data,new JsonSerializerSettings
                                    {
                                        TypeNameHandling = TypeNameHandling.Objects
                                    });
    foreach (var item in container.Items) {

最初,我开始收到错误500“没有为u0027system.string u0027类型定义的无参数构造函数”

但最终我发现了原因:从客户端到服务器的json字符串被.NET框架反序列化为包含的对象,该对象不是字符串,而是实际的JSON对象!

所以诀窍是以下,在我的ajax方法中:

$.ajax({
        type: "POST",**data: JSON.stringify(JSON.stringify(data)),**
        contentType: "application/json; charset=utf-8",error: error
    });

这意味着json对象被封装在另一个字符串中,该字符串将由我的服务器端GlobalMethod(字符串)通过Json.NET手动反序列化.

显然我不会在ajax例程中包含这个双“stringify”,但我会注意将输入中的JSON.stringified数据传递给ajax例程本身!

解决方法

这只是一个黑客,
这只是一个想法,听起来并不优雅但应该有效
我只是好奇

以这种方式更改容器:

public class Container
{
    public List<MyUnionBaseClass> Items;
}

和定义(伪代码):

public class MyUnionBaseClass{

  public void MyUnionBaseClass(BaseClass b){
     this.setValue(b);
  };

  final public BaseClass getValue(){
       if(first!=null) return (BaseClass) first;
       if(second!=null)return (BaseClass) second;
       return null;
  }

  final public setValue(BaseClass b){
    if(b instanceOf firstClass){
         first = (FirstClass) b;  
    }
    if(b instanceOf secondClass){
         second = (SecondClass) b;
    }
  }


  private FirstDerivedClass first=null;
  private SecondDerivedClass second=null;

}

P.s:这是非常好的,应该加以改进.这有意义吗?

相关文章

文章浏览阅读2.4k次。最近要优化cesium里的热力图效果,浏览...
文章浏览阅读1.2w次,点赞3次,收藏19次。在 Python中读取 j...
文章浏览阅读1.4k次。首字母缩略词 API 代表应用程序编程接口...
文章浏览阅读802次,点赞10次,收藏10次。解决一个JSON反序列...
文章浏览阅读882次。Unity Json和Xml的序列化和反序列化_uni...