Problems with user secrets in .Net console apps - c#

I've created a .Net 6 console app. I added user secrets, but I only get the values defined in the appsettings.json file. I use Visual Studio Professional 2022 version 17.0.4.
Initial steps
Create a new .Net 6 console app from Visual Studio 2022's project templates.
Install the Microsoft.Extensions.Hosting nuget package (version 6.0.0).
Install the Microsoft.Extensions.Configuration.UserSecrets nuget package (version 6.0.0).
Add the appsettings.json file and set Copy to Output Directory to Copy always.
Right-click on the project and select Manage User Secrets.
Code
Program.cs
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var host = Host.CreateDefaultBuilder()
.ConfigureServices((context, services) =>
{
services.Configure<GlobalSettings>(context.Configuration.GetSection("GlobalSettings"));
services.AddTransient<Worker>();
})
.Build();
var work = host.Services.GetRequiredService<Worker>();
await work.ExecuteAsync();
Worker.cs
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
public class Worker
{
private readonly ILogger<Worker> _logger;
private readonly GlobalSettings _globalSettings;
public Worker(ILogger<Worker> logger, IOptions<GlobalSettings> globalSettings)
{
_logger = logger;
_globalSettings = globalSettings.Value;
}
public async Task ExecuteAsync()
{
_logger.LogInformation(_globalSettings.Foo);
_logger.LogInformation(_globalSettings.Bar);
await Task.CompletedTask;
}
}
GlobalSettings.cs:
public class GlobalSettings
{
public string Foo { get; set; }
public string Bar { get; set; }
}
.csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
<UserSecretsId>deedd476-f5d6-47f4-982e-1645c89789c7</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
appsettings.json:
{
"GlobalSettings": {
"Foo": "Normal Foo",
"Bar": "Normal Bar"
}
}
secrets.json:
{
"GlobalSettings": {
"Foo": "Secret Foo",
"Bar": "Secret Bar"
}
}
What I've tried
Checked whether the user secret id in csproj matched the folder, which it did: C:\Users\Dennis\AppData\Roaming\Microsoft\UserSecrets\deedd476-f5d6-47f4-982e-1645c89789c7
Rebuilded the project.
Closed Visual Studio 2022 and ran it again as administrator.
Created a new project from scratch.
Compared the code with one of my colleague's projects. I couldn't find any difference, but his code works when I run it.
Changed IOptionsSnapshot to IOptions and IOptionsMonitor.
Changed AddTransient to AddSingleton.
Did the same steps, but with a .Net 5 project instead.
Thanks.

I'd misunderstood the way the Host.CreateDefaultBuilder method worked. According to the documentation (docs):
load app IConfiguration from User Secrets when EnvironmentName is 'Development' using the entry assembly
My environment is Production (probably a fallback value). It worked in my colleague's project because it included a launchSettings.json file with the DOTNET_ENVIRONMENT environment variable set to Development.

Related

Azure Function Could not load file or assembly 'Newtonsoft.Json, Version=13.0.0.0'

Our azure function was working fine with Newtonsoft.json nuget package version 13.0.1. We updated a code that is not related to the nuget and once deployed to Azure function ( the code referenced via nuget); we got the exception"Could not load file or assembly 'Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed'. The system cannot find the file specified "
I am sure it is the runtime issue , we have not changed the newtonsoft reference version. Any idea?
My .csproj code for below Azure Functions Test Case in checking the breaking changes for the NewtonSoft.Json NuGet Package:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.1.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project>
Check if your Newtonsoft.Json NuGet Package version is compatible with the .NET version and Azure Functions Core Tools version.
The Same issue registered in SO 62853320 and resolved by the user #ThiagoCustodio like downgrading the Version of that NuGet Package and check the version compatibility with the other dependencies used in the Function Code.
Following these MS Doc1 & Doc2, Created a Sample code snippet to test any breaking changes in that NuGet Pakcage with the .NET 6 Azure Functions:
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace KrishNet6FunAppAWJTest
{
public class Account
{
public string Name { get; set; }
public string Email { get; set; }
public DateTime DOB { get; set; }
}
public static class Function1
{
[FunctionName("Function1")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
Account account = new Account
{
Name = "John Doe",
Email = "john#nuget.org",
DOB = new DateTime(1980, 2, 20, 0, 0, 0, DateTimeKind.Utc),
};
string json = JsonConvert.SerializeObject(account, Formatting.Indented);
Console.WriteLine(json);
string responseMessage = "Hello Krishna, This HTTP triggered function executed successfully.";
return new OkObjectResult(responseMessage);
}
}
}
Checked with the latest version of the NuGet Package Newtonsoft.Json with the Azure Functions .NET 6 Core with the sample code snippet and working successfully and check by downgrading the NuGet Package Version along with all other Code, Dependencies Versions Compatibility.

