简体   繁体   English

如何在以Azure辅助角色托管的WCF服务中以公共域名发布WSDL?

[英]How to publish the WSDL at the public domain name in a WCF service hosted in an Azure worker role?

I host a WCF service in an Azure worker role . 我以Azure辅助角色托管WCF服务。
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. 可通过云服务实例的公共域名(myservice.cloudapp.net)访问该服务,但是,到WSDL的链接以及WSDL中的URL使用内部IP地址代替,无法从外部访问。 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. 因此,“添加服务引用”和WCFTestClient.exe之类的工具无法正常运行,因为它们试图访问内部IP地址。

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();

What am I doing wrong? 我究竟做错了什么? How should I configure the service to use the public domain name in the WSDL as well? 我应该如何配置服务以在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). 更新: Peter的回答帮助我解决了这个问题,在我的情况下,我只需要向服务添加UseRequestHeadersForMetadataAddressBehavior行为,然后WSDL使用了公共域名(我想现在它使用了客户端向其发送请求的域) 。

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();

Edit: 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. 尝试注册端点时将引发内部错误。

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. 我必须更改确实有权执行此操作的应用程序池用户(该凭据与您用于rdp到工作角色的凭据相同。

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. 一些位省略了,等等。这花了很长时间才弄清楚,还有很多白发。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM