【发布时间】:2021-09-10 07:19:21
【问题描述】:
我目前正在学习 ASP。 NET Core 通过编写带有 cookie 身份验证的 Web 应用程序。我在 Azure SQL 数据库中有两个表 - Users(包含登录名和密码数据)和 UserLinks(包含用于将登录用户重定向到某个页面的链接)。 p>
问题是,在登录后,每个经过身份验证的用户都应该被重定向到该用户唯一的页面(指向该页面的链接存储在数据库的 UserLinks 表中)。我试图通过使用这行代码来实现这一点:
return RedirectToAction(db2.UserLinks.Find(user.Id).Link);
这显然行不通,并给我这个错误消息:
SqlNullValueException:数据为空。不能对 Null 值调用此方法或属性
这意味着 Find() 方法在这里不合适。
我的问题是:解决我的表以找到与 Users.Id 对应的正确 UserLinks.Link 的正确方法是什么?
所有相关代码(包括SQL表)如下:
表 dbo.Users:
CREATE TABLE [dbo].[Users] (
[Id] INT NOT NULL,
[Email] NVARCHAR (50) NOT NULL,
[Password] NVARCHAR (50) NOT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
表 dbo.USerLinks(通过外键 UserID 链接到 dbo.Users):
CREATE TABLE [dbo].[UserLinks] (
[Post_ID] INT NOT NULL,
[UserID] INT NOT NULL,
[TableName] NVARCHAR (50) NOT NULL,
[Options] INT NULL,
[Link] NVARCHAR (MAX) NOT NULL,
PRIMARY KEY CLUSTERED ([Post_ID] ASC),
UNIQUE NONCLUSTERED ([UserID] ASC),
FOREIGN KEY ([UserID]) REFERENCES [dbo].[Users] ([Id])
);
AccountController.cs:
public class AccountController : Controller
{
private UserContext db;
private UserLinkContext db2;
public AccountController(UserContext context, UserLinkContext ulcontext)
{
db = context;
db2 = ulcontext;
}
[HttpGet]
public IActionResult Login()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginModel model)
{
if (ModelState.IsValid)
{
User user = await db.Users.FirstOrDefaultAsync(u => u.Email == model.Email && u.Password == model.Password);
if (user != null)
{
await Authenticate(model.Email);
return RedirectToAction(db2.UserLinks.Find(user.Id).Link);
}
ModelState.AddModelError("", "Incorrect login and(or) password");
}
return View(model);
}
private async Task Authenticate(string userName)
{
var claims = new List<Claim>
{
new Claim(ClaimsIdentity.DefaultNameClaimType, userName)
};
ClaimsIdentity id = new ClaimsIdentity(claims, "ApplicationCookie", ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType);
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(id));
}
[HttpPost]
public async Task<IActionResult> Logout()
{
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return RedirectToAction("Index", "Home");
}
}
Startup.cs:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
string connection = Configuration.GetConnectionString("DefaultConnection");
services.AddDbContext<UserContext>(options => options.UseSqlServer(connection));
services.AddDbContext<UserLinkContext>(options => options.UseSqlServer(connection));
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options => //CookieAuthenticationOptions
{
options.LoginPath = new Microsoft.AspNetCore.Http.PathString("/Account/Login");
});
services.AddControllersWithViews();
}
public void Configure(IApplicationBuilder app)
{
app.UseDeveloperExceptionPage();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
【问题讨论】:
-
代码优先方法,对吧?你确定你已经应用了你的迁移吗?也许您的数据库仍然是空的。
-
检查您的数据库数据,是否所有字段都具有在您的实体模型中标记为 [required] 的字段的数据。
-
您可能正在尝试读取响应,然后它有时间从数据库中获取它。您可能需要等待响应并将其放入变量中,例如
var userLink = await db2.UserLinks.FindAsync(user.Id).Link(也许它在语法上不正确,但你明白了:await响应和FindAsync)。然后:RedirectToAction(userLink); -
如果数据为Null,则不能调用包含特定类型的方法,因为它们内部涉及类型转换。解决方法:可以先调用IsDBNull检查数据是否为Null,或者直接指定数据库字段不能为Null,从根本上消除Null值。
-
感谢您的建议,我检查了我的数据库并确保我在 dbo.UserLinks 中确实有数据,并且表中的“链接”字段不能为空。不幸的是,这没有帮助,我仍然遇到同样的错误消息。
标签: c# sql-server asp.net-core