Read *.csproj property values using Roslyn APIs?

I am currently building a tool which will support the development of an ASP.NET Core project. This tool uses the Roslyn APIs and other methods for verifying some development requirements (such as project-specific attributes being applied on API Controllers, enforcing naming conventions, and generating some source code for the JavaScript SPA which accesses an API written using the ASP.NET Core Web API template).
In order to do that, I am currently using hardcoded paths to generate code for the SPA app. But in the app's *.csproj file there is actually a "SpaRoot" property specifying where the SPA application is located inside the project:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
<IsPackable>false</IsPackable>
<SpaRoot>ClientApp\</SpaRoot>
...
</PropertyGroup>
...
</Project>
My question is: how can I read the "SpaRoot" property's value using the Roslyn APIs?
I have written a minimum code sample to create a Workspace, open the Solution, and retrieve the Project's reference, which resembles the following:
static async Task Main(string[] args)
{
string solutionFile = #"C:\Test\my-solution.sln";
using (var workspace = MSBuildWorkspace.Create())
{
var solution = await workspace.OpenSolutionAsync(solutionFile);
string projectName = "some-project";
var project = solution.Projects.Single(p => p.Name == projectName);
// How to extract the value of "SpaRoot" from the Project here?
}
I've tried searching on how to extract the "SpaRoot" property from the Project reference, and even went as far as debugging to see if I could spot a way myself. Unfortunately, I came up with no answers to that, and I'm still using hardcoded paths in my original code.
Is it even possible to retrieve the value of .csproj properties of a Project using the current Roslyn APIs?
This is more difficult that you would think :) The Roslyn apis only know what the compiler knows and the compiler is not going to be given anything regarding the SpaRoot property. We can use the MSBuild apis to figure this out though. specifically the Microsoft.Build.Evaluation.Project class.
Some assumptions I am making
You only want to examine .NET Core projects
You will have the .NET Core SDK installed on which ever system runs this tool
So first we want a project file that looks like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<!--NOTE: If the project you are analyzing is .NET Core then the commandline tool must be as well.
.NET Framework console apps cannot load .NET Core MSBuild assemblies which is required
for what we want to do.-->
<TargetFramework>netcoreapp3.1</TargetFramework>
<LangVersion>Latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<!-- NOTE: We put ExcludeAssets="runtime" on all direct MSBuild references so that we pick up whatever
version is being used by the .NET SDK instead. This is accomplished with the Microsoft.Build.Locator
referenced further below. -->
<PackageReference Include="Microsoft.Build" Version="16.4.0" ExcludeAssets="runtime" />
<PackageReference Include="Microsoft.Build.Locator" Version="1.2.6" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="2.9.8" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.4.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.Workspaces" Version="3.4.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="3.4.0" />
<!-- NOTE: A lot of MSBuild tasks that we are going to load in order to analyze a project file will implicitly
load build tasks that will require Newtonsoft.Json version 9. Since there is no way for us to ambiently
pick these dependencies up like with MSBuild assemblies we explicitly reference it here. -->
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
</ItemGroup>
</Project>
and a Program.cs file that looks like this:
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml;
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Locator;
using Microsoft.CodeAnalysis.MSBuild;
// I use this so I don't get confused with the Roslyn Project type
using MSBuildProject = Microsoft.Build.Evaluation.Project;
namespace loadProject {
class Program {
static async Task Main(string[] args) {
MSBuildWorkspaceSetup();
// NOTE: we need to make sure we call MSBuildLocator.RegisterInstance
// before we ask the CLR to load any MSBuild types. Therefore we moved
// the code that uses MSBuild types to its own method (instead of being in
// Main) so the CLR is not forced to load them on startup.
await DoAnalysisAsync(args[0]);
}
private static async Task DoAnalysisAsync(string solutionPath) {
using var workspace = MSBuildWorkspace.Create();
// Print message for WorkspaceFailed event to help diagnosing project load failures.
workspace.WorkspaceFailed += (o, e) => Console.WriteLine(e.Diagnostic.Message);
Console.WriteLine($"Loading solution '{solutionPath}'");
// Attach progress reporter so we print projects as they are loaded.
var solution = await workspace.OpenSolutionAsync(solutionPath, new ConsoleProgressReporter());
Console.WriteLine($"Finished loading solution '{solutionPath}'");
// We just select the first project as a demo
// you will want to use your own logic here
var project = solution.Projects.First();
// Now we use the MSBuild apis to load and evaluate our project file
using var xmlReader = XmlReader.Create(File.OpenRead(project.FilePath));
ProjectRootElement root = ProjectRootElement.Create(xmlReader, new ProjectCollection(), preserveFormatting: true);
MSBuildProject msbuildProject = new MSBuildProject(root);
// We can now ask any question about the properties or items in our project file
// and get the correct answer
string spaRootValue = msbuildProject.GetPropertyValue("SpaRoot");
}
private static void MSBuildWorkspaceSetup() {
// Attempt to set the version of MSBuild.
var visualStudioInstances = MSBuildLocator.QueryVisualStudioInstances().ToArray();
var instance = visualStudioInstances.Length == 1
// If there is only one instance of MSBuild on this machine, set that as the one to use.
? visualStudioInstances[0]
// Handle selecting the version of MSBuild you want to use.
: SelectVisualStudioInstance(visualStudioInstances);
Console.WriteLine($"Using MSBuild at '{instance.MSBuildPath}' to load projects.");
// NOTE: Be sure to register an instance with the MSBuildLocator
// before calling MSBuildWorkspace.Create()
// otherwise, MSBuildWorkspace won't MEF compose.
MSBuildLocator.RegisterInstance(instance);
}
private static VisualStudioInstance SelectVisualStudioInstance(VisualStudioInstance[] visualStudioInstances) {
Console.WriteLine("Multiple installs of MSBuild detected please select one:");
for (int i = 0; i < visualStudioInstances.Length; i++) {
Console.WriteLine($"Instance {i + 1}");
Console.WriteLine($" Name: {visualStudioInstances[i].Name}");
Console.WriteLine($" Version: {visualStudioInstances[i].Version}");
Console.WriteLine($" MSBuild Path: {visualStudioInstances[i].MSBuildPath}");
}
while (true) {
var userResponse = Console.ReadLine();
if (int.TryParse(userResponse, out int instanceNumber) &&
instanceNumber > 0 &&
instanceNumber <= visualStudioInstances.Length) {
return visualStudioInstances[instanceNumber - 1];
}
Console.WriteLine("Input not accepted, try again.");
}
}
private class ConsoleProgressReporter : IProgress<ProjectLoadProgress> {
public void Report(ProjectLoadProgress loadProgress) {
var projectDisplay = Path.GetFileName(loadProgress.FilePath);
if (loadProgress.TargetFramework != null) {
projectDisplay += $" ({loadProgress.TargetFramework})";
}
Console.WriteLine($"{loadProgress.Operation,-15} {loadProgress.ElapsedTime,-15:m\\:ss\\.fffffff} {projectDisplay}");
}
}
}
}

