L'erreur Azure est:
.Net Core: Exception au démarrage de l'application: System.IO.FileNotFoundException: Le fichier de configuration 'appsettings.json' est introuvable et n'est pas facultatif.
C'est donc un peu vague. Je n'arrive pas à comprendre. J'essaie de déployer un projet d'API Web .Net Core sur Azure et j'obtiens cette erreur:
:( Oops. 500 Internal Server Error Une erreur s'est produite lors du démarrage de l'application.
J'ai déployé de vieux .APP Web Net simples et ils ont travaillé. J'ai suivi des tutoriels en ligne et ils ont travaillé. Mais de toute façon mon projet est fauché. Activer stdoutLogEnabled sur Web.config et consulter les journaux de streaming Azure me donne ceci:
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, cela semble simple. Il ne peut pas trouver appsettings.json. En regardant ma config (startup.cs), il semble très bien défini. Ma startup ressemble à ceci:
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();
}
}
Cela fonctionne bien localement. Mais une fois que nous publions sur Azure, cela échoue. Je suis à perte. J'ai créé un nouveau projet principal .Net qui se déploie sur Azure. Mais ce projet, dans lequel je mets tout mon temps, semble échouer. Je suis sur le point de copier et coller du code du projet qui ne fonctionne pas et qui est intégré dans un nouveau projet, mais je suis vraiment curieux de savoir ce qui ne fonctionne pas.
Des idées?
EDIT: Donc mon Program.cs était:
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: Par Frans, j'ai vérifié les publishOptions. C'était:
"publishOptions": {
"include": [
"wwwroot",
"web.config"
]
J'ai pris un publishOptions d'un projet en cours de travail et je l'ai changé pour:
"publishOptions": {
"include": [
"wwwroot",
"Views",
"Areas/**/Views",
"appsettings.json",
"web.config"
]
},
Il a toujours donné une erreur 500, mais il n'a pas donné de trace de pile indiquant qu'il pouvait charger load appsettings.json. Maintenant, il se plaignait d'une connexion à SQL. J'ai remarqué que mon code de chaîne de connexion SQL est mentionné dans de nombreux articles de blog RC1. RC2 de .Net Core l'a changé. Alors je l'ai mis à jour pour:
"Data": {
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\MSSQLLocalDB;Database=QuantaDb;Trusted_Connection=True;MultipleActiveResultSets=true"
}
},
Et a changé mon démarrage à:
services.AddDbContext<QuantaContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
b => b.MigrationsAssembly("Quanta.API")));
Enfin, cela a fonctionné.
J'ai dû suivre un exemple plus ancien de RC1 et ne pas m'en rendre compte.
Vérifiez les options publishOptions dans project.json et assurez-vous que la section "include" contient "appsettings.json". Ils ont modifié le modèle de publication dans RTM pour vous obliger à spécifier tout ce que vous voulez copier du répertoire de compilation dans le dossier Web.
EDIT: Voir la réponse de Jensdc ci-dessous pour savoir comment procéder avec .csproj après la mort de project.json.
Dans les versions ultérieures .net, un fichier *. Csproj est utilisé à la place du fichier project.json.
Vous pouvez modifier le fichier pour obtenir le résultat souhaité en ajoutant:
<ItemGroup>
<Content Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
Dans votre project.json
assurez-vous que vous avez inclus appsettings.json
comme copyToOutput
"buildOptions": {
"emitEntryPoint": true,
"preserveCompilationContext": true,
"copyToOutput": {
"include": [ "appsettings.json" ]
}
},
Dans mon cas, le fichier appsettings.json
dans le dossier du projet, mais il n'a pas été marqué Do not copy
, J'ai changé le réglage en Copy always
(voir les images ci-dessous). Et cela a fonctionné pour moi.
Il sera automatiquement ajouté après XML à votre project.csproj
fichier:
<ItemGroup>
<Content Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
J'ai regardé une autre réponse, project.json
est mort comme cela réponse dit.
Vous n'avez pas besoin d'ajouter votre fichier .json pour publier des options. c'est juste qu'il cherche le fichier au mauvais chemin.
définir le chemin de base, puis ajouter un fichier JSON et cela fonctionnera.
public Startup(IHostingEnvironment environment)
{
var builder = new ConfigurationBuilder()
.SetBasePath(environment.ContentRootPath)
.AddJsonFile("TestJson.json");
Configuration = builder.Build();
}
ici, le constructeur de démarrage est construit avec HostingEnviornment et le chemin de base est défini sur le chemin racine actuel. et ça va marcher!
Pour moi, l'erreur utilisait Directory.GetCurrentDirectory()
. Cela fonctionnait bien en local, mais sur un serveur de production, cela a échoué au démarrage du programme à partir de Powershell
. Remplacé par Assembly.GetEntryAssembly().Location
et tout a fonctionné.
Code complet:
var builder = new ConfigurationBuilder()
.SetBasePath(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location))
.AddJsonFile("appsettings.json");
var configuration = builder.Build();
En ce qui me concerne, cette erreur est due à une erreur de syntaxe de fichier Json (typo: virgule supprimée). Par défaut, la propriété "Copier dans le répertoire de sortie" de appsettings.json est définie sur "Ne pas copier", ce qui me semble être correct.