question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

How to enables CORS for Service Fabric Stateless Web API?

See original GitHub issue

Hello,

I have been trying for hours now to properly configure CORS on Service Fabric Stateless Web API. But having no success.

This is the response I get (for the OPTIONS pre-flight) whenever I try to POST anything to the API endpoint.

XMLHttpRequest cannot load https://api-dev.myservice.com/tokens/verify. Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://tenant-dev.myservice.com:8000’ is therefore not allowed access. The response had HTTP status code 503.

Here is how my current setup looks like:

Program.cs

internal static class Program
    {
        private static void Main()
        {
            try
            {
                ServiceRuntime.RegisterServiceAsync("MyService_IdentityServiceType",
                    context => new Web(context)).GetAwaiter().GetResult();

                ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof (Web).Name);

                Thread.Sleep(Timeout.Infinite);
            }
            catch (Exception e)
            {
                ServiceEventSource.Current.ServiceHostInitializationFailed(e.ToString());
                throw;
            }
        }
    }

Web.cs

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

        protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
        {
            return new[]
            {
                new ServiceInstanceListener(serviceContext =>
                    new OwinCommunicationListener(
                        Startup.ConfigureApp, serviceContext, ServiceEventSource.Current,
                        Context.CodePackageActivationContext.GetConfigurationPackageObject("Config"),
                        "ServiceEndpoint", "identity"))
            };
        }
    }

OwinCommunicationListener.cs

internal class OwinCommunicationListener : ICommunicationListener
    {
        private readonly string _appRoot;
        private readonly ConfigurationPackage _configurationPackage;
        private readonly string _endpointName;
        private readonly ServiceEventSource _eventSource;
        private readonly ServiceContext _serviceContext;
        private readonly Action<IAppBuilder, ConfigurationPackage> _startup;
        private string _listeningAddress;
        private string _publishAddress;

        private IDisposable _webApp;

        public OwinCommunicationListener(Action<IAppBuilder, ConfigurationPackage> startup,
            ServiceContext serviceContext,
            ServiceEventSource eventSource, ConfigurationPackage configurationPackage, string endpointName)
            : this(startup, serviceContext, eventSource, configurationPackage, endpointName, null)
        {
        }

        public OwinCommunicationListener(Action<IAppBuilder, ConfigurationPackage> startup,
            ServiceContext serviceContext, ServiceEventSource eventSource, ConfigurationPackage configurationPackage,
            string endpointName, string appRoot)
        {
            if (startup == null)
            {
                throw new ArgumentNullException(nameof(startup));
            }

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

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

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

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

            _startup = startup;
            _serviceContext = serviceContext;
            _endpointName = endpointName;
            _eventSource = eventSource;
            _configurationPackage = configurationPackage;
            _appRoot = appRoot;
        }

        public bool ListenOnSecondary { get; set; }

        public Task<string> OpenAsync(CancellationToken cancellationToken)
        {
            var serviceEndpoint = _serviceContext.CodePackageActivationContext.GetEndpoint(_endpointName);
            var port = serviceEndpoint.Port;

            if (_serviceContext is StatefulServiceContext)
            {
                var statefulServiceContext = _serviceContext as StatefulServiceContext;

                _listeningAddress = string.Format(
                    CultureInfo.InvariantCulture,
                    "https://+:{0}/{1}{2}/{3}/{4}",
                    port,
                    string.IsNullOrWhiteSpace(_appRoot)
                        ? string.Empty
                        : _appRoot.TrimEnd('/') + '/',
                    statefulServiceContext.PartitionId,
                    statefulServiceContext.ReplicaId,
                    Guid.NewGuid());
            }
            else if (_serviceContext is StatelessServiceContext)
            {
                _listeningAddress = string.Format(
                    CultureInfo.InvariantCulture,
                    "https://+:{0}/{1}",
                    port,
                    string.IsNullOrWhiteSpace(_appRoot)
                        ? string.Empty
                        : _appRoot.TrimEnd('/') + '/');
            }
            else
            {
                throw new InvalidOperationException();
            }

            _publishAddress = _listeningAddress.Replace("+", FabricRuntime.GetNodeContext().IPAddressOrFQDN);

            try
            {
                _eventSource.ServiceMessage(_serviceContext, "Starting web server on " + _listeningAddress);

                _webApp = WebApp.Start(_listeningAddress,
                    appBuilder => _startup.Invoke(appBuilder, _configurationPackage));

                _eventSource.ServiceMessage(_serviceContext, "Listening on " + _publishAddress);

                return Task.FromResult(_publishAddress);
            }
            catch (Exception ex)
            {
                _eventSource.ServiceMessage(_serviceContext, "Web server failed to open. " + ex);

                StopWebServer();

                throw;
            }
        }

        public Task CloseAsync(CancellationToken cancellationToken)
        {
            _eventSource.ServiceMessage(_serviceContext, "Closing web server");

            StopWebServer();

            return Task.FromResult(true);
        }

        public void Abort()
        {
            _eventSource.ServiceMessage(_serviceContext, "Aborting web server");

            StopWebServer();
        }

        private void StopWebServer()
        {
            if (_webApp == null) return;

            try
            {
                _webApp.Dispose();
            }
            catch (ObjectDisposedException)
            {
                // no-op
            }
        }
    }

