Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Environment variables not being used when debugging through a Service Fabric project

When creating an ASP.NET Core app an environment variable called ASPNETCORE_ENVIRONMENT=Development will be set for you and when debugging you will see that the IHostingEnvironment is set to Development.

The problem is that when I use the same project in a solution set up for Service Fabric the environment variables don't seem to get injected and IHostingEnvironment just returns "Production".

How can I resolve this?

Note: I've set a breakpoint in the startup class to observe the IHostingEnvironment variable.

like image 961
The Muffin Man Avatar asked Aug 23 '16 19:08

The Muffin Man


People also ask

How do I set an environment variable in debug?

From the main menu, select Run | Edit Configurations or choose Edit Configurations from the run/debug configurations selector on the toolbar. In the Run/Debug Configurations dialog, select a configuration you want to add the environment variables to. Type the variable name and value: <name>=<value> .

How do I open a fabric Explorer service?

For developer workstation setup, you can launch Service Fabric Explorer on your local cluster by navigating to https://localhost:19080/Explorer.

How do you set up a service in fabric local cluster?

To set up a local cluster, press Start and type Service Fabric Local Cluster Manager and press Enter. From system tray right click to the Service Fabric icon and navigate to Setup Local Cluster → 1 Node. Wait few seconds until you see a notification Service Fabric Local Cluster Manager setup completed successfully.


3 Answers

Reference for this answer: https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-manage-multiple-environment-app-configuration

I ran into the same issue with the default template. The following is similar to Duncan's answer but with two important differences: 1) You will not have to change any template code within the service, and 2) the IHostingEnvironment will be properly set.

First, add the ASPNETCORE_ENVIRONMENT variable to the <CodePackage> element of the PackageRoot\ServiceManifest.xml file of the application service:

<CodePackage Name="Code" Version="1.0.0">
  <EntryPoint>
    <ExeHost>
      <Program>MyService.exe</Program>
      <WorkingFolder>CodePackage</WorkingFolder>
    </ExeHost>
  </EntryPoint>
  <EnvironmentVariables>
    <EnvironmentVariable Name="ASPNETCORE_ENVIRONMENT" Value=""/>
  </EnvironmentVariables>
</CodePackage>

As in Duncan's response, there are two changes you'll make to the ApplicationManifest.xml of your Service Fabric Application project. First, setup a parameter (variable) so that it can be modified when the ApplicationParameters files are substituted based on the way you deploy the project. Then, add an EnvironmentalOverrides section to your ServiceManifestImport element. The results of the two additions will look something like this:

<Parameters>
  <Parameter Name="MyService_InstanceCount" DefaultValue="-1" />
  <Parameter Name="AspNetCoreEnvironment" DefaultValue="" />
</Parameters>

<ServiceManifestImport>
  <ServiceManifestRef ServiceManifestName="MyServicePkg" ServiceManifestVersion="1.0.0" />
  <EnvironmentOverrides CodePackageRef="Code">
    <EnvironmentVariable Name="ASPNETCORE_ENVIRONMENT" Value="[AspNetCoreEnvironment]" />
  </EnvironmentOverrides>
</ServiceManifestImport>

Finally, you can add in the proper values in the individual ApplicationParameters files:

<Parameters>
  <Parameter Name="MyService_InstanceCount" Value="-1" />
  <Parameter Name="AspNetCoreEnvironment" Value="Development" />
</Parameters>

At this point, you can remove the variable from your service's Properties - Debug environmental variables.

like image 77
Paul Armbruster Avatar answered Oct 23 '22 15:10

Paul Armbruster


I ran into the same issue and was able to create a solution that worked for me.

If you look at your ASP.NET Core project, you should see a Program.cs file. At the bottom of it you should see the following interface implementation:

Task<string> ICommunicationListener.OpenAsync(CancellationToken cancellationToken)
{
...
}

You're going to first want to change it to something like the following:

Task<string> ICommunicationListener.OpenAsync(CancellationToken cancellationToken)
{
    var context = FabricRuntime.GetActivationContext();
    var endpoint = context.GetEndpoint(_endpointName);
    var config = context.GetConfigurationPackageObject("Config");
    var environment = config.Settings.Sections["Environment"].Parameters["ASPNETCORE_ENVIRONMENT"].Value;

    var serverUrl = $"{endpoint.Protocol}://{FabricRuntime.GetNodeContext().IPAddressOrFQDN}:{endpoint.Port}";

    _webHost = new WebHostBuilder().UseKestrel()
                                   .UseContentRoot(Directory.GetCurrentDirectory())
                                   .UseStartup<Startup>()
                                   .UseEnvironment(environment)
                                   .UseUrls(serverUrl)
                                   .Build();

    _webHost.Start();

    return Task.FromResult(serverUrl);
}

The key portion is the .UseEnvironment(environment) call, along with the supporting retrieval of the environment from the configuration. This will give ASP.NET Core the necessary information it needs to choose the environment.

Having done this, you'll obviously need to add the ASPNETCORE_ENVIRONMENT setting to the config section. That looks like the following:

Under your ASP.NET Core project you'll find a directory called PackageRoot/Config. Inside of that there should be a Settings.xml file. Add the following code inside the <Settings> tag...

<Section Name="Environment">
  <Parameter Name="ASPNETCORE_ENVIRONMENT" Value="" />
</Section>

Next, you're going to want to look at the ApplicationPackageRoot/ApplicationManifest.xml file inside the actual Service Fabric Project (this is NOT the ASP.NET Core project). Two file changes are required.

  1. Add the ASPNETCORE_ENVIRONMENT parameter inside the <Parameters> tag at the top of the file like so:

    <Parameter Name="ASPNETCORE_ENVIRONMENT" DefaultValue="" />
    
  2. Modify your <ServiceManifestImport> tag to include a <ConfigOverrides> section like so:

    <ConfigOverrides>
      <ConfigOverride Name="Config">
        <Settings>
          <Section Name="Environment">
            <Parameter Name="ASPNETCORE_ENVIRONMENT" Value="[ASPNETCORE_ENVIRONMENT]" />
          </Section>
        </Settings>
      </ConfigOverride>
    </ConfigOverrides>
    

Finally, modify your ApplicationParameters/Local.1Node.xml and friends to contain the ASPNETCORE_ENVIRONMENT parameter:

<Parameter Name="ASPNETCORE_ENVIRONMENT" Value="Development" />

It's a lot of steps to add a freaking variable you can retrieve, but it does allow you a great deal of flexibility and follows the standard Service Fabric pattern to make deployments simple. I hope this helps!

like image 20
Duncan Hill Avatar answered Oct 23 '22 14:10

Duncan Hill


The answer from Duncan worked for me, but there is a small variation for me, maybe due to the version of ASP.NET Core and Service Fabric I use.

I need to override the method CreateServiceInstanceListeners in my Web Stateless Service. So that means I'll have this code:

protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
    return new ServiceInstanceListener[]
    {
        new ServiceInstanceListener(serviceContext =>
            new WebListenerCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
            {
                ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting WebListener on {url}");

                var environment = FabricRuntime.GetActivationContext()
                    ?.GetConfigurationPackageObject("Config")
                    ?.Settings.Sections["Environment"]
                    ?.Parameters["ASPNETCORE_ENVIRONMENT"]?.Value;

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

Of course, you need to set the ASPNETCORE_ENVIRONMENT variable as explained by Duncan.

like image 35
Remy Burney Avatar answered Oct 23 '22 15:10

Remy Burney