ApplicationDbContext.OnModelCreating() in .Net Standard 2.0 has MissingMethodException

this is one of the problems that I issued in "Found conflicts between different versions" OR System.MissingMethodException when using aspnetcore.identity, but I wanted to explain it separately with a small example:
SetUp:
A .Net Standard 2.0 Library
A .Net Framework 4.7.2 WebForms application
The .Net standard Library has this Code:
public class Class1
{
public static void doStuff()
{
var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
optionsBuilder.UseSqlServer("MyConnectionString");
var userStore = new UserStore<ApplicationUser, MyRole, ApplicationDbContext, Guid>(
new ApplicationDbContext(optionsBuilder.Options)
); // the userStore.Users property shows already the exception in the debugger
AspNetUserManager<ApplicationUser> userManager = new AspNetUserManager<ApplicationUser>(
userStore,
null,
new PasswordHasher<ApplicationUser>(),
new List<UserValidator<ApplicationUser>>() { new UserValidator<ApplicationUser>() },
null,
null,
null,
null,
null
);
var x = userManager.Users; // exception throw (see next code snipped)
}
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, MyRole, Guid>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder); // after userManager.Users is called the exception is thrown here
}
}
And in the WebForms-Project just:
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
Class1.doStuff();
}
}
Exception:
System.MissingMethodException: 'Methode nicht gefunden: "Microsoft.EntityFrameworkCore.Metadata.Builders.IndexBuilder Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder1.HasIndex(System.Linq.Expressions.Expression1>)".'
Configuration of .Net Standard 2.0 Project:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="2.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.1" />
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="3.1.1" />
</ItemGroup>
</Project>
References:
https://github.com/dotnet/aspnetcore/issues/8467 Here they say to update to "Microsoft.AspNetCore.Identity" 3.x, but I cannot do that because its not compatible with the .Net Standard 2.0 project and I need that for the WebForms Project.
So my question would be if someone knows a workaround to generate an Usermanager in a different way... I need to Get and Set Users (and validate) using aspnetcore-identity (database etc. is already migrated)
So, I have a solution for my problem:
use Microsoft.EntityFrameworkCore.SqlServer version 2.2.6 (NOT 3.1.1 even though its supposed to work with .net standard 2.0...)
And a sequence of
deleting nuget packages
clearing nuget cache
deleting nuget packages on the local computer (in the C:/../Users/.../.nuget folder)
changing the nuget management format to "PackageReference"
cry a lot
reinstalling everything and dealing with warnings helped
(I cant say what exactly the issue was regarding the version-conflicts)

