使用VPN或者ER服务建立云服务和本地服务网络通道来搭建混合应用的方式,需要网络设备的配合和比较复杂的网络配置,所以不是特别的方便。如果是不希望对本地网络环境做修改,而只是服务层面的混合,那么可以使用一个更方便的服务 – Azure中继服务。基于Azure中继服务访问本地服务,客户端不需要与本地服务建立直接连接,也不需要了解服务所在的位置,并且本地服务无需在防火墙上打开任何入站端口。

Azure中继服务支持传统的单向消息传送、请求/响应消息传送和对等消息传送。它还支持 Internet 范围的事件分发,以实现发布-订阅方案和双向套接字通信,从而提高点到点通信效率。在中继消息传送模式中,本地服务会通过出站端口连接至中继服务,并为绑定至特定会合地址的通信创建一个双向套接字。然后,客户端可以通过将消息发送到抵达会合地址的中继服务来与本地服务通信。

目前Azure提供两种中继服务,WCF(Windows Communication Foundation)中继和混合连接。其中WCF中继是传统的服务,适合于基于WCF的本地服务。(关于WCF请参阅 WCF 官方文档)。而混合连接使用开放标准Web套接字,可实现多平台方案,适用性更广。

本文介绍如何使用WCF中继来构建混合应用。

WCF中继

WCF中继允许你向公有云公开位于企业网络内的WCF服务,而无需打开防火墙连接,也无需对企业网络基础结构进行彻底的更改。而且它还允许你安全的控制谁可以访问这些服务。另外对你原来的WCF项目所需要做的改动也是很小的。

基于TCP的SOAP访问

适用于支持SOAP协议的客户端。

创建WCF中继服务

可以登陆Azure中国门户网站,按照界面提示一步步创建。也可以通过PowerShell命令,如下,其中创建wcf中继时,WcfRelayType设置为NetTcp。RequiresTransportSecurity和RequiresClientAuthorization默认都是true,这里显示指定只是处于演示作用。

# login to Azure China with your account
Login-AzureRmAccount -Environment AzureChinaCloud $rgName = "relaydemorg"
$namespaceName = "relaydemons"
$location = "China East"
$relayType = "NetTcp"
$relayName = "tcpdata" New-AzureRmResourceGroup -Name $rgName -Location $location
New-AzureRmRelayNamespace -ResourceGroupName $rgName -Name $namespaceName -Location $location
New-AzureRmWcfRelay -ResourceGroupName $rgName -Namespace $namespaceName -Name $relayName -WcfRelayType $relayType -RequiresTransportSecurity $true -RequiresClientAuthorization $true

创建出来的WCF中继服务地址是sb://relaydemons.servicebus.chinacloudapi.cn/tcpdata

通过WCF中继公开本地WCF服务

给本地服务安装服务总线NuGet包,默认安装最新版本。

PM> Install-Package WindowsAzure.ServiceBus

安装完成后,在config文件里面会自动添加一些扩展的行为和绑定声明,比如:

<behaviorExtensions>
<add name="transportClientEndpointBehavior"
type="Microsoft.ServiceBus.Configuration.TransportClientEndpointBehaviorElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</behaviorExtensions>
<bindingExtensions>
<add name="netTcpRelayBinding"
type="Microsoft.ServiceBus.Configuration.NetTcpRelayBindingCollectionElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</bindingExtensions>

View

文件配置方式

修改config文件,添加如下endpointBehavior,其中key需要有监听权限

<endpointBehaviors>
<behavior name="sbTokenProvider">
<transportClientEndpointBehavior>
<tokenProvider>
<sharedAccessSignature keyName="<listenKey>" key="<keyValue>" />
</tokenProvider>
</transportClientEndpointBehavior>
</behavior>
</endpointBehaviors>

View

前面创建的WCF中继服务类型时NetTcp,所以这里添加绑定为netTcpRelayBinding的终结点,并指向前面创建的WCF中继服务地址

<endpoint contract="<yourcontract>"
binding="netTcpRelayBinding"
address="sb://relaydemons.servicebus.chinacloudapi.cn/tcpdata"
behaviorConfiguration="sbTokenProvider"/>

View

代码方式

