在ASP.NET Core 10 Web API项目中遇到连接字符串为空的错误
我在.NET 10上运行,所有东西都已更新到最新版。我在使用EF Core和 ASP.NET Core。
这是我的 program.cs 文件;获取连接字符串时,返回的正是我预期的结果。当我进入 LoginController 时,我能看到传入的 IConfiuguration 中的设置。然而,当我在 FSMUserStore 构造函数中设置断点时,查看传入的上下文,发现它的连接字符串根本没有被正确设置。
我已经用Visual Studio调试器调试了无数次,尝试了无数方法,现在真的有点迷茫。有人有什么建议吗?
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 文件:
[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 文件:
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;
}
}
}
解决方案
问题在于你把第一次检索到的 "DefaultConnection" 连接字符串的 获取到的值,作为同一连接字符串配置段中第二次查找的 键 来使用。
var connString = configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<POA_CSMContext>(options => options.UseSqlServer(
configuration.GetConnectionString(connString))); // <-- second lookup with
// the value of the DefaultConnection as the key
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。