4

私は私の問題から始めます:

AJAX/JSONを介して呼び出しているWebメソッドがあります。これを「GlobalMethod」と呼びましょう。これは、同じ「baseclass」から派生したアイテムのリストを持つ「container」オブジェクトを管理するために使用されます。これは私の状況のコードサンプルです:

[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である可能性があります。

それで、私の問題の解決策をWebで閲覧すると、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) {
   ...

次に、 「u0027system.string u0027のタイプに対してパラメーターなしのコンストラクターが定義されていない」ため、別のサーバーエラー500が発生します。

わかりました、うまくいけば私の問題は明らかです...私はそれに一日を費やしてきました、そして私は解決策を見つけられないようです。派生クラスの使用を回避するためにメソッドのアーキテクチャを再検討することは、まったくオプションではありません(実際のコードははるかに複雑であることに注意してください。要点を理解するために、単純化しただけです!)。

ちなみに、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.stringu0027の型に対してパラメーターなしのコンストラクターが定義されていません」を受け取り始めました。

しかし、最終的に理由がわかりました。クライアントからサーバーに移動していたjson文字列が、.NET Frameworkによって、文字列ではなく実際のJSONオブジェクトである含まれているオブジェクトに逆シリアル化されていました。

したがって、私のajaxメソッドでのトリックは次のとおりです。

    $.ajax({
        type: "POST",
        url: wsUrl + method,
        **data: JSON.stringify(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
    });

これは、jsonオブジェクトが別の文字列内にカプセル化されていることを意味します。この文字列は、サーバー側のGlobalMethod(string)によってJson.NETを介して手動で逆シリアル化されます。

明らかに、この二重の「stringify」をajaxルーチンに含めませんが、入力としてJSON.stringifiedデータをajaxルーチン自体に渡すことに注意します。

4

2 に答える 2

3

これは単なるハックです。単なるアイデアです。エレガントに聞こえませんが、うまくいくはずです。興味があります。

この方法でコンテナを変更します。

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;

}

Ps: これは非常に大雑把であり、改善する必要があります。これは理にかなっていますか?

于 2012-12-12T14:30:54.217 に答える
2

を受け入れるようにwebmethodを変更しますobject

[WebMethod]
public string GlobalMethod(object data)

これにより、発生している問題が解決するはずです。

于 2012-12-11T21:34:48.073 に答える