[英]Azure Relay Service Bus with webHttpRelayBinding with REST/JSON and POST
以下文章介绍了如何使用Azure中继服务总线构建简单的WCF服务: https : //azure.microsoft.com/zh-cn/documentation/articles/service-bus-dotnet-how-to-use-relay/示例显示了TCP绑定的用法。 我复制了它,它的工作无懈可击。 现在,我想要与webHttpRelayBinding相同,但无法按预期工作。 我将服务代码拆分为一个通用的dll,一个WCFServiceWebRole项目,一个命令行主机(作为web.config的替代)和客户端:
具有接口定义的通用dll和具有总线密钥,名称空间和协议(tcp或http)名称空间WCFRelayCommon {使用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();
}
}
}
我只需要将设置参数更改为http或tcp即可使用webHttpRelayBinding或netTcpRelayBiding
如前所述,使用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门户上进行一些配置? 我只是按照教程中的说明进行操作...
通过处理WebHttpBinding / WebHttpRelayBinding时,将WCFRelayClient.Program.CreateChannel
方法更改为使用WebChannelFactory<T>
,可以使您的示例在“ http”模式下工作:
static IProblemSolverChannel CreateChannel(Binding binding, Uri uri, TransportClientEndpointBehavior transportClientEndpointBehavior)
{
ChannelFactory<IProblemSolverChannel> cf;
if (binding is WebHttpBinding || binding is WebHttpRelayBinding)
{
cf = new WebChannelFactory<IProblemSolverChannel>(binding, uri);
}
else
{
cf = new ChannelFactory<IProblemSolverChannel>(binding, new EndpointAddress(uri));
}
cf.Endpoint.Behaviors.Add(transportClientEndpointBehavior);
return cf.CreateChannel();
}
如果使用* HttpRelayBinding以外的其他HTTP客户端进行发送,并且中继端点需要客户端身份验证,则需要构建SAS令牌并将授权放入HTTP Authorization标头中。
NodeJs,JAVA,PHP,C#示例以及如何构建SAS令牌的一般说明: https ://azure.microsoft.com/zh-cn/documentation/articles/service-bus-sas-overview/
该页面似乎有一个Javascript示例(我尚未验证它的工作原理): http : //developers.de/blogs/damir_dobric/archive/2013/10/17/how-to-create-shared-access-signature- for-service-bus.aspx
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.