WebSurfer's Home

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

HttpWebRequest で WCF サービスを呼出

by WebSurfer 2017年3月26日 14:36

先の記事 WCF と jQuery AJAX では、JSON 文字列をデータとしてやり取りする WCF サービスのメソッドを、jQuery.ajax を使って呼び出してデータを取得する方法を書きました。

この WCF サービスのメソッドを HttpWebRequest / HttpWebResponse を利用して呼び出して JSON 文字列のデータを取得し、それを逆シリアル化して C# のオブジェクトに変換する方法を書きます。

ここでは例として先の記事の WCF サービスの GetCarsByDoors(int doors) メソッドを POST 要求してみます。

まず、JSON 文字列が逆シリアル化された際の C# のクラス / プロパティを書き、それらに DataContract / DataMember 属性を付与してデータコントラクトを定義します。

JSON 文字列から C# のクラス / プロパティの変換は json2csharp のような変換サービスを利用すると簡単にできると思います。

先の記事のコードでは、WCF サービスの GetCarsByDoors(int doors) メソッドの応答の JSON 文字列は "GetCarsByDoorsResult" でラップされるように設定されていますので、それを考慮して以下のようなデータコントラクト定義になります。

[DataContract]
public class RootObject
{
    // GetCarsByDoorsResult は WCF サービスメソッドに付与した
    // BodyStyle = WebMessageBodyStyle.WrappedRequest による
    // ラップの名前(ラップするのはセキュリティ対策)
    [DataMember]
    public List<Car> GetCarsByDoorsResult { get; set; }
}

[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; }
}

HttpWebRequest を利用して WCF サービスの GetCarsByDoors(int doors) メソッドを要求し JSON 文字列をデータとして POST 送信します。ここでは例として "{\"doors\":5}" という 5 ドア車を要求する JSON 文字列を設定しています。

HttpWebResponse を利用して応答を取得し、DataContractJsonSerializer クラスを利用して応答ストリームに含まれる JSON 文字列を C# のオブジェクトにデシリアライズします。

詳しくは以下のサンプルコードとそれに付与したコメントを見てください。

using System;
using System.Net;
using System.Text;
using System.IO;
using System.Runtime.Serialization;
using System.Collections.Generic;
using System.Runtime.Serialization.Json;

namespace ConsoleApplication7
{
  class Program
  {
    static void Main(string[] args)
    {
      // 指定した Uri を要求する HttpWebRequest を初期化
      HttpWebRequest endpointRequest =
          (HttpWebRequest)HttpWebRequest.
          Create("http://.../carservice.svc/GetCarsByDoors");

      endpointRequest.Method = "POST";
      endpointRequest.ContentType = 
          "application/json; charset=utf-8";

      // POST データの設定。とりあえず 5 ドアを要求してみる
      string postData = "{\"doors\":5}";

      Encoding encoding = Encoding.GetEncoding("utf-8");
      byte[] byte1 = encoding.GetBytes(postData);
      endpointRequest.ContentLength = byte1.Length;

      // POST データを書き込むストリームを取得
      using (Stream requestStream = 
             endpointRequest.GetRequestStream())
      {
        // POST データを要求ストリームに書き込み
        requestStream.Write(byte1, 0, byte1.Length);

        // WCF サービスメソッドからの応答を取得
        using (HttpWebResponse endpointResponse =
               (HttpWebResponse)endpointRequest.GetResponse())
        {
          // 応答のコンテンツを読むストリームを取得
          using (Stream responseStream = 
                 endpointResponse.GetResponseStream())
          {
            // JSON シリアライザの初期化
            DataContractJsonSerializer ser = 
              new DataContractJsonSerializer(typeof(RootObject));

            // 応答のコンテンツを逆シリアル化して C# の
            // オブジェクトを取得
            RootObject rootObject = 
              (RootObject)ser.ReadObject(responseStream);
                        
            foreach (Car car in rootObject.GetCarsByDoorsResult)
            {
              Console.WriteLine("Make:{0}, Model:{1}, Doors:{2}",
                                car.Make, car.Model, car.Doors);

            /*
            結果は:
            Make:Audi, Model:A4, Doors:5
            Make:Ford, Model:Focus, Doors:5
            Make:Renault, Model:Laguna, Doors:5
            Make:Toyota, Model:Previa, Doors:5
            */

            }
          }
        }
      }
    }
  }
}

DataContractJsonSerializer クラスを利用したシリアル化 / 逆シリアル化については、MSDN ライブラリの記事「方法 : JSON データをシリアル化および逆シリアル化する」が参考になると思います。

Tags: ,

.NET Framework

URL Rewrite Module の Outbound Rules

by WebSurfer 2017年3月20日 16:56

gzip 圧縮済みのコンテンツを応答としてブラウザに返す場合、下の画像のように応答ヘッダに Content-Encoding: gzip を設定する必要があります。

応答ヘッダ

HTTP ハンドラを使って自分でダウンロードするコードを書く場合は自由に応答ヘッダを追加できますが、IIS の静的ハンドラを使う場合(例えば、img 要素の src 属性に .svgz 画像のパスを設定したような場合)はどうすればいいでしょう?

URL Rewrite Module 2.0 の Outbound Rules を利用すると応答ヘッダに Content-Encoding: gzip を設定できます。.svgz 画像の場合を例にとって以下にその方法を書きます。(注: Content-Type: image/svg+xml も必要ですが applicationHost.config の MIME Map で設定済みであれば何もする必要はありません。IIS Manager で調べてください)

URL Rewrite Module の Outbound Rules

IIS Manager を起動して、上の画像のように Add Rule(s) ダイアログで Outbound Rules の Blank rules を選択し、OK ボタンをクリックすると Edit Outbound Rule という編集画面が開くので、そこでまず Precondition を定義します。

