[英]External Clients unable to access WCF Communication Listener on Azure Service Fabric
我正在嘗試使用 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)
{
}
}
這是一種適用於具有WebHttpBinding
的 WCF 服務的WebHttpBinding
: https : //github.com/loekd/ServiceFabric.WcfCalc
試着改變你的代碼,因此它不使用endpointResourceName
但address
包含一個明確的URL來代替。 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);
這是我根據 LoekD 的回答更新的代碼。
服務更改:要使 Internet 客戶端可以使用該服務,您必須向 WCFCommunicationListener 添加“地址”屬性,以告訴服務要偵聽的端點( http://mycluster.region.azure.com或http://本地主機)
客戶端更改:使用普通 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;
}
示例外部/Internet 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;
}
}
}
您還可以通過在服務實現上放置以下屬性來嘗試為 WCF 服務啟用任何地址綁定模式:
[ServiceBehavior(AddressFilterMode=AddressFilterMode.Any)]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.