global.json missing in visual studio 2017 [duplicate] - c#

I have asp.net core library project.
I want to add connection string to it. I don't have startup class in this. Where I need to place connection string and how to fetch it?

In dotnet core you can manage configuration using json files, which is one in many ways to configure your application.
According to the dotnet core configuration documentation you can simply do (copied from link reference)
using Microsoft.Extensions.Configuration;
using System;
using System.IO;
// Add NuGet <package id="Microsoft.Extensions.Configuration" and
// <package id="Microsoft.Extensions.Configuration.Json"
// .NET Framework 4.x use the following path:
//.SetBasePath(Path.Combine(Directory.GetCurrentDirectory(), #"..\.."))
public class Program
{
static public IConfigurationRoot Configuration { get; set; }
public static void Main(string[] args = null)
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json");
Configuration = builder.Build();
Console.WriteLine($"option1 = {Configuration["option1"]}");
Console.WriteLine($"option2 = {Configuration["option2"]}");
Console.WriteLine(
$"option1 = {Configuration["subsection:suboption1"]}");
}
}
Then in your appsettings.json file you can add:
{
"ConnectionStrings": {
"BloggingDatabase": "Server=(localdb)\\mssqllocaldb;Database=EFGetStarted.ConsoleApp.NewDb;Trusted_Connection=True;"
},
}
And access it in code using Configuration.GetConnectionString("BloggingDatabase")
I can recommend also reading the dotnet core documentation regarding connection strings
EDIT: As the commentors mention on your post, don't add connection strings and config files to your library code - do this from your console application or the web application!
Additional forms of configuration for dotnet core includes user secrets, environment variables and perhaps XML files or other forms of storage, as pointed out in the comments

Related

Steps needed to have a .NET Console Application read secrets.json in Visual Studio

I'm following the docs for Configuration in .Net, and having trouble getting it working with User Secrets in Visual Studio 2022 (.Net 6.0).
Thus far I've:
Installed Microsoft.Extensions.Configuration.UserSecrets, and Microsoft.Extensions.Hosting.
Confirmed that <UserSecretsId> was added to the .csproj file
Code
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
// Retrieve App Secrets
using IHost host = Host.CreateDefaultBuilder(args).Build();
IConfiguration config = host.Services.GetRequiredService<IConfiguration>();
string secret = config.GetValue<string>("DUMMY_VALUE");
...
await host.RunAsync();
secrets.json (Opened by right-clicking the project and choosing 'Manage User Secrets')
{
"DUMMY_VALUE": "dummy-test-value"
}
In the above, secret is null. Based on this line from the docs, I thought the code above would create a default config capable of reading the secrets.json file.
It seems like the way this works has been updated since similar questions were asked and answered, like this one. I've also been referencing the docs on Secrets in ASP applications, but still having trouble spotting what I'm missing.
With help from this answer and the docs for AddUserSecrets, I have a working solution: construct a custom config object with the desired capability.
code
using Microsoft.Extensions.Configuration;
// Retrieve App Secrets
IConfiguration config = new ConfigurationBuilder()
.AddUserSecrets<SomeClass>()
.Build();
string secret = config.GetValue<string>("DUMMY_VALUE");
...
Here, SomeClass can be any class in the assembly. The in-IDE description for AddUserSecrets<T> says:
AddUserSecrets will search the assembly that contains class T for some instance of Microsoft.Configuration.UserSecrets.UserSecretsIdAttribute which specifies the user secrets ID.
After following the steps listed in the question, this code succeeds in reading the secrets.json file. This solution is hinted at in the docs on Secrets in ASP.NET Core applications.
As mentioned by Bellrampion, the steps described in the Configuration in .Net docs will only read the secrets.json file in the Development configuration - which I do not see as an option in Visual Studio 2022. Based on this, if you want to use User Secret management in a .Net Console application in VS 2022, you may need to construct the custom config object like above.
In Vistual Studio 2022:
Select a project that will use the secrets;
Open context menu, select Manage User Secrets:
Library “Microsoft.Extensions.Configuration” will be auto added;
A secrets.json file will be auto created: fill it with access token, etc.
{
"github": {
"accessToken": "xx"
}
}
use the following lines to fetch a secret in a class, e.g. Program.cs
using Microsoft.Extensions.Configuration;
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
IConfiguration configuration = configurationBuilder.AddUserSecrets<Program>().Build();
string githubToken = configuration.GetSection("github")["accessToken"];

