WebSurfer's Home

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

ASP.NET AJAX と Web サービス

by WebSurfer 2011年6月4日 17:52

ASP.NET AJAX Web ページから Web サービスにアクセス

AJAX 対応 ASP.NET Web ページからクライアントスクリプトを使って Web サービスにアクセスする方法を、MSDN ライブラリの ASP.NET AJAX での Web サービスの使用 を参考に実装してみました。

参考にした MSDN ライブラリのページに記載されていたサンプルコードではあまり面白くないし、jQuery AJAX を利用してアクセスする方法と比較してみたかったので、ググって探したページ Handling JSON Arrays returned from ASP.NET ... に記載されていたサンプルを使って、呼び出し側を ASP.NET AJAX Web ページに変更して実装してみました。

非同期要求の要となるのが、プロキシクラスに定義されている JavaScript のメソッド類です。クライアントとサーバーの通信におけるプロキシクラスの位置づけなどの説明は上に紹介した MSDN ライブラリを参照してください。

ASP.NET Web ページに ScriptManager コントロールを追加し、その Services 要素に asp:ServiceReference 要素を追加し、Path 属性に Web サービスの URL 設定することにより、自動的にプロキシクラスが生成されます。

自動生成されたプロキシクラスがページの読み込み時にブラウザにダウンロードされるように、初期画面の html ソースに以下のような外部スクリプトファイルへの参照が含まれます。(下記で js は web.config の設定がデバッグモードになっていると jsdebug になります)

<script src="WebService.asmx/js" type="text/javascript">
</script>

このプロキシクラスに定義されたメソッドを使用して Web サービスメソッドに対して JavaScript の非同期要求を行います。

ブラウザとサーバー間で交換されるデータのシリアル化形式としては JSON が使用されます。Web サービスが JSON 形式のデータを返すようにするには、Web サービスクラスに、System.Web.Script.Services 名前空間の ScriptService 属性を付与します。

(1) Web サービス、(2) aspx ページでプロキシクラスを操作するための JavaScript、(3) aspx ページのコードを、その順に以下にアップしておきます。Web サービスのコードは、上に紹介したページのサンプルと同じです。(リンク切れになると困るのでここに貼っておきます)

jQuery AJAX を利用した場合と比較してのメリットは、.NET 3.5 で追加された d パラメータがプロキシで適切に処置されるところと、コードが若干少なくなる点でしょうか。

以下のコードは、実際に動かして試せるよう 実験室 にアップしましたので、興味のある方は試してみてください。

(1) Web サービス (097_jQueryAjaxAndWebService.asmx)

クライアントスクリプトから呼び出すことができるように、クラスに ScriptService 属性を追加しているところがポイントです。

<%@ WebService Language="C#" Class="CarService" %>

using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Web.Script.Services;
using System.Collections.Generic;
using System.Linq;

public class Car
{
    public string Make;
    public string Model;
    public int Year;
    public int Doors;
    public string Colour;
    public float Price;
}

/// <summary>
/// Summary description for CarService
/// </summary>

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class CarService : WebService
{
    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}
    };
    
    [WebMethod]
    public List<Car> GetAllCars()
    {
        return Cars;
    }

    [WebMethod]
    public List<Car> GetCarsByDoors(int doors)
    {
        var query = from c in Cars
                    where c.Doors == doors
                    select c;

        return query.ToList();
    }
}

(2) JavaScript (097_ASPNETAjaxAndWebService.js)

Succeeded コールバック関数の引数に渡されるのは JSON の文字列ではなく、パース済みの JavaScript オブジェクトとなる点に注意してください。セキュリティ対策のため .NET 3.5 で JSON 文字列に追加された d パラメータはプロキシクラスで適切に除去されるようです。

var serviceProxy;

// プロキシの初期化とコールバック関数の設定
function pageLoad() {
    serviceProxy = new CarService();
    serviceProxy.set_defaultSucceededCallback(Succeeded);
    serviceProxy.set_defaultFailedCallback(Failed);
}

// ボタンクリックで呼び出されるサービスメソッド  
function getCars(doors) {
    serviceProxy.GetCarsByDoors(doors);
}

