Search After Usage API not returning logs - c#

I am wanting to return the logs that contain "level": "error" from elasticsearch in a asp.net core web api application using NEST. I looked into the search_after api Search After API and looked into another resource for Paginate Search After. On the Kibana CLI, I wrote the following:
GET elastic-search-app-log*/_search
{
"size": 3000,
"query": {
"match": {
"level": "Error"
}
},
"search_after": [3000],
"sort":[
{"#timestamp": "asc"}
]
}
I just set the size to something random along and for it just to search after each 3000 indice.
So on the .net side of it, I attempted to translate it as so:
ESFieldsController
private readonly IElasticClient _elasticClient;
public ESFieldsController(IElasticClient elasticClient)
{
_elasticClient = elasticClient;
}
[HttpGet]
public async Task<ESFields> Get()
{
var response = await _elasticClient.SearchAsync<ESFields>(s => s
.Index("elastic-search-app-logs*")
.Size(3000)
.Query(q => q.Match(m => m.Field(f => f.Level == "error")))
.SearchAfter(3000)
.Sort(srt => srt
.Ascending(p => p.TimeStamp)));
Console.WriteLine(response);
return response?.Documents?.FirstOrDefault();
}
ESFields
namespace ESPractice.Models
{
public class ESFields
{
public String Level { get; set; }
public DateTime TimeStamp { get; set; }
}
}
However, when I run the application and swagger comes up, I try to execute the get cmd to see if it works but it does not return the logs that contain "level": "error". Is there something I am doing incorrectly with the translation?
Additional info:
startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "ESPractice", Version = "v1" });
});
// create a new node instance
var node = new Uri("http://localhost:9200");
// settings instance for the node
var settings = new ConnectionSettings(node);
services.AddSingleton<IElasticClient>(new ElasticClient(settings));
}
Everything below is from a separate application where I am writing the logs to elasticsearch:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog((context, configuration) =>
{
configuration.Enrich.FromLogContext()
.Enrich.WithMachineName()
.WriteTo.Console()
.WriteTo.Elasticsearch(
new ElasticsearchSinkOptions(new Uri(context.Configuration["ElasticConfiguration:Uri"]))
{
IndexFormat = $"{context.Configuration["ApplicationName"]}-logs-{context.HostingEnvironment.EnvironmentName?.ToLower().Replace(".", "-")}-{DateTime.UtcNow:yyyy-MM}",
AutoRegisterTemplate = true,
})
.Enrich.WithProperty("Environment", context.HostingEnvironment.EnvironmentName)
.ReadFrom.Configuration(context.Configuration);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
appsettings.json
{
"ApplicationName": "elastic-search-app",
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Information",
"System": "Warning"
}
}
},
"ElasticConfiguration": {
"Uri": "http://localhost:9200"
},
"AllowedHosts": "*"
}

Related

ILogger does not write to console using serilog

I'm trying to use serligo as my main logging utilitie but I can't seem to get it to work correctly.
In the Program.cs file, I configure the logger and also log a startup message, this message gets outputted to the console.
I also have, in one of my controllers, an ILogger<HomeController> instance that logs information when a certain action is called. These logs are not outputted to the console, and I cannot understand why.
Startup.cs
public class Program
{
public static void Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
try
{
Log.Information("Starting up version {version}", Defaults.Version); // WORKS
CreateHostBuilder(args).Build().Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "Application start-up failed");
}
finally
{
Log.CloseAndFlush();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration.ReadFrom.Configuration(hostingContext.Configuration))
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
Controller
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
_logger.LogInformation("Home/Index"); //Does not work
return View();
}
}
appsettings.json
"Serilog": {
"Using": [ "Serilog.Sinks.Console" ],
"MinimumLevel": {
"Default": "Verbose",
"Override": {
"Microsoft": "Warning",
"Microsoft.AspNetCore": "Warning",
"System": "Error"
}
},
"WriteTo": [
{
"Name": "Async",
"Args": {
"configure": [
{
"Name": "Console",
"Args": {
"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console",
"formatter": "Serilog.Formatting.Compact.RenderedCompactJsonFormatter, Serilog.Formatting.Compact"
}
}
]
}
}
]
},
.UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration.ReadFrom.Configuration(hostingContext.Configuration))
The issue relates the above code, in this part of code, you should also configure it to write to the console.
Modify the code as below:
.UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration.ReadFrom.Configuration(hostingContext.Configuration).WriteTo.Console())
Then, the output like this:

