2017-02-06 37 views
7

是否可以綁定服務結構應用程序以偵聽多個端口?服務結構綁定到多個端點

基本上我試圖有一個面向公衆的服務,它監聽http:80和https:443,並將任何http請求重定向到https。

我創建了一個新的ASP.net核心服務,它可以單獨工作。即與SSL 443或只是非SSL 80,但是當我添加兩個ServiceInstanceListeners它只是失敗!

服務織物資源管理器中說超時幾次後出現以下錯誤:

Unhealthy event: SourceId='System.RA', Property='ReplicaOpenStatus', HealthState='Warning', ConsiderWarningAsError=false. 
Replica had multiple failures in API call: IStatelessServiceInstance.Open(); Error = System.Fabric.FabricElementAlreadyExistsException (-2146233088) 
Unique Name must be specified for each listener when multiple communication listeners are used 
    at Microsoft.ServiceFabric.Services.Communication.ServiceEndpointCollection.AddEndpointCallerHoldsLock(String listenerName, String endpointAddress) 
    at Microsoft.ServiceFabric.Services.Communication.ServiceEndpointCollection.AddEndpoint(String listenerName, String endpointAddress) 
    at Microsoft.ServiceFabric.Services.Runtime.StatelessServiceInstanceAdapter.d__13.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at Microsoft.ServiceFabric.Services.Runtime.StatelessServiceInstanceAdapter.d__0.MoveNext() 

,因爲兩者的聽衆有不同的名字這是奇怪的 - 所以它似乎。是否有某處我應該設置我錯過的聽衆姓名?

我爲此使用了Asp.net核心模板。我的狀態服務的代碼如下:

internal sealed class Web : StatelessService 
{ 
    public Web(StatelessServiceContext context) 
     : base(context) 
    { } 

    /// <summary> 
    /// Optional override to create listeners (like tcp, http) for this service instance. 
    /// </summary> 
    /// <returns>The collection of listeners.</returns> 
    protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners() 
    { 
     return new ServiceInstanceListener[] 
     { 
      new ServiceInstanceListener(serviceContext => 
       new WebListenerCommunicationListener(serviceContext, "ServiceEndpointHttps", url => 
       { 
        ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting WebListener on {url}"); 

        return new WebHostBuilder() 
           .UseWebListener() 
           .ConfigureServices(
            services => services 
             .AddSingleton<StatelessServiceContext>(serviceContext)) 
           .UseContentRoot(Directory.GetCurrentDirectory()) 
           .UseStartup<Startup>() 
           .UseUrls(url) 
           .Build(); 
       })), 


      new ServiceInstanceListener(serviceContext => 
       new WebListenerCommunicationListener(serviceContext, "ServiceEndpointHttp", url => 
       { 
        ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting WebListener on {url}"); 

        return new WebHostBuilder() 
           .UseWebListener() 
           .ConfigureServices(
            services => services 
             .AddSingleton<StatelessServiceContext>(serviceContext)) 
           .UseContentRoot(Directory.GetCurrentDirectory()) 
           .UseStartup<Startup>() 
           .UseUrls(url) 
           .Build(); 
       })) 
     }; 
    } 
} 

回答

6

我需要設置ServiceInstanceListener具有構造函數的名稱

public ServiceInstanceListener(Func<StatelessServiceContext, ICommunicationListener> createCommunicationListener, string name = ""); 

我沒有意識到它有額外參數:)

+1

該名稱應該與服務設置中端點的名稱相匹配。對於具有單個類型端點的服務,可以將其留空,但只要有多個端點,您需要按名稱標識它們。 – yoape

+1

很高興知道,謝謝!將來不會讓我絆倒。 – Mardoxx

1

你可以通過使用下面的代碼自動執行所有這些操作,並在需要的地方記錄所需的信息。

var currentEndpoint = ""; 
try 
{ 
    IList<ServiceInstanceListener> listeners = new List<ServiceInstanceListener>(); 
    var endpoints = FabricRuntime.GetActivationContext().GetEndpoints(); 

    foreach (var endpoint in endpoints) 
    { 
    currentEndpoint = endpoint.Name; 
    logger.LogInformation("Website trying to LISTEN : " + currentEndpoint); 

    var webListner = new ServiceInstanceListener(serviceContext => 
     new WebListenerCommunicationListener(serviceContext, endpoint.Name, (url, listener) => 
     { 
     url = endpoint.Protocol + "://+:" + endpoint.Port; 
     logger.LogInformation("Website Listening : " + currentEndpoint); 
     return new WebHostBuilder().UseWebListener()  .UseContentRoot(Directory.GetCurrentDirectory()) 
       .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None) 
       .UseStartup<Startup>() 
       .UseUrls(url) 
       .Build(); 
     }), endpoint.Name.ToString()); 
    listeners.Add(webListner); 
    } 
    return listeners; 
} 
catch (Exception ex) 
{ 
    logger.LogError("Exception occured while listening endpoint: " + currentEndpoint, ex); 
    throw; 
} 
+0

fwiw,它似乎像「url」實際上設置爲'endpoint.Protocol +「:// +:」+ endpoint.Port;'已經,所以我沒有結束必須做的那部分。感謝您的詳細解答! – JohnnyFun