How to write program.cs file for .NET 6 Library Project? - getting error "Program using top-level statements must be an executable"

I keep all the data related classes, interfaces, configurations, etc in a separate library project so it can easily be reused for any other project I need (API, WebAssembly, Mobile, Server Pages, etc..)
I have converted all the projects from the solution to .NET6. They all work and build, as the did before, except for the data library which is giving me the following error: Program using top-level statements must be an executable.
How do I write the new .NET 6 Program.cs file for a .NET 6 library?
The new Program.cs file that is not working:
using FlasherData.Context;
using FlasherData.Repositories;
using FlasherData.Repositories.Interfaces;
using Microsoft.AspNetCore.Builder;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<FlasherContext>(options => options.UseSqlite(builder.Configuration.GetConnectionString("FlasherDb")));
builder.Services.AddScoped<IUnitOfWork, UnitOfWork>();
var app = builder.Build();
app.Run();
The old .NET 5 Startup.cs file that worked:
using FlasherData.Context;
using FlasherData.Repositories;
using FlasherData.Repositories.Interfaces;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace FlasherData
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
// SQLite connection and database context
services.AddDbContext<FlasherContext>(options => options.UseSqlite(Configuration.GetConnectionString("FlasherDb")));
// Dependency Injection
services.AddScoped<IUnitOfWork, UnitOfWork>();
}
}
}
The .NET 5 library did not have a Program.cs file as it was not needed in a .NET 5 library project.
This is a link to the entire solution: Flasher
The first example you show isn't library code, but the entry point of an application. Top-level-statements are internally transformed into the Main method of the assembly, it's really just a syntactical alternative. But a library must not have a Main method, and that's why you get the mentioned error.
Therefore, for a library, either just remove the startup code or (to get the equivalent behavior than before) change it back to what it was before. There's no need to use top-level-statements anywhere. When updating an application from .NET 5.0 to .NET 6.0, typically you don't have to change anything (except in the project files), because the existing code base is fully backwards compatible.

Reference Web API appsettings.json file in console app project in the same solution - issue with dotnet run

I have a .net 5 ASP.NET Core Web API and a console app in one Visual Studio solution. I have an appsettings.json file in my API's host project, which file I want to reference in my console app. The file has Copy if newer for Copy to Output Directory.
The solution structure is as follows (non-relevant projects omitted):
Solution
ApiHostProject
appsettings.json
ConsoleAppProject
This is my console app's Program.cs:
public class Program
{
public static Task Main(string[] args) => CreateHostBuilder(args).Build().RunAsync();
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((_, services) => services.AddStockUpdater());
}
Extension method AddStockUpdater, where I add the console app's dependencies:
internal static IServiceCollection AddStockUpdater(this IServiceCollection services)
{
var netFolder = Directory.GetCurrentDirectory();
var debugFolder = Directory.GetParent(netFolder).FullName;
var binFolder = Directory.GetParent(debugFolder).FullName;
var consoleAppFolder = Directory.GetParent(binFolder).FullName;
var solutionFolder = Directory.GetParent(consoleAppFolder).FullName;
var pathToFile = Path.Combine(solutionFolder, "StockTradingSimulator.ApiHost", "appsettings.json");
var configuration = new ConfigurationBuilder()
.AddJsonFile(pathToFile, false)
.Build();
//URL of the Web API
services.AddHttpClient("trading", client => client.BaseAddress = new Uri("http://localhost:4000"));
return services
.AddSingleton(configuration)
.Configure<AppSettings>(configuration.GetSection("AppSettings"))
// other dependencies omitted
}
This works if I set up the API host and the console app as startup projects and run them through Visual Studio (either via the Start button, or Ctrl + 5).
The pathToFile is "C:\\Users\\UserName\\Desktop\\SolutionFolder\\StockTradingSimulator.ApiHost\\appsettings.json"
However, if I run the console app project with dotnet run (from the directory containing the console app project file, or from another directory giving the path to the project file as --project parameter to dotnet run), I get an error:
System.IO.FileNotFoundException: The configuration file 'StockTradingSimulator.ApiHost\appsettings.json' was not found and is not optional. The physical path is 'C:\Users\StockTradingSimulator.ApiHost\appsettings.json'.
Could you help me get the console app to find the API host's appsettings.json no matter whether the console app is run through Visual Studio or a dotnet run command?
I tried this and this SO posts but they didn't help.
I have added the following to the console app project file:
<!-- Try and nest the appsettings when it's not a web sdk project. -->
<ItemGroup Condition="'$(IsSdkProject)' == 'true' AND '$(IsWebSdkProject)' == 'false'">
<Content Include="..\StockTradingSimulator.ApiHost\appsettings.*.json">
<DependentUpon>appsettings.json</DependentUpon>
</Content>
<Content Include="appsettings*.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
When running the console app with dotnet run, the Web API appsettings.json file is now found.
I want to send an email from my console app, the email sender is in the web API project and has a dependency on the dbContext.
The Web API class derived from DbContext uses the following to get the connection string:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseSqlServer(_configuration.GetConnectionString("StockTrading"));
appsettings.json contains the connection string to my SQL Server database.
dotnet run for the console app throws an error System.ArgumentNullException: Value cannot be null. (Parameter 'connectionString')
UPDATE:
Below is how I access the database connection string.
I have this constructor in my derived DbContext class:
public TradingDbContext(DbContextOptions options) : base(options) { }
I wanted to get the connection string in OnConfiguring() method in the derived DbContext and just use AddDbContext<TradingDbContext>() here but this didn't work when running with dotnet run:
internal static IServiceCollection AddStockUpdater(this IServiceCollection services)
{
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", false)
.Build();
services.AddHttpClient("trading", client => client.BaseAddress = new Uri("http://localhost:4000"));
services
.AddSingleton(configuration)
.Configure<AppSettings>(configuration.GetSection("AppSettings"))
.AddScoped<IEmailSender, EmailSender>()
.AddScoped<IEmailService, EmailService>()
.AddDbContext<TradingDbContext>(options => options
.UseSqlServer(configuration.GetConnectionString("StockTrading")))
.AddAutoMapper(typeof(BusinessLayerServiceCollectionExtensions).Assembly)
// other dependencies
return services;
}

Self hosting HTTP(s) endpoints in .net core app without using asp.net?

