WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

jQuery.ajax で JSONP

by WebSurfer 2017年5月3日 14:30

jQuery.ajax を使うと、JSONP(JSON with Padding・・・script タグを使用してクロスドメインでデータを取得する仕組み)を利用してデータを取得するのがかなり簡単にできるという話を書きます。

JSONP の応答を alert に表示

何が簡単になるかというと以下のことを jQuery.ajax が自動的にやってくれることです。

  1. jQuery.ajax を呼び出した時点で script タグを生成し DOM ツリーへ追加。(本来は、src 属性に呼出先の URL を設定した script タグを生成して DOM ツリーに追加するためのスクリプトを自力で書かなければなりません)
  2. 呼出先の URL にコールバックの名前を指定するクエリ文字列 &callback=jQuery... を追加。
  3. 応答が返ってくるとコールバックが呼び出され、引数に設定された JSON 文字列が JavaScript オブジェクトにパースされ、success: function (data) の data に渡される。

以下に具体例を書きます。MVC を例にとっていますが、もちろん Web Forms でも同様なことは可能です。

まず、ブラウザからの要求を受けて応答を返す窓口を作ります。MVC アプリの場合は、以下のようにアクションメソッドを使うのが簡単そうです。

具体的にどういう操作をしているかはコメントに書きましたのでそちらを見てください。

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using AdventureWorksLT;
using System.Web.Script.Serialization;

namespace Mvc5App.Controllers
{
  public class AddressesController : Controller
  {
    // サンプルデータベース AdventureWorksLT をベースに
    // Visual Studio のウィザードで作った EDM を利用。
    // AdventureWorksLTEntities は DbContext を継承
    private AdventureWorksLTEntities db = 
                            new AdventureWorksLTEntities();

    // JSONP が呼び出すアクションメソッド
    public ActionResult Jsonp(int? id, string callback)
    {
      if (id == null)
      {
          return new HttpStatusCodeResult(
                                 HttpStatusCode.BadRequest);
      }

      // Address テーブルから指定された AddressID(主キー)
      // でレコードを検索。
      // 当該レコードの AddressID, AddressLine1, City フィー
      // ルドのデータを匿名クラスのオブジェクトとして取得
      var address = (from a in db.Address
         where a.AddressID == id
         select new { a.AddressID, a.AddressLine1, a.City }).
         FirstOrDefault();

      if (address == null)
      {
          return HttpNotFound();
      }

      // 取得したオブジェクトを JSON 文字列にシリアライズし
      // 変数 callback に名前が指定されたコールバックメソッ
      // ドの引数に設定。
      // code は「コールバック(JSON 文字列)」という文字列に
      // なる
      JavaScriptSerializer ser = new JavaScriptSerializer();
      string code = string.Format("{0}({1})", 
                          callback, ser.Serialize(address));

      // 文字列「コールバック(JSON 文字列)」を返す。その際
      // ヘッダに Content-Type: application/x-javascript; が
      // 付与される
      return JavaScript(code);
    }
    // ・・・中略・・・
  }
}

上記のアクションメソッドを、例えば /Addresses/Jsonp?id=25&callback=name で呼び出すと、以下の応答が返ってきます。

name({"AddressID":25,"AddressLine1":"9178 Jumping St.","City":"Dallas"})

呼び出し側(View)のコードは以下のようになります。上にも書きましたが、script 要素を DOM に追加するコードを書く必要はありません。以下のコードだけで jQuery.ajax が自動的にやってくれます。

<input type="text" id="tb1" />
<input type="button" value="検索" onclick="btn_click()" />

@section Scripts {
  <script type="text/javascript">
  //<![CDATA[
    function btn_click() {
      var address = '/Addresses/Jsonp?id=' + $("#tb1").val();

      $.ajax({
          url: address,
          dataType: 'jsonp',
          success: function (data) {
              alert(data.AddressID + ', ' +
                    data.AddressLine1 + ', ' + 
                    data.City);
          }
      });
    }
  //]]>
  </script>    
}

上記には jQuery の外部スクリプトファイルの参照が書いてありませんが、Visual Studio 2015 のテンプレートで自動生成した _Layout.cshtml を利用していますので、デフォルトで取り込まれるようになっています。

