编辑:这似乎也可以在打开正确的命名空间后使用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>