Getting a ConnectionString empty error in a webapi project with .net 10

11 hours ago 1
ARTICLE AD BOX

I'm running in .NET 10 with the most recent update for everything. I'm in EF. I'm ASP.NET Core. Below is my program.cs file. Inside of the program.cs file, when I call to get my connection string, I get back what I expect. When I hit the LoginController, I see the settings in the IConfiuguration that is handed in. However, when I set a breakpoint in the FSMUserStore constructor, I check the context that is handed in, and it's connection string is not set correctly (at all). I've run through Visual Studio debugger so many times, and tried so many things, I'm just lost on this. Anyone have a suggestion?

using ElmahCore.Mvc; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using Portal.Libraries; using PortalDataModels.Models; using System.Text; using Twilio.TwiML.Voice; var builder = WebApplication.CreateBuilder(args); IConfiguration configuration = new ConfigurationBuilder() .AddJsonFile("appsettings.json") .AddEnvironmentVariables() .Build(); var connString = configuration.GetConnectionString("DefaultConnection"); // Add services to the container. // For Entity Framework builder.Services.AddDbContext<PortalDataModels.Models.POA_CSMContext>(options => options.UseSqlServer(configuration.GetConnectionString(connString))); builder.Services.AddScoped<IUserStore<FSMUser>, FSMUserStore>(); builder.Services.AddIdentity<FSMUser, IdentityRole>() .AddEntityFrameworkStores<POA_CSMContext>() .AddUserManager<UserManager<FSMUser>>() .AddSignInManager<SignInManager<FSMUser>>() .AddDefaultTokenProviders(); builder.Services.AddElmah<ElmahCore.Sql.SqlErrorLog>(options => { options.ConnectionString = connString; options.SqlServerDatabaseTableName = "Elmah_Error"; //Defaults to ELMAH_Error if not set options.OnPermissionCheck = context => false; }); // Adding Authentication builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; }) // Adding Jwt Bearer .AddJwtBearer(options => { options.SaveToken = true; options.RequireHttpsMetadata = false; options.MapInboundClaims = false; options.TokenValidationParameters = new TokenValidationParameters() { ValidateIssuer = true, ValidateAudience = true, ValidAudience = configuration["Jwt:ValidAudience"], ValidIssuer = configuration["Jwt:ValidIssuer"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Jwt:Key"])) }; }); builder.Services.AddScoped<UserManager<FSMUser>>(); builder.Services.AddElmah<ElmahCore.Sql.SqlErrorLog>(options => { options.ConnectionString = connString; options.SqlServerDatabaseTableName = "Elmah_Error"; //Defaults to ELMAH_Error if not set options.OnPermissionCheck = context => false; }); builder.Services.AddControllers(); // Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi builder.Services.AddOpenApi(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.MapOpenApi(); } app.UseHttpsRedirection(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();

LoginController.cs file:

