public CorsMiddleware(OcelotRequestDelegate next, IOptions <GatewayOptions> options, IOcelotLoggerFactory loggerFactory)
            : base(loggerFactory.CreateLogger <CorsMiddleware>())
        {
            _next = next;

            _gatewayOptions = options.Value;
        }
Пример #2
0
 private static void CreateGateway(Token token, string appName, GatewayOptions options, int shardId, int shardCount, Action <GatewayClient> runner)
 {
     CreateGateway(token, appName, options, shardId, shardCount, client => {
         runner(client);
         return(Task.CompletedTask);
     });
 }
Пример #3
0
 public static void CreateShardedGateway(Token token, string appName, GatewayOptions options, params Action <GatewayClient>[] runners)
 {
     for (int i = 0; i < runners.Length; i++)
     {
         CreateGateway(token, appName, options, i, runners.Length, runners[i]);
     }
 }
Пример #4
0
 public RouteDefinitionMatcher(IConfigurationRetriever configurationRetriever,
                               IOptions <GatewayOptions> gatewayOptions)
 {
     _configurationRetriever = configurationRetriever;
     _gatewayOptions         = gatewayOptions.Value;
     _asyncLock = new AsyncLock();
 }
Пример #5
0
 public RedisGatewayListProvider(IMembershipTable table, GatewayOptions options, ILoggerFactory loggerFactory)
 {
     GatewayOptions = options;
     LoggerFactory  = loggerFactory;
     Logger         = loggerFactory?.CreateLogger <RedisGatewayListProvider>();
     Logger?.LogInformation("In RedisGatewayListProvider constructor");
     _table = table as RedisMembershipTable;
 }
Пример #6
0
 public GatewayManager(
     IOptions <GatewayOptions> gatewayOptions,
     IGatewayListProvider gatewayListProvider,
     ILoggerFactory loggerFactory,
     ConnectionManager connectionManager)
 {
     this.gatewayOptions      = gatewayOptions.Value;
     this.logger              = loggerFactory.CreateLogger <GatewayManager>();
     this.connectionManager   = connectionManager;
     this.gatewayListProvider = gatewayListProvider;
     this.timerLogger         = loggerFactory.CreateLogger <SafeTimer>();
 }
Пример #7
0
        protected void Test_GatewaySelection(IGatewayListProvider listProvider)
        {
            IList <Uri> gatewayUris = listProvider.GetGateways().GetResult();

            Assert.True(gatewayUris.Count > 0, $"Found some gateways. Data = {Utils.EnumerableToString(gatewayUris)}");

            var gatewayEndpoints = gatewayUris.Select(uri =>
            {
                return(new IPEndPoint(IPAddress.Parse(uri.Host), uri.Port));
            }).ToList();

            var cfg = new ClientConfiguration
            {
                Gateways = gatewayEndpoints
            };
            var gatewayOptions = new GatewayOptions()
            {
                GatewayListRefreshPeriod = cfg.GatewayListRefreshPeriod,
                PreferedGatewayIndex     = cfg.PreferedGatewayIndex
            };
            var gatewayManager = new GatewayManager(gatewayOptions, listProvider, NullLoggerFactory.Instance);

            var counts = new int[4];

            for (int i = 0; i < 2300; i++)
            {
                var ip   = gatewayManager.GetLiveGateway();
                var addr = IPAddress.Parse(ip.Host);
                Assert.Equal(IPAddress.Loopback, addr);  // "Incorrect IP address returned for gateway"
                Assert.True((0 < ip.Port) && (ip.Port < 5), "Incorrect IP port returned for gateway");
                counts[ip.Port - 1]++;
            }

            // The following needed to be changed as the gateway manager now round-robins through the available gateways, rather than
            // selecting randomly based on load numbers.
            //Assert.True((500 < counts[0]) && (counts[0] < 1500), "Gateway selection is incorrectly skewed");
            //Assert.True((500 < counts[1]) && (counts[1] < 1500), "Gateway selection is incorrectly skewed");
            //Assert.True((125 < counts[2]) && (counts[2] < 375), "Gateway selection is incorrectly skewed");
            //Assert.True((25 < counts[3]) && (counts[3] < 75), "Gateway selection is incorrectly skewed");
            //Assert.True((287 < counts[0]) && (counts[0] < 1150), "Gateway selection is incorrectly skewed");
            //Assert.True((287 < counts[1]) && (counts[1] < 1150), "Gateway selection is incorrectly skewed");
            //Assert.True((287 < counts[2]) && (counts[2] < 1150), "Gateway selection is incorrectly skewed");
            //Assert.True((287 < counts[3]) && (counts[3] < 1150), "Gateway selection is incorrectly skewed");

            int low = 2300 / 4;
            int up  = 2300 / 4;

            Assert.True((low <= counts[0]) && (counts[0] <= up), "Gateway selection is incorrectly skewed. " + counts[0]);
            Assert.True((low <= counts[1]) && (counts[1] <= up), "Gateway selection is incorrectly skewed. " + counts[1]);
            Assert.True((low <= counts[2]) && (counts[2] <= up), "Gateway selection is incorrectly skewed. " + counts[2]);
            Assert.True((low <= counts[3]) && (counts[3] <= up), "Gateway selection is incorrectly skewed. " + counts[3]);
        }
