【问题标题】:Blazor Server Sider without Razor没有 Razor 的 Blazor Server Sider
【发布时间】:2021-04-13 11:29:37
【问题描述】:

上下文: 引导使用服务器端 blazor/razor 组件但不使用 razor 定义组件的 F# 应用程序。相反,我使用FsBoleros DSL。

一切正常,但.cshtml 文件 (_Host.cshtml) 上仍有我想用 (F#) 代码替换的文件,原因如下:

  • 我所有的代码都将用 F# 编写 - 但如果我需要更改内容/将代码添加到主机剃须刀文件中,我需要混合使用 C#。虽然这可行,但它不是最优的,我宁愿只使用 F# 代码,没有特殊的剃须刀文件。

  • F# 项目依赖于文件排序。 razor 文件在这方面表现得有点奇怪(我不能像使用 IDE 工具在我的项目中的其他文件一样重新排序它)。

所以目标是删除_Host.cshtml 文件并用代码替换它。

我已经投入了 2 天的时间来尝试这样做。关于如何仅用代码替换 razor 页面或如何从非 razor 代码调用标签助手的内容似乎很少甚至没有。非常感谢您提供有关如何解决此问题的一些指导,否则我将花费更多时间。

我目前对自己要做的事情的理解是:

呈现一个包含以下内容的 html 响应

  • 服务器端 Blazor 框架
  • 带有特殊注释注释的预渲染根组件

这样对吗?

如果是这样:

生成所需的 html 页面是微不足道的,除了预渲染的带注释的组件。调用标签助手是实现这一目标的正确方法吗(因为我遇到了一些问题)?

其他组件渲染类(和接口)是内部的,所以我怀疑我不应该使用它们。我还假设我必须使用标签助手才能正确注释 html。

注意:实际上不需要将其替换为完全相同的代码(例如,剃刀页面),而是以可维护的方式执行引导 blazor 所需的操作(因此没有魔术字符串管道)。

(这是要替换的_Host.cshtml文件)

@page "/"
@namespace X.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Bolero Application</title>
    <base href="~/">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.4/css/bulma.min.css">
    <link rel="stylesheet" href="css/index.css">
</head>

<body>
<h1>Blazor Host</h1>

<component type="typeof(App)" render-mode="ServerPrerendered"/>

<script src="_framework/blazor.server.js"></script>
</body>
</html>

【问题讨论】:

    标签: c# asp.net-core f# blazor


    【解决方案1】:

    查看生成的代码文件 _Host.cshtml.g.cs 并将其转换为 F#

    我不使用 F#,因此无法评论这会有多困难,但查看生成的代码至少应该回答您关于如何调用 taghelpers 等的问题...

    【讨论】:

    • 看看 Razor 页面编译成什么,有点神秘。当我试图模仿那里发生的大部分事情时(继承自Page,实现ExecuteAsync)并没有被拾起。如果你能得到一个 C# 版本来工作,那么将它移植到 F# 是没有问题的。关于如何将剃须刀页面转换为 C#/F# 代码,这是一个更普遍的问题。
    【解决方案2】:

    编辑:这似乎也可以在打开正确的命名空间后使用IHtmlHelper

    task {  
        let htmlHelper = container.GetService<IHtmlHelper>()
        
        (htmlHelper :?> IViewContextAware).Contextualize(ViewContext(HttpContext = httpContext))
    
        // RenderComponentAsync is an extension from "Microsoft.AspNetCore.Mvc.Rendering"
        let! componentHtmlContent = htmlHelper.RenderComponentAsync<App>(RenderMode.ServerPrerendered)
        
        let componentHtml: string =
            using (new StringWriter()) (fun writer ->
                componentHtmlContent.WriteTo (writer, HtmlEncoder.Default)
                writer.Flush()
                writer.ToString()
            )
    }
    

    旧答案如下:

    我发现的解决方案有效,但涉及调用 ASP.NET Core 未公开的内部类型的方法。

    模块通过反射调用IComponentRenderer.RenderComponentAsync

    [<RequireQualifiedAccess>]
    module ComponentRenderer =
        open System
        open System.Reflection
        open System.Threading.Tasks
        open Microsoft.AspNetCore.Html
        open Microsoft.AspNetCore.Mvc.Rendering
        
        let private ``reflected IComponentRenderer``: Type  =
            let assemblyName = "Microsoft.AspNetCore.Mvc.ViewFeatures"
            let assembly = Assembly.Load assemblyName
            let componentRendererInterface = assembly.GetType $"{assemblyName}.IComponentRenderer"
            componentRendererInterface
       
        let private getRef (serviceContainer: IServiceProvider) : obj =
            serviceContainer.GetService ``reflected IComponentRenderer`` 
            
        let private getMethodRef () : MethodInfo =
            let flags = BindingFlags.Public ||| BindingFlags.Instance 
            let method = ``reflected IComponentRenderer``.GetMethod ("RenderComponentAsync", flags)
            method
    
        let callRenderComponentAsync
           (serviceContainer: IServiceProvider,
            viewContext: ViewContext,
            componentType: Type,
            renderMode: RenderMode,
            parameters: obj) : Task<IHtmlContent> =
            
            let renderer = getRef serviceContainer
            let method = getMethodRef ()
            let result = method.Invoke(renderer, [| viewContext; componentType; renderMode; parameters |])
            
            result :?> Task<IHtmlContent>
    

    基本上只需要一个包含以下内容的 HTML 响应:

    • 服务器端 Blazor 框架
    • 带有特殊注释注释的预渲染根组件

    有多种方法可以达到所需的结果,这是一个简单的示例处理程序。

    module HttpHandlers =
    
        let htmlTemplate (comp: string) =
            $"""
            <!DOCTYPE html>
            <html lang="en">
    
            <head>
                <meta charset="UTF-8">
                <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
                <title>Bolero Application</title>
                <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.4/css/bulma.min.css">
                <link rel="stylesheet" href="css/index.css">
            </head>
    
            <body>
                {comp}
                <script src="_framework/blazor.server.js"></script>
            </body>
            </html>
            """
            
        let index (container: IServiceProvider) (httpContext: HttpContext) : Task =
            task {
                let! componentHtmlContent =
                    ComponentRenderer.callRenderComponentAsync (
                        container,
                        ViewContext(HttpContext = httpContext),
                        typeof<App>,
                        RenderMode.ServerPrerendered,
                        null
                    )
                    
                let componentHtml: string =
                    using (new StringWriter()) (fun writer ->
                        componentHtmlContent.WriteTo (writer, HtmlEncoder.Default)
                        writer.Flush()
                        writer.ToString()
                    )
                
                let! _ =
                    (htmlTemplate componentHtml)
                    |> Encoding.UTF8.GetBytes
                    |> ReadOnlyMemory
                    |> httpContext.Response.BodyWriter.WriteAsync
                    
                return ()
            } :> _
    
    
    

    生成的 html 响应现在应该如下所示:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.4/css/bulma.min.css">
        <link rel="stylesheet" href="css/index.css">
    </head>
    
    <body>
        <!--Blazor:{"sequence":0,"type":"server","prerenderId":"de4cefeb845c4241810b39a9fa6fb09d","descriptor":"CfDJ8B1PPZs/SbNIpyDpD4CgsZTZ9MSJjiAAdULVygxQGjm2QdNlb19sKvxXV\u002B0ZZh\u002Br43icwKyOdOw0RCK6auj2fziShHMZNiE/kNp0XnqJywdEpAAGuNROLgewx4NSSwKJ5lUUWq\u002BiuwKOnKNwQEJA1BAQ1B0IJbE6gKqHkKPMK3vYVjnB/jgpX01f2DS7djVlH\u002Bc/D8hr2jjuqt08527OrAPky7Fm71HejVDjEwZApZUj853dq3sDpmyNO2uWJaTRufSeBX1UISwofgBwDobZ8RBSVTfzMP8HPJ\u002BKBJxt\u002BNXueXpxcXXQwva9n5tqWKyFEahW4lOQFLrr3/Gvh9mRY1EExZapEiO/b5qHc9CtwgqDQN8U7fwtH2il8uPBs3Hsdg=="}-->
        <div>
            <p>Hello World and welcome to my app!</p>
        </div>
        <!--Blazor:{"prerenderId":"de4cefeb845c4241810b39a9fa6fb09d"}-->
    
        <script src="_framework/blazor.server.js"></script>
    </body>
    </html>
    

    【讨论】:

      猜你喜欢
      • 2021-08-28
      • 2018-07-17
      • 2021-12-20
      • 1970-01-01
      • 2020-03-14
      • 2019-07-31
      • 2020-09-12
      • 2020-10-30
      • 2021-06-20
      相关资源
      最近更新 更多