ASP NET CORE GetConnectionString doesn't work - asp.net-core

I'm new to ASP NET CORE and I'm writing new web API. I'm not able to retrieve connection string from the appsettings.json file and I get an
ArgumentNullException.
This is the code in my Startup class:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddDbContext<MyDBContext>(options => options.UseSqlServer(Configuration.GetConnectionString("MyDBConnection")));
...
}
}
This is my appsettings.json file:
{
"ConnectionStrings": {
"MyDBConnection": "..."
},
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
}
},
"Console": {
"LogLevel": {
"Default": "Warning"
}
}
}
}
What am I missing?
EDIT:
This is also my Program.cs class:
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>();
}

Just to answer this. Directory.GetCurrentDirectory() will get the bin/debug or release location.
This means that it will not be the project location. So it can not find the application.json and also it would also not be able to find your MVC views later on.

Related

How to log exception to appinsights using serilog?

Net core application. I am trying to log exceptions but this is not working as expected. Below is my configuration
Program.cs
public static void Main(string[] args)
{
Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(configuration).CreateLogger();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog((hostContext, loggerConfiguration) =>
{
loggerConfiguration.ReadFrom.Configuration(hostContext.Configuration);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
Startup.cs
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddApplicationInsightsTelemetry(Configuration["APPINSIGHTS_CONNECTIONSTRING"]);
services.AddApplicationInsightsTelemetry();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseMiddleware<ExceptionMiddleware>();
app.UseSerilogRequestLogging();
}
}
ExceptionMiddleware.cs
public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
//private readonly ILogger _logger;
private readonly ILogger _logger = Serilog.Log.ForContext<ExceptionMiddleware>();
public ExceptionMiddleware(RequestDelegate next, ILogger logger)
{
_logger = logger;
_next = next;
}
public async Task InvokeAsync(HttpContext httpContext)
{
try
{
await _next(httpContext);
}
catch (Exception ex)
{
// _logger.Error($"Something went wrong: {ex}");
_logger.Error(ex.Message, $"Something went wrong:");
await HandleExceptionAsync(httpContext, ex);
}
}
private async Task HandleExceptionAsync(HttpContext context, Exception exception)
{
var user = string.Empty;
if (context.User.Claims.Any())
user = context.User.Claims?.FirstOrDefault(cl => cl.Type.Contains("preferred_username"))?.Value ?? "Anonymous User";
context.Response.ContentType = "application/json";
context.Response.StatusCode = ConfigurateExceptionTypes(exception);
await context.Response.WriteAsync(new Models.ErrorDetails()
{
UserName = user,
StatusCode = context.Response.StatusCode,
Message = exception.Message
}.ToString());
}
private static int ConfigurateExceptionTypes(Exception exception)
{
int httpStatusCode;
switch (exception)
{
case var _ when exception is ValidationException:
httpStatusCode = (int)HttpStatusCode.BadRequest;
break;
default:
httpStatusCode = (int)HttpStatusCode.InternalServerError;
break;
}
return httpStatusCode;
}
}
AppSettings.json
"Serilog": {
"Using": [],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"WriteTo": [
{
"Name": "Console"
},
{
"Name": "ApplicationInsights",
"Args": {
"instrumentationKey": "",
"restrictedToMinimumLevel": "Information",
"telemetryConverter": "Serilog.Sinks.ApplicationInsights.Sinks.ApplicationInsights.TelemetryConverters.TraceTelemetryConverter, Serilog.Sinks.ApplicationInsights"
}
}
],
"Enrich": [
"FromLogContext",
"WithMachineName",
"WithProcessId",
"WithThreadId"
]
}
This is not logging exceptions as expected. I can see status code 500 in app insights but I want to see exception message logged as well. Can someone help me to understand what could be I am missing here. Any help would be appreciated. Thanks
Try adding this values in your appsettings.json:
"Serilog":
{
"Using":
["Serilog",
"Serilog.Sinks.ApplicationInsights",
"Serilog.Sinks.Console"],
...
}
Just try to configure Logger in Startup.cs
var log = new LoggerConfiguration()
.WriteTo
.ApplicationInsights(serviceProvider.GetRequiredService<TelemetryConfiguration>(), TelemetryConverter.Traces)
.CreateLogger();
Whether you choose Events or Traces, if the LogEvent contains any exceptions it will always be sent as ExceptionTelemetry.
In Application Insights you can configure whether the exceptions appear as Exceptions vs Traces
See here