_Layout.cshtml を利用していますので、インラインのスクリプトは、上記のように View に @section Scripts { ... } を追加して、その中に書くのが適当です。header タグ内に書くと jQuery の外部スクリプトファイルが取り込まれる前になってしまいますので注意してください。

コールバックのメソッド名は、上にも書きましたが、jQuery.ajax がクエリ文字列として自動的に自動的にデフォルトの名前を追加しますので、それを利用しています。(デフォルトの名前では不都合がある場合は指定することも可能です)

data には、コールバックの引数の JSON 文字列が JavaScript オブジェクトに変換されて渡されます。なので、上記のようにプロパティを使ってデータを取得することができます。

Tags: ,

AJAX

クロスドメインの WCF サービス

by WebSurfer 2016年12月27日 21:58

先の記事「WCF と jQuery AJAX」で書いた ASP.NET がホストする WCF サービスを、クロスドメインで利用する方法について書きます。

プリフライトリクエスト

MSDN Blog の記事「JavaScript のクロス ドメイン (Cross-Domain) 問題の回避と諸注意」では以下の 3 つの方法が紹介されています。それぞれの概要が説明されていて分かりやすいので一読されるといいと思います。

  1. Cross Document Messaging (XDM)
  2. Cross-Origin Resource Sharing (CORS)
  3. JSONP

ここでは 2 番目の Cross-Origin Resource Sharing (CORS) という方法を使います。上の画像は CORS でのプリフライトリクエストとそれに対する応答を Fiddler で見たものです。

(最初は jQuery.ajax を利用した JSONP が一番簡単かと思ったのですが、jQuery.ajax では応答のスクリプトにコールバック jQuery1830...26( ... ) で囲んだ JSON 文字列を期待しているのに、WCF サービスは JSON 文字列しか返さないので使えませんでした)

CORS は HTML 5 の仕様なので依然として使えないブラウザがありますが、対応ブラウザが増えるにつれ今後の本命になるだろうということです。(ちなみに、IE9 は対応してませんでした。上に紹介した MSDN Blog の記事によると独自の XDomainRequest オブジェクトを使用するという回避方法はあるそうですが)

まず、この記事を書くに当たって自分が参考にさせていただいた記事へのリンクを張っておきます。私の説明では分からない場合はそちらを読まれるといいと思います。手抜きでスミマセン。(汗)

  1. HTTP アクセス制御 (CORS)
  2. CORS(Cross-Origin Resource Sharing)について整理してみた

ブラウザが CORS をサポートしていれば、クライアント側の処理はブラウザが自動的に行いますので、開発者はクライアント側の対応は何もする必要がないです。

サーバー側すなわち ASP.NET Web アプリで CORS に必要な応答ヘッダ返せるようにするだけで対応できます。基本的には Global.asax ファイルに以下のコードを記述してやれば可能になります。(厳格なセキュリティを要求せず無条件で応答するというような場合はもっと簡単になります)

protected void Application_BeginRequest(object sender, 
                                                 EventArgs e)
{
  CrossOriginResourceSharingSetting();
}

private void CrossOriginResourceSharingSetting()
{
  HttpRequest request = HttpContext.Current.Request;
  HttpResponse response = HttpContext.Current.Response;

  // プリフライトリクエストの場合
  if (request.HttpMethod == "OPTIONS")
  {
    // 要求ヘッダの origin フィールドを取得
    string origin = request.Headers["origin"];

    // ここで origin に指定されたドメインのチェックを行った
    // 方がいいかもしれないが省略。要求ヘッダの origin フィ
    // ールドで送信されてきたものをそのまま返す

    // 要求ヘッダに origin フィールドがなければ何もしない
    if (!string.IsNullOrEmpty(origin))
    {
      string method = 
       request.Headers["Access-Control-Request-Method"];
      string header = 
        request.Headers["Access-Control-Request-Headers"];

      // 要求ヘッダに Access-Control-Request-Method および
      // Access-Control-Request-Headers がなければ何もしない
      if (!string.IsNullOrEmpty(method) && 
          !string.IsNullOrEmpty(header))
      {
        // method が GET または POST 以外は対応しない
        // header もチェックした方がいいかもしれない・・・
        if (method.Contains("GET") || method.Contains("POST"))
        {                            
          response.
            AddHeader("Access-Control-Allow-Origin", origin);                            
          response.
            AddHeader("Access-Control-Allow-Methods", method);                            
          response.
            AddHeader("Access-Control-Allow-Headers", header);

          // Access-Control-Max-Age ヘッダも任意で追加できる。
          // 指定した時間(秒)プリフライトの結果をキャッシュで
          // きるので、実際に運用に移す際は追加する方がよさそう
          //response.AddHeader("Access-Control-Max-Age", "600");

          response.End();
        }
      }
    }                
  }
  else
  {
    // 要求ヘッダの origin フィールドを取得
    string origin = request.Headers["origin"];

    // ここで origin に指定されたドメインのチェックを行った方
    // がいいかもしれないが省略。要求ヘッダの origin フィール
    // ドで送信されてきたものをそのまま返す

    // 要求ヘッダに origin フィールドがなければ何もしない
    if (!string.IsNullOrEmpty(origin))
    {                    
      response.AddHeader("Access-Control-Allow-Origin", origin);
    }
  }            
}

