方法: AJAX 対応 ASP.NET Web サービスを WCF に移行する
このトピックでは、基本 ASP.NET AJAX サービスを、同等の AJAX 対応 Windows Communication Foundation (WCF) サービスに移行する手順を説明します。 ここでは、ASP.NET AJAX サービスの、機能的に同等の WCF バージョンを作成する方法を示します。 この 2 つのサービスを並行して使用するか、WCF サービスを ASP.NET AJAX サービスと置き換えて使用することができます。
既存の ASP.NET AJAX サービスを WCF AJAX サービスに移行すると、次のような利点が得られます。
最小限の追加構成で、AJAX サービスを SOAP サービスとして公開できます。
トレースなどの WCF の機能の利点が得られます。
次の手順では、Visual Studio 2012 を使用していることを前提としています。
手順に続く例で、ここで説明する手順によって作成されるコードを示します。
AJAX 対応エンドポイントを介した WCF サービスの公開の詳細については、「方法: 構成を使用して ASP.NET AJAX エンドポイントを追加する」トピックを参照してください。
ASP.NET Web サービス アプリケーションを作成してテストする
Visual Studio 2012 を開きます。
[ファイル] メニューの [新規作成] をクリックし、 [プロジェクト] 、 [Web] の順にクリックしてから [ASP.NET Web サービス アプリケーション] を選択します。
プロジェクトに
ASPHello
という名前を付け、 [OK] をクリックします。Service1.asmx.cs ファイルで、
System.Web.Script.Services.ScriptService]
が含まれた行のコメントを解除し、このサービスに対して AJAX を有効にします。[ビルド] メニューの [ソリューションのビルド] を選択します。
[デバッグ] メニューから [デバッグなしで開始] を選択します。
生成された Web ページで、
HelloWorld
操作を選択します。HelloWorld
テスト ページで [起動] をクリックします。 次の XML 応答を受信します。<?xml version="1.0" encoding="utf-8" ?> <string xmlns="http://tempuri.org/">Hello World</string>
この応答は、ASP.NET AJAX サービスが現在機能していること、およびこのサービスが現在 Service1.asmx/HelloWorld でエンドポイントを公開していることを確認するものです。このエンドポイントが HTTP POST 要求に応答し、XML を返します。
これで、このサービスを変換して WCF AJAX サービスを使用する準備ができました。
同等の WCF AJAX サービス アプリケーションを作成するには
ASPHello プロジェクトを右クリックし、 [追加] 、 [新しい項目] 、 [AJAX 対応 WCF サービス] の順にクリックします。
サービスに
WCFHello
という名前を付け、 [追加] をクリックします。WCFHello.svc.cs ファイルを開きます。
Service1.asmx.cs から、
HelloWorld
操作の次の実装をコピーします。public string HelloWorld() { return "Hello World"; }
コピーした
HelloWorld
操作の実装を、WCFHello.svc.cs ファイルの次のコードの場所に貼り付けます。public void DoWork() { // Add your operation implementation here return; }
ServiceContractAttribute の
Namespace
属性をWCFHello
として指定します。[ServiceContract(Namespace="WCFHello")] [AspNetCompatibilityRequirements(RequirementsMode=AspNetCompatibilityRequirementsMode.Required)] public class WCFHello { … }
WebInvokeAttribute を
HelloWorld
操作に追加し、Xml を返すように ResponseFormat プロパティを設定します。 この設定を行わない場合、既定の戻り値の型は Json です。[OperationContract] [WebInvoke(ResponseFormat=WebMessageFormat.Xml)] public string HelloWorld() { return "Hello World"; }
[ビルド] メニューの [ソリューションのビルド] を選択します。
WCFHello.svc ファイルを開き、 [デバッグ] メニューの [デバッグなしで開始] を選択します。
これで、サービスが
WCFHello.svc/HelloWorld
でエンドポイントを公開します。このエンドポイントが HTTP POST 要求に応答します。 HTTP POST 要求をブラウザーからテストすることはできませんが、エンドポイントは次の XML を返します。<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">Hello World</string>
これで、
WCFHello.svc/HelloWorld
とService1.aspx/HelloWorld
エンドポイントが機能的に同等になりました。
例
このトピックで説明した手順によって作成されるコードを次の例に示します。
//This is the ASP.NET code in the Service1.asmx.cs file.
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;
using System.Web.Script.Services;
namespace ASPHello
{
/// <summary>
/// Summary description for Service1.
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
[System.Web.Script.Services.ScriptService]
public class Service1 : System.Web.Services.WebService
{
[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
}
}
//This is the WCF code in the WCFHello.svc.cs file.
using System;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
namespace ASPHello
{
[ServiceContract(Namespace = "WCFHello")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class WCFHello
{
// Add [WebInvoke] attribute to use HTTP GET.
[OperationContract]
[WebInvoke(ResponseFormat=WebMessageFormat.Xml)]
public string HelloWorld()
{
return "Hello World";
}
// Add more operations here and mark them with [OperationContract].
}
}
XmlDocument 型は、DataContractJsonSerializer によってシリアル化できないため、XmlSerializer ではサポートされていません。 XDocument 型を使用するか、DocumentElement をシリアル化します。
ASMX Web サービスが WCF サービスと並行してアップグレードおよび移行される場合は、クライアントで 2 つの型を、同じ名前に割り当てないようにします。 同じ名前が割り当てられていると、WebMethodAttribute と ServiceContractAttribute で同じ型が使用されている場合に、シリアライザーで次のような例外が発生します。
最初に WCF サービスが追加された場合は、ASMX Web サービスでメソッドを呼び出すと、ConvertValue(Object, Type, String) で例外が発生します。これは、プロキシでの順序の定義で WCF スタイル定義が優先されるためです。
ASMX Web サービスが最初に追加された場合は、WCF サービスでメソッドを呼び出すと、DataContractJsonSerializer で例外が発生します。これは、プロキシでの順序の定義で Web サービス スタイル定義が優先されるためです。
DataContractJsonSerializer と ASP.NET AJAX JavaScriptSerializer の動作には大きな違いがあります。 たとえば、DataContractJsonSerializer はディクショナリをキーと値のペアの配列として表しますが、ASP.NET AJAX JavaScriptSerializer はディクショナリを実際の JSON オブジェクトとして表します。 したがって、ASP.NET AJAX では、ディクショナリが次のように表されます。
Dictionary<string, int> d = new Dictionary<string, int>();
d.Add("one", 1);
d.Add("two", 2);
このディクショナリは、JSON オブジェクトでは次のように表されます。
DataContractJsonSerializer では [{"Key":"one","Value":1},{"Key":"two","Value":2}] と表され、
ASP.NET AJAX JavaScriptSerializer では、{"one":1,"two":2} と表されます。
DataContractJsonSerializer は、キーの種類が文字列ではないディクショナリを処理でき、JavaScriptSerializer はできません。この点で前者はより強力と言えます。 しかし、後者の方が JSON で使いやすいと言えます。
これらのシリアライザーの主な違いを次の表に示します。
相違点のカテゴリ | DataContractJsonSerializer | ASP.NET AJAX JavaScriptSerializer |
---|---|---|
空きバッファー (新しい byte[0]) の Object (または Uri、あるいは他の一部のクラス) への逆シリアル化 | SerializationException | null |
Value のシリアル化 | {} (または {"__type":"#System"}) | [Null] |
[Serializable] 型のプライベート メンバーのシリアル化 | できるか | シリアル化できません |
ISerializable 型のパブリック プロパティのシリアル化 | シリアル化できません | できるか |
JSON の「拡張機能」 | オブジェクト メンバー名で引用符を必要とする ({"a":"hello"}) JSON 仕様に準拠しています。 | 引用符のないオブジェクト メンバー名 ({a:"hello"}) をサポートします。 |
DateTime 協定世界時刻 (UTC) | "\/Date(123456789U)\/" および "\/Date(\d+(U|(\+\-[\d{4}]))?)\\/)" の形式はサポートされていません。 | DateTime 値として、"\/Date(123456789U)\/" および "\/Date(\d+(U|(\+\-[\d{4}]))?)\\/)" の形式がサポートされています。 |
ディクショナリの表現 | KeyValuePair<K,V> の配列。文字列以外のキーの種類を処理します。 | 実際の JSON オブジェクトですが、文字列の種類のキーのみ処理します。 |
エスケープ文字 | 必ず、エスケープ文字であるスラッシュ (/) を付けます。"\n" などのエスケープされない無効な JSON 文字は使用できません。 | DateTime 値には、エスケープ文字スラッシュ (/) を付けます。 |