Пример #8
0
 protected MessageReceivedHandlerBase(
     IParameterParser parameterParser,
     ISerializer serializer,
     IOptions <RpcOptions> rpcOptions,
     IOptions <GatewayOptions> gatewayOptions,
     IServiceExecutor serviceExecutor)
 {
     _parameterParser = parameterParser;
     _serializer      = serializer;
     _serviceExecutor = serviceExecutor;
     _rpcOptions      = rpcOptions.Value;
     _gatewayOptions  = gatewayOptions.Value;
 }
Пример #9
0
        private static GatewayOptions GetOptions(string relativePath, Uri serviceUri)
        {
            var unitServiceOptions = new GatewayOptions
            {
                RelativePath           = new Uri(relativePath, UriKind.Relative),
                ServiceUri             = serviceUri,
                OperationRetrySettings = new OperationRetrySettings(
                    TimeSpan.FromSeconds(2),
                    TimeSpan.FromSeconds(2),
                    30)
            };

            return(unitServiceOptions);
        }
Пример #10
0
        private void AddHttpClients(IServiceCollection services)
        {
            GatewayOptions options = new GatewayOptions();

            Configuration.Bind(nameof(GatewayOptions), options);

            AddClient(services, HttpClientNames.Properties, options.PropertiesAPI, options.PropertiesAPIKey);
            AddClient(services, HttpClientNames.HousingSearch, options.HousingSearchAPI, options.HousingSearchAPIKey);
            AddClient(services, HttpClientNames.Asset, options.AssetAPI, options.AssetAPIKey);
            AddClient(services, HttpClientNames.Alerts, options.AlertsApi, options.AlertsAPIKey);
            AddClient(services, HttpClientNames.TenureInformation, options.TenureInformationAPI, options.TenureInformationAPIKey);
            AddClient(services, HttpClientNames.Contacts, options.HousingResidentInformationApi, options.HousingResidentInformationApiKey);
            AddClient(services, HttpClientNames.ContactDetails, options.ContactDetailsAPI, options.ContactDetailsAPIKey);
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="HelloEventController" /> class.
 /// </summary>
 /// <param name="gateway">The gateway service to use.</param>
 /// <param name="reporter">Reporter to use to report metrics with.</param>
 /// <param name="adapterOptions">Options used across the adapter.</param>
 /// <param name="gatewayOptions">The options to use for the gateway.</param>
 /// <param name="logger">Logger used to log information to some destination(s).</param>
 public HelloEventController(
     IGatewayService gateway,
     IMetricReporter reporter,
     IOptions <AdapterOptions> adapterOptions,
     IOptions <GatewayOptions> gatewayOptions,
     ILogger <HelloEventController> logger
     )
 {
     this.gateway        = gateway;
     this.reporter       = reporter;
     this.adapterOptions = adapterOptions.Value;
     this.gatewayOptions = gatewayOptions.Value;
     this.logger         = logger;
 }
Пример #12
0
        public GatewaySettings Create(GatewayOptions options)
        {
            var system = Create(options.System);

            var routes = options.Routes
                         .Select(o => Create(o.Key, o.Value))
                         .WhereNotNull()
                         .ToArray();

            if (routes.Length == 0)
            {
                LogError("No routes are specified.");
            }

            return(new GatewaySettings(system, routes));
        }
Пример #13
0
        public void Configure(IApplicationBuilder app)
        {
            //base
            var smsOptions = new GatewayOptions()
            {
                ServiceUri = new Uri("fabric:/NursingHomes.App/Base", UriKind.Absolute),

                OperationRetrySettings = new OperationRetrySettings(TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(2), 30),
            };

            app.Map("/base",
                    subApp =>
            {
                subApp.RunGateway(smsOptions);
            }
                    );
        }
Пример #14
0
#pragma warning restore SA1401 // Fields should be private

        protected void Initialize(CommandBase cmd)
        {
            this.logicTokenProviderFactory = new LogicTokenProviderFactory(
                new LogicTokenProviderOptions
            {
                AuthorizationScope = cmd.AuthorizationScope,
                ClientId           = cmd.ClientId,
                ClientSecret       = cmd.ClientSecret,
            });

            this.gatewayOptions = new GatewayOptions
            {
                SubscriptionId = cmd.SubscriptionId,
                ProviderId     = cmd.ProviderId,
            };
            this.gatewayOptions.GatewayServiceUri = cmd.GatewayUrl ?? this.gatewayOptions.GatewayServiceUri;
        }
Пример #15
0
        public GatewayManager(
            IOptions <GatewayOptions> gatewayOptions,
            IGatewayListProvider gatewayListProvider,
            ILoggerFactory loggerFactory,
            ConnectionManager connectionManager)
        {
            this.gatewayOptions = gatewayOptions.Value;
            knownDead           = new Dictionary <SiloAddress, DateTime>();
            rand                        = new SafeRandom();
            logger                      = loggerFactory.CreateLogger <GatewayManager>();
            this.loggerFactory          = loggerFactory;
            this.connectionManager      = connectionManager;
            lockable                    = new object();
            gatewayRefreshCallInitiated = false;

            ListProvider = gatewayListProvider;

            var knownGateways = ListProvider.GetGateways().GetAwaiter().GetResult();

            if (knownGateways.Count == 0)
            {
                string gatewayProviderType = gatewayListProvider.GetType().FullName;
                string err = $"Could not find any gateway in {gatewayProviderType}. Orleans client cannot initialize.";
                logger.Error(ErrorCode.GatewayManager_NoGateways, err);
                throw new OrleansException(err);
            }

            logger.Info(ErrorCode.GatewayManager_FoundKnownGateways, "Found {0} knownGateways from Gateway listProvider {1}", knownGateways.Count, Utils.EnumerableToString(knownGateways));

            if (ListProvider is IGatewayListObservable)
            {
                ((IGatewayListObservable)ListProvider).SubscribeToGatewayNotificationEvents(this);
            }

            roundRobinCounter = this.gatewayOptions.PreferedGatewayIndex >= 0 ? this.gatewayOptions.PreferedGatewayIndex : rand.Next(knownGateways.Count);

            this.knownGateways = cachedLiveGateways = knownGateways.Select(gw => gw.ToGatewayAddress()).ToList();

            lastRefreshTime     = DateTime.UtcNow;
            gatewayRefreshTimer = new AsyncTaskSafeTimer(
                this.loggerFactory.CreateLogger <SafeTimer>(),
                RefreshSnapshotLiveGateways_TimerCallback,
                null,
                this.gatewayOptions.GatewayListRefreshPeriod,
                this.gatewayOptions.GatewayListRefreshPeriod);
        }
Пример #16
0
 public GatewayManager(
     IOptions <GatewayOptions> gatewayOptions,
     IGatewayListProvider gatewayListProvider,
     ILoggerFactory loggerFactory,
     ConnectionManager connectionManager)
 {
     this.gatewayOptions      = gatewayOptions.Value;
     this.logger              = loggerFactory.CreateLogger <GatewayManager>();
     this.connectionManager   = connectionManager;
     this.gatewayListProvider = gatewayListProvider;
     this.gatewayRefreshTimer = new AsyncTaskSafeTimer(
         loggerFactory.CreateLogger <SafeTimer>(),
         RefreshSnapshotLiveGateways_TimerCallback,
         null,
         this.gatewayOptions.GatewayListRefreshPeriod,
         this.gatewayOptions.GatewayListRefreshPeriod);
 }
Пример #17
0
        public BridgeConfiguration(IConfiguration config)
        {
            var bridgeTypes = Enum.GetValues(typeof(BridgeType)).Cast <BridgeType>().ToList();

            Accounts = new HashSet <AccountOptions>();
            foreach (var child in config.GetChildren())
            {
                foreach (var accountOpts in bridgeTypes
                         .Where(type => child.Key.StartsWith($"{type}.", StringComparison.OrdinalIgnoreCase))
                         .Select(type => new AccountOptions {
                    Name = child.Key, Type = type
                }))
                {
                    child.Bind(accountOpts);
                    Accounts.Add(accountOpts);
                }
            }

            Gateways = config.GetChildren()
                       .Where(child => child.Key.StartsWith(GatewayPrefix, StringComparison.OrdinalIgnoreCase)).Select(child =>
            {
                var gatewayOpts = new GatewayOptions {
                    Name = child.Key.Substring(GatewayPrefix.Length)
                };
                child.Bind(gatewayOpts);

                return(gatewayOpts);
            }).Where(x => x.Enabled).Select(gatewayOpts =>
            {
                foreach (var client in gatewayOpts.Clients)
                {
                    var account = Accounts.SingleOrDefault(x => x.Name == client.Account);

                    if (account == null)
                    {
                        throw new InvalidOperationException($"Client account {client.Account} not found");
                    }
                }

                return(gatewayOpts);
            }).ToList();
        }
Пример #18
0
        private static void CreateGateway(Token token, string appName, GatewayOptions options, int shardId, int shardCount, Func <GatewayClient, Task> runner)
        {
            DiscordDebug.WriteLine("Creating gateway client...", appName);
            var env = new DiscordEnvironment(new GatewayClient(token, shardId, shardCount), appName);
            var t   = new Thread(() => {
                AsyncContext.Switch(async() => {
                    await env.RunAsync(async() => {
                        env.GatewayClient.FirePinEvents = options.HasFlag(GatewayOptions.FirePinEvents);
                        Server[] servers = null;
                        if (!options.HasFlag(GatewayOptions.ManualConnect))
                        {
                            DiscordDebug.WriteLine("Connecting...", appName);
                            servers = await env.GatewayClient.ConnectAsync();
                            DiscordDebug.WriteLine("Connected.", appName);
                        }
                        DiscordDebug.WriteLine("Gateway client created.", appName);
                        if (env.GatewayClient.FirePinEvents && servers != null)
                        {
                            DiscordDebug.WriteLine("Getting initial channel pins...");
                            var tasks = new List <Task>();
                            // ReSharper disable LoopCanBeConvertedToQuery (confusing)
                            foreach (Server s in servers)
                            {
                                foreach (IChannel channel in s.Channels.Values.Where(x => x is ServerTextChannel))
                                {
                                    var c = (ServerTextChannel)channel;
                                    tasks.Add(c.GetPinnedMessagesAsync(env.Client));
                                }
                            }
                            // ReSharper restore LoopCanBeConvertedToQuery
                            await Task.WhenAll(tasks);
                            DiscordDebug.WriteLine("Initial channel pins retreived.");
                        }
                        await runner((GatewayClient)env.Client);
                    });
                });
            });

            t.Start();
        }
        private async Task RegisterGatewayServiceAsync(string backAddress, GatewayOptions gw)
        {
            // IGatewayServiceManagerActor gateway = ActorProxy.Create<IGatewayServiceManagerActor>(new ActorId("*"), "S-Innovations.ServiceFabric.GatewayApplication", "GatewayServiceManagerActorService");
            var partitionKey = gw.Key ?? Context.CodePackageActivationContext.GetServiceManifestName();

            var gateway = ServiceProxy.Create <IGatewayManagementService>(
                new Uri("fabric:/S-Innovations.ServiceFabric.GatewayApplication/GatewayManagementService"), partitionKey.ToPartitionHashFunction());


            await gateway.RegisterGatewayServiceAsync(new GatewayServiceRegistrationData
            {
                Key                  = partitionKey, // $"{partitionKey}-{Context.NodeContext.IPAddressOrFQDN}",
                IPAddressOrFQDN      = Context.NodeContext.IPAddressOrFQDN,
                ServerName           = gw.ServerName,
                ReverseProxyLocation = gw.ReverseProxyLocation ?? "/",
                Ssl                  = gw.Ssl,
                BackendPath          = backAddress,
                ServiceName          = Context.ServiceName,
                ServiceVersion       = Context.CodePackageActivationContext.GetServiceManifestVersion(),
                CacheOptions         = gw.CacheOptions,
                Properties           = gw.Properties
            });
        }
Пример #20
0
 public ApisPreValidation(string folderPath, HttpClient httpClient, LogicTokenProviderFactory tokenProviderFactory, GatewayOptions options)
     : base(folderPath)
 {
     this.options = options;
     this.gatewayClientFactory = new GatewayClientFactory(tokenProviderFactory, httpClient, options);
 }
Пример #21
0
 public static void CreateGateway(Token token, string appName, GatewayOptions options, Func <GatewayClient, Task> runner)
 {
     CreateGateway(token, appName, options, 0, 1, runner);
 }
 public RedisGatewayListProvider(RedisMembershipTable table, IOptions <GatewayOptions> options)
 {
     _gatewayOptions = options.Value;
     _table          = table;
 }
Пример #23
0
 public PaymentsController(IGatewayHttpClient httpClient, IOptions <GatewayOptions> gatewayOptions)
 {
     _httpClient     = Guard.IsNotNull(httpClient, nameof(httpClient));
     _gatewayOptions = Guard.IsNotNull(gatewayOptions, nameof(gatewayOptions)).Value;
 }
Пример #24
0
 public GatewayClientFactory(LogicTokenProviderFactory logicTokenProviderFactory, HttpClient httpClient, GatewayOptions gatewayOptions)
 {
     this.logicTokenProviderFactory = logicTokenProviderFactory;
     this.httpClient     = httpClient;
     this.gatewayOptions = gatewayOptions;
 }
Пример #25
0
        public async Task InvokeAsync(HttpContext context, GatewayOptions options)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            //
            // NOTE:
            // Some of the code is copied from https://github.com/AspNet/Proxy/blob/dev/src/Microsoft.AspNetCore.Proxy/ProxyMiddleware.cs for prototype purpose.
            // Reviewing the license of the code will be needed if this code is to be used in production.
            //

            var servicePartitionClient = await ResolveServicePartitionClientAsync(context, options);

            await servicePartitionClient.InvokeWithRetryAsync(async communicationClient =>
            {
                var requestMessage = new HttpRequestMessage();

                //
                // Copy the request method
                //
                requestMessage.Method = new HttpMethod(context.Request.Method);

                //
                // Copy the request content
                //
                if (!StringComparer.OrdinalIgnoreCase.Equals(context.Request.Method, "GET") &&
                    !StringComparer.OrdinalIgnoreCase.Equals(context.Request.Method, "HEAD") &&
                    !StringComparer.OrdinalIgnoreCase.Equals(context.Request.Method, "DELETE") &&
                    !StringComparer.OrdinalIgnoreCase.Equals(context.Request.Method, "TRACE"))
                {
                    requestMessage.Content = new StreamContent(context.Request.Body);
                }

                //
                // Copy the request headers
                //
                foreach (var header in context.Request.Headers)
                {
                    if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) && requestMessage.Content != null)
                    {
                        requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
                    }
                }

                //
                // Construct the request URL
                //
                var endpoint     = communicationClient.ResolvedServiceEndpoint;
                var pathAndQuery = PathString.FromUriComponent(endpoint) + context.Request.Path + context.Request.QueryString;

                requestMessage.RequestUri = new Uri($"{endpoint.Scheme}://{endpoint.Host}:{endpoint.Port}{pathAndQuery}", UriKind.Absolute);

                //
                // Set host header
                //
                requestMessage.Headers.Host = communicationClient.ResolvedServiceEndpoint.Host + ":" + communicationClient.ResolvedServiceEndpoint.Port;

                //
                // Send request and copy the result back to HttpResponse
                //
                using (var responseMessage = await _httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted))
                {
                    //
                    // Copy the status code
                    //
                    context.Response.StatusCode = (int)responseMessage.StatusCode;

                    //
                    // Copy the response headers
                    //
                    foreach (var header in responseMessage.Headers)
                    {
                        context.Response.Headers[header.Key] = header.Value.ToArray();
                    }

                    foreach (var header in responseMessage.Content.Headers)
                    {
                        context.Response.Headers[header.Key] = header.Value.ToArray();
                    }

                    // SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response.
                    context.Response.Headers.Remove("transfer-encoding");

                    //
                    // Copy the response content
                    //
                    await responseMessage.Content.CopyToAsync(context.Response.Body);
                }
            });
        }
