我有两种表单,一种用于登录,一种用于注册。它们都在同一 View 上并使用同一模型。我正在使用 Controller 处理表单提交。
访问登录页面时出现以下错误
InvalidOperationException: Incorrect Content-Type:
完整错误日志:https://pastebin.com/JjfDtr6q
我在网上查找过,找不到任何与我的问题直接相关的内容,而且我在 C#/.NET Core 方面的经验不足,无法理解导致问题的原因。
我的观点
@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>
我的 Controller
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);
}
}
}
}
最佳答案
我会放弃 HttpContextAccessor(或者更确切地说 IHttpContextAccessor)的整个继承,因为您将失去具体 HttpContextAccessor 提供的功能。相反,将 HttpContextAccessor 注入(inject) Controller ,然后使用登录模型上的操作结果来设置 session 值。像这样:
在您的 Startup.ConfigureServices
中添加以下行:
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
这使得 HttpContext 能够被注入(inject)到 Controller 中。
然后在 Controller 中添加一个接受 IHttpContextAccessor 的构造函数:
public LoginController(IHttpContextAccessor contextAccessor)
{
// save to a field, like _httpContext = contextAccessor.HttpContext;
}
然后将该 HttpContext 作为参数传递到 LoginModel.AttemptLogin
中。这样您仍然可以满足访问 HTTP 变量的要求,并且代码更易于维护和预测。
有一个警告 - 将 HttpContextAccessor 添加到服务会对性能造成一点影响。但总体来说还是比较好的。
关于c# - 无效操作异常 : Incorrect Content-Type: ASP. NET Core,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48672104/