// AJAX 通信が成功したときに呼び出され、戻ってきたデータ
// を処置するコールバック関数。
// 引数 cars は JSON 文字列ではなく、パース済みのオブジェ
// クト。.NET 3.5 で追加された d パラメータはプロキシで
// 適切に処置されるらしい。
function Succeeded(cars) {
    $('#output').empty();
    $.each(cars, function (index, car) {
        $('#output').append(
            '<p><strong>' + car.Make + ' ' +
            car.Model + '</strong><br /> Year: ' +
            car.Year + '<br />Doors: ' +
            car.Doors + '<br />Colour: ' +
            car.Colour + '<br />Price: £' +
            car.Price + '</p>');
    });
}

// 通信に失敗したとき呼び出されるコールバック関数。 
function Failed(error, userContext, methodName) {
    if (error !== null) {
        var msg = "An error occurred: " +
            error.get_message();
        $('#output').text(msg);
    }
}

if (typeof (Sys) !== "undefined") {
    Sys.Application.notifyScriptLoaded();
}

(3) apsx ページ (097_ASPNETAjaxAndWebService.aspx)

プロキシクラスを自動生成するために、ScriptManager コントロールを追加し、その Services 要素に asp:ServiceReference 要素を追加し、Path 属性に Web サービスの URL 設定するところがポイントです。

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title>ASP.NET AJAX and Web Service</title>
  <script src="Scripts/jquery-1.4.1.js" type="text/javascript">
  </script>
</head>
<body>
  <form id="form1" runat="server">
    <asp:ScriptManager runat="server" ID="scriptManager">
      <Services>
        <asp:ServiceReference 
          Path="~/097_jQueryAjaxAndWebService.asmx" />
      </Services>
      <Scripts>
        <asp:ScriptReference 
          Path="~/097_ASPNETAjaxAndWebService.js" />
      </Scripts>
    </asp:ScriptManager>
    <div>
      Number of doors: 
      <asp:DropDownList ID="ddlDoors" runat="server">
        <asp:ListItem>2</asp:ListItem> 
        <asp:ListItem>3</asp:ListItem>
        <asp:ListItem>4</asp:ListItem>
        <asp:ListItem>5</asp:ListItem>
      </asp:DropDownList>   
    </div>
    <input 
      type="button" 
      id="Button1" 
      value="Get Cars" 
      onclick="getCars($('#<%= ddlDoors.ClientID %>').val());" /> 
    <div id="output"></div>
  </form>
</body>
</html>

----- 2012/7/16 追記(2014/3/24 一部訂正) -----

Web サービスのメソッドに ScriptService 属性を追加することにより JSON 形式のデータが返されるというわけではありません。MSDN ライブラリの ScriptServiceAttribute クラス にもそのようなことは書いてなくて、"Web サービス メソッドを ECMAScript (JavaScript) から起動する" ためだけのようです。

Web サービスのメソッドが返すのは、Json か Xml 形式のいずれかになりますが、それを決めるのは要求ヘッダの Content-Type の設定のようです。

MSDN ライブラリには Content-Type で決まるというような記述は見つけられませんでしたが、自分が試した限りでは以下の通りでした。

  1. Content-Type: application/x-www-form-urlencoded もしくは指定しない場合は Xml
  2. Content-Type: application/json の場合は Json

この記事のように、プロキシクラスを利用する場合は、自動的に要求ヘッダに Content-Type: application/json と指定され、Json 形式でデータが帰ってきます。

jQuery AJAX と Web サービス のページで紹介した jQuery Ajax を使う場合は、contentType に application/json を指定しないと、Web サービスのメソッドが返すデータ合は Xml 形式になってしまうので注意が必要です。

(注) jQuery のサイトの API Documentation の説明によると、jQuery.ajax() の contentType のデフォルトは 'application/x-www-form-urlencoded; charset=UTF-8' とのことですが、何も設定しないと要求ヘッダには Content-Type: そのものが設定されません(1.4.1 でしか試してませんが)。その場合でも、Web サービスのメソッドが返すデータ合は Xml 形式になります。

なお、要求ヘッダが Content-Type: application/x-www-form-urlencoded もしくは何も指定しない場合は ScriptMethodAttribute クラスResponseFormat プロパティ を Json に指定しても無視されます。

ただし、要求ヘッダが Content-Type: application/json の場合は ResponseFormat プロパティの設定は意味があって、Xml に設定すると Web サービスのメソッドが返すデータは Xml 形式になります。

Tags: ,

AJAX

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年4月  >>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar