次の記事では、Azure Relay Service Bus を使用して単純な WCF サービスを構築する方法について説明してい ます 。例は、TCP バインディングでの使用を示しています。私はそれを再現し、完璧に動作します。今、私は webHttpRelayBinding でも同じことを望んでいますが、期待どおりに機能しません。サービスのコードを、共通の dll、WCFServiceWebRole プロジェクト、およびコマンド ライン ホスト (web.config の代わりとして) とクライアントに分割します。
バス キー、名前空間、およびプロトコル (tcp または http) を含むインターフェイス定義と設定ファイルを含む共通 dll 名前空間 WCFRelayCommon { using System.ServiceModel; System.ServiceModel.Web の使用;
[ServiceContract(Namespace = "urn:ps")]
public interface IProblemSolver
{
[OperationContract
WebInvoke(UriTemplate = "/solver", Method = "POST",
RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Wrapped)]
int AddNumbers(int a, int b);
}
public interface IProblemSolverChannel : IProblemSolver, IClientChannel { }
public enum BusProtocol { tcp, http };
public class Utils
{
public static BusProtocol Protocol
{
get
{
BusProtocol mode;
if (!Enum.TryParse(AzureSettings.Default.Protocol, out mode))
{
throw new ArgumentException("wrong input, exiting");
}
return mode;
}
}
}
}
WCFServiceWebRole プロジェクト。最初に Web.config ですべてのサービス設定 (動作、入札) を定義したので、そのままで十分です。
namespace WCFServiceWebRoleRelay
{
public class ProblemSolver : WCFRelayCommon.IProblemSolver
{
public int AddNumbers(int a, int b)
{
return a + b;
}
}
}
しかし、デバッグしやすいように、すべての設定をコードで行う代替ホスト プロジェクトも定義しました。したがって、設定ファイルを使用したコマンド ライン プロジェクトのみです。2 つの実装: NetTcpRelayBinding または WebHttpRelayBinding を使用。安全な輸送で。
namespace WCFRelayHost
{
class Program
{
static void Main(string[] args)
{
var transportClientEndpointBehavior = new TransportClientEndpointBehavior
{
TokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider("RootManageSharedAccessKey", AzureSettings.Default.BusKey)
};
ServiceHost sh;
switch (Utils.Protocol)
{
case BusProtocol.http:
sh = CreateWebHost(AzureSettings.Default.BusNamespace, transportClientEndpointBehavior);
break;
case BusProtocol.tcp:
sh = CreateTcpBindingHost(AzureSettings.Default.BusNamespace, transportClientEndpointBehavior);
break;
default:
throw new Exception("wrong mode");
}
sh.Open();
Console.WriteLine("Press ENTER to close");
Console.ReadLine();
sh.Close();
}
static ServiceHost CreateTcpBindingHost(string busNamespace, TransportClientEndpointBehavior transportClientEndpointBehavior)
{
Uri tcpAddress = ServiceBusEnvironment.CreateServiceUri("sb", busNamespace, "solver");
ServiceHost sh = new ServiceHost(typeof(ProblemSolver));
var binding = new NetTcpRelayBinding(EndToEndSecurityMode.Transport, new RelayClientAuthenticationType());
return AddServiceEndpoint(sh, binding, tcpAddress, transportClientEndpointBehavior);
}
static ServiceHost CreateWebHost(string busNamespace, TransportClientEndpointBehavior transportClientEndpointBehavior)
{
// https://<namespace>.servicebus.windows.net/solver
Uri webAddress = ServiceBusEnvironment.CreateServiceUri("https", busNamespace, "solver");
var binding = new WebHttpRelayBinding(EndToEndWebHttpSecurityMode.Transport, new RelayClientAuthenticationType());
WebServiceHost wsh = new WebServiceHost(typeof(ProblemSolver), webAddress);
return AddServiceEndpoint(wsh, binding, webAddress, transportClientEndpointBehavior);
}
static ServiceHost AddServiceEndpoint(ServiceHost sh, Binding binding, Uri uri, TransportClientEndpointBehavior transportClientEndpointBehavior)
{
sh.AddServiceEndpoint(typeof(IProblemSolver), binding, uri).Behaviors.Add(transportClientEndpointBehavior);
return sh;
}
}
}
そして、クライアント コマンド ライン アプリ。
namespace WCFRelayClient
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enter 2 numbers to add separated by space");
var line = Console.ReadLine();
var array = line.Split(' ');
int first, second;
if (!int.TryParse(array[0], out first) || !int.TryParse(array[1], out second))
{
Console.WriteLine("wrong input, exiting");
}
else
{
Console.WriteLine("Wait the host to run, press ENTER when ready to send the request");
Console.ReadLine();
var transportClientEndpointBehavior = new TransportClientEndpointBehavior
{
TokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider("RootManageSharedAccessKey", AzureSettings.Default.BusKey)
};
IProblemSolverChannel ch;
switch (Utils.Protocol)
{
case BusProtocol.http:
ch = WebBinding(AzureSettings.Default.BusNamespace, transportClientEndpointBehavior);
break;
case BusProtocol.tcp:
ch = TcpBinding(AzureSettings.Default.BusNamespace, transportClientEndpointBehavior);
break;
default:
throw new Exception("wrong mode");
}
Console.WriteLine(ch.AddNumbers(first, second));
ch.Dispose();
}
Console.ReadLine();
}
static IProblemSolverChannel TcpBinding(string busNamespace, TransportClientEndpointBehavior transportClientEndpointBehavior)
{
var binding = new NetTcpRelayBinding(EndToEndSecurityMode.Transport, new RelayClientAuthenticationType());
var uri = ServiceBusEnvironment.CreateServiceUri("sb", busNamespace, "solver");
return CreateChannel(binding, uri, transportClientEndpointBehavior);
}
static IProblemSolverChannel WebBinding(string busNamespace, TransportClientEndpointBehavior transportClientEndpointBehavior)
{
var binding = new WebHttpRelayBinding(EndToEndWebHttpSecurityMode.Transport, new RelayClientAuthenticationType());
var uri = ServiceBusEnvironment.CreateServiceUri("https", busNamespace, "solver");
return CreateChannel(binding, uri, transportClientEndpointBehavior);
}
static IProblemSolverChannel CreateChannel(Binding binding, Uri uri, TransportClientEndpointBehavior transportClientEndpointBehavior)
{
var cf = new ChannelFactory<IProblemSolverChannel>(binding, new EndpointAddress(uri));
cf.Endpoint.Behaviors.Add(transportClientEndpointBehavior);
return cf.CreateChannel();
}
}
}
webHttpRelayBinding または netTcpRelayBiding のいずれかを使用するには、設定パラメーターを http または tcp に変更するだけです。
前述のとおり、netTcpRelayBiding を使用すると、コードは期待どおりに実行されます。
webHttpRelayBinding を使用すると、mscorlib で InvalidOperationException が発生します
System.InvalidOperationException was unhandled
HResult=-2146233079
Message=Manual addressing is enabled on this factory, so all messages sent must be pre-addressed.
Source=mscorlib
私は何を取りこぼしたか?おそらく、Azure ポータルでの構成でしょうか。チュートリアルの指示に従っただけです...