WebSurfer's Home

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

ローカル .wsdl ファイルからプロキシ作成

by WebSurfer 2020年5月11日 12:06

.NET Framework アプリから Web / WCF サービスに接続して情報を取得する場合、Visual Studio の「サービス参照の追加」を利用してアプリと Web / WCF サービス間のインターフェイスとなるプロキシクラスを生成し、それを利用すると思います。

サービス参照の追加

Microsoft のチュートリアルなどでは、上の画像で[アドレス(A):]に設定するのはサービスの URL(例: http://example.com/service.svc)という記述しか目にしてこなかったので、URL 以外はダメだと思い込んでいましたが、実はローカルの .wsdl ファイルでも OK でしたという話を書きます。

Microsoft のドキュメント「Web サービス プロキシの作成」に ".NET Framework SDK には、Web サービス記述言語ツール (Wsdl.exe) が含まれています。これにより、.NET Framework 開発環境で使用する Web サービス プロキシを生成できます" という記述があります。

その記事のコード例では、やはりサービスの URL を設定していますが、Wsdl.exe のヘルプ(以下の画像参照)を見るとローカル .wsdl ファイルのパスでもよさそうです。

Wsdl.exe のヘルプ

一方、.wsdl ファイルですが、@IT の記事「WSDL:Webサービスのインターフェイス情報」によると十分なインターフェイス情報が含まれているようで、それからプロキシクラスが生成できないわけはなさそうです。

Visual Studio も「サービス参照の追加」ウィザードには Wsdl.exe を使っているはずです。なので、自分が作った Web サービスから .wsdl ファイルを作り、それを自分の PC のローカルフォルダにおいて、そのバスを「サービス参照の追加」ダイアログの[アドレス(A):]に設定して試してみました。

結果、以下の通りプロキシクラスを生成できます。

生成されたプロキシクラス

アプリから生成されたプロキシクラスを使って Web サービスに接続し、期待通りの結果が得られることも確認できました。

実際に URL ではなくローカルの .wsdl ファイルからプロキシクラスを作成しなけれなならないケースがどれぐらいあるのか分かりませんが、Visual Studio でこういうこともできるということで参考になれば幸いです。

(ちなみに http://example.com/service.svc というサービスの URL から .wsdl ファイルをダウンロードするには、その URL に ?wsdl というクエリ文字列を追加して要求をかけます。)

Tags: , ,

DevelopmentTools

Web サービス経由で非接続型データアクセス

by WebSurfer 2014年8月23日 16:50
2018/3/4 追記:
Microsoft によると Web サービスは "Legacy Technology" なので WCF を使えとのことゆえ、接続先を WCF サービスに変更し、非同期にアクセスするサンプルを作ってみました。興味がありましたら記事「WCF サービス経由で非接続型データアクセス」を見てください。

DataGridView と型付 DataSet + TableAdapter を用いて非接続型データアクセスを行う Windows アプリケーションで、Web サービス経由で SQL Server のデータの取得更新を行う例の紹介です。(Windows アプリから直接 SQL Server に接続するのではなく)

DataGridView

Visual Studio のデータソース構成ウィザードを使うと、MSDN ライブラリの Windows フォーム アプリケーションでのデータへの接続 の図のような構成の Windows アプリケーションを作成できます。具体的な作成手順例は、チュートリアル「10 行でズバリ !! 非接続型のデータ アクセス」を見てください。

上に紹介したチュートリアルの例では Windows アプリから直接 SQL Server に接続していますが、セキュリティ上の問題などで、Windows アプリ ⇔ サーバー ⇔ SQL Server というようにサーバーを介してアクセスしたいということがあると思います。

Web サーバー (IIS) を利用し、それに Web サービス(.asmx)を実装して、Windows アプリケーションとの間で型付 DataSet をやりとりすることで Windows アプリ ⇔ サーバー ⇔ SQL Server という構成を実現できます。

(1) Web サービス

まず Web サービスですが、(a) SQL Server から型付 DataSet にデータを取得して Windows アプリケーション渡すメソッド、(b) ユーザーが編集済みの型付 DataSet を受け取って SQL Server のレコードを更新するメソッドを実装します。

具体例は以下のようになります。GetDataSet メソッドが上記 (a)、Update メソッドが上記 (b) に該当します。

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

namespace WebApplication1
{
  using ProductsDataSetTableAdapters;
    
  [WebService(Namespace = "http://tempuri.org/")]
  [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
  [System.ComponentModel.ToolboxItem(false)]
  public class ProductsWebService : WebService
  {
    [WebMethod]
    public ProductsDataSet GetDataSet()
    {
      ProductsDataSet dataset = new ProductsDataSet();
      ProductsTableAdapter adapter = 
                          new ProductsTableAdapter();            
      adapter.Fill(dataset.Products);
      return dataset;
    }

    [WebMethod]
    public int Update(ProductsDataSet dataset)
    {
      TableAdapterManager manager = new TableAdapterManager();
      manager.ProductsTableAdapter = new ProductsTableAdapter();
      return manager.UpdateAll(dataset);
    }
  }
}

SQL Server データベースには、Microsoft が無償で提供しているサンプルデータベース Northwind の Products テーブルを使っています。

ProductsDataSet, ProductsTableAdapter, TableAdapterManager は、 Visual Studio のデータソース構成ウィザードを使って自動生成させた .xsd ファイル下の .Designer.cs に含まれる型付 DataSet + TableAdapter + TableAdapterManager です。

(2) クライアント・アプリケーション

上記の Web サービスをクライアント・アプリケーションでは以下のように利用できます。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace UpdateUsingWebService
{
  public partial class Form2 : Form
  {
    private ProductsServiceReference.
                        ProductsWebServiceSoapClient client;
    private ProductsServiceReference.
                        ProductsDataSet productsDataSet;

    public Form2()
    {
      InitializeComponent();
      InitializeComponent2();
      this.client = new ProductsServiceReference.
                            ProductsWebServiceSoapClient();
    }

    private void productsBindingNavigatorSaveItem_Click(
        object sender, EventArgs e)
    {
      this.Validate();
      this.productsBindingSource.EndEdit();
            
      // Web サービスに渡すのはユーザーが編集した行のみで可
      ProductsServiceReference.ProductsDataSet ds =
                  (ProductsServiceReference.ProductsDataSet)
                           this.productsDataSet.GetChanges();

      // 編集済みの型付 DataSet を Web サービスに渡し、更新
      // をかける。戻り値 n は更新されたレコード数
      int n = this.client.Update(ds);

      // 更新後の型付 DataSet を取得。DataGridView 書き換え
      this.productsDataSet = this.client.GetDataSet();
      this.productsBindingSource.DataSource = 
                                    this.productsDataSet;
    }

    private void Form2_Load(object sender, EventArgs e)
    {
      // Web サービスより型付 DataSet を取得
      this.productsDataSet = this.client.GetDataSet();
      this.productsBindingSource.DataSource = 
                                     this.productsDataSet;
    }

    // ・・・中略・・・

    private void InitializeComponent2()
    {
      // ・・・中略・・・
    }

  }
}

まず、Visual Studio のサービス参照の追加ウィザードを利用して、上記 (1) で作成した Web サービスを参照し、プロキシクラスと型付 DataSet(上記のコード例では ProductsWebServiceSoapClient と ProductsDataSet)を自動生成させます。

次に、Visual Studio のデータソース構成ウィザードを使って、上記 (1) で作成した型付 DataSet + TableAdapter + TableAdapterManager と全く同じものを自動生成させます。

その上で、Visual Studio のデザイン画面で、「データソース」ウィンドウの項目を Form 画面にドラッグ&ドロップすると、DataGridView, BindingSource, BindingNavigatorなどのコードが自動生成されます。

それらを組み合わせれば容易に実装できるはずです。

Tags: , ,

.NET Framework

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