上記のコードが何をしているかと言うと、要求が「プリフライトリクエスト」になる場合と「シンプルなリクエスト」になる場合とに処置を分けて、CORS に必要な応答ヘッダを設定しているだけです。詳しくはコード中のコメントに書きましたのでそれを見てください。

CORS をサポートしているブラウザがクロスドメインでどのような処置を行うかは、要求が「シンプルなリクエスト」になるか否かによって異なってきます。要求が「シンプルなリクエスト」になる条件は、上に紹介した記事「HTTP アクセス制御 (CORS)」を読んでください。

例えば、先の記事「WCF と jQuery AJAX」で言うと「(3) WCF AJAX サービスへのアクセス」のコードで getAllCars メソッドを使う方が「シンプルなリクエスト」になります。

getCarsByDoors メソッドを使う方は要求ヘッダに contentType: "application/json; charset=utf-8" が含まれるので「シンプルなリクエスト」にはならず、「プリフライトリクエスト」が事前に行われます。

シンプルなリクエスト

要求が「シンプルなリクエスト」になる場合、CORS をサポートしているブラウザからは origin: http://<要求元のドメイン> を追加する以外には普通にサーバーに要求を出します。(ただし、IE9 では要求さえ出ませんので注意)

サーバー側では origin フィールドを見て要求側のドメインがクロスドメインアクセスを許可する対象であるかを判定し、受け入れの判断をすることができます。

ただし、上の Global.asax のコードでは要求側のドメインのチェックは行っていません。要求ヘッダの origin フィールドのドメインをそのまま応答ヘッダの Access-Control-Allow-Origin に設定して返しています。それだけでも、* を設定するよりはよさそうです。

ブラウザは応答ヘッダの Access-Control-Allow-Origin: http://<求元のドメイン> を見てクロスドメインアクセスに成功したと判断し、応答に含まれる JSON 文字列などのコンテンツを処置します。

プリフライトリクエスト

要求が「シンプルなリクエスト」にならない場合、CORS をサポートしているブラウザからは実際のリクエストを送信しても安全かを確かめるための「プリフライトリクエスト」が事前に行われます。

上の画像はその要求と応答を Fiddler で見たものです。

左下のウィンドウはブラウザがクロスドメインに対する要求でかつ「シンプルなリクエスト」にならないと判定して自動的にプリフライトリクエストを要求した要求ヘッダの内容です。

赤枠で囲った部分を見てください。HTTP メソッドの OPTIONS、要求ヘッダに含まれる origin, Access-Control-Request-Method, Access-Control-Request-Headers に注目です。

サーバーがクロスドメインからのリクエストを受け、それがプリフライトリクエストであるかどうかを判断するにはそれらの情報をチェックします。

そして、プリフライトリクエストであると判断した場合は上の画像の右下のウィンドウの赤枠で囲ったような応答ヘッダを返します。ここでは、Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers は要求ヘッダで受けたものと同じ内容に設定しています。

