Razor Pages中InvalidOperationException多处理器匹配问题求助
问题描述
开发基于Razor Pages和C#的资产处置Web应用,采用LDAP验证用户账号密码,登录后将用户姓名传递到资产处置页面显示欢迎信息。用户登录后加载资产处置表单页面时触发以下错误:
An unhandled exception occurred while processing the request. InvalidOperationException: Multiple handlers matched. The following handlers matched route data and had all constraints satisfied: Void OnGet(), Void OnGet(System.String, System.String) Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.DefaultPageHandlerMethodSelector.Select(PageContext context) Stack Query Cookies Headers Routing InvalidOperationException: Multiple handlers matched. The following handlers matched route data and had all constraints satisfied: Void OnGet(), Void OnGet(System.String, System.String) Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.DefaultPageHandlerMethodSelector.Select(PageContext context) Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted) Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeInnerFilterAsync() Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync() Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
相关代码如下:
登录页C#代码
using System.DirectoryServices.AccountManagement; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; namespace Surplus.Pages { public class LoginModel : PageModel { [BindProperty] public string Username { get; set; } [BindProperty] public string Password { get; set; } public string ErrorMessage { get; set; } public IActionResult OnPost() { if (!ValidateUser(Username, Password)) { ErrorMessage = "Invalid username or password."; return Page(); } var user = GetUserDetailsFromLDAP(Username); if (user == null) { ErrorMessage = "Failed to retrieve user details from Server."; return Page(); } // Pass user details to the surplus entry form return RedirectToPage("/SurplusEntryForm", new { firstName = user.FirstName, lastName = user.LastName }); } private bool ValidateUser(string username, string password) { try { using (var context = new PrincipalContext(ContextType.Domain)) { // Validate the user's credentials against the LDAP server return context.ValidateCredentials(username, password); } } catch (Exception ex) { // Handle any exception that occurred during the LDAP authentication // Log the exception or perform error handling as per your application's requirements Console.WriteLine($"LDAP authentication failed: {ex.Message}"); } return false; // Return false if authentication fails or an error occurs } private User GetUserDetailsFromLDAP(string username) { try { using (var context = new PrincipalContext(ContextType.Domain)) { var userPrincipal = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, username); if (userPrincipal != null) { var firstName = userPrincipal.GivenName; var lastName = userPrincipal.Surname; // Create and return a User object return new User { FirstName = firstName, LastName = lastName }; } } } catch (Exception ex) { // Handle any exception that occurred while retrieving user details from LDAP // Log the exception or perform error handling as per your application's requirements Console.WriteLine($"Failed to retrieve user details from Server: {ex.Message}"); } return null; // Return null if the user is not found or an error occurs } } }
User.cs模型代码
using System; using System.Data.SqlClient; using System.DirectoryServices; namespace Surplus.Pages { public class User { public string FirstName { get; set; } public string LastName { get; set; } public string DatabaseConnectionString { get; set; } public bool ValidateLDAP(string userId, string password) { try { var ldapManager = new LdapManager(); return ldapManager.Validate(userId, password); } catch (Exception ex) { // Handle any exception that occurred during LDAP validation Console.WriteLine($"LDAP validation failed: {ex.Message}"); } return false; } public void ConnectToDatabase() { try { using (var connection = new SqlConnection(DatabaseConnectionString)) { connection.Open(); // Perform database operations here connection.Close(); } } catch (Exception ex) { // Handle any database connectivity exceptions Console.WriteLine($"Database connection failed: {ex.Message}"); } } internal object GetUserDetailsFromLDAP(string username) { throw new NotImplementedException(); } } public class LdapManager { public bool Validate(string userId, string password) { try { string path = LdapPath(); string username = UserFullId(userId); DirectoryEntry de = new DirectoryEntry(path, username, password, AuthenticationTypes.Secure); DirectorySearcher ds = new DirectorySearcher(de); ds.FindOne(); return true; } catch (DirectoryServicesCOMException) { return false; } } private string UserFullId(string userId) { string value = string.Format(@"{0}@{1}", userId, "YourDomainName"); return value; } private string LdapPath() { string value = string.Format(@"LDAP://{0}:{1}", "YourDomainName", 389); return value; } } }
资产处置页C#代码
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using System.Collections.Generic; using System.Data.SqlClient; namespace Surplus.Pages { public class SurplusEntryFormModel : PageModel { private readonly string _connectionString = "Data Source=dbname;Initial Catalog=tablename;User ID=dbusername;Password=dbpassword;"; public string FirstName { get; set; } public string LastName { get; set; } public string WelcomeMessage { get; set; } [BindProperty] public string AssetTag { get; set; } [BindProperty] public string BulidingName { get; set; } [BindProperty] public string ItemName { get; set; } [BindProperty] public string Description { get; set; } [BindProperty] public string Reason { get; set; } public List<string> BuildingOptions { get; set; } public void OnGet() { // Initialize the BuildingOptions list BuildingOptions = new List<string>(); try { using (var connection = new SqlConnection(_connectionString)) { connection.Open(); string query = "SELECT ID, BuildingName FROM SurplusItemsNew"; using (var command = new SqlCommand(query, connection)) { using (var reader = command.ExecuteReader()) { while (reader.Read()) { string buildingName = reader["BuildingName"].ToString(); BuildingOptions.Add(buildingName); } } } connection.Close(); } } catch (SqlException ex) { // Handle the exception // For simplicity, this example just rethrows the exception throw ex; } } public List<string> ReasonOptions { get; } = new List<string> { "Broken", "Burned Out", "Extinction", "No Longer Used", "Obsolete", "Other" }; public void OnGet(string firstName, string lastName) { FirstName = firstName; LastName = lastName; WelcomeMessage = $"Welcome, {FirstName} {LastName}!"; } public IActionResult OnPostSearchItem() { if (string.IsNullOrEmpty(AssetTag)) { ModelState.AddModelError(string.Empty, "Please enter a valid Asset Tag."); return Page(); } if (!ModelState.IsValid) { return Page(); } try { using (var connection = new SqlConnection(_connectionString)) { connection.Open(); string query = "SELECT BulidingName, ItemName, Description, Reason FROM Items WHERE AssetTag = @assetTag"; using (var command = new SqlCommand(query, connection)) { command.Parameters.AddWithValue("@assetTag", AssetTag); using (var reader = command.ExecuteReader()) { if (reader.Read()) { BulidingName = reader["BulidingName"].ToString(); ItemName = reader["ItemName"].ToString(); Description = reader["Description"].ToString(); Reason = reader["Reason"].ToString(); } else { ModelState.AddModelError(string.Empty, "Item not found with the given Asset Tag."); } } } connection.Close(); } } catch (SqlException ex) { ModelState.AddModelError(string.Empty, $"Database connection failed: {ex.Message}"); } return Page(); } } }
解决方案
错误原因
Razor Pages不允许同一个PageModel存在多个签名不同的OnGet方法。当页面被请求时,路由系统无法区分应该调用哪个OnGet,因此抛出Multiple handlers matched异常。你在SurplusEntryFormModel中定义了两个OnGet:无参数的和带firstName、lastName参数的,这就是问题根源。
修复步骤
将两个OnGet方法合并为一个,把参数设为可选(可为null),在同一个方法中处理初始化建筑选项和用户欢迎信息的逻辑:
public void OnGet(string firstName = null, string lastName = null) { // 初始化建筑选项列表 BuildingOptions = new List<string>(); try { using (var connection = new SqlConnection(_connectionString)) { connection.Open(); string query = "SELECT ID, BuildingName FROM SurplusItemsNew"; using (var command = new SqlCommand(query, connection)) { using (var reader = command.ExecuteReader()) { while (reader.Read()) { string buildingName = reader["BuildingName"].ToString(); BuildingOptions.Add(buildingName); } } } connection.Close(); } } catch (SqlException ex) { throw ex; } // 处理用户欢迎信息 if (!string.IsNullOrEmpty(firstName) && !string.IsNullOrEmpty(lastName)) { FirstName = firstName; LastName = lastName; WelcomeMessage = $"Welcome, {FirstName} {LastName}!"; } }
这样修改后,无论是否传递firstName和lastName参数,都会调用同一个OnGet方法,路由系统可以正确匹配,解决异常问题。
额外优化建议
- 用户信息传递方式优化:通过URL参数传递用户姓名存在安全风险(可被篡改),建议登录后将用户信息存储到
HttpContext.Session中,在资产处置页面直接从Session读取:- 在
LoginModel的OnPost方法中添加:HttpContext.Session.SetString("FirstName", user.FirstName); HttpContext.Session.SetString("LastName", user.LastName); - 在
SurplusEntryFormModel的OnGet中读取:FirstName = HttpContext.Session.GetString("FirstName"); LastName = HttpContext.Session.GetString("LastName"); if (!string.IsNullOrEmpty(FirstName) && !string.IsNullOrEmpty(LastName)) { WelcomeMessage = $"Welcome, {FirstName} {LastName}!"; } - 在
Program.cs中启用Session:builder.Services.AddSession(); // ... app.UseSession();
- 在
- 异常处理优化:避免直接抛出数据库异常到页面,建议添加日志记录,并返回友好的错误提示。
内容的提问来源于stack exchange,提问作者djjailbreak
相关产品推荐
相关产品推荐