注意,这里中继服务地址不能用ServiceBusEnvironment.CreateServiceUri("sb", "namespace", "tcpdata"))来生成,因为它生成的地址不是中国Azure的。

string relaySvcAddress = "sb://relaydemons.servicebus.chinacloudapi.cn/tcpdata";
ServiceHost sh = new ServiceHost(typeof(<yourservice>));
sh.AddServiceEndpoint(typeof(<yourservice>), new NetTcpRelayBinding(), relaySvcAddress)
.EndpointBehaviors.Add(new TransportClientEndpointBehavior
{
TokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider("listenKey", "keyValue")
});

因为WCF支持对同一个服务使用多个网络终结点,所以可以在添加中继服务终结点以便外部访问的同时保留现有的内部终结点。

创建客户端进行SOAP访问

客户端也需要安装服务总线NuGet包,相应的中继服务相关扩展也会自动添加在Config文件中。

文件配置方式,跟服务端一样,也需要添加同样的endpointBehavior,只是key换成需要发送权限。另外添加跟服务端完全一致的终结点配置。

<endpointBehaviors>
<behavior name="sbTokenProvider">
<transportClientEndpointBehavior>
<tokenProvider>
<sharedAccessSignature keyName="<sendKey>" key="<keyValue>" />
</tokenProvider>
</transportClientEndpointBehavior>
</behavior>
</endpointBehaviors>

View

代码方式也是跟服务端类似,添加相应的NetTcpBinding,终结点地址和TransportClientEndpointBehavior。

string relaySvcAddress = "sb://relaydemons.servicebus.chinacloudapi.cn/tcpdata";
var cf = new ChannelFactory<yourcontract>(
new NetTcpRelayBinding(),
new EndpointAddress(relaySvcAddress)); cf.Endpoint.Behaviors.Add(new TransportClientEndpointBehavior
{
TokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider("<sendKey>","<keyValue>")
});

基于HTTP的REST访问

WCF服务本身支持服务以REST的形式公开出来,那么同样的,客户端也希望能用普通的HTTP来访问。对于这种形式,WCF中继服务也是支持的。

创建WCF中继服务

跟前面TCP方式的步骤一样,唯一的区别是WcfRelayType设置为Http,服务名称也做相应的命名,比如httpdata。这样创建出来的WCF中继服务地址是https://relaydemons.servicebus.chinacloudapi.cn/httpdata

通过WCF中继公开本地WCF服务

与TCP方式对比,有两个不一样的地方

  1. Host使用WebServiceHost
  2. 绑定使用WebHttpRelayBinding

通过HTTP方式公开,默认情况下是可以允许任何客户端访问的,这样不安全,所以需要在WebHttpRelayBinding里配置RelayClientAuthenticationType为RelayAccessToken,这样客户端就必须提供正确令牌才能访问。

文件配置方式

<system.serviceModel>
<bindings>
<webHttpRelayBinding>
<binding name="default">
<security relayClientAuthenticationType="RelayAccessToken"/>
</binding>
</webHttpRelayBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="sbTokenProvider">
<transportClientEndpointBehavior>
<tokenProvider>
<sharedAccessSignature keyName="listenKey" key="keyValue" />
</tokenProvider>
</transportClientEndpointBehavior>
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="yourservice">
<endpoint name="sbRelayEndpoint"
address="https://relaydemons.servicebus.chinacloudapi.cn/httpdata"
binding="webHttpRelayBinding"
bindingConfiguration="default"
behaviorConfiguration="sbTokenProvider"
contract="yourcontract" />
</service>
</services>
<extensions>
<!—Install Microsoft Service Bus NuGet package will automatically add needed all extensions -->
……
</extensions>
</system.serviceModel>

View

代码方式

string relaySvcAddress = "https://relaydemons.servicebus.chinacloudapi.cn/httpdata";
WebServiceHost wsh = new WebServiceHost(typeof(yourservice));
wsh.AddServiceEndpoint(
typeof(yourservice),
new WebHttpRelayBinding(
EndToEndWebHttpSecurityMode.Transport,
RelayClientAuthenticationType.RelayAccessToken),
relaySvcAddress)
.EndpointBehaviors.Add(new TransportClientEndpointBehavior
{
TokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider("listeningKey", "keyValue")
});

客户端

