I am starting a web api which uses postgres as the backend.
I am on a team of developers that will each have a local db for development. How can I ensure that if a new developer comes on the team that their local db is created without manually creating it themself.
As of right now, we each created our local db's through command line and update our appsettings.Development.json to use our local db connection string (which is on the gitignore incase we use sensitive passwords).
It's annoying to have to manually set this portion up however. Is there anyway to just have a database be created on the fly? As in, right when they launch the API, the db should be created and the migrations applied onto it.
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"Local": "Server=localhost;Port=5432;Database=mydb;User ID=xxx;Password=xxx;"
}
}
Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
UpdateDatabase(app);
// Other configurations
}
public virtual void UpdateDatabase(IApplicationBuilder app)
{
using var serviceScope = app.ApplicationServices
.GetRequiredService<IServiceScopeFactory>()
.CreateScope();
using var context = serviceScope.ServiceProvider.GetService<MyDbContext>();
context.Database.EnsureCreated();
context.Database.Migrate();
}
Related
I've been trying to create a migration and then update the database (using EF Core tools and SSMS to check the database). I've been struggling because I have different projects. The organization of my solution is the following:
I want to have the migration and the related DB interactions in VSC.Repo. This means that the context is in this project. Besides that, I have my connection string in the default appsettings, which is in VSC.API (different assembly). I've tried various ways of trying to get the connection string from there, but I always get the following error when I run the "dotnet ef database update" in the VSC.Repo project:
This is my context class:
public class DataContext : DbContext
{
private readonly string connectionString;
public DataContext()
{
}
public DataContext(DbContextOptions<DataContext> options, IConfiguration configuration) : base(options)
{
connectionString = configuration.GetSection("ConnectionStrings:DefaultConnection").Value;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(connectionString);
}
I can't figure out what I'm doing wrong. Any help would me much appreciated.
EDIT: With the hardcoded string it works perfectly fine, but this is bad practice and I don't want to implement this way.
appsettings.json:
"ConnectionStrings": {
"DefaultConnection": "server=localhost;database=vscDatabase;trusted_connection=true;TrustServerCertificate=True;"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
program.cs:
WebApplicationBuilder? builder =
WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
var connectionString =
builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<DataContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
//builder.AddRepoConfigurations();
var app = builder.Build();
Okay so #Panagiotis Kanavos found out that I was executing the command in the wrong project, more precisely, in one that did not have the program.cs, and this was the issue. When I executed in the correct one, it worked just fine.
I have a solution with 2 projects:
function app project
web api .net core 6.0 project
The function app is succesfully logging to app insights, but the web api project is not! Azure portal is showing that both of the projects are configured to write to the same instance of app insights.
Is it a problem that two different resources are writing to the same app insights instance? If not, what am I doing wrong?
To configure Application Insights with telemetry you need to configure both telemetry and logging independently. Manual configuration or convention based in config configuration can both be used:
https://learn.microsoft.com/en-us/azure/azure-monitor/app/asp-net-core?tabs=netcore6
Manually setting options when configuring DI:
public void ConfigureServices(IServiceCollection service)
{
// ...
ApplicationInsightsServiceOptions telemetryOptions = new ();
telemetryOptions.InstrumentationKey = YourInstrumentationKey;
// Can enable/disable adaptive sampling here.
// https://learn.microsoft.com/en-us/azure/azure-monitor/app/sampling
telemetryOptions.EnableAdaptiveSampling = false;
services.AddApplicationInsightsTelemetry(telemetryOptions);
services.AddLogging(logBuilder =>
{
logBuilder.AddApplicationInsights(YourInstrumentationKey)
// adding custom filter for specific use case.
.AddFilter("Orleans", (level) => level == LogLevel.Error);
});
// ...
}
When using appsettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ApplicationInsights": {
"ConnectionString": "Copy connection string from Application Insights Resource Overview"
}
}
Then DI is can be slightly simplified:
public void ConfigureServices(IServiceCollection service)
{
// ...
services.AddApplicationInsightsTelemetry();
services.AddLogging(logBuilder => logBuilder.AddApplicationInsights()});
// ...
}
Currently i am working on a .Net core 3.1 App. I am using below code in the startup to Add the Dbcontext.
services.AddDbContext<sampleContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
As this is the code first approach i have below code in the Dbcontext
public class sampleContext: DbContext
{
public sampleContext()
{
}
public sampleContext(DbContextOptions<sampleContext> options) : base(options){ }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(Environment.GetEnvironmentVariable("DefaultConnection", EnvironmentVariableTarget.Process));
}
}
}
When i am running the API, its working as expected as optionsBuilder.IsConfigured=true.
Appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\MSSQLLocalDB;Initial Catalog=sampleDb; Integrated Security=true;"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"UploadFAUrl": "http://localhost:7071/Api"
}
Coming to issue:-
When i am running the CLI command ADD-MIGRATION sampleCongetting **Value cannot be null. (Parameter 'connectionString')**
Whys is so? As we will be moving to different env, we may need to run this command. Atleast in local, we need to run the command. How to fix this issue? Referred some of the question but non helped. PLease suggest if i am missing anything.
The EF Core command line tools, will attempt to locate all required services and configuration, based on your current project. By looking for your CreateHostBuilder method, and calling it;
public static IHostBuilder CreateHostBuilder(string[] args) => ...
You shouldn't need to override OnConfiguring. But you may need to provide an explicit --startup-project command line parameter.
Do you have multiple projects?
Mark the project Set as startup project which contains Appsettings.json.
I have Serilog configured to write to both an MSSQL table and to a File (to try and determine whats happening.) on a WebApi with ASP.NET core (running Core 2.1).
I add the Serilog logging in my startup.cs as follows;
public async void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
var log = new LoggerConfiguration()
.MinimumLevel.Verbose()
.WriteTo.MSSqlServer(
DbGlobals.DevDatabase, "Logs", schemaName:DbGlobals.SchemaName)
.WriteTo.File("Logs\\Serilog\\log.txt", rollingInterval: RollingInterval.Day)
.CreateLogger();
loggerFactory.AddSerilog(log);
where DbGlobals.DevDatbase and Dbglobals.SchemaName are string read from the configuration.
UPDATE For reference these values are;
DbGlobals.Schema = "MySchema";
DbGlobals.DevDatabase = "Data Source=xx.xx.xx.xx;Initial Catalog=DevDatabase;Integrated Security=False;Persist Security Info=False;User ID=LOGIN;Password=PASSWORD;MultipleActiveResultSets=true;";
When running locally with IIS Express and under both debug and release configurations, both logging functions are working correctly. So for example in my controller;
public class ReviewPublicController : Controller
{
private readonly IReviewService _service;
private readonly IMapper _mapper;
private readonly IMailService _mailService;
private readonly ILogger _logger;
public ReviewController(
IReviewService service,
ILogger<ReviewController> logger)
{
_service = service;
_logger = logger;
}
[HttpPost]
[ProducesResponseType(typeof(Review), 201)]
[Route("")]
public async Task<IActionResult> Post([FromBody]ReviewPostModel model)
{
_logger.LogDebug("Posting Review");
...
return Ok();
}
So locally "Posting Review" is written to both my File and DbSchema.
However, when I publish to my server, the above "Posting Review" entry is not written to either.
Both appear to be working as information entries are being added from EF and routing etc but not when I specifically try to write an entry?
Can anyone direct me here as to what the issue could be please?
The current nuget versions are;
Serilog 2.7.1
Serilog.AspNetCore 2.1.1
Serilog.Sinks.MSSqlServer 5.1.2
Serilog.Sinks.File 4.0.0
Also, I have the following in my appsettings.json;
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
}
},
"Release": {
"LogLevel": {
"Default": "Warning"
}
},
"Console": {
"LogLevel": {
"Default": "Warning"
}
}
update
As in the docs:
Default Level - if no MinimumLevel is specified, then Information level events and higher will be processed.
So basically, it seems that your configuration is either invalid or overwritten. see: https://github.com/serilog/serilog/wiki/Configuration-Basics
LogDebug is disabled by default in a Release build, which is probably what your publish is.
Please try with
_logger.LogInformation("Posting Review");
For me what was the solution is to remove the "restrictedToMinimumLevel": "Information" from appsettings.json.
It was exactly the same in appsettings.Development.json and it was working well in Development environment.
For me, I have configured all above. It logs db in my local environment, where as it does not work in dev environment. The issue is due to authentication. I am using azure ad authentication for my application that restricts serilog to write into server. So, In my program.cs file, I have added the below settings.
Program.cs
var sqlSinkOptions = new MSSqlServerSinkOptions
{
TableName = "MyLogTableName",
UseAzureManagedIdentity = true, // This line
AzureServiceTokenProviderResource = "https://database.windows.net/" // This line
};
After that, I can see logging is happening in dev environment too. May be this helps some one. Happy coding!
I can't seem to get Trace level log information outputted after upgrading to .NET Core 2.0 (+ASP.NET Core 2.0).
In fact, if I do a dotnet new webproject and add the code below in Startup for Configure, I do not get any trace or debug log messages, but I get the Information and Error messages twice. Commenting out the .AddConsole()call will output these (Information and Error) only once - suggesting that it gets configured automatically with a console provider by default. Keep in mind, this is a "File -> New" project experience, there is nothing setup in Program.cs for logging or configuration at all for this - except for what I've added. Anyone seen things? Or should I register a GitHub issue for it.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Microsoft.Extensions.Logging.LogLevel.Trace);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.Run(async (context) =>
{
var logger = loggerFactory.CreateLogger("Blah");
logger.LogTrace("Hello world : Trace");
logger.LogDebug("Hello world : Debug");
logger.LogInformation("Hello world : Information");
logger.LogError("Hello world : Error");
await context.Response.WriteAsync("Hello World!");
});
}
The way logging is configured has changed a little... The recommended way (and it's pretty well documented in this GitHub issue/announcement to do it now is to configure the loggers on the AddLogging method, such as
services.AddLogging(builder =>
{
builder.AddConfiguration(Configuration.GetSection("Logging"))
.AddConsole()
.AddDebug();
});
And have an appsettings.json like
Notice
Seems a few people are confused, because the example only demonstrates the configuration of Console provider and not all loggers.
The LogLevel section configures logging level for all namespaces (Default key) or for a specific namespace (System overrides the default value for all classes logging whose namespace starts with System.*.
This is for the class used in T in ILogger<T>). This allows to set a higher or lower than default logging level for loggers from this namespace.
{
"ApplicationInsights": {
"InstrumentationKey": ""
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Information",
"System": "Warning",
"Microsoft": "Information"
},
"Console": {
"LogLevel": {
"Default": "Warning",
"System": "Information",
"Microsoft": "Information"
}
}
}
}
Please note that the structure of the appsettings.json changed from what it used to be in .NET Core 1.x and that Logging entry in the appsettings.json now has logger provider names in it, which allows you to configure logging levels per logging provider.
Previously, the entry in appsettings.json would only be applicable to the console logger.
Alternatively, the logging can now be moved within the WebHostBuilder instead.
public static void Main()
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddJsonFile("hosting.json", optional: false)
.AddEnvironmentVariables();
})
.ConfigureLogging((webhostContext, builder) => {
builder.AddConfiguration(webhostContext.Configuration.GetSection("Logging"))
.AddConsole()
.AddDebug();
})
.UseIISIntegration()
.UseStartup<Startup>()
.UseApplicationInsights()
.Build();
host.Run();
}
Update
In case one doesn't want to use the appsettings.json, one can register the filters in code too.
services.AddLogging(builder =>
{
builder.AddConfiguration(Configuration.GetSection("Logging"))
// filter for all providers
.AddFilter("System", LogLevel.Debug)
// Only for Debug logger, using the provider type or it's alias
.AddFilter("Debug", "System", LogLevel.Information)
// Only for Console logger by provider type
.AddFilter<DebugLoggerProvider>("System", LogLevel.Error)
.AddConsole()
.AddDebug();
});
I spent almost twenty minutes to realize that since Configuration.GetSection("Logging") in the Startup.cs file reads the section "Logging" from the config in the appsettings.json file, which was configured as "Error". Changing it to "Information" or anything lower, fixed the issue.
Here's what the appsettinsg.json file looks now:
{
"Logging": {
"IncludeScopes": true,
"Debug": {
"LogLevel": {
"Default": "Information"
}
},
"Console": {
"LogLevel": {
"Default": "Information"
}
}
}
}
To find out more about the levels of logging (such as in "Information"), check out this link, that also provides general information on ASP.NET Core logging.
I'm just posting here, just in case you bump into any trouble with getting the logging to work, make sure you've been through that JSON file.
Nothing of the above works for me
The only workaround was to write a method
private void ConfigLogging( ILoggingBuilder builder ) {
builder.SetMinimumLevel( LogLevel.Trace );
//... additional configuration...
}
and when using the AddLogging extension method write it as
services.AddLogging( ConfigLogging );
The following structure of appsettings.json seems to work fine:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"System": "Information",
"Microsoft": "Information"
},
"Console":
{
"IncludeScopes": true
}
}
}
Taken from https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-2.1
Also, see what your start up calls are, I find the following works for me:
public class Startup
{
public Startup(IHostingEnvironment env)
{
var logger = new LoggerConfiguration()
.MinimumLevel.Information()
.WriteTo.Sink(jsonSink)
.Enrich.WithExceptionDetails()
.CreateLogger();
Log.Logger = logger;
}
}