c# - 哪个文件定义了代码隐藏文件中前端和方法之间的关系?
问题描述
当我在视图中有一个表单元素时:
create.cshtml
<form method="get">
...whatever
</form>
我们在代码隐藏文件中有一个模型:
create.cshtml.cs
public class CreateModel : PageModel
{
//...whatever
public void OnGet()
{
}
}
表单将调用OnGet()
. 我知道这是一个标准,并且在大多数框架中都遵循,但这意味着它必须在 .NET 中的某个地方定义。什么文件定义了这个标准,如果可以的话,我们可以改变它(为了理解)?
解决方案
初始化时,Razor Pages Web 应用程序会构建一个PageApplicationModel
实例集合,这些实例描述来自 Web 应用程序的 Razor Pages 及其关联的处理程序方法。
要了解有关其工作原理的更多信息,请查看'方法的源代码:DefaultPageApplicationModelProvider
PopulateHandlerMethods
internal void PopulateHandlerMethods(PageApplicationModel pageModel) { var methods = pageModel.HandlerType.GetMethods(); for (var i = 0; i < methods.Length; i++) { var handler = _pageApplicationModelPartsProvider .CreateHandlerModel(methods[i]); if (handler != null) { pageModel.HandlerMethods.Add(handler); } } }
在这里,我们可以看到框架枚举了 Razor Page 类的方法,并为每个方法调用了DefaultPageApplicationModelPartsProvider
'方法。确定方法是否是处理程序(例如,它是,不是),然后解析方法名称以确定其 HTTP 方法、处理程序名称等。此解析发生在:CreateHandlerModel
CreateHandlerModel
public
static
TryParseHandlerMethod
internal static bool TryParseHandlerMethod( string methodName, out string httpMethod, out string handler) { httpMethod = null; handler = null; // Handler method names always start with "On" if (!methodName.StartsWith("On") || methodName.Length <= "On".Length) { return false; } // Now we parse the method name according to our conventions to // determine the required HTTP method and optional 'handler name'. // Valid names look like: // - OnGet // - OnPost // - OnFooBar // - OnTraceAsync // - OnPostEditAsync var start = "On".Length; var length = methodName.Length; if (methodName.EndsWith("Async", StringComparison.Ordinal)) { length -= "Async".Length; } if (start == length) { // There are no additional characters. This is "On" or "OnAsync". return false; } // The http method follows "On" and is required to be at least one // character. We use casing to determine where it ends. var handlerNameStart = start + 1; for (; handlerNameStart < length; handlerNameStart++) { if (char.IsUpper(methodName[handlerNameStart])) { break; } } httpMethod = methodName.Substring(start, handlerNameStart - start); // The handler name follows the http method and is optional. // It includes everything up to the end excluding the "Async" suffix // (if present). handler = handlerNameStart == length ? null : methodName.Substring(handlerNameStart, length - handlerNameStart); return true; }
这段代码很好地解释了自己,但最终它解析出 HTTP 方法和一个可选的处理程序名称。
最后,框架创建一个实例PageHandlerModel
来保存提取的信息。有了这些信息,路由系统就能够根据传入的请求选择处理程序。这个选择逻辑由DefaultPageHandlerMethodSelector
类处理。
该类DefaultPageApplicationModelPartsProvider
实现IPageApplicationModelPartsProvider
接口并使用 DI 进行解析。例如,您可以创建自己的实现IPageApplicationModelPartsProvider
并替换默认实现,这将允许您执行自己的方法名称解析。
要使用自定义实现,例如MyCustomPageApplicationModelPartsProvider
,添加类似以下内容的内容ConfigureServices
,最好是在调用之前AddRazorPages
:
services.AddSingleton<IPageApplicationModelPartsProvider,
MyCustomPageApplicationModelPartsProvider>();
除了解释框架如何找到处理程序之外,答案还应该解释框架如何将一个文件定义为另一个文件的代码隐藏。
页面与其之间的连接PageModel
是使用@model
.cshtml 文件中的指令建立的。例如在Index.cshtml
你会看到@model IndexModel
。您可以重命名Index.cshtml.cs
为SomethingElse.cs
,它仍然可以工作,因此文件命名更像是一种约定。