Precondition の定義

上の画像は Precondition の名前を IsSVGZ とし(任意)、Server Variable の URL(クエリ文字列等を含まないベースの部分)が正規表現の \.svgz$ にマッチする(.svgz で終わる)という条件になっています。URL の代わりに PATH_INFO を使っている記事がありますが、 ASP.NET の場合はどちらも同じ結果になりますので、分かりやすいと思われる URL を使用しました。

Precondition 設定後 Edit Outbound Rule 編集画面に戻って、Rule 名(任意)と Match 条件を設定します。下の画像の赤枠で囲った部分を見てください。

Name と Match の設定

Server Variable 名の RESPONSE_CONTENT_ENCODING と言うのは、Microsoft の公式文書には見つかりませんでしたが、応答ヘッダの Content-Encoding になるようです。正規表現の .* は 0 個以上の任意の文字という意味です。

ちなみに、RESPONSE_ が頭に付いている Server Variables には、RESPONSE_CONTENT_ENCODING 以外に、以下の画像の項目があるようです。未検証未確認ですが、それらは全て URL Rewrite Module で書き換え可能かもしれません。

Action の設定

次に Edit Outbound Rule 編集画面の下の方にある Action の設定を行います。下の画像の赤枠で囲った部分を見てください。

Action の設定

上記の操作の結果、当該サイトの web.config に以下のコードが生成されます。(逆に言えば、IIS Manager を操作しなくても、web.config を編集して以下のコードを追加しても同じ結果が得られます)

 
<system.webServer>
  <rewrite>
    <outboundRules>
      <rule name="Rewrite SVGZ header" 
        preCondition="IsSVGZ" stopProcessing="true">
        <match serverVariable="RESPONSE_CONTENT_ENCODING" 
          pattern=".*" />
        <action type="Rewrite" value="gzip" />
      </rule>
      <preConditions>
        <preCondition name="IsSVGZ">
          <add input="{URL}" pattern="\.svgz$" />
        </preCondition>
      </preConditions>
    </outboundRules>
  </rewrite>
</system.webServer>

上の web.config の設定により、Server Variable の URL が .svgz で終わっている要求に対しては、応答ヘッダの Content-Encoding を gzip に書き換える(無ければ追加する)という操作が URL Rewrite Module によって行われ、一番上の画像で示したように Content-Encoding: gzip が付与されます。

<注意>

URL Rewrite Module は自分でダウンロードしてインストールする必要があります。インストールしてないと web.config を書き換えても効果はありません。

Microsoft URL Rewrite Module 2.0 for IIS 7 (x64)

Microsoft URL Rewrite Module 2.0 for IIS 7 (x86)

Windows 10 にはインストールできない(レジストリの設定変更が必要)という話がありますが、その場合は、英語版しか見つかりませんが、以下のページからダウンロードしたものがレジストリの設定変更なしでインストールできます。

Microsoft URL Rewrite Module 2.0 for IIS (x64)

自分は英語版を使ったので、IIS Manager の Url Write の部分のみ英語になってしまいました。上の画像の表示は日本語版とは異なると思います。

Tags: , ,

Windows Server

ブラウザーリンク

by WebSurfer 2017年2月25日 15:44

先日買った Windows 10 Pro 64-bit のノート PC に OS が Vista の旧マシンでは使えなかった Visual Studio 2015 Communuty をインストールして使い始めました。

手始めに、テンプレートを使ってインターネット上でフォーム認証を使う Web サイトプロジェクトを作って、Fiddler で要求 / 応答をキャプチャしてみると、以下の画像のように localhost との正体不明な通信が行われています。(驚)

Fiddler によるキャプチャ

(ちなみに、vortex.data.microsoft.com, urs.smartscreen.microsoft.com の正体は分かっています。Tunnel to とは Fiddler が HTTP CONNECT 要求を受けてブラウザとサーバー間で直接通信するようにトンネルを開けたということだそうです)

一体これは何なんだと驚いて、URL にある browserLink をキーワードにググって調べてみると、MSDN Blog の記事に「クロスブラウザのテストに Visual Studio 2013 のブラウザーリンクをどうぞ」というのが見つかりました。

ブラウザーリンクというのは、Visual Studio 2013 から搭載された新機能で、IE, Forefox, Chrome などの複数のブラウザを同時に立ち上げて表示させたり、Visual Studio 上でのコードの修正を複数のブラウザに同時に反映させたりする機能だそうです。

そのために、Visual Studio が HTML ソースにスクリプトを追加し、そのスクリプトによって Visual Studio と各ブラウザが通信を行っているそうです。その結果が、上の画像にある localhost との正体不明な通信だったようです。

MSDN Blog の記事にも書いてありますが、ブラウザーリンクは Visual Studio の設定で無効にできます。(2023/12/25 追記: Visual Studio 2022 ではデフォルトで[ブラウザーリンクを有効にする]のチェックは外れていますが、それでもブラウザーリンクによる Visual Studio とブラウザ間の通信が行われます。それを行わないようにする方法は別の記事「Visual Studio 2022 のブラウザーリンク」に書きましたので見てください)

具体的には、上の画像の ▼ 印をクリックすると表示されるドロップダウンメニューで[Browser link を有効にする]のチェックを外します。

早速チェックを外して試してみると、HTML ソースへのスクリプトの追加はなくなり、localhost との正体不明な通信も行われなくなったのが確認できました。

Visual Studio 2010 から 2015、ASP.NET 4 から 4.5 とそれほど長くはない間に、ブラウザーリンク以外にも、いろいろな進化があったようです。

その進化に完全に取り残されていると感じる今日この頃です。(汗)

Tags:

DevelopmentTools

About this blog

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

Calendar

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

View posts in large calendar