HotwiredDotNet.Ui 1.0.2

dotnet add package HotwiredDotNet.Ui --version 1.0.2                
NuGet\Install-Package HotwiredDotNet.Ui -Version 1.0.2                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="HotwiredDotNet.Ui" Version="1.0.2" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add HotwiredDotNet.Ui --version 1.0.2                
#r "nuget: HotwiredDotNet.Ui, 1.0.2"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install HotwiredDotNet.Ui as a Cake Addin
#addin nuget:?package=HotwiredDotNet.Ui&version=1.0.2

// Install HotwiredDotNet.Ui as a Cake Tool
#tool nuget:?package=HotwiredDotNet.Ui&version=1.0.2                

Hotwired .Net

Installation

Find the NuGet packages here:

HotwiredDotNet.Core

HotwiredDotNet.Ui

Once installed add the following to your program.cs file:

builder.RegisterHotwiredDotNetCore(); 

If you want intellisense for the TurboStream ViewComponent, add the following to your _ViewImports.cshtml file:

@addTagHelper *, HotwiredDotNet.Ui

Usage

TurboFrames

Turbo frames can be rendered using a tag-helper to generate the url like with the .net anchorTagHelper and formTagHelper.

<turbo-frame id="frame" asp-page="TurboFrame" asp-page-handler="OnGet" >
        
</turbo-frame>

This will result in:

<turbo-frame id="frame" src="https://localhost:44362/TurboFrame?handler=OnGet" complete="">

</turbo-frame>

It also works for mvc routes eg. asp-controller and asp-action

TurboStream

Views

In a view you can use your view-component with either tag-helper syntax,

<vc:turbo-stream action="Update" target="stream-target" template="Html"></vc:turbo-stream>

or Component.Invoke

@await Component.InvokeAsync(TurboStream.Name, new
{
    target = "stream-target",
    action = TurboStreamAction.Append,
    template = "Html content"
})
Controller

Sometimes it can be useful to get the Turbo-stream view component as a string, for example when you want to chain multiple Turbo-streams in one request

public async Task<IActionResult> OnGet()
{
    //the HttpContext.SetTurboStreamMimeType(), is an extension method that sets the content-type header to text/vnd.turbo-stream.html, which allows turbo to pick up stream responses from normal http requests.
    HttpContext.SetTurboStreamMimeType();
    
    var resultString = await TurboStream.AsStringAsync(_razorViewComponentStringRenderer, "first-target", TurboStreamAction.Append, "Html");
    resultString += await TurboStream.AsStringAsync(_razorViewComponentStringRenderer, "second-target", TurboStreamAction.Append, "Html");
    return new ContentResult(resultString);
}

Rendering ViewComponent inside a stream response

The RazorViewComponentStringRenderer can be used to make a view component render as a string.

public async Task<IActionResult> OnGetRenderComponent()
{
    HttpContext.SetTurboStreamMimeType();
        
    var template = await _razorViewComponentStringRenderer.RenderAsync(AlertViewComponent.Name, new
    {
        alertType = AlertType.Success,
        text = "I'm a view component rendered from a turbo stream"
    });
    return ViewComponent(TurboStream.Name,new { target = "http-stream", action = TurboStreamAction.Append, template = template });
}

Alternatively there is another helper method on TurboStream that can be used to render a view component inside a stream response

public async Task<IActionResult> OnGetRenderComponent()
{
   HttpContext.SetTurboStreamMimeType();

   return ContentResult(await TurboStream.AsStringAsync(_razorViewComponentStringRenderer, "target", TurboStreamAction.Append,
            AlertViewComponent.Name, new
            {
                alertType = AlertType.Success,
                text = "I'm a view component rendered from a turbo stream"
            });
}

Post / Redirect / Get

Turbo expects the server to return 303 on form submission. To better allow for this, a new ActionResult has been introduces called SeeOther. While a standard 302 redirect will sometimes work it's important to note the differences between 302 and 303. 302 will redirect but if you use put, delete or patch the same method will be used for the redirect while 303 will always use GET after a redirect:.

fetchoriginal method fetchoriginal response redirect method
GET 302 GET
GET 303 GET
POST 302 GET
POST 303 GET
PUT 302 PUT
PUT 303 GET
PATCH 302 PATCH
PATCH 303 GET
DELETE 302 DELETE
DELETE 303 GET
    public IActionResult OnPost()
    {
        //You can pass data between pages using the TempData dictionary as normal
        AlertHelper.SetAlert(TempData, "I'm an alert from before the redirect");
        AlertHelper.SetAlertType(TempData, AlertType.Warning);
        
        //The see other result allows ud to use the Post/Redirect/Get pattern https://en.wikipedia.org/wiki/Post/Redirect/Get
        //This is necessary since turbo expects form redirects to be 303 and not 301 or 302
        return new SeeOtherResult("SeeOtherPage");
    }

Sometimes it makes sense to return the current page after a form submission, for this there is an extension method on Page and View results.

    public IActionResult OnPost()
    {
        return Page().SeeOther();
    }
    public IActionResult OnPost()
    {
        return View().SeeOther();
    }

Form errors

for form errors you can use a similar extension method on the Page and View results to change the status code to 422, since turbo expects either 422 or 50X on form errors.

    public IActionResult OnPost()
    {
        if (!ModelState.IsValid)
        {
            return Page().UnprocessableEntity();
        }
        return Page().SeeOther();
    }
    public IActionResult OnPost()
    {
        if (!ModelState.IsValid)
        {
            return View().UnprocessableEntity();
        }
        return View().SeeOther();
    }

Other stuff

This is all the stuff that works behind the scenes, that you don't have to actively use.

AnchorTagHelper

A tag-helper that looks whether an anchor tag has the data-turbo-method attribute. If it does, it will add an anti-forgery token so that when turbo generates a form it validate correctly.

Middleware

TurboFrame Middleware

The TurboFrame middleware removes unused html from the response body when the request has the turbo-frame header present, which is default in turbo-frame requests. This is done to reduce the amount of data sent over the wire. It also ensures that any turbo-streams will not be removed from the response.

To add the middleware to your pipeline, add the following to your Startup.cs/Program.cs file:

app.UseTurboFrameMiddleware();

Work in progress

The socket implementation seen in the demo project is a work in progress. I'm still trying to figure out if there is a good way to make some generic implementation.

Product Compatible and additional computed target framework versions.
.NET net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.2 384 9/13/2023
1.0.1 519 4/5/2023