Add client ip to graylog output with Gelf.Extensions.Logging package

I am using the Gelf.Extensions.Logging package to send log info to graylog from an asp.net core 3 website, and I would like additional fields like current user name, client ip, user agent.
In startup.cs, I have the following, but I don't know how to add the data to AdditionalFields that I want - I'm not even sure that this would be the right place, as I can't see how to inject the http context at this early stage.
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>()
.ConfigureLogging((context, builder) => builder.AddGelf(options =>
{
options.AdditionalFields["machine_name"] = Environment.MachineName;
options.AdditionalFields["environment_name"] = context.HostingEnvironment.EnvironmentName;
options.AdditionalFields["app_version"] = Assembly.GetEntryAssembly()?.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
}));
});
My appsettings.json is like so:
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Information",
"Microsoft": "Information",
"System": "Warning"
},
"GELF": {
"Host": "graylog",
"Port": 12202,
"Protocol": "HTTP",
"LogSource": "DataEntry",
"LogLevel": {
"Default": "Information",
"Microsoft": "Information",
"System": "Warning"
}
}
},
"AllowedHosts": "*",
/* snip */
}
It turns out the recommended approach here it to use a middleware like this example to add information about the current request as fields:
public class Startup
{
public void Configure(IApplicationBuilder app)
{
// Register the middleware like so:
app.UseAppEnvironmentInfo();
}
}
public static class RequestAppEnvironmentInfoMiddlewareExtensions
{
public static IApplicationBuilder UseAppEnvironmentInfo(
this IApplicationBuilder builder)
{
return builder.UseMiddleware<AppEnvironmentInfoMiddleware>();
}
}
public class AppEnvironmentInfoMiddleware
{
private readonly RequestDelegate _next;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ILogger<AppEnvironmentInfoMiddleware> _logger;
public AppEnvironmentInfoMiddleware(RequestDelegate next,
IHttpContextAccessor httpContextAccessor, ILogger<AppEnvironmentInfoMiddleware> logger)
{
_next = next;
_httpContextAccessor = httpContextAccessor;
_logger = logger;
}
public async Task Invoke(HttpContext context)
{
using (_logger.BeginScope(("machine_name", Environment.MachineName)))
using (_logger.BeginScope(("environment_name", context.HostingEnvironment.EnvironmentName)))
using (_logger.BeginScope(("app_version", Assembly.GetEntryAssembly()?.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion)))
{
await _next.Invoke(context);
}
}
}

ASP.NET Core MVC Entity Framework Core: the context type 'DatenbankKontext' only declares a parameterless constructor

I have tried to implement Entity Framework Core to my Application I have some trouble.
Following error message occurs when I try to debug:
System.ArgumentException: "AddDbContext was called with configuration,
but the context type 'DatenbankKontext' only declares a parameterless
constructor. This means that the configuration passed to AddDbContext
will never be used. If configuration is passed to AddDbContext, then
'DatenbankKontext' should declare a constructor that accepts a
DbContextOptions and must pass it to the base
constructor for DbContext."
That's my DatabaseContext:
using Microsoft.EntityFrameworkCore;
namespace PlaudertischSoftware.Models
{
public class DatenbankKontext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite(
#"Server=(localdb)\mssqllocaldb;Database=PlaudertischSoftwareDatenbankCore;Integrated Security=True");
}
public virtual DbSet<ObstSpielDaten> ObstSpielDaten { get; set; }
public virtual DbSet<AutoGaugeDaten> AutoGaugeDaten { get; set; }
}
}
That's my Startup.cs:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using PlaudertischSoftware.Models;
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.HttpOverrides;
using System.Net;
namespace PlaudertischSoftware
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
services.AddMvc(option => option.EnableEndpointRouting = false);
services.AddControllersWithViews()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = null;
});
services.Configure<ForwardedHeadersOptions>(options =>
{
options.KnownProxies.Add(IPAddress.Parse("0.0.0.0"));
});
services.AddDbContext<DatenbankKontext>(options => {
options.UseSqlite(Configuration.GetConnectionString("PlaudertischSoftwareDatenbank"));
});
}
[System.Obsolete]
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
app.UseAuthentication();
}
}
}
And that's my appsettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"PlaudertischSoftwareDatenbank": "Server=(localdb)\\mssqllocaldb;Database=PlaudertischSoftwareDatenbank;Integrated Security=True"
}
}
The error is telling you that you need to add a constructor that takes options.
'DatenbankKontext' should declare a constructor that accepts a DbContextOptions and must pass it to the base constructor for DbContext.
So add one:
public class DatenbankKontext : DbContext
{
public DatenbankKontext(DbContextOptions options)
: base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite(
#"Server=(localdb)\mssqllocaldb;Database=PlaudertischSoftwareDatenbankCore;Integrated Security=True");
}
public virtual DbSet<ObstSpielDaten> ObstSpielDaten { get; set; }
public virtual DbSet<AutoGaugeDaten> AutoGaugeDaten { get; set; }
}