Startup.cs

public static class Startup
    {
        public static void ConfigureApp(IAppBuilder appBuilder, ConfigurationPackage configurationPackage)
        {
            appBuilder.UseCors(CorsOptions.AllowAll);

            var configurationManager =
                new ConfigurationManager(configurationPackage.Settings.Sections["IdentityService"].Parameters);

            var config = new HttpConfiguration();
            config.MapHttpAttributeRoutes();
            ConfigureFormatters(config.Formatters);

            var container = new Container();
            RegisterDependencies(container, config, configurationManager);

            appBuilder.UseWebApi(config);
        }

        private static void ConfigureFormatters(MediaTypeFormatterCollection formatters)
        {
            foreach (var formatter in formatters.OfType<JsonMediaTypeFormatter>())
            {
                formatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));

                formatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                formatter.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
                formatter.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;

                break;
            }
        }

        private static void RegisterDependencies(Container container, HttpConfiguration config,
            ConfigurationManager configurationManager)
        {
            container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();

            container.RegisterWebApiControllers(config);
            container.RegisterSingleton<IConfigurationManager>(configurationManager);

            container.Verify();
            config.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
        }
    }

I must be missing something here. If someone can please point me into the right direction, it would be really great 😃

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:1
  • Comments:12 (1 by maintainers)

github_iconTop GitHub Comments

5reactions
ghostcommented, Jul 7, 2017

@munjalpatel Can you please share with us what you changed to fix the issue? Another seeker in the same path!

4reactions
boarmanccommented, Dec 14, 2016

@vturecek

I have the following evidence to suggest this is a Service Fabric issue:

  1. when making a GET request to a stateless service using WebAPI2 using a URL that goes directly to a cluster node:port, the browser-issued CORS pre-flight check (HTTP OPTIONS method) works as expected, returning a 204 response with Access-Control-Allow-Origin: http://localhost, and the GET request can proceed
  2. when making the same GET request using the service fabric reverse proxy URL format, the browser issued OPTIONS pre-flight request (which is identical to the first case) still returns a 204, but no Access-Control-Allow-Origin header is returned.

So the CORS issue seems to be related to the use of the service fabric reverse proxy. Are there specific configuration settings for the SF reverse proxy that need to be set up for this to work?

Thanks Chris

Read more comments on GitHub >

github_iconTop Results From Across the Web

Enabling CORS in Azure Service Fabric Web Api
In your Startup.cs class, do you have this line? : public void ConfigureAuth(IAppBuilder app) { app.UseCors(Microsoft.Owin.Cors.CorsOptions.
Read more >
ASP.NET Core in Azure Service Fabric Reliable Services
Run inside a reliable service. This way allows better integration with the Service Fabric runtime and allows stateful ASP.NET Core services.
Read more >
Enabling CORS in Azure Service Fabric ... - appsloveworld.com
In your Startup.cs class, do you have this line? : public void ConfigureAuth(IAppBuilder app) { app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); }.
Read more >
Azure Service Fabric - Tutorial 5 - Stateless API - YouTube
In this video we will learn how to create a highly available and reliable API using the Service Fabric platform. The API will...
Read more >
Active Directory is not used for Service Fabric authentication
A Service Fabric cluster requires creating Azure Active Directory (AD) applications to control access to the cluster: one web application and one native ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found