使用ViewComponents将服务器端html异步加载到页面(服务器端)

时间:2016-11-05 03:16:49

标签: c# asynchronous async-await asp.net-core-mvc asp.net-core-viewcomponent

我正在尝试使用基本的ASP.NET核心MVC和随附的ViewComponents来尝试一些我不确定的东西。

我很陌生等待,但仍然没有完全掌握这个概念。另外,我也是ASP.NET Core和新的ViewComponents功能的新手。因此,请耐心试图解释我想要实现的目标。

这里的主要目标是将外部端点的HTML异步注入ASP.NET Core MVC站点。

假设我有以下端点可以提供HTML的简单摘要:

http://fragments.mydomain.com/component1 --> Returns <div>Component 1</div> in 1000ms
http://fragments.mydomain.com/component2 --> Returns <div>Component 2</div> in 500ms

请注意,第一个需要 1000毫秒来响应,第二个需要 500毫秒才能响应。

现在,我想在ASP.NET Core MVC的各个部分中注入这些端点的响应。以下是我试图实现这一目标的方法。

首先,我创建了一个从端点吸入HTML的ViewComponents,例如:

public class PieceViewComponent : ViewComponent
{
    public async Task<IHtmlContent> InvokeAsync(string pieceUrl)
    {
        var contentString = "";
        try
        {
            using (var client = new HttpClient())
            {
                // Make the call to the html end point
                contentString = await client.GetStringAsync(url);

                // Return the Piece to the caller
                return new HtmlString(contentString);
            }

        }
        catch (Exception)
        {
            // TODO: Handle, log exceptions
            return new HtmlString("");
        }
    }
}

然后,我在视图中调用视图组件,例如 Views / Home / Index.cshtml

<p>Render Component 1 here:<p>
@await Component.InvokeAsync("Piece", new {pieceUrl="http://fragments.mydomain.com/component1"});

<p>Render Component 2 here:<p>
@await Component.InvokeAsync("Piece", new {pieceUrl="http://fragments.mydomain.com/component2"});

正如您所期望的,运行上述内容的结果是:

<p>Render Component 1 here:<p>
<div>Component 1</div>

<p>Render Component 2 here:<p>
<div>Component 2</div>

...但是,结果是以同步方式构建的,返回结果需要1500ms,1000ms + 500ms(endpoint1 + endpoint2)。我想让它在1000毫秒内返回(最慢端点的时间,在这种情况下为endpoint1

所以我在 Views / Home / Index.cshtml 中尝试了以下更改:

@{
    var piece1Task = Component.InvokeAsync("Piece", new {pieceUrl="http://fragments.mydomain.com/component1"});
    var piece2Task = Component.InvokeAsync("Piece", new {pieceUrl="http://fragments.mydomain.com/component2"});
}

<p>Render Component 1 here:<p>
@await piece1Task

<p>Render Component 2 here:<p>
@await piece1Task

GREAT!结果以1000毫秒返回,这是我希望它返回的理想时间。

....但是,这仅适用于对ComponentInvokeAsync()的所有调用都在同一个View文件中。当您尝试在应用程序中的各种视图周围进行调用时,您最终会再次获得同步结果。例如:

查看/主页/ Index.cshtml:

@{
    var piece1Task = Component.InvokeAsync("Piece", new {pieceUrl="http://fragments.mydomain.com/component1"});
}
<p>Render Component 1 here:<p>
@await piece1Task

查看/共享/ _Layout.cshtml:

@{
    var piece2Task = Component.InvokeAsync("Piece", new {pieceUrl="http://fragments.mydomain.com/component2"});
}

<html>
    ....

    <p>Render Component 2 here:<p>
    @await piece1Task

    @RenderBody()

    ....
</html>

同样,正如您所期望的那样,结果将如下所示:

<html>
    ...

    <p>Render Component 2 here:<p>
    <div>Component 2</div>

    <p>Render Component 1 here:<p>
    <div>Component 1</div>

    ...
</html>

不幸的是,上述回报时间为1500毫秒。

我可能会以完全错误的方式解决这个问题,但是使用ViewComponents非常方便地将外部HTML部分同步到您的网站应用程序中(就像我上面所说的那样)(特别是在今天的面向服务的世界中)。基本上,响应时间应该是(或大约)最慢外部终点的时间。

如果我可以按照需要使上述工作正常工作,我们可以将其进一步扩展到TagHelpers并具有以下内容:

<piece url="http://fragment.mydomain.com/component1" paramters="..." client-async="true" />

......不会那么好。

例如,当client-async = true时,在客户端而不是服务器上异步加载该段html。

有没有人试图使用ASP.NET MVC Core + ViewComponents做这个或类似的东西,或者我是否想要过于雄心勃勃。

也许其他人已经实现了这一点?

提前致谢,我对这篇长篇文章感到非常抱歉,但我找不到更短的解释方式

0 个答案:

没有答案