ブラウザはそれらの情報を見て実際のリクエストを送信しても安全かを確認し、サーバーに要求を出して(上の画像で #3 がそれ)応答を取得し、コンテンツに含まれる JSON 文字列などの情報を処置します。

Tags: , , ,

AJAX

WCF と jQuery AJAX

by WebSurfer 2015年10月15日 21:01

Web サービスは "Legacy Technology" なので Windows Communication Foundation (WCF) を使うようにと言われています。なので、今さらながらですが、先の記事 jQuery AJAX と Web サービスで作ったサンプルと同様なものを WCF で実装してみました。

AJAX 対応 WCF サービス

作成に当たって参考にしたのは以下の 2 つの記事です。しかし、読んだだけではほとんど意味が分かりません。(汗)

自分の手を動かして作ってみれば少しは理解が深まるであろうということで、自分の環境(Vista SP2 32-bit の IIS7、ASP.NET 4, Visual Studio 2010 Professional、ASP.NET Web Forms アプリ)で実際にやってみました。やってみていろいろ分かったことがありましたので備忘録として書いておきます。

まず、開発マシンの IIS7 上で動く既存の ASP.NET Web Forms アプリに、上の画像のように Visual Studio の[新しい項目の追加(W)...]メニューからテンプレートを使って[AJAX 対応 WCF サービス]を CarService.svc という名前で追加します。([WCF サービス]の方は従来の SOAP を使う WCF サービス)

CarService.svc を追加すると以下のコードが自動生成されます。今回の記事では Web アプリケーションプロジェクトを使っています。Web サイトプロジェクトの場合は、コードビハンド CarService.svc.cs が CarService.cs という名前になって App_Code フォルダに置かれる、アセンブリ名 / 名前空間名が付与されないという違いがありますので注意してください。

CarService.svc(xxx は名前空間名)

<%@ ServiceHost
  Language="C#"
  Debug="true"
  Service="xxx.CarService"
  CodeBehind="CarService.svc.cs"
%>

CarService.svc.cs(xxx は名前空間名)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Text;

namespace xxx
{
  [ServiceContract(Namespace = "")]
  [AspNetCompatibilityRequirements(RequirementsMode = 
                AspNetCompatibilityRequirementsMode.Allowed)]
  public class CarService
  {
    // HTTP GET を使用するために [WebGet] 属性を追加します 
    // (既定の ResponseFormat は WebMessageFormat.Json)。
    // XML を返す操作を作成するには、
    // [WebGet(ResponseFormat=WebMessageFormat.Xml)] を追加し、
    // 操作本文に次の行を含めます。
    // WebOperationContext.Current.OutgoingResponse.ContentType = 
    //     "text/xml";
    [OperationContract]
    public void DoWork()
    {
      // 操作の実装をここに追加してください
      return;
    }

    // 追加の操作をここに追加して、[OperationContract] とマーク
    // してください
  }
}

web.config への追加(xxx は名前空間名)

<system.serviceModel>
  <behaviors>
    <endpointBehaviors>
      <behavior name="xxx.CarServiceAspNetAjaxBehavior">
        <enableWebScript />
      </behavior>
    </endpointBehaviors>
  </behaviors>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
    multipleSiteBindingsEnabled="true" />
  <services>
    <service name="xxx.CarService">
      <endpoint address=""
        behaviorConfiguration="xxx.CarServiceAspNetAjaxBehavior"
        binding="webHttpBinding"
        contract="xxx.CarService" />
    </service>
  </services>
</system.serviceModel>

上記は、web.config に <enableWebScript /> とあることから分かるように、ASP.NET AJAX の ScriptManager を使用する Web ページからサービスを使用するための WCF AJAX サービスのコードです。

これらのコードを、上の 2 つの記事を参考に、JavaScript / jQuery を使用する Web ページからアクセスできるように書き換えてみました。

上に紹介した ASP.NET を使用せずに WCF AJAX サービスを作成する方法 に書いてあるように、以下の 3 つの手順に分けて説明します。

(1) ブラウザーからアクセスできる AJAX エンドポイントの作成
(2) AJAX 互換サービス コントラクトの作成
(3) WCF AJAX サービスへのアクセス


(1) ブラウザーからアクセスできる AJAX エンドポイントの作成

AJAX エンドポイントを作成するためには、

  1. .svc ファイルの @ServiceHost の Factory 属性に WebServiceHostFactory を設定する、または
  2. web.config の <system.serviceModel> 要素で WebHttpBinding と WebHttpBehavior を使用してエンドポイントを構成する

のいずれかの方法を取るのだそうです。具体例は上の記事(前者)のサンプルコードを参照してください。

1 の方が簡単そうに思えますが、実は 2 の方は web.config に自動生成されて追加されたコード(上のコードを見てください)の中の <enableWebScript /> を <webHttp /> に書き換えるだけで済みますので、手間的には大差はないです。

今回は 2 の方法(.svc ファイルには手を加えないで、web.config に自動生成されたコードの中の <enableWebScript /> を <webHttp /> に書き換え)を取りました。

エンドポイントアドレス名を指定してサービスを呼び出したい場合は、自動生成された address="" を修正してください。例えば、address="ajaxEndpoint" とすると、carservice.svc/ajaxEndpoint/GetAllCars でアクセスできます。(ちなみに、そのように address を設定すると、carservice.svc/GetAllCars では HTTP 404 Not Found になります)

1 の方法を取る場合、web.config に自動生成されたコードは削除した方がよさそうです。<enableWebScript /> を <webHttp /> に書き換えれば WebScriptEnablingBehavior では BodyStyle の Wrapped がサポートされてない等の問題は回避できますが、既存のサービスなどと競合してエラーになることがありましたので。


(2) AJAX 互換サービス コントラクトの作成

先の記事 ASP.NET AJAX と Web サービスの Web サービス(.asmx ファイル)のコードを CarService.svc.cs に移植します。

GetAllCars は GET 要求で呼び出せるようにしました。(JSON サービスを GET で要求するのは潜在的なセキュリティ上のリスクがあるそうです。詳しくはこのセクションの下の方で紹介した記事を見てください)

GetCarsByDoors は先の例と同様に POST 要求で呼び出すようにしました。サンプルコードは以下のようになります。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Text;

namespace WebApplication1
{
    // web.config で aspNetCompatibilityEnabled="true" と設定され
    // ているので [AspNetCompatibilityRequirements(...)] が必要
    [ServiceContract(Namespace = "")]
    [AspNetCompatibilityRequirements(RequirementsMode = 
        AspNetCompatibilityRequirementsMode.Allowed)]
    public class CarService
    {
        List<Car> cars = new List<Car> {
            new Car {Make="Audi",Model="A4",Year=1995,
                Doors=5,Colour="Red",Price=2995f},
            new Car {Make="Ford",Model="Focus",Year=2002,
                Doors=5,Colour="Black",Price=3250f},
            new Car {Make="BMW",Model="5 Series",Year=2006,
                Doors=4,Colour="Grey",Price=24950f},
            new Car {Make="Renault",Model="Laguna",Year=2000,
                Doors=5,Colour="Red",Price=3995f},
            new Car {Make="Toyota",Model="Previa",Year=1998,
                Doors=5,Colour="Green",Price=2695f},
            new Car {Make="Mini",Model="Cooper",Year=2005,
                Doors=2,Colour="Grey",Price=9850f},
            new Car {Make="Mazda",Model="MX 5",Year=2003,
                Doors=2,Colour="Silver",Price=6995f},
            new Car {Make="Ford",Model="Fiesta",Year=2004,
                Doors=3,Colour="Red",Price=3759f},
            new Car {Make="Honda",Model="Accord",Year=1997,
                Doors=4,Colour="Silver",Price=1995f}
        };

        [OperationContract]
        [WebGet(ResponseFormat = WebMessageFormat.Json, 
            BodyStyle = WebMessageBodyStyle.Wrapped)]
        public List<Car> GetAllCars()
        {
            return cars;
        }

        [OperationContract]
        [WebInvoke(ResponseFormat = WebMessageFormat.Json, 
            BodyStyle = WebMessageBodyStyle.Wrapped)]
        public List<Car> GetCarsByDoors(int doors)
        {
            var query = from c in cars
                        where c.Doors == doors
                        select c;

            return query.ToList();
        }
    }

    [DataContract]
    public class Car
    {
        [DataMember]
        public string Make { get; set; }

        [DataMember]
        public string Model { get; set; }

        [DataMember]
        public int Year { get; set; }

        [DataMember]
        public int Doors { get; set; }

        [DataMember]
        public string Colour { get; set; }

        [DataMember]
        public float Price { get; set; }
    }
}

ポイントは WebGetAttribute 属性と WebInvokeAttribute 属性の設定で、具体的には以下の通りです。

  • ResponseFormat = WebMessageFormat.Json を設定して、応答に XML ではなく JSON を明示的に指定します。
  • 上に紹介した記事(後者)には "WebGetAttribute または WebInvokeAttribute 属性に Wrapped の本文スタイルが必要です" とありますが、その通りにすると応答もラップされて {"GetAllCarsResult":[{"Colour":"Red", ... ,"Year":1997}]} というような形になります。
  • BodyStyle = WebMessageBodyStyle.Wrapped を削除すると "GetAllCarsResult" というラップはなくなりますが、今度は POST 要求で HTTP 400 Bad Request となってしまいます。なので、少なくとも POST 要求する方は BodyStyle = WebMessageBodyStyle.WrappedRequest とする必要があります。

今回は記事に従って BodyStyle = WebMessageBodyStyle.Wrapped とし、ラップを外す処置をクライアントスクリプトにコーディングしました。具体的には、下の「(3) WCF AJAX サービスへのアクセス」のセクションを見てください。

ラップすると、Web サービスの JSON 応答を "d" でラップするのと同様に、セキュリティ上のリスクの軽減に効果があるはずです。

Web サービスの JSON 応答は .NET 3.5 から "d" でラップされるようになりましたが、それは JSON サービスの脆弱性に起因する XSS 対策だそうです。そのメカニズムは以下の記事に詳しく書いてあります。

WCF では "<メソッド名>Result" でラップされますが、Web サービスで "d" でラップするのと同様に JSON 配列を返さないという効果があります。(JSON 配列は JavaScript として有効というところが問題だそうです)

あと、上に紹介した記事に書いてありますが、GET 要求を使うことにもリスクがあるそうです。

いろいろ条件が重ならないとリスクにはならないですが、「君子危うきに近寄らず」ということで、(1) ラップする、(2) POST 要求を使う、という 2 つのことは実施した方がよさそうです。(ちなみに、ASP.NET AJAX を利用する場合はデフォルトでそうなります)


(3) WCF AJAX サービスへのアクセス

これは先の記事 jQuery AJAX と Web サービス とほぼ同様な jQuery.ajax のコードを利用して可能です。

上記 (2) の手順で、GetAllCars は GET 要求で、GetCarsByDoors は POST 要求で取得するようにしたので、それぞれ以下のようなコードで要求をかけ、JSON 文字列の応答を得てそれを処置することができます。

function getAllCars() {
    $.ajax({
        type: "GET",
        url: "carservice.svc/GetAllCars",
                
        success: function (cars) {
            if (cars.hasOwnProperty('GetAllCarsResult')) {
                cars = cars.GetAllCarsResult;

                // ・・・cars の処置(省略)・・・
            }
        },
        error: function (jqXHR, textStatus, errorThrown) {
            // ・・・省略・・・
        }
    });
}
        
function getCarsByDoors() {
    $.ajax({
        type: "POST",
        url: "carservice.svc/GetCarsByDoors",
        data: '{"doors":' + $("#ddlDoors").val() + '}',
        contentType: "application/json; charset=utf-8",

        success: function (cars) {
            if (cars.hasOwnProperty('GetCarsByDoorsResult')) {
                cars = cars.GetCarsByDoorsResult;

                // ・・・cars の処置(省略)・・・
            }
        },
        error: function (jqXHR, textStatus, errorThrown) {
            // ・・・省略・・・
        }
    });                
}

POST の方には contentType: "application/json; charset=utf-8" の設定は必須です。それがないと HTTP 400 Bad Request となって失敗します。

success オプションに設定したコールバックの引数 cars にはパース済みの JavaScript オブジェクトが渡されます。上の「(2) AJAX 互換サービス コントラクトの作成」のセクションで述べたように "<メソッド名>Result" でラップされていますので、ラップを外す処置が必要です。具体的には上のコードを見てください。(命名規則が不明なので、ラップを外す処置をハードコーディングするのはちょっと不安なのですが)

Tags: , ,

AJAX

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  2017年5月  >>
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

View posts in large calendar