I have a .net 6 project, and I have two json files for config, appsettings.json & appsettings.Development.json.
In my launch settings, I have my ASPNETCORE_ENVIRONMENT set to Development. In Program.cs I have the standard code of:
var builder = WebApplication.CreateBuilder(args);
I can see that the settings from appsettings.json are loaded when CreateBuilder is run.
I read from a Microsoft site, that, if you have an environmental appsettings file loaded, by default, it should replace the appsettings.json file. But in my project, this is not the behaviour.
This is meaning, for my connection strings, I am getting those in appsettings.json, not appsettings.Development.json
I have tried adding the file myself using:
var environment = builder.Environment;
builder.Host.ConfigureAppConfiguration(hostingContext, config) =>
{
config.AddJsonFile($"appsettings.{enironment.EnvironmentName}.json", optional: true, reloadOnChange: true)
});
But, this does not override either.
I am presuming that I am missing a setting, or something similar to get it to overwrite the config.
Is anyone able to shed any light on what my mistake is?
I have found a solution to this, but, I have no idea why it caused an issue in the first place.
I am using dapper, and I have an extension method to register it.
When this was not working, I was doing the following:
var db = "test";
builder.Services.AddDapperSqlServer(builder.Configuration.GetConnectionString(db));
I changed it to be:
var db = "test";
var connectionString = builder.Configuration.GetConnectionString(db);
builder.Service.AddDapperSqlServer(connectionString);
And it now works. If anyone knows why, I would love to know.
Related
The API is using .NET Core 3.1 and the folder structure is as follows:
Solution
--Project1
--Project2
Where Project 2 depends on Project 1 and is the entry point.
The API is hosted on kubernetes and a NFS share is mounted at /storage. The API will need to retrieve and serve files in this file share. So what I did was using the following in my startup.cs in Project2:
app.UseFileServer(new FileServerOptions()
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), #"storage")),//this will return /app/storage
RequestPath = new PathString("/resources")
});
I know one of the file is there by checking:
System.IO.File.Exists(#"/app/storage/test.JPG");
However, when I tried to access the file by going to http://myapiurl/resources/test.JPG, I always got a 404 not found.
I was wondering what I was missing?
You're using UseFileServer, but you're not enabling directory browsing nor serving default files, so I'd recommend narrowing instead to using UseStaticFiles.
The easiest way to enable this is to just place the following in your Startup.cs file in your Configure() method.
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.ContentRootPath, "storage")),
RequestPath = "/resources"
});
My guess for why this isn't working for you is that Directory.GetCurrentDirectory, when running in K8 isn't yielding the same path you see when running locally, so it's not ultimately pointing at /app/storage (which is why your File.Exists check works fine because you're not building the path out dynamically).
Use some logging to verify that it's pulling from the right path in your configuration at runtime.
I had a similar problem with static files after switching from AppService to k8s with ingress. It turned out to be problem with case-sensitivity in the URL. Some directories were uppercase, but in paths I had all lowercase letters. It was working locally on Windows and on AppService but not on k8s.
In the documentation it says that I can do the following in code to further configure my integration:
Each key provides an in code example and a config file example.
configuration.ReleaseStage = "development";
What I am trying to do is:
public static void Register(HttpConfiguration config)
{
var configuration = Bugsnag.ConfigurationSection.Configuration.Settings;
configuration.ReleaseStage = ConfigurationManager.AppSettings["Environment"];
config.UseBugsnag(configuration);
}
However, the configuration properties are read-only (don't have setters).
The alternative is to add the configurations to the Web.config:
<bugsnag apiKey="your-api-key" releaseStage="development">
The problem is that I am reading my environment from the AppSettings and therefore cannot do it this way.
Is it possible to do the configuration in code and if so, how?
UPDATE: Since posting the question I have found the issue on GitHub.
From the GitHub issue it seems as if this isn't possible so I used the work around suggested by one of the project's contributors.
The only work around I can suggest right now is to use the core Bugsnag nuget package...
I removed all the 'old' code, uninstalled all the NuGet packages except for the base Bugsnag and added the following code to the OnException override method where I had been logging exceptions up until now.
var configuration = new Configuration("API_KEY")
{
ReleaseStage = myReleaseStage
};
var client = new Bugsnag.Client(configuration);
client.Notify(new System.Exception("Error!"));
This worked and errors are now logged along with the environment in which they occurred. My next step will be to refactor this work around so that client is available globally but for now this solves my in code problem.
From Bugsnag's latest Go documentation, you can programmatically set the release stage. In your example, it would look like this:
configuration.ReleaseStage = ConfigurationManager.AppSettings["Environment"];
I am building an application in ASP.NET Core 2.0 and I am having problems with EntityFramework Migrations.
I have my DbContext in a separate project (SolutionName\ProjectNamePrefix.Data) and therefore I created an implementation for the IDesignTimeDbContextFactory interface.
I wanted to use different connection strings for different environments and I need appsettings.json for that.
So after a quick search I found that I can create a new IConfigurationRoot object inside the CreateDbContext function as shown here:
https://codingblast.com/entityframework-core-idesigntimedbcontextfactory/
I added that and then for testing, tried to run dotnet ef migrations list -c MyContext from the Data project root folder.
Then I got the following error:
The configuration file 'appsettings.json' was not found and is not optional. The physical path is 'C:\dev\*SolutionName*\*ProjectNamePrefix*.Data\bin\Debug\netcoreapp2.0\appsettings.json'.
So, basically, I tried 3 options for getting the correct root path:
Directory.GetCurrentDirectory();
env.ContentRootPath; (IHostingEnvironment object, I found a way to get it here: https://github.com/aspnet/Home/issues/2194)
AppDomain.CurrentDomain.BaseDirectory;
and all of them returned the same ..\bin\debug\netcoreapp2.0\ path. When I run the Data project from VS, then the two first options give me the correct project root folder.
Is there a way to get the correct project content root folder?
Because when I added --verbose to the EF command, it logged out a row:
Using content root 'C:\dev\FitsMeIdentity\FitsMeIdentity.Data\'.
So I understand that EF somehow knows the project root but all the options mentioned above return the path for the already built application.
The only option I found that works is that I change Copy output to root folder to Copy always but found from here: https://www.benday.com/2017/02/17/ef-core-migrations-without-hard-coding-a-connection-string-using-idbcontextfactory/ that it's not a good idea.
At first I even thought about creating a Constructor for the IDesignTimeDbContextFactory implementation which gets IOptions as a parameter but that didn't work, had the same problem as explained here:
Injecting Env Conn String into .NET Core 2.0 w/EF Core DbContext in different class lib than Startup prj & implementing IDesignTimeDbContextFactory
A little late, but here is the solution for those who hate hard-coding connections strings:
internal class MigrationDbContextFactory : IDesignTimeDbContextFactory<AppDbContext>
{
public AppDbContext CreateDbContext(string[] args)
{
IConfigurationRoot configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", false)
.Build();
string connectionString = configuration.GetConnectionString("DefaultConnection");
DbContextOptionsBuilder<AppDbContext> optionsBuilder = new DbContextOptionsBuilder<AppDbContext>();
optionsBuilder.UseMySql(connectionString,
ServerVersion.AutoDetect(connectionString),
mySqlOptions =>
mySqlOptions.EnableRetryOnFailure(
maxRetryCount: 10,
maxRetryDelay: TimeSpan.FromSeconds(30),
errorNumbersToAdd: null));
return new AppDbContext(optionsBuilder.Options);
}
}
No. You can't do this, and more to the point: you're not supposed to do this. The whole entire point of IDesignTimeDbContextFactory is that it's a way to get a DbContext instance from in a context where there is no ASP.NET Core framework to work with, i.e. from a class library. If you're running migrations from an ASP.NET Core project, you don't need it, and if you're not, none of the configuration stuff is available.
Additionally, it's only to be used for development, hence the "DesignTime" part of the name. As a result, there's no need for stuff like switching between connection strings for different environments. Just hard-code the connection string as the docs detail.
I am trying to get my head around the .netcore way of configuring an application.
Szenario:
I am running the same rest api (application) for client1 and client2 on the same server in the DEV-Environment.
We have environment specific configurations as well as client specific configurations.
"Old" Way:
With web.config transformations, I created build configurations for dev-client1 and dev-client2 and set the values accordingly...this all worked fine.
"New" Way:
As the appsettings.json depends on the windows environment variable (one per server) and therefore run into troubles. I could not find a way so far to run the apps in parallel on the same server with different configurations.
I might have missunderstood the new way of configuring an application, therefore any help would be appreciated.
in a typical new .NET Core web app, you will see this code in the Startup.cs:
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{environment.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables()
.Build();
all you need to do is add another appsettings file with client-specific settings, like:
.AddJsonFile($"appsettings.client.json", optional: true)
then have your build script copy in the correct build configuration to appsettings.client.json. the ConfigurationBuilder will pick up the settings in all the sources and compile them into the configuration object.
also check out the full docs:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration
I'm reading an embedded xml file using
C#:
var AssemblyRef = Assembly.GetExecutingAssembly();
TextReader reader = new StreamReader(AssemblyRef.GetManifestResourceStream("Text.xml"));
It has been working for some time, but starting throwing errors. I traced the path that it is looking for and it is looking for the dll in the root of the bin folder and not in the Debug or release folder.
Once it is published this is fine, but for local development I cannot get my one feature to work.
I have it set to Debug when compiling. Any help would be great.
You have:
Changed Assembly Name OR
Changed namespace OR
Moved the resource to a folder in the project
I changed the call to this and everything is fine.
TextReader reader = new StreamReader(Assembly.GetExecutingAssembly().AssemblyRef.GetManifestResourceStream("Text.xml"));
Making the call one statement made it work. I'm not sure why.