Пример #26
0
        private async Task <ServicePartitionClient <CommunicationClient> > ResolveServicePartitionClientAsync(HttpContext context, GatewayOptions options)
        {
            ServicePartitionClient <CommunicationClient> client = null;

            switch (options.ServiceDescription.PartitionKind)
            {
            case ServicePartitionKind.Singleton:
                client = new ServicePartitionClient <CommunicationClient>(_communicationClientFactory, options.ServiceDescription.ServiceName);
                break;

            case ServicePartitionKind.Int64Range:
                long int64RangeKey = await options.ServiceDescription.ComputeUniformInt64PartitionKeyAsync(context);

                client = new ServicePartitionClient <CommunicationClient>(_communicationClientFactory, options.ServiceDescription.ServiceName, int64RangeKey);
                break;

            case ServicePartitionKind.Named:
                string namedKey = await options.ServiceDescription.ComputeNamedPartitionKeyAsync(context);

                client = new ServicePartitionClient <CommunicationClient>(_communicationClientFactory, options.ServiceDescription.ServiceName, namedKey);
                break;

            default:
                break;
            }

            client.ListenerName = options.ServiceDescription.ListenerName;

            return(client);
        }
Пример #27
0
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            //
            // Scenarios:
            // 1. Multiple services.
            // 2. Various versions or kinds of clients side by side.
            //

            //
            // SMS
            //
            var smsOptions = new GatewayOptions()
            {
                ServiceUri = new Uri("fabric:/Hosting/SmsService", UriKind.Absolute),

                OperationRetrySettings = new OperationRetrySettings(TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(2), 30),

                GetServicePartitionKey = context =>
                {
                    var pathSegments = context.Request.Path.Value.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);

                    string user = pathSegments[pathSegments.Length - 1];

                    return(new ServicePartitionKey(Fnv1aHashCode.Get64bitHashCode(user)));
                }
            };

            app.Map("/sms",
                    subApp =>
            {
                subApp.RunGateway(smsOptions);
            }
                    );

            //
            // Counter
            //
            var counterOptions = new GatewayOptions()
            {
                ServiceUri = new Uri("fabric:/Hosting/CounterService", UriKind.Absolute),

                OperationRetrySettings = new OperationRetrySettings(TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(2), 30)
            };

            app.Map("/counter",
                    subApp =>
            {
                subApp.RunGateway(counterOptions);
            }
                    );

            app.Map("/Hosting/CounterService",
                    subApp =>
            {
                subApp.RunGateway(counterOptions);
            }
                    );

            app.MapWhen(
                context =>
            {
                StringValues serviceUri;

                return(context.Request.Headers.TryGetValue("SF-ServiceUri", out serviceUri) &&
                       serviceUri.Count == 1 &&
                       serviceUri[0] == "fabric:/Hosting/CounterService");
            },
                subApp =>
            {
                subApp.RunGateway(counterOptions);
            }
                );

            //
            // Web App
            //
            var webAppOptions = new GatewayOptions()
            {
                ServiceUri = new Uri("fabric:/Hosting/WebApp", UriKind.Absolute),

                OperationRetrySettings = new OperationRetrySettings(TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(2), 30)
            };

            app.Map("/webapp",
                    subApp =>
            {
                subApp.RunGateway(webAppOptions);
            }
                    );

            app.Run(context =>
            {
                if (context.Request.Path == "/")
                {
                    context.Response.Redirect($"{context.Request.Scheme}://{context.Request.Host}/webapp");
                }

                return(Task.FromResult(true));
            });
        }