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



我以Azure工作者角色主持WCF服务
该服务可以在云服务实例的公共域名(myservice.cloudapp.net)上访问,但是,指向WSDL的链接和WSDL内部的URL使用内部IP地址,无法从外部访问。因此,像Add服务引用和WCFTestClient.exe这样的工具无法正常工作,因为它们试图访问内部IP地址。

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

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中的公共域名?

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

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

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

编辑:我的情况因安全绑定而变得有点复杂,我相信这对你来说可能更容易

好吧,这里有几个问题。我看看我是否能把它们都记对。

首先,要以您希望的方式公开端点,您实际上没有这样做的正确权限(即使您在提升的上下文中运行,您仍然需要这样做)。当它尝试注册端点时,会抛出一个内部错误。

我不得不更改有权执行此操作的应用程序池用户(它将与您用于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();
}

这使我能够像下面这样配置服务,您可能需要根据需要对其进行修改。请密切关注标记为重要的设置,因为我相信这些设置对于公开您的服务至关重要。

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

有些地方遗漏了等等。这花了很长时间才弄清楚,而且有很多白发。

最新更新