C# Azure中继服务总线,带有webHttpRelayBinding和REST/JSON和POST
下面的文章解释了如何使用Azure中继服务总线构建简单的WCF服务: 该示例显示了如何使用TCP绑定。我复制了它,它工作得完美无缺。现在,我希望webHttpRelayBinding也能做到这一点,但它不能像预期的那样工作。 我将代码拆分为公共dll、WCFServiceWebRole项目、命令行主机(作为web.config的替代)和客户端中的服务: 带有接口定义的公共dll和带有总线密钥、命名空间和协议(tcp或http)的设置文件 名称空间wcfrelaycomon { 使用System.ServiceModel; 使用System.ServiceModel.WebC# Azure中继服务总线,带有webHttpRelayBinding和REST/JSON和POST,c#,wcf,tcp,https,azure-servicebusrelay,C#,Wcf,Tcp,Https,Azure Servicebusrelay,下面的文章解释了如何使用Azure中继服务总线构建简单的WCF服务: 该示例显示了如何使用TCP绑定。我复制了它,它工作得完美无缺。现在,我希望webHttpRelayBinding也能做到这一点,但它不能像预期的那样工作。 我将代码拆分为公共dll、WCFServiceWebRole项目、命令行主机(作为web.config的替代)和客户端中的服务: 带有接口定义的公共dll和带有总线密钥、命名空间和协议(tcp或http)的设置文件 名称空间wcfrelaycomon { 使用System.
[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种实现:使用NetCPRelayBinding或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;
}
}
}
我错过了什么?
可能是Azure门户上的一些配置?我只是按照教程中的说明进行操作…我可以通过更改
WCFRelayClient.Program.CreateChannel
方法,使您的示例在处理WebHttpBinding/WebHttpRelayBinding时使用WebChannelFactory
:
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();
}
静态IProbleSolverChannel CreateChannel(绑定绑定、Uri Uri、TransportClientEndpointBehavior TransportClientEndpointBehavior)
{
信道工厂cf;
if(绑定是WebHttpBinding | |绑定是WebHttpRelayBinding)
{
cf=新的WebChannelFactory(绑定,uri);
}
其他的
{
cf=新的ChannelFactory(绑定,新的端点地址(uri));
}
cf.Endpoint.Behaviors.Add(transportClientEndpointBehavior);
返回cf.CreateChannel();
}
如果使用*HttpRelayBinding以外的HTTP客户端发送,并且中继端点需要客户端身份验证,则需要构建SAS令牌并将授权放入HTTP授权头中
NodeJs、JAVA、PHP、C#关于如何构建SAS令牌的示例和一般说明:
此页面似乎有一个Javascript示例(我尚未验证它是否有效):
在另一个项目中,我成功地使用了带有GET方法的webHttpRelayBinding,但仍然没有使用POST方法。好极了,WebChannelFactory确实是缺失的一点!很明显,我的CreateChannel方法不再那么有意义了,我将ChannelFactory调用直接放在上面的方法中。但是,由于答案是替换了ex实际上我的方法错了!使用WebChannelFactory很有意义。我还想知道ch.addNumber(第一,第二)是如何使用的方法在http示例中处理JSON。现在我知道它是由WebChannelFactory完成的!我只通过配置文件实现了同样的目标:可能有许多客户端端点,但只有一个具有完整地址的服务主机。下一步:如果我只使用浏览器REST客户端,如Chrome中的ARC/“Advanced REST client”,我应该如何“编码”JSON中的azure总线密钥?还是应该将其放在请求uri中?
System.InvalidOperationException was unhandled
HResult=-2146233079
Message=Manual addressing is enabled on this factory, so all messages sent must be pre-addressed.
Source=mscorlib
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();
}