[Produces("application/json")] [Route("api/[controller]")] [ApiController] public class LoginController : ControllerBase { private readonly SignInManager<FSMUser> _signInManager; private readonly UserManager<FSMUser> _userManager; private readonly RoleManager<IdentityRole> _roleManager; private readonly IConfiguration _configuration; public LoginController( SignInManager<FSMUser> signInManager, UserManager<FSMUser> userManager, RoleManager<IdentityRole> roleManager, IConfiguration configuration) { _signInManager = signInManager; _userManager = userManager; _roleManager = roleManager; _configuration = configuration; } [HttpPost] public async Task<IActionResult> Login([FromBody] Login model) { var user = await _userManager.FindByNameAsync(model.Username); if (user != null && await _userManager.CheckPasswordAsync(user, model.Password)) { //var userRoles = await _userManager.GetRolesAsync(user); var authClaims = new List<Claim> { new Claim(ClaimTypes.Name, user.UserName.Trim()), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), }; //authClaims.Add(new Claim("UserId", user.Id)); var token = GetToken(authClaims); return Ok(new { token = new JwtSecurityTokenHandler().WriteToken(token), expiration = token.ValidTo, Id = user.Id.Trim(), }); } return Unauthorized(); } private JwtSecurityToken GetToken(List<Claim> authClaims) { var authSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(s: _configuration["Jwt:Key"])); var token = new JwtSecurityToken( issuer: _configuration["Jwt:ValidIssuer"], audience: _configuration["Jwt:ValidAudience"], expires: DateTime.Now.AddYears(30), claims: authClaims, signingCredentials: new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256) ); return token; } }

FSMUserStore.cs file:

using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using PortalDataModels.Models; using System.Data.Common; using System.Data.SqlClient; namespace Portal.Libraries { public class FSMUserStore : IUserStore<FSMUser>, IUserPasswordStore<FSMUser> { private bool disposedValue; private POA_CSMContext _ctx; public FSMUserStore(POA_CSMContext ctx) { _ctx = ctx; // <!-- no database connection string. } public async Task<IdentityResult> CreateAsync(FSMUser user, CancellationToken cancellationToken) { var fsmu = new Arcustmr(); fsmu.Email = user?.UserName; fsmu.Userid = user?.UserName; fsmu.Code = user?.PasswordHash; _ctx.Arcustmrs.Add(fsmu); await _ctx.SaveChangesAsync(); return IdentityResult.Success; } public async Task<IdentityResult> DeleteAsync(FSMUser user, CancellationToken cancellationToken) { var users = await (from u in _ctx.Arcustmrs where u.Email == user.UserName select u).ToListAsync(); _ctx.Arcustmrs.RemoveRange(users); await _ctx.SaveChangesAsync(); return IdentityResult.Success; } public async Task<FSMUser?> FindByIdAsync(string userId, CancellationToken cancellationToken) { var user = await (from c in _ctx.Arcustmrs where c.Custno == userId select new FSMUser() { Id = c.Custno, UserName = c.Email, NormalizedUserName = c.Email, PasswordHash = c.Code }).FirstOrDefaultAsync(); return user; } // An error occurs in the call here stating that the ConnectionString property // has not been set. public async Task<FSMUser?> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken) { var user = await (from c in _ctx.Arcustmrs where c.Email == normalizedUserName select new FSMUser() { Id = c.Custno, NormalizedUserName = c.Email, UserName = c.Email, PasswordHash = c.Code }).FirstOrDefaultAsync(); return user; } public Task<string?> GetNormalizedUserNameAsync(FSMUser user, CancellationToken cancellationToken) { return Task.FromResult(user.NormalizedUserName); } public Task<string> GetUserIdAsync(FSMUser user, CancellationToken cancellationToken) { return Task.FromResult(user.Id); } public Task<string?> GetUserNameAsync(FSMUser user, CancellationToken cancellationToken) { return Task.FromResult(user.UserName); } public Task SetNormalizedUserNameAsync(FSMUser user, string? normalizedName, CancellationToken cancellationToken) { user.NormalizedUserName = normalizedName; return Task.CompletedTask; } public Task SetUserNameAsync(FSMUser user, string? userName, CancellationToken cancellationToken) { user.UserName = userName; return Task.CompletedTask; } public Task<IdentityResult> UpdateAsync(FSMUser user, CancellationToken cancellationToken) { return Task.FromResult(IdentityResult.Success); } protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { // TODO: dispose managed state (managed objects) } // TODO: free unmanaged resources (unmanaged objects) and override finalizer // TODO: set large fields to null disposedValue = true; } } // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources // ~FSMUserStore() // { // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method // Dispose(disposing: false); // } public void Dispose() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method Dispose(disposing: true); GC.SuppressFinalize(this); } public Task SetPasswordHashAsync(FSMUser user, string? passwordHash, CancellationToken cancellationToken) { var us = (from u in _ctx.Arcustmrs where u.Email == user.UserName select u).SingleOrDefault(); if (us != null) { us.Code = passwordHash; _ctx.SaveChanges(); } return Task.CompletedTask; } public Task<string?> GetPasswordHashAsync(FSMUser user, CancellationToken cancellationToken) { return Task.FromResult(user.PasswordHash); } public async Task<bool> HasPasswordAsync(FSMUser user, CancellationToken cancellationToken) { var result = false; var email = user.UserName; var use = await (from u in _ctx.Arcustmrs where u.Email.Contains(email) select u).SingleOrDefaultAsync(cancellationToken: cancellationToken); if (use != null) { if((use.Code == null) || (String.IsNullOrEmpty(use.Code))) { result = false; } else { result = true; } } else { result = false; } return result; } public async Task<List<string>> GetRolesAsync(FSMUser user) { var rl = new List<string>(); rl.Add("User"); return rl; } } }
Read Entire Article