Frank
Frank

Reputation: 1441

The configuration file 'appsettings.json' was not found and is not optional

The Azure error is:

.Net Core: Application startup exception: System.IO.FileNotFoundException: The configuration file 'appsettings.json' was not found and is not optional.

So this is a bit vague. I can't seem to nail this down. I'm trying to deploy a .Net Core Web API project to Azure, and I'm getting this error:

:( Oops. 500 Internal Server Error An error occurred while starting the application.

I've deployed plain old .Net WebAPI's and they have worked. I've followed online tutorials and they have worked. But somehow my project is broke. Enabling stdoutLogEnabled on Web.config and looking at the Azure Streaming Logs gives me this:

2016-08-26T02:55:12  Welcome, you are now connected to log-streaming service.
Application startup exception: System.IO.FileNotFoundException: The configuration file 'appsettings.json' was not found and is not optional.
   at Microsoft.Extensions.Configuration.FileConfigurationProvider.Load(Boolean reload)
   at Microsoft.Extensions.Configuration.FileConfigurationProvider.Load()
   at Microsoft.Extensions.Configuration.ConfigurationRoot..ctor(IList`1 providers)
   at Microsoft.Extensions.Configuration.ConfigurationBuilder.Build()
   at Quanta.API.Startup..ctor(IHostingEnvironment env) in D:\Source\Workspaces\Quanta\src\Quanta.API\Startup.cs:line 50
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.Extensions.Internal.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider)
   at Microsoft.Extensions.Internal.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, Object[] parameters)
   at Microsoft.Extensions.Internal.ActivatorUtilities.GetServiceOrCreateInstance(IServiceProvider provider, Type type)
   at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetServiceOrCreateInstance(IServiceProvider provider, Type type)
   at Microsoft.AspNetCore.Hosting.Internal.StartupLoader.LoadMethods(IServiceProvider services, Type startupType, String environmentName)
   at Microsoft.AspNetCore.Hosting.WebHostBuilderExtensions.<>c__DisplayClass1_0.<UseStartup>b__1(IServiceProvider sp)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.FactoryService.Invoke(ServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.ScopedCallSite.Invoke(ServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.SingletonCallSite.Invoke(ServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.<>c__DisplayClass12_0.<RealizeService>b__0(ServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureStartup()
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureApplicationServices()
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
Hosting environment: Production
Content root path: D:\home\site\wwwroot
Now listening on: http://localhost:30261
Application started. Press Ctrl+C to shut down.

Ok, that seems simple. It can't find appsettings.json. Looking at my config ( startup.cs ) it seems very well defined. My Startup looks like this:

public class Startup
{
    private static string _applicationPath = string.Empty;
    private static string _contentRootPath = string.Empty;
    public IConfigurationRoot Configuration { get; set; }
    public Startup(IHostingEnvironment env)
    {
        _applicationPath = env.WebRootPath;
        _contentRootPath = env.ContentRootPath;
        // Setup configuration sources.

        var builder = new ConfigurationBuilder()
            .SetBasePath(_contentRootPath)
            .AddJsonFile("appsettings.json")
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

        if (env.IsDevelopment())
        {
            // This reads the configuration keys from the secret store.
            // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
            builder.AddUserSecrets();
        }

        builder.AddEnvironmentVariables();
        Configuration = builder.Build();
    }
    private string GetXmlCommentsPath()
    {
        var app = PlatformServices.Default.Application;
        return System.IO.Path.Combine(app.ApplicationBasePath, "Quanta.API.xml");
    }

    // This method gets called by the runtime. Use this method to add services to the container.
    // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
    public void ConfigureServices(IServiceCollection services)
    {
        var pathToDoc = GetXmlCommentsPath();


        services.AddDbContext<QuantaContext>(options =>
            options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"],
            b => b.MigrationsAssembly("Quanta.API")));

        //Swagger
        services.AddSwaggerGen();
        services.ConfigureSwaggerGen(options =>
        {
            options.SingleApiVersion(new Info
            {
                Version = "v1",
                Title = "Project Quanta API",
                Description = "Quant.API",
                TermsOfService = "None"
            });
            options.IncludeXmlComments(pathToDoc);
            options.DescribeAllEnumsAsStrings();
        });

        // Repositories
        services.AddScoped<ICheckListRepository, CheckListRepository>();
        services.AddScoped<ICheckListItemRepository, CheckListItemRepository>();
        services.AddScoped<IClientRepository, ClientRepository>();
        services.AddScoped<IDocumentRepository, DocumentRepository>();
        services.AddScoped<IDocumentTypeRepository, DocumentTypeRepository>();
        services.AddScoped<IProjectRepository, ProjectRepository>();
        services.AddScoped<IProtocolRepository, ProtocolRepository>();
        services.AddScoped<IReviewRecordRepository, ReviewRecordRepository>();
        services.AddScoped<IReviewSetRepository, ReviewSetRepository>();
        services.AddScoped<ISiteRepository, SiteRepository>();

        // Automapper Configuration
        AutoMapperConfiguration.Configure();

        // Enable Cors
        services.AddCors();

        // Add MVC services to the services container.
        services.AddMvc()
            .AddJsonOptions(opts =>
            {
                // Force Camel Case to JSON
                opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            });
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app)
    {
        app.UseStaticFiles();
        // Add MVC to the request pipeline.
        app.UseCors(builder =>
            builder.AllowAnyOrigin()
            .AllowAnyHeader()
            .AllowAnyMethod());

        app.UseExceptionHandler(
          builder =>
          {
              builder.Run(
                async context =>
                {
                    context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                    context.Response.Headers.Add("Access-Control-Allow-Origin", "*");

                    var error = context.Features.Get<IExceptionHandlerFeature>();
                    if (error != null)
                    {
                        context.Response.AddApplicationError(error.Error.Message);
                        await context.Response.WriteAsync(error.Error.Message).ConfigureAwait(false);
                    }
                });
          });

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");

            // Uncomment the following line to add a route for porting Web API 2 controllers.
            //routes.MapWebApiRoute("DefaultApi", "api/{controller}/{id?}");
        });


        //Ensure DB is created, and latest migration applied. Then seed.
        using (var serviceScope = app.ApplicationServices
          .GetRequiredService<IServiceScopeFactory>()
          .CreateScope())
        {
            QuantaContext dbContext = serviceScope.ServiceProvider.GetService<QuantaContext>();
            dbContext.Database.Migrate();
            QuantaDbInitializer.Initialize(dbContext);
        }


        app.UseSwagger();
        app.UseSwaggerUi();


    }
}

This works fine locally. But once we publish to Azure, this fails. I'm at a loss. I've created new .Net core project that deploy to Azure just find. But this one project, that I put all my time into to, seems to fail. I'm about ready to copy and paste code out of the project that fails to run and into a new project, but i'm really curious on what's breaking this.

Any ideas?

EDIT: So my Program.cs was:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;

namespace Quanta.API
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = new WebHostBuilder()
                .UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup<Startup>()
                .Build();

            host.Run();
        }
    }
}

Edit2: Per Frans, I checked the publishOptions. It was:

"publishOptions": {
"include": [
  "wwwroot",
  "web.config"
]

I took a publishOptions from a working project and changed it to:

 "publishOptions": {
  "include": [
    "wwwroot",
    "Views",
    "Areas/**/Views",
    "appsettings.json",
    "web.config"
  ]
  },

It still gave a 500 error, but it didn't give a stack trace saying it coulding load appsettings.json. Now it was complaining about a connection to SQL. I noticed that my SQL connection string code is mentioned in a lot of RC1 blog posts. RC2 of .Net Core changed it. So I updated it to:

  "Data": {
    "ConnectionStrings": {
      "DefaultConnection": "Server=(localdb)\\MSSQLLocalDB;Database=QuantaDb;Trusted_Connection=True;MultipleActiveResultSets=true"
    }
  },

And changed my startup to:

 services.AddDbContext<QuantaContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
        b => b.MigrationsAssembly("Quanta.API")));

Finally, it worked.

I must have followed an older RC1 example and not realized it.

Upvotes: 123

Views: 229969

Answers (16)

Maytham Fahmi
Maytham Fahmi

Reputation: 33377

In My case, the file appsettings.json existed in the project folder, but it was set to Do not copy, I changed the setting to Copy always (see images below). And it worked for me.

It will automatically add the following XML to your project.csproj file:

<ItemGroup>
    <Content Update="appsettings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
</ItemGroup>

I have looked at other answers, project.json is dead as this answer says.

enter image description here

enter image description here

Upvotes: 134

NOCARRIER
NOCARRIER

Reputation: 2635

In .NET 6.0 (dotnet core) try using:

System.AppContext.BaseDirectory

instead of

Directory.GetCurrentDirectory()

IE:

 var configuration = new ConfigurationBuilder()
     .SetBasePath(System.AppContext.BaseDirectory)
     .AddJsonFile

This is what resolved the issue for me in an ASP.NET MVC app.

Upvotes: 4

Ogglas
Ogglas

Reputation: 69928

Update:

From @bunjeeb in comments. Use System.AppContext.BaseDirectory instead of Assembly.GetEntryAssembly().Location for .NET 5 <= with <PublishSingleFile>true</PublishSingleFile>.

Original:

For me the error was using Directory.GetCurrentDirectory(). This worked fine running locally but on a production server it failed when the program was started from Powershell. Replaced with Assembly.GetEntryAssembly().Location and everything worked.

Complete code:

var builder = new ConfigurationBuilder()
        .SetBasePath(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location))
        .AddJsonFile("appsettings.json");

var configuration = builder.Build();

Upvotes: 63

dclipca
dclipca

Reputation: 1937

For me, it was using config.GetConnectionString(); to get the value instead of config.GetValue(). That's after I enabled CopyAlways in when clicking on appsettings.json Properties (right click).

Upvotes: 0

Milen Kovachev
Milen Kovachev

Reputation: 5361

For me the problem was that the appsettings.json file was hidden. How it ended up being hidden I have not idea but the .netcore ConfiguraitonFileProvider has a check for hidden files and does not load them if they are hidden.

Upvotes: 3

zmechanic
zmechanic

Reputation: 1990

I had the same error while the app is being run from network share. It even was trying to locate appsettings.json file at user's desktop.

I ended up combining the path with executable location, like below:

configuration
  .AddJsonFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "appsettings.json"), optional: false, reloadOnChange: false)
  .AddJsonFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"appsettings.{env.EnvironmentName}.json"), optional: true, reloadOnChange: false);

Upvotes: 4

Ali Kazai
Ali Kazai

Reputation: 392

Had the same problem while using .net core 3 and this is what worked.

<None Update="appsettings.json">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

hope this is good

Upvotes: 1

Robert Vogelezang
Robert Vogelezang

Reputation: 153

What worked for me was changing the Copy to Output Directory property on appsettings.json to Copy if newer.

Upvotes: 3

Malhaar Punjabi
Malhaar Punjabi

Reputation: 783

For me, I got this error because of JSON file syntax error (typo: deleted comma).

By default, property "Copy to Output Directory" of appsettings.json set to "Do not Copy" which I think is correct.

Upvotes: 0

Vikas
Vikas

Reputation: 183

This answer is for... Someone trying to debug on VS Code, but appsettings.json is not being picked up. I tried debugging the same solution in Visual Studio, and it worked. Also, I was able to access environment variables. App version: Core 2.2.

I deleted the .vscode folder and debugged again and it worked.

Upvotes: 1

Daniaal
Daniaal

Reputation: 922

I ended up here when publishing my Azure Function from Visual Studio 2019. I got this error when trying to publish my function to the portal with an appSettings.json file. It was copying the appSettings.json to the output directory but not the publish directory. I had to add the line below to the .csproj of the azure function project.

<CopyToPublishDirectory>Always</CopyToPublishDirectory>

So my .csproj would look like the below:

<ItemGroup>
<None Update="host.json">
  <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="appsettings.json">
  <CopyToOutputDirectory>Always</CopyToOutputDirectory>
  <CopyToPublishDirectory>Always</CopyToPublishDirectory>
</None>
<None Update="local.settings.json">
  <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

Upvotes: 4

flytzen
flytzen

Reputation: 7438

Check the publishOptions in project.json and make sure the "include" section has "appsettings.json" in it. They changed the publish model in RTM to require you to specify everything you want copied from the compile directory to the web folder.

EDIT: See Jensdc answer below for how to do this with .csproj after project.json was killed.

Upvotes: 22

Felipe Augusto
Felipe Augusto

Reputation: 8184

For me, what solved was setting to include the appsettings.json via interface on the output directory (Build directory), like so:

enter image description here

Upvotes: 14

S.Akruwala
S.Akruwala

Reputation: 1536

You don't need to add your .json file to publish options. it's just that it is looking for the file at the wrong path.

set base path and then add json file and it will work.

 public Startup(IHostingEnvironment environment)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(environment.ContentRootPath)
            .AddJsonFile("TestJson.json");

        Configuration = builder.Build();
    }

here, startup constructor is built with with HostingEnviornment and base path is set to the current root path. and it will work!

Upvotes: 12

Jensdc
Jensdc

Reputation: 1260

In later .net core versions a *.csproj file is used instead of the project.json file.

You can modify the file to get the desired result by adding:

   <ItemGroup>
      <Content Update="appsettings.json">
        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      </Content>
   </ItemGroup>

Upvotes: 102

devfric
devfric

Reputation: 7512

In your project.json

ensure you have inlcuded appsettings.json as a copyToOutput

"buildOptions": {
   "emitEntryPoint": true,
   "preserveCompilationContext": true,
   "copyToOutput": {
     "include": [ "appsettings.json" ]
   }
 },

Upvotes: 36

Related Questions