因为前面服务端配置为安全访问方式,所以客户端需要提供正确令牌。那么如何生成令牌呢?有两种方式,一是利用服务总线包里的内置方法,二是自己生成,前者增加了对服务总线包的依赖性,但简单方便,后者需要对服务总线令牌的要求有一定的了解。以下提供两种方式的代码示例。

利用服务总线包的内置方法

var token = TokenProvider.CreateSharedAccessSignatureTokenProvider("keyname", "key").GetWebTokenAsync(resourceUri, string.Empty, true, TimeSpan.FromDays()).Result;

自己生成

private string createToken(string resourceUri, string keyName, string key)
{
TimeSpan sinceEpoch = DateTime.UtcNow - new DateTime(, , );
var week = * * * ;
var expiry = Convert.ToString((int)sinceEpoch.TotalSeconds + week);
string stringToSign = HttpUtility.UrlEncode(resourceUri) + "\n" + expiry;
HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
var sasToken = String.Format(CultureInfo.InvariantCulture,
"SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}",
HttpUtility.UrlEncode(resourceUri),
HttpUtility.UrlEncode(signature),
expiry,
keyName);
return sasToken;
}

示例代码中的resourceUri就是前面创建的中继服务地址:https://relaydemons.servicebus.chinacloudapi.cn/httpdata

有了令牌后,就可以使用Http客户端来调用了,比如使用HttpClient。

string relaySvcAddress = "https://relaydemons.servicebus.chinacloudapi.cn/httpdata";
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Add("Authorization", token);
var requestUri = $"{relaySvcAddress}/yourapimethod";
using (var response = httpClient.GetAsync(requestUri).Result)
{
// handle response
}
}

提示:直接把服务总线的Key提供在客户端是不安全的,可以另外提供一个专门生成token的服务,这样客户端就可以需要的时候就从那个服务获取token,而不是直接拿到Key自己生成。

使用IIS托管服务

当本地服务是用IIS的方式来托管时,有一个特别需要注意的地方,IIS托管的服务只有在接受到请求后才会启动,所以如果一开始直接调用通过中继公开出来的服务是会失败的,因为本地托管在IIS里的服务还没启动,也就还没与中继服务建立链接,因此需要一些额外的配置来预热。那么该如何配置来预热呢?

可以按照以下步骤通过IIS的Application Initialization功能来做到:

确保Application Initialization功能已经安装。(角色 => Web Server (IIS) => Web Server => Application Development)

设置web应用对应的ApplicationPool启动模式为AlwaysRunning

设置web应用Preload Enabled为True

添加如下初始页配置到web应用的web.config中,一般初始页设置为访问wcf svc页面即可。

<system.webServer>
<applicationInitialization>
<add initializationPage="/WebDataService.svc"/>
</applicationInitialization>
</system.webServer>

View

这样的话,就相当于web应用部署好之后会马上访问配置好的初始页来进行预热,从而与Service bus relay建立好链接,客户端就可以访问了。如果IIS重启也会执行预热操作以保证服务的运行。

*完整示例代码:查看