C# Console App, pass multiple parameters to custom ILogger

Searching I've not found the answer I'm looking for. I will only put code snippets here to help ask my question, supplying ALL of the code would not be executable without the entire system.
I'm using the built-in logging in C# to log to Windows Event Viewer and/or the Console. I also wanted to write to a file but not third-party logging, so I wrote my own simple logger that logs the same data to files and works.
My appsettings.json as a second for some configuration parameters like a working folder. I also have a folder path for the logger. What I would like to be able to do is use the same holder path from the setting and not have 2.
appsettings.json
{
"AppSettings": {
"WorkingFolderPath": "C:\\mypath\\",
"HeartbeatIntervalMinutes": 0, // This is seconds when in debug mode.
"FileRetryDelayMinutes": 1,
"PingTimeoutMilliseconds": 200
},
"Logging": {
"LogLevel": {
"Default": "Error",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Warning"
},
"Debug": {
"LogLevel": {
"Default": "Debug"
}
},
"Console": {
"IncludeScopes": true,
"LogLevel": {
"Default": "Debug"
}
},
"EventLog": {
"LogLevel": {
"Default": "Warning"
}
},
"FileLog": {
"Options": {
"FolderPath": "C:\\mypath\\",
"RetentionDays": 5
},
"LogLevel": {
"Default": "Debug"
}
}
}
}
As you see in this file I have a "WorkingFolderPath" setting I'd like to use that as my path in my "FileLog" logger and not have to specify a path there as well.
Program.cs
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseWindowsService()
.ConfigureLogging((context, logging) =>
{
logging.ClearProviders();
logging.AddConsole();
logging.AddDebug();
logging.AddEventLog(new EventLogSettings()
{
SourceName = "FreshIQAppMessagingService"
});
logging.AddFileLogger(options =>
{
context.Configuration.GetSection("Logging").GetSection("FileLog").GetSection("Options").Bind(options);
});
})
.ConfigureAppConfiguration((hostContext, config) =>
{
config
.SetBasePath(ApplicationPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddEnvironmentVariables();
})
.ConfigureServices((hostContext, services) =>
{
services.Configure<Configuration>(hostContext.Configuration.GetSection("AppSettings"));
services.AddHostedService<Service1>();
services.AddHostedService<Service2>();
services.AddHostedService<Service3>();
services.AddHostedService<Service4>();
});
Here it's getting the options and passing them in. What I've not been able to figure out is how to change my classes so that I can send in the "WorkingFolderPath" from the top of the appsettings instead of the one with the options with the FileLog logger.
logging.AddFileLogger(options =>
{
context.Configuration.GetSection("Logging").GetSection("FileLog").GetSection("Options").Bind(options);
});
FileLoggerExtensions.cs
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
namespace FreshIQAppMessaging.Logging
{
public static class FileLoggerExtensions
{
public static ILoggingBuilder AddFileLogger(this ILoggingBuilder loggingBuilder, Action<FileLoggerOptions> configure)
{
loggingBuilder.Services.AddSingleton<ILoggerProvider, FileLoggerProvider>();
loggingBuilder.Services.Configure(configure);
return loggingBuilder;
}
}
}
FileLoggerProvider.cs
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.IO;
namespace FreshIQAppMessaging.Logging
{
[ProviderAlias("FileLog")]
public class FileLoggerProvider : ILoggerProvider
{
public readonly FileLoggerOptions Options;
public FileLoggerProvider(IOptions<FileLoggerOptions> options)
{
Options = options.Value;
if (!Directory.Exists(Options.FolderPath))
{
Directory.CreateDirectory(Options.FolderPath);
}
}
public ILogger CreateLogger(string categoryName)
{
return new FileLogger(this);
}
public void Dispose() { }
}
}
FileLogger.cs
using Microsoft.Extensions.Logging;
using System;
using System.Globalization;
using System.IO;
namespace FreshIQAppMessaging.Logging
{
public class FileLogger : ILogger
{
protected readonly FileLoggerProvider _fileLoggerProvider;
public FileLogger(FileLoggerProvider fileLoggerProvider)
{
_fileLoggerProvider = fileLoggerProvider;
}
public IDisposable? BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return logLevel != LogLevel.None;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (!IsEnabled(logLevel))
{
return;
}
// Clean up old log files
var logFiles = Directory.GetFiles(_fileLoggerProvider.Options.FolderPath, "*-MyApp.log");
foreach (var logFilePath in logFiles)
{
var logFileName = new FileInfo(logFilePath).Name;
if (DateTime.TryParseExact(logFileName.Substring(0, 8), "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var logFileDate))
{
if (logFileDate.AddDays(_fileLoggerProvider.Options.RetentionDays) < DateTime.Now)
{
File.Delete(logFilePath);
}
}
}
var fullFilePath = $"{_fileLoggerProvider.Options.FolderPath}\\{DateTime.Now.ToString("yyyyMMdd")}-MyApp.log";
var logRecord = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} [{logLevel.ToString()}] {formatter(state, exception)} {(exception != null ? exception.StackTrace : "")}";
using (var streamWriter = new StreamWriter(fullFilePath, true))
{
streamWriter.WriteLine(logRecord);
}
}
}
}
FileLoggerOptions.cs
using System;
using System.Collections.Generic;
using System.Text;
namespace FreshIQAppMessaging.Logging
{
public class FileLoggerOptions
{
public virtual string? FolderPath { get; set; }
public virtual int RetentionDays { get; set; } = 5;
}
}
You typically don't want to include custom options for your logger inside the Logging section. Most people do something like this instead:
{
"AppSettings": {
"WorkingFolderPath": "C:\\mypath\\",
...
},
"FileLog": {
"FolderPath": "C:\\mypath\\",
"RetentionDays": 5
},
"Logging": {
...
"FileLog": {
"LogLevel": {
"Default": "Debug"
}
}
}
}
You didn't share your options class but I assume you have a property on it named FolderPath. You could then configure your file logger like this:
logging.Services.Configure<FileLoggerOptions>(builder.Configuration.GetSection("FileLog"));
logging.AddFileLogger(options =>
{
options.FolderPath = builder.Configuration["AppSettings:WorkingFolderPath"];
});
You can now remove the FolderPath property from the FileLog object in the appsettings.json file since that value will be set using this line when adding the file logger:
options.FolderPath = builder.Configuration["AppSettings:WorkingFolderPath"];
The options would then look like this:
{
"AppSettings": {
"WorkingFolderPath": "C:\\mypath\\",
...
},
"FileLog": {
"RetentionDays": 5
},
"Logging": {
...
"FileLog": {
"LogLevel": {
"Default": "Debug"
}
}
}
}
I've written a similar logging provider in the Elmah.Io.Extensions.Logging repository and I copied some of the code from there. I tried mapping it to your original code in the question, but there might be something that doesn't match exactly. I hope that you still see the intent behind what I'm trying. You can look inside this repository for inspiration.

.NET Core. Logs not sent to Loggly, while using Serilog

I have a small ASP.NET Core 3.1 project that should execute the Odata request and then log either info or exception into the Loggly. I'm using Serilog for this.
But for some reason, it only sends the very first message from the Program.cs only (Log.Debug($"DEBUG: Starting at:{DateTime.Now}");), but does not send anything other than that. While it works fine for the Console or File logging.
I have tried to fake an exception to trigger the Error logging. But nothing works (in the Loggly).
Any suggestions on why is that and how to make it work properly?
Here is my code:
Program.cs:
public class Program
{
public static void Main(string[] args)
{
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
try
{
Log.Debug($"DEBUG: Starting at:{DateTime.Now}");
CreateHostBuilder(args).Build().Run();
Log.Debug($"DEBUG: Host created");
}
catch (Exception ex)
{
Log.Error("Oops something failed!");
throw new Exception(ex.Message);
}
finally
{
Log.CloseAndFlush();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.UseSerilog();
}
Startup.cs:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddDbContext<OdataTestObjectContext>(options =>
{
options.UseSqlServer(Configuration["ConnectionStrings:Database"]);
});
services.AddControllers().AddOData(opt =>
opt.Filter().Expand().Select().OrderBy().Count().SetMaxTop(100)
.AddRouteComponents("odata", GetEdmModel()));
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "OdataTest", Version = "v1" });
c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
});
var appSettings = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
var serilogConfig = new LoggerConfiguration().ReadFrom.Configuration(appSettings);
services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(serilogConfig.CreateLogger(), true));
services.AddMvc(opts => { opts.Filters.Add(new AutoLogAttribute()); });
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger(c =>
{
c.RouteTemplate = "/swagger/{documentName}/swagger.json";
});
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "OdataTest v1"));
}
app.UseHttpsRedirection();
////Send "~/$odata" to debug routing if enable the following middleware
app.UseODataRouteDebug();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
private static IEdmModel GetEdmModel()
{
var builder = new ODataConventionModelBuilder();
var entitySet = builder.EntitySet<TestObject>("TestObjects");
entitySet.EntityType.HasKey(entity => entity.Id);
return builder.GetEdmModel();
}
}
Controller.cs
[ApiController]
[Route("OData")]
public class TestController : ODataController
{
private readonly OdataTestObjectContext _context;
private readonly ILogger<TestController> _logger;
public TestController(ILogger<TestController> logger, OdataTestObjectContext context)
{
_context = context;
_logger = logger;
}
[ApiExplorerSettings(IgnoreApi = true)]
[EnableQuery]
public IActionResult Get()
{
try
{
return Ok(_context.TestObjects);
}
catch (Exception ex)
{
_logger.LogError("Error happened for Default query! - {0}", ex.Message);
throw new InvalidOperationException(ex.Message);
}
}
[HttpGet("Top({top})")]
[EnableQuery]
public IEnumerable<TestObject> GetTop(int top)
{
return _context.TestObjects.OrderByDescending(x => x.Id).Take(top);
}
[HttpGet("Enumerable")]
[EnableQuery]
public IEnumerable<TestObject> Enumerable()
{
try
{
_logger.LogDebug("Executing ENUMERABLE now.");
//string a = "asd";
//int s = Convert.ToInt32(a);
var results = _context.SaleInvoicesAndProducts.AsEnumerable();
int z = 1;
if (results.Any())
z = 0;
int i = 10 / z;
return results;
}
catch (Exception ex)
{
_logger.LogError("Error happened for Enumerable query! - {0}", ex.Message);
throw new Exception();
}
}
AutoLogAttribute.cs (this just outputs logs with some request's parameters):
public class AutoLogAttribute : TypeFilterAttribute
{
public AutoLogAttribute() : base(typeof(AutoLogActionFilterImpl))
{
}
private class AutoLogActionFilterImpl : IActionFilter
{
private readonly ILogger<AutoLogAttribute> _logger;
public AutoLogActionFilterImpl(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<AutoLogAttribute>();
}
public void OnActionExecuting(ActionExecutingContext context)
{
// perform some business logic work
_logger.LogInformation($"queryString: {context.HttpContext.Request.QueryString}");
_logger.LogDebug($"queryString (Debug): {context.HttpContext.Request.QueryString}");
}
public void OnActionExecuted(ActionExecutedContext context)
{
//TODO: log body content and response as well
_logger.LogInformation($"host: {context.HttpContext.Request.Host}");
_logger.LogInformation($"patheAndQuery: {context.HttpContext.Request.GetEncodedPathAndQuery()}");
_logger.LogDebug($"path (Debug): {context.HttpContext.Request.Path}");
_logger.LogDebug($"host (Debug): {context.HttpContext.Request.Host}");
_logger.LogDebug($"patheAndQuery (Debug): {context.HttpContext.Request.GetEncodedPathAndQuery()}");
}
}
}
appsetting.json
{
"Serilog": {
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File", "Serilog.Sinks.Loggly" ],
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Debug",
"System": "Debug"
}
},
"Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId" ],
"WriteTo": [
{ "Name": "Console" },
{
"Name": "File",
"Args": { "path": "C:\\ODATA\\log.json" }
},
{
"Name": "Loggly",
"Args": {
"customerToken": "mytoken",
"tags": "mytest"
}
}
],
},
"ConnectionStrings": {
"Database": "Server=(localdb)\\MSSQLLocalDB;Initial Catalog=MyTestDB;Integrated Security=true;MultiSubnetFailover=True;MultipleActiveResultSets=True;"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
You can try to clear providers:
Host
****
.ConfigureLogging(logging =>
{
logging.ClearProviders();
})
.UseSerilog();
Also, if you have configured logging on Host, you don't need to put the additional configuration into Startup.cs

How to use Serilog to write file for each client?

I am making .Net core application and use Serilog for logging. Now I want to use Serilog to write a log for each clients who already logged in.
I expected the application gonna have seperate logger
Global logger: write server log
Client loggers: each client gonna have their own logger to write log file.
From what I tried to do the application do generate the txt file. However, it doesn't write anything to it.
Program.cs
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.UseIISIntegration()
.UseSerilog((hostingcontext, loggerConfiguration) => loggerConfiguration.ReadFrom.Configuration(hostingcontext.Configuration))
.UseStartup<Startup>();
});
}
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<LoggerManager>();
}
...MORE CODE...
}
LoggerManager.cs
public class LoggerManager
{
public static Dictionary<string, ILogger> loggerDict = new Dictionary<string, ILogger>();
public void CreateUserLogger(string username, EnumType userType)
{
var logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console()
.WriteTo.Async(a => a.File(#$"Log/{userType}/{username}.txt",
buffered:true,
rollingInterval:RollingInterval.Day,
retainedFileCountLimit:90))
.CreateLogger();
loggerDict.TryAdd(cheID, logger);
}
public void WriteInfoLog (string username, string message)
{
loggerDict.TryGetValue(username, out ILogger logger);
logger.Information(message);
}
}
HomeController.cs
class HomeController {
private readonly LoggerManager _loggerManager;
public HomeController(LoggerManager loggerManager)
{
_loggerManager = loggerManager;
}
public IActionResult Index() {
_loggerManager.WriteInfoLog(authenticatedUser.CHEID, "HELLO HOW ARE U TODAY");
return View();
}
}
appsettings.json
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"System": "Warning",
"Microsoft": "Warning"
}
},
"WriteTo": [
{
"Name": "Async",
"Args": {
"configure": [
{
"Name": "File",
"Args": {
"path": "Logs/Server/serverlog.txt",
"rollingInterval": "Day",
"retainedFileCountLimit": 7,
"buffered": true
}
}
]
}
}
]
}
I randomly found the "sinks-map". This sinks definitely satisfy my requirement.
https://github.com/serilog/serilog-sinks-map

