【问题标题】:What file defines the relation between front-end and methods in the code-behind file?哪个文件定义了代码隐藏文件中前端和方法之间的关系?
【发布时间】:2021-01-08 09:02:03
【问题描述】:

当我在视图中有一个表单元素时:
create.cshtml

<form method="get">
    ...whatever
</form>

我们在代码隐藏文件中有一个模型:
create.cshtml.cs

public class CreateModel : PageModel 
{
    //...whatever
    public void OnGet()
    {

    }
}

表单将调用OnGet()。我知道这是一个标准,并且在大多数框架中都遵循,但这意味着它必须在 .NET 中的某个地方定义。什么文件定义了这个标准,如果可以的话,我们可以改变它(为了理解起见)?

【问题讨论】:

  • 据我了解,它不一定是表格。一个页面也可以触发OnGet。它更像是一个事件监听器。如果您查看默认的 CRUD 页面,您会看到 POST 请求也可以被该方法拦截(当然现在是 OnPost)。
  • 不,我只想知道在哪里配置框架在其页面模型类中调用OnGet 命名方法?因为OnGet 是完全用户定义和用户声明的方法。它不是从 PageModel 类继承的

标签: c# forms asp.net-core get


【解决方案1】:

在初始化时,Razor Pages Web 应用会构建一组 PageApplicationModel 实例,这些实例描述来自 Web 应用的 Razor Pages 及其关联的处理程序方法。

要了解有关其工作原理的更多信息,请查看source 中的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 的CreateHandlerModel 方法。 CreateHandlerModel 确定该方法是否为处理程序(例如,它是public,而不是static),然后解析方法名称以确定其 HTTP 方法、处理程序名称等。此解析发生在 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 之间的连接是使用.cshtml 文件中的@model 指令建立的。例如在Index.cshtml 中,您将看到@model IndexModel。您可以将Index.cshtml.cs 重命名为SomethingElse.cs,它仍然可以工作,因此文件命名更像是一种约定。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-27
    相关资源
    最近更新 更多