Skip to content
This repository was archived by the owner on Dec 14, 2018. It is now read-only.

Views should be able to trigger a background flush while they continue processing aka Make Razor flush awesome #1544

Closed
DamianEdwards opened this issue Nov 12, 2014 · 2 comments

Comments

@DamianEdwards
Copy link
Member

This is a proposed enhancement to the flush point support in Razor views.

Currently, views can force a flush to the client by calling FlushAsync, e.g.

<!doctype html>
<head>
    <title>Flushy</title>
    <link rel="stylesheet" href="styles.css" />
</head>
@{await FlushAsync();}
<body>
...

This is awesome, but there are two problems:

  1. Calling the method is ugly. Because it's void returning, it has to be invoked inside a code block (@{ }) which isn't particularly discoverable.
  2. Awaiting the flush (which is definitely the right thing to do given it's current implementation) causes the view rendering to pause until the flush completes. Typically, the flush will actually be synchronous and the method will return immediately, as it's simply copying the bytes down to the next buffer in the stack (e.g. the TCP/IP outgoing buffer), and in those cases, this is fine. However, sometimes, it will be async, and when that happens, the view effectively stops processing until the flush has completed.

The proposal is to add a new, string returning Flush method to the view (the returned string would be null/empty and is only to allow the simplified call site). This method would attempt a FlushAsync call inline and if it returned synchronously would do nothing more. If it returned async however, it would return back to the view immediately, while managing the completion of the flush along with coordination with any subsequent calls to Flush by the view. This way, the view continues to process even though an async flush may currently be in progress. The number/size of outstanding flush operations should be limited so that back-pressure can still be honored, in which case the call to Flush would block. At the end of the view processing, it would async wait for all outstanding async flush operations until continuing on with response processing.

As an example, the view might now look like this:

<!doctype html>
<head>
    <title>Flushy</title>
    <link rel="stylesheet" href="styles.css" />
</head>
@Flush()
<body>
    <h1>My Flushy Page</h1>
    <h2>First Set of Items</h2>
    <ul>
        @foreach (var item in await Model.Items1.ToListAsync()) {
            <li>@item</li>
        }
    </ul>
    @Flush()
    @* This second Flush() will get queued behind the first Flush() if the first was async and is still in progress *@
    <h2>Second Set of Items</h2>
    <ul>
        @foreach (var item in await Model.Items2.ToListAsync()) {
            <li>@item</li>
        }
    </ul>
</body>
@danroth27
Copy link
Member

@pranavkm Work with @yishaigalatzer on a prototype for this so we can make a call if this is something we want to do for beta2.

@pranavkm
Copy link
Contributor

We had a discussion about this today. I had a working prototype for this change - ab2f650, but we realized this causes issues with items on HttpContext being used concurrently by the FlushAsync task and the page. This makes the feature quite problematic and we decided it's worth the trouble in changing things to guarantee synchronization to allow this feature to work.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants