使用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. 安卓TextView限定行数最大值,点击按钮显示所有内容

    问题展示 如上图所示,在普通的TextView中,要求: 最多显示3行 超过三行显示展开按钮 且点击展开按钮显示完整内容 这个需求看似简单,但解决起来会遇到两个较为棘手的问题:1,如何判断是否填满了前 ...

  2. UGUI ScrollRect 性能优化

    测试环境 操作系统:Windows8.1 开发工具:Unity5.5.2 1.问题描述,在实际开发过程中经常会使用ScrollRect实现滚动列表,当初次加载数据比较多的情形时,Unity3D会出现比 ...

  3. 原生JS Ajax 请求

    var username = document.getElementById('username').value; var password = document.getElementById('pa ...

  4. Day1-模块初识

    模块,也叫库,分为标准库和第三方库.标准库,直接导入使用,比如import getpass:第三方库,需下载安装才能使用,比如paramiko: 一.sys模块 import sys print(sy ...

  5. MacBook使用之配置jdk&Eclipse

    查看系统版本:关于本机-软件-查看当前版本信息 打开另一个Finder的快捷键:Command + n 终端命令:Finder - 使用工具 - 终端命令 配置jdk系统变量: cd ~ touch ...

  6. GRPC在NET上的实践(记录篇)

    GRPC是什么? GRPC是一个开源RPC框架,于2015年3月开源,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于Protobuf 3.0(Protocol Buffer ...

  7. JMeter-MyEclipse编译运行问题(Could not read JMeter properties file)

    JMeter-MyEclipse编译运行问题按照 此贴 http://phoenix0529.iteye.com/blog/1530728 进行配置,然后用Ant编译Build.xml 是可以的. 但 ...

  8. wampServer 2.5 64位 更改"www 目录"不成功

    已经指到自己新目录了,修改了 apache的httpd.conf里面的内容如下 修改: DocumentRoot "e:/phproot/" 修改: <Directory & ...

  9. 关于用css实现文本和图片垂直水平居中

    关于用css实现文本和图片垂直水平居中   一直相信好记性不如烂笔头,最近遇到很多用到垂直居中的,整理一下以便日后查阅. 一.文本垂直水平居中 1.水平居中: 文字水平居中没什么好说的,用text-a ...

  10. Python教程(2.1)——控制台输入

    这一节,我们来学习如何写一个简单的Python程序. 我们知道,很多编程语言一开始就是学习怎么输出"Hello, world",对吧?那么,现在我们来学习怎么用Python输出&q ...