简体   繁体   中英

How to access appsettings.json from Azure Service Fabric stateless service

I have a solution with a stateless service project (.sfproj) and a corresponding console app project.

I have added appsettings.json to the console app project and am trying to set up access to it using this:

protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
    //return this.CreateServiceRemotingInstanceListeners(); //This line works
    return new ServiceInstanceListener[] //This line causes an error in Service Fabric Explorer
    {
        new ServiceInstanceListener(serviceContext =>
            new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
            {
                ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting Kestrel on {url}");

                return new WebHostBuilder()
                    .UseKestrel()
                    .ConfigureAppConfiguration((builderContext, config) =>
                    {
                        config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
                    })
                    .ConfigureServices(
                        services => services
                            .AddSingleton<StatelessServiceContext>(serviceContext))
                    .UseContentRoot(Directory.GetCurrentDirectory())
                    //.UseStartup<Startup>() //Startup.cs does not exist
                    .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
                    .UseUrls(url)
                    .Build();
            }))
    };
}

This doesn't compile because I don't have a Startup class as it's not a web api project, it's using a stateless service. The only classes I have in the console app are Program.cs , Service.cs and ServiceEventSource.cs

I tried removing the .UseStartup<Startup>() to get it to compile, however when I run the application, I get the following error in Service Fabric Explorer:

'System.FM' reported Error for property 'State'.
Partition is below target replica or instance count.
fabric:/Integration/Integration.Service 1 1 9810816d-5be9-4b53-9eed-c5be403219b0
  InBuild _Node_1 132003711574580709
  (Showing 1 out of 1 instances. Total available instances: 0)

I can fix this by using return this.CreateServiceRemotingInstanceListeners(); instead, however then I don't know how to set up access to appsettings.json.

How can I access appsettings.json from within my stateless service?

EDIT:

I managed to get it working using this in Service.cs :

        protected override async Task RunAsync(CancellationToken cancellationToken)
        {
            Microsoft.AspNetCore.WebHost.CreateDefaultBuilder()
                .ConfigureAppConfiguration((builderContext, config) =>
                {
                    var env = builderContext.HostingEnvironment;
                    config.SetBasePath(env.ContentRootPath)
                        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                        .AddEnvironmentVariables();
                })
                .UseStartup<Startup>()
                .Build()
                .Run();
        }

I added this to ServiceManifest.xml to make sure env.ContentRootPath points to the code package folder which contains the appsettings.json files (the default seems to be the Work folder which was empty for me):

<EntryPoint>
  <ExeHost>
    <Program>TheAppNameGoesHere.exe</Program>
    <WorkingFolder>CodePackage</WorkingFolder>
  </ExeHost>
</EntryPoint>

I added this Startup class:

public class Startup
{
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    { }
}

I feel like there must be a better way to access appsettings.json , especially considering the Startup.Configure() method is doing nothing.

Does anyone know a better way to access appsettings.json ?

it happens because you have to specify the name of the assembly running the app's entry point. The docs explain how should be set.

When you use .UseStartup<Startup>() it get the assembly information from the Startup class, because you don't have one, it does not know where the entry point is.

This github issue and this shows similar issues.

This is an example I've got from one of my apps running in SF:

        var builder = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .ConfigureServices(services => services.AddSingleton(startup))
            .UseApplicationInsights()
            .UseSetting(WebHostDefaults.ApplicationKey, startup.GetType().Assembly.FullName);

In the above example, startup is an instance of a class that implements Microsoft.AspNetCore.Hosting.IStartup with following methods:

    void Configure(IApplicationBuilder app);
    IServiceProvider ConfigureServices(IServiceCollection services);

PS: You don't use .UseStartup<Startup>() in the example above, but you could if there was one in the project.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM