方法 : HTTP トランスポートを使用する
更新 : 2007 年 11 月
HTTP トランスポートを使用すると、デスクトップ上の Windows Communication Foundation (WCF) サービスに接続するデバイス上のアプリケーションを作成できます。
ここでは、接続デバイスを処理する WCF サービスを構成する方法と、クライアント アプリケーションを作成する方法について説明します。モバイル デバイスからサービスに接続できるようにするには、特別な WCF サービス構成とクライアント側コーディングが必要であることを説明します。デスクトップ用の WCF アプリケーションを作成する方法について、詳しくは WCF 資料の「チュートリアル入門」を参照してください。
デスクトップ用の WCF サービスを作成するには
新しい Web サービス プロジェクトを作成します。
以下の例のように Web.config ファイルの内容を変更します。ファイル内の次の要素と属性を変更します。
<endpoint>binding 属性の値を "basicHttpBinding" に変更します。.NET Compact Framework はテキスト エンコーディングをサポートしますが、バイナリ エンコーディングはサポートしません。
新しい動作の名前を参照するように behaviorConfiguration 属性を変更します。
<behavior> 要素を、この例のように置き換えます。
Web.config ファイル内に HTTP サービス ハンドラを登録する必要がある場合、この例のような情報を指定する新しい <system.WebServer> 要素を追加します。
<?xml version="1.0"?> <configuration xmlns="https://schemas.microsoft.com/.NetConfiguration/v2.0"> <system.serviceModel> <services> <service name="CalculatorService" behaviorConfiguration="MyServiceTypeBehaviors"> <endpoint contract="ICalculatorService" binding="basicHttpBinding"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="MyServiceTypeBehaviors"> <serviceMetadata httpGetEnabled="true" /> <serviceDebug httpHelpPageEnabled="true" includeExceptionDetailInFaults="true" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> <system.web> <compilation debug="true"/> </system.web> <system.webServer> <handlers> <add name="HttpSvcHandler" path="*.svc" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" resourceType="Unspecified" /> </handlers> </system.webServer> </configuration>
WCF サービスのソース コードで、ServiceContract 属性と OperationContract 属性で指定されているすべてのパラメータをコードから削除します。
メモ : この例は、ServiceContract や OperationContract などのコントラクトで指定されるパラメータのサポートを実装しません。これらのコントラクト用のパラメータ サポートが必要な場合は、WCF .NET Compact Framework ServiceModel Utility ツール (NetCFSvcUtil.exe) を使ってクライアント コードを生成できます。このツールは、このような多くのパラメータのサポートを、.NET Compact Framework に基づくアプリケーションの中に構築します。NetCFSvcUtil.exe は Power Toys for .NET Compact Framework に含まれています。詳しくは、「Power Toys for .NET Compact Framework」を参照してください。
次の例は、簡単な電卓アプリケーション用の WCF サービスのソース コードです。
<ServiceContract()> _ Public Interface ICalculatorService <OperationContract()> _ Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double '<OperationContract()> _ Function Subtract(ByVal n1 As Double, ByVal n2 As Double) As Double End Interface Public Class CalculatorService Implements ICalculatorService Public Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculatorService.Add Return n1 + n2 End Function Public Function Subtract(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculatorService.Subtract Return n1 - n2 End Function End Class
[ServiceContract()] public interface ICalculatorService { [OperationContract] double Add(double n1, double n2); [OperationContract] double Subtract(double n1, double n2); } public class CalculatorService : ICalculatorService { public double Add(double n1, double n2) { return n1 + n2; } public double Subtract(double n1, double n2) { return n1 - n2; } }
WCF サービスを、Web サーバー上の特定のポートに設定します。
10000 ~ 650000 の範囲の任意のポート番号を使用できます。この例ではポート 50505 を使用しています。
Web サーバーを起動します。
localhost 上で Web サービス記述言語 (WSDL: Web Services Description Language) 出力を表示しサービスを実行するには、https://localhost:50505/CalculatorService/Service.svc?wsdl を参照します。WCF サービス用に指定したのと同じポート番号および Web プロジェクト名を使用してください。
リモート コンピュータまたはデバイスから Web サーバーに接続する予定の場合は、Web プロジェクトを格納するディレクトリを指すように仮想ディレクトリを設定します。
メモ : Visual Studio の ASP.NET 開発サーバーは、ローカルの開発コンピュータからの要求だけに応答します。仮想ディレクトリを指定するには Internet Information Services (IIS) を使用することをお勧めします。こうすると、サーバーが到達可能である限り、リモート デバイスから Web サーバーに接続できます。
デスクトップ ブラウザおよびデバイス ブラウザからディレクトリにアクセスできることを確認します。
.NET Compact Framework クライアントを作成するには
サービスの実行中に、コマンド ラインを開いて、WCF サービスが入っているディレクトリに移動します。
コマンド ラインから、WCF ServiceModel Desktop Utility ツール (SvcUtil.exe) を実行して WCF クライアント プロキシを生成します。SvcUtil を呼び出すためのコマンド ラインの例を次に示します。ここではサービスが localhost でホストされています。
svcutil.exe /language:c# https://localhost:50505/CalculatorService/Service.svc
次の例は、簡単な電卓の例に基づく SvcUtil によって生成されるクライアント プロキシを示しています。
//------------------------------------------------------------------------------ // <auto-generated> // This code was generated by a tool. // Runtime Version:2.0.50727.42 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // </auto-generated> //------------------------------------------------------------------------------ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")] [System.ServiceModel.ServiceContractAttribute(ConfigurationName="ICalculatorService")] public interface ICalculatorService { [System.ServiceModel.OperationContractAttribute(Action="https://fabrikam.com/ICalculatorService/Add", ReplyAction="https://fabrikam.com/ICalculatorService/AddResponse")] double Add(double n1, double n2); [System.ServiceModel.OperationContractAttribute(Action="https://fabrikam.com/ICalculatorService/Subtract", ReplyAction="https://fabrikam.com/ICalculatorService/SubtractResponse")] double Subtract(double n1, double n2); } [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")] public interface ICalculatorServiceChannel : ICalculatorService, System.ServiceModel.IClientChannel { } [System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")] public partial class CalculatorServiceClient : System.ServiceModel.ClientBase<ICalculatorService>, ICalculatorService { public CalculatorServiceClient() { } public CalculatorServiceClient(string endpointConfigurationName) : base(endpointConfigurationName) { } public CalculatorServiceClient(string endpointConfigurationName, string remoteAddress) : base(endpointConfigurationName, remoteAddress) { } public CalculatorServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : base(endpointConfigurationName, remoteAddress) { } public CalculatorServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : base(binding, remoteAddress) { } public double Add(double n1, double n2) { return base.Channel.Add(n1, n2); } public double Subtract(double n1, double n2) { return base.Channel.Subtract(n1, n2); } }
生成されたクライアント プロキシ コードから、以下のものを含む、サポートされない属性と要素を削除します。
すべての System.ServiceModel 属性。
IClientChannel クラスへの参照。
<endpoint> 構成名への参照。
内部チャネル上の ServiceContract インターフェイスのメソッドを呼び出すメソッド実装。
このように変更した後のコードは、次の例のようになります。
'------------------------------------------------------------------------------ ' <auto-generated> ' This code was generated by a tool. ' Runtime Version:2.0.50727.312 ' ' Changes to this file may cause incorrect behavior and will be lost if ' the code is regenerated. ' </auto-generated> '------------------------------------------------------------------------------ Option Strict Off Option Explicit On Public Interface ICalculatorService Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double Function Subtract(ByVal n1 As Double, ByVal n2 As Double) As Double End Interface Partial Public Class CalculatorServiceClient Inherits System.ServiceModel.ClientBase(Of ICalculatorService) Implements ICalculatorService ' Add a variable containing the endpoint address. Public Shared ServiceEndPoint As New System.ServiceModel.EndpointAddress("https://fabrikam.com/CalcService/CalculatorService/Service.svc") Public Sub New(ByVal binding As System.ServiceModel.Channels.Binding, ByVal remoteAddress As System.ServiceModel.EndpointAddress) MyBase.New(binding, remoteAddress) End Sub Public Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculatorService.Add Return MyBase.Channel.Add(n1, n2) End Function Public Function Subtract(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculatorService.Subtract Return MyBase.Channel.Subtract(n1, n2) End Function End Class
//------------------------------------------------------------------------------ // <auto-generated> // This code was generated by a tool. // Runtime Version:2.0.50727.42 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // </auto-generated> //------------------------------------------------------------------------------ public interface ICalculatorService { double Add(double n1, double n2); double Subtract(double n1, double n2); } public partial class CalculatorServiceClient : System.ServiceModel.ClientBase<ICalculatorService>, ICalculatorService { // Add a variable to specify the server address. public static System.ServiceModel.EndpointAddress ServiceEndPoint = new System.ServiceModel.EndpointAddress("https://fabrikam.com/CalcService/CalculatorService/Service.svc"); public CalculatorServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : base(binding, remoteAddress) { } public double Add(double n1, double n2) { return base.Channel.Add(n1, n2); } public double Subtract(double n1, double n2) { return base.Channel.Subtract(n1, n2); } }
クライアント プロジェクトを作成します。
生成されたクライアント プロキシをプロジェクトに追加します。
生成されたプロキシ コード内で、ClientBase<TChannel> への完全修飾された参照をユーザー定義の ClientBase クラスに変更します。
生成されたプロキシ コード内で、ユーザー定義の ClientBase クラス内の Call メソッドを呼び出すことにより、メソッド実装を追加します。
Public Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculatorService.Add Return System.Convert.ToDouble(MyBase.Call("Add", "https://fabrikam.com/CalcService/ICalculatorService/Add", New String() {"n1", "n2"}, New Object() {n1, n2}, GetType(Double))) End Function
public double Add(double n1, double n2) { return (double)base.Call("Add", "https://fabrikam.com/CalcService/ICalculatorService/Add", new string[] { "n1", "n2" }, new object[] { n1, n2 }, typeof(double)); }
プロキシの基本クラスをプロジェクトに追加します。このクラスの名前は ClientBase です。
ClientBase の実装を指すように、クライアント プロキシの基本クラス参照を変更します。
メモ : この例では、ClientBase 内の CustomBodyWriter クラスはプリミティブ型だけをサポートします。非プリミティブ型をサポートするには、OnWriteBodyContents メソッドを拡張する必要があります。たとえば、カスタム シリアライザを呼び出してメッセージ データをシリアル化することができます。この場合、生成されたクライアント プロキシ内のコード属性を、XML シリアライザで処理可能な属性に変換できます。このシナリオでは、SvcUtil 実行時に、まず /serializer:xmlserializer http://endpoint というスイッチを追加する必要があります。
次のコードは、ClientBase クラスの例を示しています。
Public Class ClientBase(Of TChannel As Class) Private requestChannel As IRequestChannel Private messageVersion As MessageVersion Public Sub New(ByVal binding As System.ServiceModel.Channels.Binding, ByVal remoteAddress As System.ServiceModel.EndpointAddress) 'this.remoteAddress = remoteAddress; Me.messageVersion = binding.MessageVersion Dim channelFactory As IChannelFactory(Of IRequestChannel) channelFactory = binding.BuildChannelFactory(Of IRequestChannel)(New BindingParameterCollection()) channelFactory.Open() Me.requestChannel = channelFactory.CreateChannel(remoteAddress) End Sub Public Function [Call](ByVal op As String, ByVal action As String, ByVal varnames() As String, ByVal varvals() As Object, ByVal returntype As Type) As Object requestChannel.Open(TimeSpan.MaxValue) Dim msg As Message = Message.CreateMessage(Me.messageVersion, action, New CustomBodyWriter(op, varnames, varvals, "<ns passed in from Proxy>")) Dim reply As Message = requestChannel.Request(msg, TimeSpan.MaxValue) Dim reader As XmlDictionaryReader = reply.GetReaderAtBodyContents() reader.ReadToFollowing(op + "Result") Return reader.ReadElementContentAs(returntype, Nothing) End Function End Class Friend Class CustomBodyWriter Inherits BodyWriter Private op As String Private varnames() As String Private varvals() As Object Private ns As String Public Sub New(ByVal op As String, ByVal varnames() As String, ByVal varvals() As Object, ByVal ns As String) MyBase.New(True) Me.op = op Me.varnames = varnames Me.varvals = varvals Me.ns = ns End Sub Protected Overrides Sub OnWriteBodyContents(ByVal writer As XmlDictionaryWriter) writer.WriteStartElement(op, ns) Dim i As Integer For i = 0 To varnames.Length writer.WriteElementString(varnames(i), varvals(i).ToString()) Next i writer.WriteEndElement() End Sub End Class
public class ClientBase<TChannel> where TChannel : class { private IRequestChannel requestChannel; private MessageVersion messageVersion; public ClientBase(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) { //this.remoteAddress = remoteAddress; this.messageVersion = binding.MessageVersion; IChannelFactory<IRequestChannel> channelFactory = binding.BuildChannelFactory<IRequestChannel>( new BindingParameterCollection()); channelFactory.Open(); this.requestChannel = channelFactory.CreateChannel(remoteAddress); } public object Call(string op, string action, string[] varnames, object[] varvals, Type returntype) { requestChannel.Open(TimeSpan.MaxValue); //Message msg = //Message.CreateMessage(MessageVersion.<FromBinding>, // action, // new CustomBodyWriter(op, varnames, varvals, //"<ns passed in from Proxy>")); Message msg = Message.CreateMessage(this.messageVersion, action, new CustomBodyWriter(op, varnames, varvals, "<ns passed in from Proxy>")); Message reply = requestChannel.Request(msg, TimeSpan.MaxValue); XmlDictionaryReader reader = reply.GetReaderAtBodyContents(); reader.ReadToFollowing(op + "Result"); return reader.ReadElementContentAs(returntype, null); } } internal class CustomBodyWriter : BodyWriter { private string op; private string[] varnames; private object[] varvals; private string ns; public CustomBodyWriter(string op, string[] varnames, object[] varvals, string ns) : base(true) { this.op = op; this.varnames = varnames; this.varvals = varvals; this.ns = ns; } protected override void OnWriteBodyContents(XmlDictionaryWriter writer) { writer.WriteStartElement(op, ns); for (int i = 0; i < varnames.Length; i++) writer.WriteElementString(varnames[i], varvals[i].ToString()); writer.WriteEndElement(); } }
クライアント プロキシをインスタンス化および使用するクラスを追加します。
クライアント プロキシを呼び出すコードの例を次に示します。
Shared Sub Main(ByVal args() As String) Dim serverAddress As String = CalculatorServiceClient.ServiceEndPoint.Uri.AbsoluteUri ' Using basic http connection. WS binding should be also available. Dim proxy As ICalculatorService = New CalculatorServiceClient(New BasicHttpBinding, New EndpointAddress(serverAddress)) MessageBox.Show("Add 3 + 6...") MessageBox.Show(proxy.Add(3, 6).ToString) MessageBox.Show("Subtract 8 - 3...") MessageBox.Show(proxy.Subtract(8, 3).ToString) End Sub
static void Main() { string serverAddress = CalculatorServiceClient.ServiceEndPoint.Uri.AbsoluteUri; // Using basic http connection. WS binding should be also available. ICalculatorService proxy = new CalculatorServiceClient(new BasicHttpBinding(), new EndpointAddress(serverAddress)); MessageBox.Show("Add 3 + 6..."); MessageBox.Show((proxy.Add(3, 6)).ToString()); MessageBox.Show("Subtract 8 - 3..."); MessageBox.Show((proxy.Subtract(8, 3)).ToString()); }
クライアント アプリケーションをビルドして、それをデバイスに配置します。
WCF サービスが実行中で、デバイスがネットワークに接続されているときに、デバイス上のクライアント アプリケーションを起動します。
コードのコンパイル方法
WCF サービスのソース コードでは、以下の名前空間への参照が必要です。
ClientBase クラスのソース コードでは、以下の名前空間への参照が必要です。
クライアント アプリケーション内の Main メソッドを含むクラスのソース コードでは、以下の名前空間への参照が必要です。
セキュリティ
この例では、WCF セキュリティ機能は何も実装されていません。サポートされるセキュリティ機能の詳細については、「.NET Compact Framework でのメッセージング」を参照してください。
参照
概念
.NET Compact Framework でのメッセージング
その他の技術情報
Windows Communication Foundation (WCF) 開発と .NET Compact Framework