【问题标题】:Having trouble with accessing database table in ASP. NET Core在 ASP 中访问数据库表时遇到问题。网络核心
【发布时间】: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


【解决方案1】:

查找与主键一起使用,在表 user_links 中它是 post_id 列。

改为find() 使用

firstOrDefault(x=&gt;x.UserId== user.Id)

【讨论】:

  • 尝试了这种方法,但仍然收到相同的错误消息。但无论如何感谢您的帮助。
  • 首先,Find() 方法可以返回空值(出于任何原因),因此您必须检查它是否不为空。 Find method 或者使用默认值(页面)的空传播运算符RedirectToAction(db2.UserLinks.Find(user.Id)?.Link??"defaultPage")
【解决方案2】:

我想通了。问题是我错误地映射了我的 UserLinks 表。由于在我的示例中“选项”列可以为空,我应该在我的 UserLinks.cs 文件中使用 int? 而不仅仅是 int

    [Key]
    public int Post_ID { get; set; }
    public int UserID { get; set; }
    public string TableName { get; set; }
    public int? Options { get; set; }
    public string Link { get; set; }

【讨论】:

猜你喜欢
  • 2011-02-02
  • 2017-08-06
  • 1970-01-01
  • 2021-04-02
  • 2020-01-27
  • 2017-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多