如何在以Azure辅助角色托管的WCF服务中以公共域名发布WSDL? [英] How to publish the WSDL at the public domain name in a WCF service hosted in an Azure worker role?

查看:49
本文介绍了如何在以Azure辅助角色托管的WCF服务中以公共域名发布WSDL?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我以 Azure worker角色托管 WCF 服务.
可通过云服务实例的公共域名(myservice.cloudapp.net)访问该服务,但是,到WSDL的链接以及WSDL中的URL使用内部IP地址代替,无法从外部访问.因此,添加服务引用"和WCFTestClient.exe之类的工具无法正常运行,因为它们尝试访问内部IP地址.

I host a WCF service in an Azure worker role.
The service is accessible at the public domain name of the cloud services instance (myservice.cloudapp.net), however, the links to the WSDL, and the URLs inside the WSDL use the internal IP address instead, that cannot be accessed from outside. Thus tools like Add service reference and WCFTestClient.exe does not work as smoothly as they should, because they try to access the internal IP address.

我正在使用以下代码创建服务:

I am creating my service with the following code:

RoleInstanceEndpoint endpoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["MyServiceEndpoint"];
string endpointAddr = String.Format( "http://{0}/MyInteropService", endpoint.IPEndpoint );

this.serviceHost = new ServiceHost( typeof( MyInteropService ), new Uri( endpointAddr ) );

BasicHttpBinding binding = new BasicHttpBinding();

serviceHost.AddServiceEndpoint( typeof( IMyInteropService ), binding, "" );

ServiceMetadataBehavior smb = new ServiceMetadataBehavior
{
    HttpGetEnabled = true,
    HttpsGetEnabled = true,
};

serviceHost.Description.Behaviors.Add( smb );
//serviceHost.AddServiceEndpoint( ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexHttpBinding(), "mex"); It does not matter whether I include this line or not.

serviceHost.Open();

我做错了什么?我应该如何配置服务以在WSDL中也使用公共域名?

What am I doing wrong? How should I configure the service to use the public domain name in the WSDL as well?

更新:Peter的回答帮助我解决了这个问题,在我的情况下,我只需向服务添加 UseRequestHeadersForMetadataAddressBehavior 行为,然后WSDL使用公共域名称(我想现在它使用客户端将请求发送到的域).

UPDATE: Peter's answer helped me solve the problem, in my case I only had to add a UseRequestHeadersForMetadataAddressBehavior behavior to the service, after that the WSDL used the public domain name (I guess now it uses the domain the client is sending the request to).

因此,完整的工作代码如下:

So the complete working code is the following:

RoleInstanceEndpoint endpoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["MyServiceEndpoint"];
string endpointAddr = String.Format( "http://{0}/MyInteropService", endpoint.IPEndpoint );

this.serviceHost = new ServiceHost( typeof( MyInteropService ), new Uri( endpointAddr ) );

BasicHttpBinding binding = new BasicHttpBinding();

serviceHost.AddServiceEndpoint( typeof( IMyInteropService ), binding, "" );

ServiceMetadataBehavior smb = new ServiceMetadataBehavior
{
    HttpGetEnabled = true,
    HttpsGetEnabled = true,
};

serviceHost.Description.Behaviors.Add( smb );

// This part solved the problem.
var requestHeaderBehavior = new UseRequestHeadersForMetadataAddressBehavior();
this.serviceHost.Description.Behaviors.Add(requestHeaderBehavior);

serviceHost.Open();

推荐答案

我的安全绑定使我的情况有些复杂,对您来说可能会容易一些

my situation was complicated a bit by the security binding I believe, it may be a bit easier for you

好的,所以这里有一些问题.我会看看我是否能正确记住它们.

Okay, so there's a few issues here. I'll see if I can remember them all correctly.

首先,以您希望的方式公开端点,实际上您没有正确的权限(即使您在提升的环境中运行-仍然需要这样做).尝试注册端点时将引发内部错误.

Firstly, to expose the endpoints in the manner that you wish you don't actually have the correct permissions to do so (even if you run in an elevated context - which you will still need to do). It'll throw an internal error when it tries to register the endpoint.

