internal KestrelListenerBuilder( string name, ServiceFabricIntegrationOptions options, Action <IWebHostBuilder> builderExtension) { Name = name; m_options = options; m_builderExtension = builderExtension; }
/// <summary> /// Add Kestrel service listener to stateful service /// </summary> /// <typeparam name="TStartup">The type containing the startup methods for the web listener</typeparam> public static ServiceFabricHostBuilder <OmexStatefulService, StatefulServiceContext> AddKestrelListener <TStartup>( this ServiceFabricHostBuilder <OmexStatefulService, StatefulServiceContext> builder, string name, ServiceFabricIntegrationOptions options, Action <IWebHostBuilder>?builderExtension = null) where TStartup : class => builder.AddKestrelListener <TStartup, OmexStatefulService, StatefulServiceContext>( name, options, builderExtension);
private static ServiceFabricHostBuilder <TService, TContext> AddKestrelListener <TStartup, TService, TContext>( this ServiceFabricHostBuilder <TService, TContext> builder, string name, ServiceFabricIntegrationOptions options, Action <IWebHostBuilder>?builderExtension = null, Action <WebHostBuilderContext, KestrelServerOptions>?kestrelOptions = null) where TStartup : class where TService : IServiceFabricService <TContext> where TContext : ServiceContext => builder.AddServiceListener(provider => new KestrelListenerBuilder <TStartup, TService, TContext>(
internal KestrelListenerBuilder( string name, IServiceProvider serviceProvider, ServiceFabricIntegrationOptions options, Action <IWebHostBuilder> builderExtension, Action <WebHostBuilderContext, KestrelServerOptions> kestrelOptions) { Name = name; m_serviceProvider = serviceProvider; m_options = options; m_kestrelOptions = kestrelOptions; m_builderExtension = builderExtension; }
/// <summary> /// Build stateless service with Kestrel service listener /// </summary> /// <param name="hostBuilder">Host builder</param> /// <param name="serviceName">Name of Service Fabric stateless service</param> /// <param name="endpoint">Web listener endpoint name</param> /// <param name="integrationOptions">Service Fabric integration options, default value is UseReverseProxyIntegration</param> /// <param name="kestrelOptions">Action to configure Kestrel additional, for example witch to https</param> /// <param name="serviceBuilder">Action to configure SF stateless service additional, for example to add more listeners or actions</param> /// <typeparam name="TStartup">The type containing the startup methods for the web listener</typeparam> public static IHost BuildStatelessWebService <TStartup>( this IHostBuilder hostBuilder, string serviceName, WebEndpointInfo endpoint, ServiceFabricIntegrationOptions integrationOptions = DefaultServiceFabricIntegrationOptions, Action <WebHostBuilderContext, KestrelServerOptions>?kestrelOptions = null, Action <ServiceFabricHostBuilder <OmexStatelessService, StatelessServiceContext> >?serviceBuilder = null) where TStartup : class => hostBuilder.BuildStatelessWebService <TStartup>( serviceName, new[] { endpoint }, integrationOptions, kestrelOptions, serviceBuilder);
/// <summary> /// Tests Url for ServiceFabricIntegrationOptions.UseUniqueServiceUrl /// 1. When endpoint name is provided (protocol and port comes from endpoint.) : /// a. url given to Func to create IWebHost should be protocol://+:port. /// b. url returned from OpenAsync should be protocol://IPAddressOrFQDN:port/PartitionId/ReplicaId /// /// </summary> protected void UseUniqueServiceUrlOptionVerifier() { this.IntegrationOptions = ServiceFabricIntegrationOptions.UseUniqueServiceUrl; var expectedProtocol = ExpectedProtocolFromEndpoint.ToString().ToLower(); var expectedPort = DefaultExpectedPort; Console.WriteLine("Starting Verification of urls with UseUniqueServiceUrl option when endpoint ref is provided"); var context = this.Listener.ServiceContext; var expectedUrlToBuildFunc = string.Format("{0}://+:{1}", expectedProtocol, expectedPort); var expectedUrlFromOpen = string.Format("{0}://{1}:{2}/{3}/{4}", expectedProtocol, context.NodeContext.IPAddressOrFQDN, expectedPort, context.PartitionId, context.ReplicaOrInstanceId); var actualUrlFromOpen = this.Listener.OpenAsync(CancellationToken.None).GetAwaiter().GetResult(); this.UrlFromListenerToBuildFunc.Should().Be(expectedUrlToBuildFunc, "listener generates the url."); actualUrlFromOpen.Should().Be(actualUrlFromOpen, "url from OpenAsync with endpoint ref"); Console.WriteLine("Completed Verification of urls with endpoint ref"); }
internal OmexServiceFabricSetupFilter(ServiceFabricIntegrationOptions options) => m_options = options;
public void UseIntegrationOptions( ServiceFabricIntegrationOptions integrationOptions) { this.IntegrationOptions = integrationOptions; }
/// <summary> /// Configures the Service to use ServiceFabricMiddleware and tells the listener that middleware is configured for the service so that it can /// suffix PartitionId and ReplicOrInstanceId to url before providing it to Service Fabric Runtime. /// </summary> /// <param name="hostBuilder">The Microsoft.AspNetCore.Hosting.IWebHostBuilder to configure.</param> /// <param name="listener">The <see cref="AspNetCoreCommunicationListener"/> to configure.</param> /// <param name="options">Options to configure ServiceFabricMiddleware and AspNetCoreCommunicationListener</param> /// <returns>The Microsoft.AspNetCore.Hosting.IWebHostBuilder.</returns> public static IWebHostBuilder UseServiceFabricIntegration(this IWebHostBuilder hostBuilder, AspNetCoreCommunicationListener listener, ServiceFabricIntegrationOptions options) { if (hostBuilder == null) { throw new ArgumentNullException("hostBuilder"); } // Check if 'UseServiceFabricIntegration' has already been called. if (hostBuilder.GetSetting(SettingName) != null && hostBuilder.GetSetting(SettingName).Equals(true.ToString(), StringComparison.Ordinal)) { return(hostBuilder); } // Set flag to prevent double service configuration hostBuilder.UseSetting(SettingName, true.ToString()); // Configure listener to use PartitionId and ReplicaId as urlSuffix only when specified in options. if (options.Equals(ServiceFabricIntegrationOptions.UseUniqueServiceUrl)) { // notify listener to use urlSuffix when giving url to Service Fabric Runtime from OpenAsync() listener.ConfigureToUseUniqueServiceUrl(); } hostBuilder.ConfigureServices(services => { // Configure MiddleWare services.AddSingleton <IStartupFilter>(new ServiceFabricSetupFilter(listener.UrlSuffix)); }); return(hostBuilder); }
/// <summary> /// Build stateless service with Kestrel service listeners /// </summary> /// <param name="hostBuilder">Host builder</param> /// <param name="serviceName">Name of Service Fabric stateless service</param> /// <param name="endpoints">Name of the web listener</param> /// <param name="integrationOptions">Service Fabric integration options, default value is UseReverseProxyIntegration</param> /// <param name="kestrelOptions">Action to configure Kestrel additional, for example witch to https</param> /// <param name="serviceBuilder">Action to configure SF stateless service additional, for example to add more listeners or actions</param> /// <typeparam name="TStartup">The type containing the startup methods for the web listener</typeparam> public static IHost BuildStatelessWebService <TStartup>( this IHostBuilder hostBuilder, string serviceName, WebEndpointInfo[] endpoints, ServiceFabricIntegrationOptions integrationOptions = DefaultServiceFabricIntegrationOptions, Action <WebHostBuilderContext, KestrelServerOptions>?kestrelOptions = null, Action <ServiceFabricHostBuilder <OmexStatelessService, StatelessServiceContext> >?serviceBuilder = null) where TStartup : class { if (integrationOptions.HasFlag(ServiceFabricIntegrationOptions.UseUniqueServiceUrl)) { // Supporting this options would require some hacks: // * Creating UrlSuffix like PartitionId/InstanceId where PartitionId could be taken from Env variable 'Fabric_PartitionId', for InstanceId we might thy to use new guid instead // * Adding this path to address returned by OmexKestrelListener // * In OmexServiceFabricSetupFilter initially add app.UseServiceFabricMiddleware(UrlSuffix) or create new similar middleware that with work with list of suffixes throw new ArgumentException("ServiceFabricIntegrationOptions.UseUniqueServiceUrl currently not supported"); } return(hostBuilder .ConfigureServices(collection => { collection .AddHttpContextAccessor() .AddOmexMiddleware() .AddSingleton <IStartupFilter>(new OmexServiceFabricSetupFilter(integrationOptions)); }) .ConfigureWebHost(webBuilder => { webBuilder .UseKestrel((WebHostBuilderContext context, KestrelServerOptions options) => { foreach (WebEndpointInfo endpoint in endpoints) { options.Listen(IPAddress.IPv6Any, endpoint.Port, listenOptions => { if (endpoint.UseHttps) { string certificateSubject = context.Configuration.GetValue <string>(endpoint.SettingForCertificateCommonName); listenOptions.UseHttps(StoreName.My, certificateSubject, true, StoreLocation.LocalMachine); } }); } kestrelOptions?.Invoke(context, options); }) .UseContentRoot(Directory.GetCurrentDirectory()) .UseStartup <TStartup>() .UseUrls(endpoints.Select(e => e.GetListenerUrl()).ToArray()); }) .BuildStatelessService( serviceName, builder => { string publisherAddress = SfConfigurationProvider.GetPublishAddress(); foreach (WebEndpointInfo endpoint in endpoints) { builder.AddServiceListener(endpoint.Name, (p, s) => new OmexKestrelListener( p.GetRequiredService <IServer>(), publisherAddress, endpoint.Port)); } serviceBuilder?.Invoke(builder); })); }
internal ServiceFabricSetupFilter(string urlSuffix, ServiceFabricIntegrationOptions options) { this.urlSuffix = urlSuffix; this.options = options; }