I love the web and HTML. It’s certainly come a long way since its inception and what it provides as a core experience for web developers. While folks can certainly build HTML-exclusive experiences, adding forms on a page inevitably leads to introducing a backend tech stack. Recently, I’ve been experimenting with Blazor Server-side Rendering (SSR) and how developers can use its component-driven approach while still building the web experience they know and love.
In this post, we’ll see how to use the plain-old form tag with a Blazor SSR page, handle form posts, and attach
antiforgery tokens.
Why not use EditForm?
Anyone familiar with Blazor would likely immediately think, “Why not use
the EditForm
component?” Well, for my taste, the EditForm component has so many hooks, fields, and requirements that it begins to
feel like a burden compared to the humble HTML form. In my opinion, much of the EditForm functionality is overkill for
an SSR scenario.
You’re welcome to use EditForm if you find its features useful.
HTML Form Blazor Basics
Blazor is a component-driven framework, and even top-level pages are considered components. In a way, it’s simpler to think of each component as a tree of other components, and you have to start somewhere. This approach means that a component page must handle all incoming requests and “route” those requests to the appropriate handlers.
In a Blazor application, there are two levels of “routing”. The first is what you’d consider traditional HTTP path
routing using the @page directive. The second uses the @formname attribute on a form to inject a handler name into
forms, in which you can use that additional information for application logic.
Let’s add a basic form to a page and submit it to a Blazor component. THIS WILL NOT WORK
As soon as we submit the page, we get the following error.
The POST request does not specify which form is being submitted. To fix this, ensure <form> elements have a @formname attribute with any unique value, or pass a FormName parameter if using <EditForm>.
To fix this, we need to add the @formname SSR attribute and give it a unique name within the page scope.
We still have an issue as you may notice when you submit this form.
A valid antiforgery token was not provided with the request. Add an antiforgery token, or disable antiforgery validation for this endpoint.
Blazor has an AntiforgeryToken component we forgot to add to the form.
Woot! Now it works. If we look at the HTML rendered to the page, you’ll see what Blazor is doing to transform our form into one compatible with the Blazor request pipeline.
The hidden inputs are notable, as they provide values for _handler and our antiforgery token.
Being Extra with @onsubmit
I hinted at this in the previous section, but Blazor is processing the “HTML” in our components to inject and add input
elements that we didn’t specify. We can take advantage of another attribute, @onsubmit, to ensure that all submissions
are handled by the appropriate handler on the page.
You’ll notice a few new elements in the previous code examples.
- Our form now has an
@onsubmitattribute. This allows Blazor to execute the method at the time of a request according to the_handlervalue passed on a submit. - The
SupplyParameterFromFormnow has aFormNameproperty to match our form name. This is optional and only necessary when dealing with multiple forms on a single page. - We have a
Submitmethod with a bit more complex logic for our component.
Cool! We have a functioning form on a Blazor SSR page and haven’t sacrificed security or HTML readability. We also now understand how to add additional forms and handlers as we expand the page’s functionality.
Conclusion
HTML is great, and using it with ASP.NET Core is pretty great as well. Having Blazor SSR support makes it easy to write performant server-rendered pages while still maintaining a component-driven approach that so many folks like. I hope you found this article helpful. Cheers.
Photo by 