EF-Core Single Deployment; Multiple Databases; Migrations

I currently have a .net core web api that has a SQL Server database per client. An api key is required to be passed in for every call and then is looked up in a master tenant database to get the correct connection string. The api will then set the connection string in the startup file and run the call.
Within the api, I have an endpoint that allows me to update all tenants to the latest migration and I also have a console app that will do the same. Something like this:
public async Task UpdateAllDatabases()
{
var qry = await GetAll(null, true);
foreach (var i in qry)
{
var optionsBuilder = new DbContextOptionsBuilder<MigrationContext>()
.UseSqlServer(i.DatabaseConnectionString);
using (var tenantContext = new MigrationContext(optionsBuilder.Options, _appSettings))
{
tenantContext.Database.Migrate();
}
}
}
The issue I am having is when I need to remove-migration. How can I remove a migration from all tenant databases?
You can use the same Migrate method but with the parameter ‘targetMigration’.
This will upgrade or rollback all databases to the specified target migration.
public void Migrate (string targetMigration = null);
(https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.migrations.imigrator.migrate)
Update: added example
MigrationContext.cs
public class MigrationContext : DbContext
{
}
Execute migrations
using (var tenantContext = new MigrationContext())
{
tenantContext.Database.GetService<IMigrator>().Migrate("targetMigration");
}
.csproj file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.2.4" />
</ItemGroup>
</Project>
i'm resloved
EFCoreMigrateMultiDatabase
this is my demo,need replace service IMigrationsScaffolder and IMigrationsAssembly support different database with single dbcontext to migration

WcfTestClient not opening when running a simple webservice program using c# instead opens a webpage - New to c# programming

I am trying to run a simple webservice for random numbers using c#. When running the program, it opens a webpage instead of running the WCF Test Client. I have a VS 2019 installed. I also see the wcftestclient.exe in the folder.
Please help me if I am missing any setup/ where to enable it so that it runs in the wcftestclient.
Thanks in Advance.
I tried to as /client:"wcftestclient.exe" in application arguments in project properties -> debug
added project extensions as below in .csproj,
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Design"
Version="2.1.2" PrivateAssets="All" />
</ItemGroup>
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{123c5851-25df-10da-9384-00011b846f00}">
<WebProjectProperties>
<EnableWcfTestClientForSVCDefaultValue>
True
</EnableWcfTestClientForSVCDefaultValue>
</WebProjectProperties>
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
</Project>
tried to disable launch browser in proj properties-> debug
namespace SampleWebServiceasp
{
class RandomNumberGeneratorService
{
public NumberModel GetRandomNumbers()
{
var random = new Random();
var numberobject = new NumberModel
{
RandomNumber1 = random.Next(-500, 5000),
RandomNumber2 = random.Next(-500, 5000),
RandomNumber3 = random.Next(-500, 5000)
};
return numberobject;
}
}
}
namespace SampleWebServiceasp.Models
{
public class NumberModel
{
public int RandomNumber1 { get; set; }
public int RandomNumber2 { get; set; }
public int RandomNumber3 { get; set; }
}
}
Expected to run it in wcftestclient and it opens a webpage
For me, "Windows Communication Foundation" component was not installed in Visual Studio. Installing it solved.
Before you start running or debugging select the service svc.cs file in "Solution Explorer"
As indicated in the notes for the default wcf template
// NOTE: In order to launch WCF Test Client for testing this service, please select Service1.svc or Service1.svc.cs at the Solution
Explorer and start debugging.

Categories

Resources