我不得不更改确实有权执行此操作的应用程序池用户(它将与您用于rdp的辅助角色具有相同的凭据.

I had to change the application pool user that did have the rights to do it (it'll be the same credentials as those you use to rdp to the worker roles.

var roleEndpoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["SslEndpoint"];
this.roleProtocol = roleEndpoint.Protocol;
this.rolePort = roleEndpoint.IPEndpoint.Port.ToString();
if (!RoleEnvironment.IsEmulated)
{
      this.roleHostname = "yourexternalhostname.com";
      var appPoolUser = "user";
      var appPoolPass = "password";
      using (var serverManager = new ServerManager())
      {
           string appPoolName = serverManager.Sites[0].Applications.First().ApplicationPoolName;
           var appPool = serverManager.ApplicationPools[appPoolName];
           appPool.ProcessModel.UserName = appPoolUser;
           appPool.ProcessModel.IdentityType = ProcessModelIdentityType.SpecificUser;
           appPool.ProcessModel.Password = appPoolPass;
           appPool.AutoStart = true;
           appPool["startMode"] = "AlwaysRunning";
           appPool.ProcessModel.IdleTimeout = TimeSpan.Zero;
           appPool.Recycling.PeriodicRestart.Time = TimeSpan.Zero;
           serverManager.CommitChanges();
       } 
}
else
{
     this.roleHostname = roleEndpoint.IPEndpoint.Address.ToString();
}

这使我能够配置如下所示的服务,您可能需要根据需要对其进行修改.请密切注意标记为重要的设置,因为我认为这些设置对于公开您的服务至关重要.

This gave me the ability to configure the service like below, you may need to modify it to your needs. Pay close attention to settings marked important as I believe these are vital in exposing your service.

var clientUrl = new Uri(string.Format("{0}://{1}:{2}/{3}", protocol, ip, port, serviceAddress + clientId));
var contractDescription = ContractDescription.GetContract(typeof(TServiceInterface));
var host = new ServiceHost(typeof(TServiceImplementation), clientUrl);

 var serviceBehaviorAttribute = new ServiceBehaviorAttribute();
 serviceBehaviorAttribute.AddressFilterMode = AddressFilterMode.Any; // Important
 serviceBehaviorAttribute.ConcurrencyMode = ConcurrencyMode.Multiple; 
 serviceBehaviorAttribute.InstanceContextMode = InstanceContextMode.PerCall;
 host.Description.Behaviors.Remove<ServiceBehaviorAttribute>();
 host.Description.Behaviors.Add(serviceBehaviorAttribute);

 var serviceMetadataBehavior = new ServiceMetadataBehavior();
 serviceMetadataBehavior.HttpGetEnabled = false;
 serviceMetadataBehavior.HttpsGetEnabled = true;
 host.Description.Behaviors.Remove<ServiceMetadataBehavior>();
 host.Description.Behaviors.Add(serviceMetadataBehavior);

 var serviceDebugBehavior = new ServiceDebugBehavior();
 serviceDebugBehavior.IncludeExceptionDetailInFaults = true;
 host.Description.Behaviors.Remove<ServiceDebugBehavior>();
 host.Description.Behaviors.Add(serviceDebugBehavior);

 var requestHeaderBehavior = new UseRequestHeadersForMetadataAddressBehavior(); // Important
 host.Description.Behaviors.Remove<UseRequestHeadersForMetadataAddressBehavior>();
 host.Description.Behaviors.Add(requestHeaderBehavior);

host.AddServiceEndpoint(new ServiceEndpoint(
            contractDescription,
            new InternalBinding(),
            new EndpointAddress(clientUrl, EndpointIdentity.CreateX509CertificateIdentity(serviceCertificate))));
host.Open();

一些位省略了,等等.这花了很长时间才弄清楚,还有很多白发.

Some bits omitted etc. This took a seriously long time to figure out and a lot of grey hairs.

这篇关于如何在以Azure辅助角色托管的WCF服务中以公共域名发布WSDL?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