外部客户端无法访问 Azure Service Fabric 上的 WCF 通信侦听器
Posted
技术标签:
【中文标题】外部客户端无法访问 Azure Service Fabric 上的 WCF 通信侦听器【英文标题】:External Clients unable to access WCF Communication Listener on Azure Service Fabric 【发布时间】:2016-11-09 06:37:04 【问题描述】:我正在尝试使用 WCF 通信侦听器将运行 WCF 的 Azure Web 角色迁移到 Azure Service Fabric 中的无状态服务。一切都在我的本地服务集群中运行。发布到 Azure 后,集群中的其他服务能够访问无状态 WCF 服务,但外部(互联网)客户端(包括我的开发机器)由于暂时的网络错误而无法连接。
我验证了资源组中的负载均衡器具有针对端口 80 和 8080 的规则/探测,并且已经使用 TCP 和 HTTP 进行了测试。我还尝试在 WCF 客户端上设置分区解析器以指向服务集群上的“客户端连接端点”(默认情况下,它在服务集群中工作)。
此时,我不确定我是否有配置问题,或者外部(互联网)客户端是否有可能连接到运行 WCF 通信侦听器的无状态服务。
这是我的配置:
WCF 通信监听器
private Func<StatelessServiceContext, ICommunicationListener> CreateListener()
return delegate (StatelessServiceContext context)
var host = new WcfCommunicationListener<IHello>(
wcfServiceObject: this,
serviceContext: context,
endpointResourceName: "ServiceEndpoint",
listenerBinding: CreateDefaultHttpBinding()
);
return host;
;
WCF 绑定
public static Binding CreateDefaultHttpBinding()
var binding = new WSHttpBinding(SecurityMode.None)
CloseTimeout = new TimeSpan(00, 05, 00),
OpenTimeout = new TimeSpan(00, 05, 00),
ReceiveTimeout = new TimeSpan(00, 05, 00),
SendTimeout = new TimeSpan(00, 05, 00),
MaxReceivedMessageSize = int.MaxValue,
;
var quota = new XmlDictionaryReaderQuotas
MaxArrayLength = int.MaxValue,
MaxDepth = int.MaxValue
;
binding.ReaderQuotas = quota;
return binding;
ServiceManifest.xml(我还使用了各种端口的默认 TCP 绑定)
<Endpoints>
<Endpoint Name="ServiceEndpoint" Protocol="http" Port="8080" />
</Endpoints>
WCF 控制台应用程序
var address = new Uri("fabric:/ServiceFabricWcf.Azure/ServiceFabricWcf");
var client = GetClient(address, CreateDefaultHttpBinding());
try
var results = client.InvokeWithRetry(x => x.Channel.Hello());
System.WriteLine($"Results from WCF Service: 'results'");
Console.ReadKey();
catch (Exception e)
System.Console.WriteLine("Exception calling WCF Service: 'e'");
WCF 客户端
public static WcfServiceFabricCommunicationClient<IHello> GetClient(Uri address, Binding binding)
//ServicePartitionResolver.GetDefault(); Works with other services in cluster
var partitionResolver = new ServicePartitionResolver("<clientConnectionEndpointOfServiceCluster>:8080");
var wcfClientFactory = new WcfCommunicationClientFactory<IHello>(binding, null, partitionResolver);
var sfclient = new WcfServiceFabricCommunicationClient<IHello>(wcfClientFactory, address, ServicePartitionKey.Singleton);
return sfclient;
WCF 客户端工厂
public class WcfServiceFabricCommunicationClient<T> : ServicePartitionClient<WcfCommunicationClient<T>> where T : class
public WcfServiceFabricCommunicationClient(ICommunicationClientFactory<WcfCommunicationClient<T>> communicationClientFactory,
Uri serviceUri,
ServicePartitionKey partitionKey = null,
TargetReplicaSelector targetReplicaSelector = TargetReplicaSelector.Default,
string listenerName = null,
OperationRetrySettings retrySettings = null
)
: base(communicationClientFactory, serviceUri, partitionKey, targetReplicaSelector, listenerName, retrySettings)
【问题讨论】:
【参考方案1】:这是一种适用于具有WebHttpBinding
的 WCF 服务的方法:https://github.com/loekd/ServiceFabric.WcfCalc
尝试更改您的代码,使其不使用 endpointResourceName
,而是使用包含显式 URL 的 address
。 URL 应该是集群的公共名称,例如 mycluster.region.cloudapp.azure.com。
编辑:url 应该使用节点名,这样更容易。
string host = context.NodeContext.IPAddressOrFQDN;
var endpointConfig = context.CodePackageActivationContext.GetEndpoint
("CalculatorEndpoint");
int port = endpointConfig.Port;
string scheme = endpointConfig.Protocol.ToString();
string uri = string.Format(CultureInfo.InvariantCulture,
"0://1:2/", scheme, host, port);
【讨论】:
谢谢。我能够保留我的 WsHttpBinding,并使用您发布的 HTTP uri 格式将“地址”添加到 WCF 通信侦听器。它在本地工作,并在发布到 Azure Service Fabric 时工作。值得注意的是,在这种情况下(互联网访问),您可以使用普通的 WCF 客户端,而不是发布示例(假设仅限内部)【参考方案2】:这是我根据 LoekD 的回答更新的代码。
服务变更: 要使服务对 Internet 客户端可用,您必须向 WCFCommunicationListener 添加一个“地址”属性,以告诉服务要监听哪个端点(http://mycluster.region.azure.com 或 http://localhost)
客户端更改:使用普通的 WCF 客户端,没有任何 WCFCommunicationListener 引用。仅在服务结构内部使用 WCFCommunicationListener 客户端(我的原始代码在这种情况下工作正常)。
WCF 服务器监听器
return delegate (StatelessServiceContext context)
string host = HostFromConfig(context);
if (string.IsNullOrWhiteSpace(host))
host = context.NodeContext.IPAddressOrFQDN;
var endpointConfig = context.CodePackageActivationContext.GetEndpoint("ServiceEndpoint");
int port = endpointConfig.Port;
string scheme = endpointConfig.Protocol.ToString();
//http://mycluster.region.cloudapp.azure.com or http://localhost
string uri = string.Format(CultureInfo.InvariantCulture, "0://1:2", scheme, host, port);
var listener = new WcfCommunicationListener<IHello>(
wcfServiceObject: this,
serviceContext: context,
listenerBinding: CreateDefaultHttpBinding(),
address: new EndpointAddress(uri)
);
return listener;
;
WCF 客户端应用程序
static void Main(string[] args)
System.Console.WriteLine("\nPress any key to start the wcf client.");
System.Console.ReadKey();
System.Console.WriteLine("*************Calling Hello Service*************");
try
var binding = CreateDefaultHttpBinding();
var address = new EndpointAddress("http://cluster.region.cloudapp.azure.com/"); //new EndpointAddress("http://localhost");
var results = WcfWebClient<IHello>.InvokeRestMethod(x => x.Hello(),binding, address );
System.Console.WriteLine($"*************Results from Hello Service: 'results'*************");
Console.ReadKey();
catch (Exception e)
System.Console.WriteLine($"*************Exception calling Hello Service: 'e'*************");
WCF 绑定
public static Binding CreateDefaultHttpBinding()
var binding = new WSHttpBinding(SecurityMode.None)
CloseTimeout = new TimeSpan(00, 05, 00),
OpenTimeout = new TimeSpan(00, 05, 00),
ReceiveTimeout = new TimeSpan(00, 05, 00),
SendTimeout = new TimeSpan(00, 05, 00),
MaxReceivedMessageSize = int.MaxValue,
;
var quota = new XmlDictionaryReaderQuotas
MaxArrayLength = int.MaxValue,
MaxDepth = int.MaxValue
;
binding.ReaderQuotas = quota;
return binding;
外部/互联网 WCF 客户端示例:
public abstract class WcfWebClient<T> where T : class
public static TResult InvokeRestMethod<TResult>(Func<T, TResult> method, Binding binding, EndpointAddress address)
var myChannelFactory = new ChannelFactory<T>(binding, address);
var wcfClient = myChannelFactory.CreateChannel();
try
var result = method(wcfClient);
((IClientChannel)wcfClient).Close();
return result;
catch (TimeoutException e)
Trace.TraceError("WCF Client Timeout Exception" + e.Message);
// Handle the timeout exception.
((IClientChannel)wcfClient).Abort();
throw;
catch (CommunicationException e)
Trace.TraceError("WCF Client Communication Exception" + e.Message);
// Handle the communication exception.
((IClientChannel)wcfClient).Abort();
throw;
【讨论】:
【参考方案3】:您还可以尝试通过在服务实现上添加以下属性来为 WCF 服务启用任何地址绑定模式:
[ServiceBehavior(AddressFilterMode=AddressFilterMode.Any)]
【讨论】:
以上是关于外部客户端无法访问 Azure Service Fabric 上的 WCF 通信侦听器的主要内容,如果未能解决你的问题,请参考以下文章
Azure Service Fabric 群集:无法为 RPC 访问机器 10.0.0.X
Azure Service Fabric 错误:访问被拒绝。部署失败
设置service的nodeport以后外部无法访问对应的端口的问题