Read appsettings.json - Fields remain null

Think I have a problem with the startup.cs as I do not get any values from my <IOption> config
So.. We have our appsettings.json
"Config": {
"ApplicationName": "some name",
"ConnectionString": "someconstring",
"Version": "1.0.0"
},
Here we have our model
public class Config
{
public string ApplicationName { get; set; }
public string ConnectionString { get; set; }
public string Version { get; set; }
}
The startup.cs
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public static IConfiguration Configuration { get; set; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// Add functionality to inject IOptions<T>
services.AddOptions();
// Add our Config object so it can be injected
services.Configure<Config>(Configuration);
}
And then in our controller I try to load those data but unfortunately they remain empty.
private IOptions<Config> config;
public CompaniesController(IOptions<Config> config)
{
this.config = config;
}
I've tried to change the startup.cs with something like
services.Configure<Config>(options =>
{
options.ConnectionString = Configuration.GetSection("Config:ConnectionString").Value;
});
but that doesn't seems to work.
Resources I've been using:
https://dzone.com/articles/dynamic-connection-string-in-net-core
https://stackoverflow.com/questions/31453495/how-to-read-appsettings-values-from-json-file-in-asp-net-core
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-2.2
but Obviously I am missing a crucial point here.
edit: I am using ASP.Net Core 2.0
edit2:
the Program.cs
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
The entire Appsettings.json file
{
"Config": {
"ApplicationName": "somename",
"ConnectionString": "someconstring",
"Version": "1.0.0"
},
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
}
},
"Console": {
"LogLevel": {
"Default": "Warning"
}
}
}
}
edit 3:
In my front-end application I import the API like this.
services.Configure<Config>(Configuration);
This line doesn't achieve the desired result because the JSON properties you're looking for are nested under a Config property in your appsettings.json file. To load these values as intended, use GetSection to grab the Config section and pass that into the Configure<TOptions> method:
services.Configure<Config>(Configuration.GetSection("Config"));
services.Configure<Config>(options =>
{
options.ConnectionString = Configuration.GetValue<string>("Config:ConnectionString");
options.ApplicationName = "test";
});
If you want to configure your options more granuarly.

Categories