李甲蔚

你创想,云实现

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

在Worker Role中承载WCF服务,首先需要配置Endpoint,这个例子配置了Internal和External两个Endpoint,Internal Endpoint仅供Cloud Service内部调用(外部无法访问),External Endpoint可供本地(云之外)的应用调用,配置如图所示:

此处使用TCP协议,注意到对于Internal Endpoint,其端口是动态分配的,在运行时才能获取到分配的端口号。

配置好Endpoint以后,则可以发布WCF服务,代码如下:

this.serviceHost = new ServiceHost(typeof(UserService));

ServiceMetadataBehavior metadataBehavior;
metadataBehavior = this.serviceHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (metadataBehavior == null)
{
    metadataBehavior = new ServiceMetadataBehavior();
    this.serviceHost.Description.Behaviors.Add(metadataBehavior);
}

NetTcpBinding tcpBinding = new NetTcpBinding(SecurityMode.None);;

Binding mexTcpBinding = MetadataExchangeBindings.CreateMexTcpBinding();

//Get the Internal Endpoint(dynamic port) at runtime
RoleInstanceEndpoint internalEndpoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["Internal"];

this.serviceHost.AddServiceEndpoint(
   typeof(IUserContract),
   tcpBinding,
   String.Format("net.tcp://{0}/Internal", internalEndpoint.IPEndpoint));


this.serviceHost.AddServiceEndpoint(
    typeof(IMetadataExchange),
    mexTcpBinding,
    String.Format("net.tcp://{0}/MEX", internalEndpoint.IPEndpoint));

RoleInstanceEndpoint externalEndpoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["External"];

this.serviceHost.AddServiceEndpoint(
   typeof(IUserContract),
   tcpBinding,
   String.Format("net.tcp://{0}/External", externalEndpoint.IPEndpoint));

this.serviceHost.AddServiceEndpoint(
    typeof(IMetadataExchange),
    mexTcpBinding,
    String.Format("net.tcp://{0}/MEX", externalEndpoint.IPEndpoint));

try
{
    this.serviceHost.Open();
    Trace.WriteLine("WCF service host started successfully.", "Information");
}
catch (TimeoutException timeoutException)
{
    Trace.WriteLine("The service operation timed out. " + timeoutException.Message, "Error");
}
catch (CommunicationException communicationException)
{
    Trace.WriteLine("Could not start WCF service host. " + communicationException.Message, "Error");
}
catch (Exception ex)
{
    Trace.WriteLine(ex.Message, "Error");
}

这段代码是典型的发布WCF服务的代码,通过添加MEX终结点使得可以解析元数据。在WorkerRole的Run方法中执行该段代码,当Worker Role启动时则会启动WCF服务。
WCF服务发布完成以后,我们来尝试通过Cloud Service内部和外部方式来访问这两个Endpoint。

首先,我们在Cloud Service内部的Web Role中来访问Internal Endpoint。

在访问内部Endpoint时,需要获得Worker Role的Instance,通过InstanceEndpoints获取动态分配的端口号。Client端调用服务的代码如下:

IUserContract service = null;

NetTcpBinding tcpBinding = new NetTcpBinding(SecurityMode.None, false);
EndpointAddress address = null;

string endpointType = "Internal";
string serviceRoleName = "WorkerRoleName";
Role serviceRole = RoleEnvironment.Roles[serviceRoleName];
if (serviceRole.Instances.Count > 0)
{
    RoleInstance instance = serviceRole.Instances[0];
    RoleInstanceEndpoint endpoint = instance.InstanceEndpoints[endpointType];
    address = new EndpointAddress(string.Format("net.tcp://{0}/" + endpointType, endpoint.IPEndpoint));
}

if(address != null)
{
    service = ChannelFactory<IUserContract>.CreateChannel(tcpBinding, address);
}

return service;

请注意:在初始化NetTcpBinding时,由于服务端的安全模式为None,所以客户端必须保持一致。

接下来,我们通过本地WcfTestClient.exe来测试External Endpoint。

(WcfTestClient.exe所在目录,C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE)

在WcfTextClient加入服务地址:net.tcp://[yourdomain.cloudapp.net]:10100/mex,其中yourdomain需要替换成自己的Cloud Service的名字。

具体地址请登录Portal获取,如图所示:

通过WcfTestClient解析后,我们发现不仅是External Endpoint,Internal Endpoint同样被解析出来了。如配置文件所示:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.serviceModel>
        <bindings>
            <netTcpBinding>
                <binding name="NetTcpBinding_IUserContract" sendTimeout="00:05:00">
                    <security mode="None" />
                </binding>
            </netTcpBinding>
        </bindings>
        <client>
            <endpoint address="net.tcp://10.146.150.136:20000/Internal" binding="netTcpBinding"
                bindingConfiguration="NetTcpBinding_IUserContract" contract="IUserContract"
                name="NetTcpBinding_IUserContract" />
            <endpoint address="net.tcp://10.146.150.136:10100/External" binding="netTcpBinding"
                bindingConfiguration="NetTcpBinding_IUserContract" contract="IUserContract"
                name="NetTcpBinding_IUserContract1" />
        </client>
    </system.serviceModel>
</configuration>

我们需要将Internal Endpoint的配置删除,因为根据Azure的安全策略,该Endpoint从外部无法访问。

还有一点非常关键的是,我们看到在address URL中,域名被替换成了IP,这是Worker Role所在虚拟机的内部IP,通过这个IP我们是无法成功调用服务的,需要将IP替换成域名,让Azure DNS去自动解析。修改后的配置如下:

 

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.serviceModel>
        <bindings>
            <netTcpBinding>
                <binding name="NetTcpBinding_IUserContract" sendTimeout="00:05:00">
                    <security mode="None" />
                </binding>
            </netTcpBinding>
        </bindings>
        <client>
            <endpoint address="net.tcp://[yourdomain.cloudapp.net]:10100/External" binding="netTcpBinding"
                bindingConfiguration="NetTcpBinding_IUserContract" contract="IUserContract"
                name="NetTcpBinding_IUserContract1" />
        </client>
    </system.serviceModel>
</configuration>

 

同理,我们在Visual Studio通过Add Service Reference来添加WCF服务时也需要做出上述修改。然后,我们就能成功从外部调用Worker Role Input类型的终结点了。

 

posted on 2013-01-14 22:51  李甲蔚  阅读(621)  评论(0编辑  收藏  举报