Controllers are not found in ASP.NET core in console application

I'm trying to get a a simple asp.net core projection set with just a basic configuration and a controller working but no avail so far. I did use the code from the web template project to create a new console project but no controllers are found.
Here is what the project looks like so far:
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMvc();
}
}
[ApiController]
public class TestController : ControllerBase
{
[HttpGet]
[Route("Test")]
public ActionResult<string> Get()
{
return "Hello world!";
}
}
//appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*"
}
I'm missing something very obvious here but can't figure it out, any help is welcome.
Thanks
UPDATE 1
UPDATE 2
#marco
just add Route to your controller, it should be like
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
[HttpGet]
[Route("Test")]
public ActionResult<string> Get()
{
return "Hello world!";
}
}
and url will look like:
https://localhost:5001/api/test/test
UPDATE:
added screenshot
I didn't pay attention but I had a warning in one of the dependencies and after adding them again, I got my original code working, thanks guys.

App Settings .Net Core

I am trying to add an appsettings.json and followed a lot of tutorials and still can not do it.
I create appsettings.json
{
"option1": "value1_from_json",
"ConnectionStrings": {
"DefaultConnection": "Server=,\\SQL2016DEV;Database=DBName;Trusted_Connection=True"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
}
}
Add my class:
public class MyOptions
{
public string Option1 { get; set; }
}
public class ConnectionStringSettings
{
public string DefaultConnection { get; set; }
}
then on my Startup.cs
public IConfiguration Configuration { get; set; }
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
if (env.IsDevelopment())
{
builder.AddUserSecrets<Startup>();
}
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
and :
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddScoped<IDataService<Sale>, DataService<Sale>>();
// add My services
// Register the IConfiguration instance which MyOptions binds against.
services.AddOptions();
// Load the data from the 'root' of the json file
services.Configure<MyOptions>(Configuration);
// load the data from the 'ConnectionStrings' section of the json file
var connStringSettings = Configuration.GetSection("ConnectionStrings");
services.Configure<ConnectionStringSettings>(connStringSettings);
}
and also injected the Dependency into the controller constructor.
public class ForecastApiController : Controller
{
private IDataService<Sale> _SaleDataService;
private readonly MyOptions _myOptions;
public ForecastApiController(IDataService<Sale> service, IOptions<MyOptions> optionsAccessor)
{
_SaleDataService = service;
_myOptions = optionsAccessor.Value;
var valueOfOpt1 = _myOptions.Option1;
}
}
EDITED:
The problem is that I get Configuration underlined in red
services.Configure<MyOptions>(Configuration);
Error CS1503
Argument 2: cannot convert from 'Microsoft.Extensions.Configuration.IConfiguration' to 'System.Action Exercise.Models.MyOptions
I know there are similar questions explaining how to:
ASP.NET Core MVC App Settings
but it doesn't work for me
Cheers
Did you include the correct namespace?
using Microsoft.Extensions.DependencyInjection;
Also did you have a reference to?:
Microsoft.Extensions.Options.ConfigurationExtensions
In above Assembly we have:
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, IConfiguration config) where TOptions : class;
Most probably you are using the extension method from Microsoft.Extensions.Options assembly (which is wrong)
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, Action<TOptions> configureOptions) where TOptions : class;
Make sure that you imported everything that is necessary and have the required packages installed. Then you can do the following
services.Configure<MyOptions>(options => Configuration.GetSection("options1").Bind(options));
this will cause the options to be updated at runtime whenever you change the appssettings programatically.