构建混合应用方式之WCF中继的更多相关文章

  1. 构建混合应用方式之 - Azure混合连接

    前面介绍了通过WCF中继构建混合应用的方式,由于对WCF的依赖,使得其使用有一定的局限性,基本上只适用于本地服务是WCF的.NET应用.而混合连接则弥补了这一块的缺陷,除了支持原有WCF中继的功能之外 ...

  2. 完全使用接口方式调用WCF 服务

    客户端调用WCF服务可以通过添加服务引用的方式添加,这种方式使用起来比较简单,适合小项目使用.服务端与服务端的耦合较深,而且添加服务引用的方式生成一大堆臃肿的文件.本例探讨一种使用接口的方式使用WCF ...

  3. WCF技术剖析之二十九:换种不同的方式调用WCF服务[提供源代码下载]

    原文:WCF技术剖析之二十九:换种不同的方式调用WCF服务[提供源代码下载] 我们有两种典型的WCF调用方式:通过SvcUtil.exe(或者添加Web引用)导入发布的服务元数据生成服务代理相关的代码 ...

  4. Post方式调用wcf服务

    我们平常在PC端调用WCF服务,只要知道WCF服务的地址,客户端直接添加引用服务就可以使用了,殊不知还有其他方式,其实,我们也可以 通过HTTP POST的方式调用WCF服务,这样就不用添加引用了,在 ...

  5. 通过代码的方式完成WCF服务的寄宿工作

    使用纯代码的方式进行服务寄宿 服务寄宿的目的是为了开启一个进程,为WCF服务提供一个运行的环境.通过为服务添加一个或者多个终结点,使之暴露给潜在的服务消费,服务消费者通过匹配的终结点对该服务进行调用, ...

  6. 用c/c++混合编程方式为ios/android实现一个自绘日期选择控件(一)

    本文为原创,如有转载,请注明出处:http://www.cnblogs.com/jackybu 前言 章节: 1.需求描述以及c/c++实现日期和月历的基本操作 2.ios实现自绘日期选择控件 3.a ...

  7. 如果选择构建ui界面方式,手写代码,xib和StoryBoard间的博弈

    代码手写UI这种方法经常被学院派的极客或者依赖多人合作的大型项目大规模使用. 大型多人合作项目使用代码构建UI,主要是看中纯代码在版本管理时的优势,检查追踪改动以及进行代码合并相对容易一些. 另外,代 ...

  8. 通过Web Deploy方式部署WCF

    如何发布WCF, 其实它有很多种方式去发布WCF服务到IIS上,这篇文章将介绍通过Web Deploy的发布方式去部署. 步骤: 在IIS上创建一个网站 打开IIS, 右击“Site” -> & ...

  9. 构建混合云:配置Azure site to site VPN连接(1)

      用户在构建自己云计算解决方案的时候,往往会选择私有云或者公有云来做部署,但在一些场景下,用户更加希望通过混合云的方案来满足自己的业务需求.Azure为混合云的部署提供多种不同的连接方案,最常见的是 ...

随机推荐

  1. error C2039: 'SetDefaultDllDirectories'错误解决办法

    使用VS2013+WDK8.1+Win7开发UMDF驱动,当使用了CComPtr类,包含了atlcomcli.h头文件却报错,错误如下: Error 3 error C2039: 'SetDefaul ...

  2. 如何升级php版本---从php5.5.12 升级php7.1.5 wamp实践

    1.从官网下载一个php7.1.5 2.将刚下载的压缩包解压缩,修改命名为php7.1.5,即php+版本号. 3.将这个文件夹放在wamp/bin/php 目录下. 4.将原来版本的php5.5.1 ...

  3. jar包和war包

    Jar (Java archive), 是将实现了某功能的所有类及辅助资源用ZIP压缩形式打包而成的一个文件, 便于代码的管理和重复使用.当使用别人提供的jar时,只需要在classpath环境变量中 ...

  4. 安装配置rsync服务端

    rsync是类unix系统下的数据镜像备份工具——remote sync.一款快速增量备份工具 Remote Sync,远程同步 支持本地复制,或者与其他SSH.rsync主机同步. rsync使用方 ...

  5. java设计模式之 装饰器模式

    装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构. 这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装 ...

  6. sublime text 快捷收集

    1. 文件快速导航: 这是sublime上面很好用的功能之一,ctrl+p可以调出窗口,菜单上的解释是gotoanythings ,确实如其所言,调出窗口后,直接输入关键字,可以在已打开的项目文件夹中 ...

  7. [Leetcode] Binary search, Divide and conquer--240. Search a 2D Matrix II

    Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the follo ...

  8. TeamViewer——可以实现在手机上随时远程控制你的电脑

    小编今天给大家推荐一款强大的远程控制软件——TeamViewer,可以让你的手机连接你自己的电脑,不管你身处何处,只要电脑和手机都能联网,那么你就可以在手机上控制你的电脑了.以下介绍下如何安装和使用方 ...

  9. [BZOJ1597]土地购买

    Description 农夫John准备扩大他的农场,他正在考虑N (1 <= N <= 50,000) 块长方形的土地. 每块土地的长宽满足(1 <= 宽 <= 1,000, ...

  10. 原生javascript实现网页显示日期时钟效果

    刚接触javascript中Date内置对象时,以为这些方法都太简单了,结果要自己实际操作写一个时钟效果还真一时把我难住了,主要有几点大家要注意的.先看实际效果 要实现这样的效果 某年某月某日星期几几 ...