I have a .net core application running in Windows and Linux as well (I use .net core runtime >= 2.1). To get better insights I'd like to expose a metrics endpoint (simple HTTP GET endpoint) for Prometheus publishing some internal stats of my application.
Searching through the WWW and SO I always ended up on using asp.net core. Since I only want to add a quite simple HTTP GET endpoint to an existing .net core app it seems a little bit overkill, to port the whole application to asp.net.
The alternative I already considered was to write my own handler based on HttpListener. This is quite straight forward when it comes to a simple HTTP endpoint, but since all information I found regarding SSL and Linux was, this is not supported at the moment and I should go with asp.net. (https://github.com/dotnet/runtime/issues/33288#issuecomment-595812935)
So I'm wondering what I missunderstood! Am I the only one?
Is there already a good library providing a simple http(s) server for .net core?
EDIT: [SOLVED]
As #ADyson mentioned in the comments below the existing application does not need to be ported to asp.net core!
Project files generated with dotnet new web in version 2.1 automatically added
references to "Microsoft.AspNetCore.App" and "Microsoft.AspNetCore.Razor.Design"
When I referenced my asp.net core project from a .net core project and executed the code hosting the web service I ended up with an System.IO.FileNotFoundException stating it "Could not load file or assembly 'Microsoft.AspNetCore.Mvc.Core'".
Microsoft.AspNetCore.App is a metapackage also referencing said Microsoft.AspNetCore.MVC! Thus, the executing assembly also has to reference this metapackage. This observation missled me that using asp.net core renders my whole application to be built around Microsoft.AspNetCore.App.
After removing these references and adding only a reference to "Microsoft.AspNetCore" everything works as expected.
After checking the generated project files from dotnet new web in version 3.1 these references were not added. This is not a problem for folks using newer versions of dotnet!
As mentioned by #ADyson, OWIN is the way to go. You can easily self-host a HTTP endpoint in your existing application. Here is a sample to self-host it in a .Net Core 3.1 console application. It exposes a simple endpoint listening on port 5000 for GET requests using a controller. All you need is to install the Microsoft.AspNetCore.Owin Nuget package.
The code files structure is as follows:
.
├── Program.cs
├── Startup.cs
├── Controllers
├── SayHi.cs
Program.cs
using Microsoft.AspNetCore.Hosting;
namespace WebApp
{
class Program
{
static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseUrls("http://*:5000")
.UseStartup<Startup>()
.Build();
host.Run();
}
}
}
Startup.cs
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
namespace WebApp
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
}
public void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
SayHi.cs
using Microsoft.AspNetCore.Mvc;
namespace WebApp.Controllers
{
public class SayHi : ControllerBase
{
[Route("sayhi/{name}")]
public IActionResult Get(string name)
{
return Ok($"Hello {name}");
}
}
}
Then a simple dotnet WebApp.dll would start the app and web server.
As you can see, the sample uses Kestrel. The default web server. You can check Microsoft's related documentation.
For more configuration and routing options you can check Microsoft's documentation.
One option is to use EmbeddIo
https://unosquare.github.io/embedio/
I find the documentation is not always the best, especially as they recently upgrade and many samples etc. are not valid. But you can get there!
You can self host a REST API like this:
WebServer ws = new WebServer(o => o
.WithUrlPrefix(url)
.WithMode(HttpListenerMode.EmbedIO))
.WithWebApi("/api", m => m
.WithController<ApiController>());
this.Cts = new CancellationTokenSource();
var task = Webserver.RunAsync(Cts.Token);
Then define your API Controller like this.
class ApiController : WebApiController
{
public ApiController() : base()
{
}
[Route(HttpVerbs.Get, "/hello")]
public async Task HelloWorld()
{
string ret;
try
{
ret = "Hello from webserver # " + DateTime.Now.ToLongTimeString();
}
catch (Exception ex)
{
//
}
await HttpContext.SendDataAsync(ret);
}
}
Project files generated with dotnet new web in version 2.1 automatically added references to "Microsoft.AspNetCore.App" and "Microsoft.AspNetCore.Razor.Design" which, when referenced by a .net core project and executed ended up with an System.IO.FileNotFoundException stating it "Could not load file or assembly 'Microsoft.AspNetCore.Mvc.Core'".
Creating a project with dotnet new web in version 3.1 does not reference these, thus the project can be referenced and executed from a .net core application.
-> Using asp.net core is a viable solution for me (again)!

How to add an App.Config in Visual Studio Code?

How to configure a C# program with a connection string in Visual Studio Code?
This is for .Net Core 2.2 using .Net Core SDK version 2.2.203 in Visual Studio Code 1.34.0
I have tried to add App.Config file to the project, but I'm not able to resolve this issue. Do let me know any solution to configure connection string.
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Linq;
using System.Web;
using System.Configuration;
using System.Collections.Specialized;
using Dapper;
namespace Sample_Dapper
{
class Program
{
static void Main(string[] args)
{
IDbConnection db = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString);
var SqlString = "SELECT TOP 100 [CustomerID],[CustomerFirstName],
[CustomerLastName],[IsActive] FROM [Customer]";
var ourCustomers = (List<Customer>)db.Query<Customer>(SqlString);
}
}
}
Install Microsoft.Extensions.Configuration.Json
Then add appsettings.json file to project and right click on file -properties and select copy to output as copy if newer
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
IConfigurationRoot configuration = builder.Build();
Console.WriteLine(configuration.GetConnectionString("Test"));
Console.WriteLine(configuration.GetSection("SampleObj:AnyPropName").Value);
sample appsetting.json file
{
"SampleObj": {
"AnyPropName" : "testProp"
} ,
"ConnectionStrings": {
"Test": "CONNECTION-STRING"
}
}
Your code has ConfigurationManager.ConnectionStrings to get the connection string. This code will not work in .NET Core 2.2 and later, because ConfigurationManager.ConnectionStrings is used to get connection strings in web.config for ASP.NET project and app.config for console and Winforms/WPF projects if your app is using .NET Framework.
In .NET Core 2.0 and later, most configuration is stored as JSON file, and by default the equivalent of web.config/app.config is appsettings.json file, and you can also have your own configuration file as well, because it is highly extensible.
The official .NET Core 2.0 (or later) documentation on how to manage configuration files is available at: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-2.2

Categories