簡體   English   中英

外部客戶端無法訪問 Azure Service Fabric 上的 WCF 通信偵聽器

[英]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 服務的WebHttpBindinghttps : //github.com/loekd/ServiceFabric.WcfCalc

試着改變你的代碼,因此它不使用endpointResourceNameaddress包含一個明確的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.comhttp://本地主機)

客戶端更改:使用普通 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM