我有两种形式,一种用于登录,另一种用于注册。这些都在同一视图上并使用相同的模型。我正在使用控制器处理表单提交。
访问登录页面时出现以下错误
@model PastPapers.Models.LoginModel
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Login</title>
</head>
<body>
<!-- Register form inside modal -->
<div id="registerModal" class="">
<div class="">
<header class="">
<span onclick="document.getElementById('registerModal').style.display = 'none'" class="">×</span>
<h2>Register</h2>
</header>
<div class="">
<form asp-controller="Login" asp-action="AttemptRegister" method="post">
<input asp-for="newUsername" type="text" placeholder="Username" />
<input asp-for="newEmail" type="email" placeholder="Email" />
<input asp-for="newPassword" type="password" placeholder="Password" />
<input type="submit" value="Register" />
</form>
</div>
</div>
</div>
<!-- Login form -->
<form asp-controller="Login" asp-action="AttemptLogin" method="post">
<input asp-for="username" type="text" placeholder="Username" />
<input asp-for="password" type="password" placeholder="Password" />
<input type="submit" value="Login" />
</form>
<button onclick="document.getElementById('registerModal').style.display='block'" class="">Register</button>
</body>
</html>
完整错误日志:https://pastebin.com/JjfDtr6q
我看过网上找不到任何与我的问题直接相关的内容,而且在C#/ .NET Core中没有足够的经验来了解造成问题的原因。
我的观点
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using PastPapers.Models;
namespace PastPapers.Controllers
{
public class LoginController : Controller
{
public IActionResult Index(LoginModel loginModel = null)
{
if (loginModel == null)
{
return View();
} else
{
return View(loginModel);
}
}
[HttpPost]
public IActionResult AttemptLogin(LoginModel loginModel = null)
{
if (loginModel != null)
{
loginModel.AttemptLogin();
if (loginModel.loginSuccess)
{
return RedirectToAction("Index", "Home", null);
} else
{
return RedirectToAction("Index", loginModel);
}
} else
{
return RedirectToAction("Index");
}
}
[HttpPost]
public IActionResult AttemptRegister(LoginModel loginModel = null)
{
if (loginModel != null)
{
loginModel.AttemptRegister();
if (loginModel.registerSuccess)
{
return RedirectToAction("Index");
} else
{
return RedirectToAction("Index", loginModel);
}
} else
{
return RedirectToAction("Index");
}
}
}
}
我的控制器
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MySql.Data.MySqlClient;
using Newtonsoft.Json;
using PastPapers.Helpers;
using Microsoft.AspNetCore.Http;
namespace PastPapers.Models
{
public class LoginModel : HttpContextAccessor
{
public string username { get; set; }
public string password { get; set; }
public bool loginSuccess { get; set; }
public string loginErrorMessage { get; set; }
public string newUsername { get; set; }
public string newPassword { get; set; }
public string newEmail { get; set; }
public bool registerSuccess { get; set; }
public string registerErrorMessage { get; set; }
[JsonIgnore]
public AppDb Db { get; set; }
public LoginModel(AppDb db = null)
{
Db = db;
loginSuccess = false;
registerSuccess = false;
}
public LoginModel()
{
}
public void AttemptRegister()
{
try
{
Db.Connection.Open();
string sql = "INSERT INTO users (id, username, password, email) VALUES (DEFAULT, @username, @password, @email)";
MySqlCommand cmd = new MySqlCommand(sql, Db.Connection);
cmd.Prepare();
cmd.Parameters.AddWithValue("@username", newUsername);
cmd.Parameters.AddWithValue("@password", SecurePasswordHasher.Hash(newPassword));
cmd.Parameters.AddWithValue("@email", newEmail);
if (cmd.ExecuteNonQuery() == 0)
{
System.Diagnostics.Debug.WriteLine("Account failed to create!");
registerSuccess = false;
} else
{
registerSuccess = true;
}
} catch (Exception ex)
{
registerErrorMessage = "Error connecting to database";
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
public void AttemptLogin()
{
try
{
Db.Connection.Open();
string sql = "SELECT password FROM users WHERE username=@username";
MySqlCommand cmd = new MySqlCommand(sql, Db.Connection);
cmd.Prepare();
cmd.Parameters.AddWithValue("@username", username);
MySqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
{
string dbPassword = reader.GetString(0);
if (SecurePasswordHasher.Verify(password, dbPassword))
{
loginSuccess = true;
HttpContext.Session.SetString("username", username);
} else
{
loginSuccess = false;
loginErrorMessage = "Incorrect password";
}
} else
{
loginErrorMessage = "Unknown username";
}
} catch (Exception ex)
{
loginErrorMessage = "Error connecting to database";
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
}
}
我的模特
.sidenav-container {
height: 100%;
background-image: url("../../images/background.jpg");
}
.app-content {
padding: 10px;
height: calc(100% - 84px);
}
mat-card {
border-radius: 1px;
padding: 20px;
}
.toolbar {
background-color: rgba(0, 0, 0, 0.5);
}
.themathon-text {
background-color: rgba(42,42,42,.7);
}
答案 0 :(得分:4)
我放弃了HttpContextAccessor(或者更确切地说是IHttpContextAccessor)的整个继承,因为你将失去具体的HttpContextAccessor提供的功能。相反,将HttpContextAccessor注入控制器,然后使用Login模型上的操作结果来设置会话值。像这样:
在Startup.ConfigureServices
添加此行:
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
这样可以将HttpContext注入控制器。
然后在您的控制器中,添加一个接受IHttpContextAccessor的构造函数:
public LoginController(IHttpContextAccessor contextAccessor)
{
// save to a field, like _httpContext = contextAccessor.HttpContext;
}
然后将该HttpContext作为参数传递给LoginModel.AttemptLogin
。这样您仍然可以满足访问HTTP变量的要求,并且代码更易于维护和预测。
有一点需要注意 - 通过将HttpContextAccessor添加到服务中会有很小的性能损失。但总的来说它更好。
答案 1 :(得分:0)
用IHttpContextAccessor替换了HttpContextAccessor的继承,并添加了一个公共的HttpContext属性。下面的新模型。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MySql.Data.MySqlClient;
using Newtonsoft.Json;
using PastPapers.Helpers;
using Microsoft.AspNetCore.Http;
namespace PastPapers.Models
{
public class LoginModel : IHttpContextAccessor
{
public string username { get; set; }
public string password { get; set; }
public bool loginSuccess { get; set; }
public string loginErrorMessage { get; set; }
public string newUsername { get; set; }
public string newPassword { get; set; }
public string newEmail { get; set; }
public bool registerSuccess { get; set; }
public string registerErrorMessage { get; set; }
[JsonIgnore]
public AppDb Db { get; set; }
public HttpContext HttpContext { get; set; }
public LoginModel(AppDb db = null)
{
Db = db;
loginSuccess = false;
registerSuccess = false;
}
public LoginModel()
{
}
public void AttemptRegister()
{
try
{
Db.Connection.Open();
string sql = "INSERT INTO users (id, username, password, email) VALUES (DEFAULT, @username, @password, @email)";
MySqlCommand cmd = new MySqlCommand(sql, Db.Connection);
cmd.Prepare();
cmd.Parameters.AddWithValue("@username", newUsername);
cmd.Parameters.AddWithValue("@password", SecurePasswordHasher.Hash(newPassword));
cmd.Parameters.AddWithValue("@email", newEmail);
if (cmd.ExecuteNonQuery() == 0)
{
System.Diagnostics.Debug.WriteLine("Account failed to create!");
registerSuccess = false;
} else
{
registerSuccess = true;
}
} catch (Exception ex)
{
registerErrorMessage = "Error connecting to database";
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
public void AttemptLogin()
{
try
{
Db.Connection.Open();
string sql = "SELECT password FROM users WHERE username=@username";
MySqlCommand cmd = new MySqlCommand(sql, Db.Connection);
cmd.Prepare();
cmd.Parameters.AddWithValue("@username", username);
MySqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
{
string dbPassword = reader.GetString(0);
if (SecurePasswordHasher.Verify(password, dbPassword))
{
loginSuccess = true;
HttpContext.Session.SetString("username", username);
} else
{
loginSuccess = false;
loginErrorMessage = "Incorrect password";
}
} else
{
loginErrorMessage = "Unknown username";
}
} catch (Exception ex)
{
loginErrorMessage = "Error connecting to database";
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
}
}