dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.37k stars 9.99k forks source link

RenderModeSSR #50206

Closed KennethHoff closed 1 year ago

KennethHoff commented 1 year ago

Is there an existing issue for this?

Is your feature request related to a problem? Please describe the problem.

It's not really a problem as much as a seeming inconsistency. Currently (or rather, there will be in .Net 8) there are 3 ways (4 if you count the possibility to statically render them) to render Blazor Components: SSR, WebAssembly, Server.

However, only 2 of those options have their own RenderMode (WebAssembly and Server respectively). I've been looking to figure out why there's none for SSR as well, so this is an issue mostly just to understand your reasoning and clear up my confusion. Is it because SSR is the default unless you manually add either one of those attributes, so it'd kinda be like specifying = default on a variable? That seems to be the case when I tested it.

Describe the solution you'd like

Add a RenderModeSSR (andRenderModeStatic? IIRC you mentioned adding built-in support for Static rendering in a future version, so I imagine this would come in .Net 9+ (RenderModeStreaming? Nested questions here..)) alongside RenderModeWebAssembly and RenderModeServer.

.. Or simply explain to me why you haven't done it.

Additional context

I have not actually used Blazor despite following it for years, so I don't really understand how it works, but I've been trying it for the last few hours and I couldn't for the life of me understand why my form posted (and validation triggered), but the input data itself was always the default value.

After like an hour or so I figured out it was due to me rendering it using SSR (which is what I want; I was testing SSR using Blazor components). Adding AddServerComponents() in Program.cs and @attribute [RenderModeServer] to the form file "fixed it", but that converts my app into WebSocket-mode, which is not what I want; I just want to create a simple SSR page with a form:

@page "/login"
@using FluentValidation

<EditForm Model="Input" FormName="LoginForm" OnValidSubmit="SubmitFormAsync" OnInvalidSubmit="OnInvalidSubmit">
    <FluentValidationValidator Validator="@Validator"/>
    <ValidationSummary/>
    <InputText type="email" @bind-Value="Input.Email"/>
    <InputText type="password "@bind-Value="Input.Password"/>
    <button type="submit">Login</button>
</EditForm>

@code {
    private InputModel Input { get; set; } = new();

    [Inject]
    private IValidator<InputModel> Validator { get; set; } = null!;
    private void OnInvalidSubmit()
    {
        Console.WriteLine("Invalid");
    }

    private Task SubmitFormAsync()
    {
        Console.WriteLine("valid");

        return Task.CompletedTask;
    }

    internal sealed class InputModel
    {
        public string? Email { get; set; }
        public string? Password { get; set; }
    }

    internal sealed class InputModelValidator : AbstractValidator<InputModel>
    {
        public InputModelValidator()
        {
            RuleFor(x => x.Email).Cascade(CascadeMode.Stop)
                .NotEmpty()
                .WithMessage("Email is required")
                .EmailAddress()
                .WithMessage("Email is not valid");

            RuleFor(x => x.Password).Cascade(CascadeMode.Stop)
                .NotEmpty()
                .WithMessage("Password is required")
                .MinimumLength(6)
                .WithMessage("Password must be at least 6 characters");
        }
    }
}

This issue might seem very incoherent - it is - and most of the content is seemingly not about what the issue title implies, but I just wanted to add some context into why I asked the question.

Also, if there's a bug with inputs not working in SSR, pretend like I didn't come up with that example -- It's entirely tangential to the question at hand, and I assume https://github.com/dotnet/aspnetcore/issues/50078 rectifies it in some way.

As a closing statement(albeit added in like the 15th edit.. lol); If this is all the code I need to write to get all of this functionality, that's really nice compared to the ugly MVC syntax we had to use previously. :rocket:

ddjerqq commented 1 year ago

not related to the issue, but a question related to the FluentValidationValidator, are you using Blazored.FluentValidation?

KennethHoff commented 1 year ago

not related to the issue, but a question related to the FluentValidationValidator, are you using Blazored.FluentValidation?

I am

MackinnonBuck commented 1 year ago

Thanks for reaching out.

The component hierarchy is rendered using SSR until a descendant specifies an interactive render mode. Once a render mode is specified for a subtree, it's not possible for a child component to change it (e.g., a component with a "WebAssembly" render mode can't render a component with a "Server" or "SSR" render mode).

Therefore, there isn't a valid case where specifying an "SSR" render mode is valid. Either SSR is already the render mode, or an interactive render mode is used (in which case switching to SSR is not possible).

Closing as by design.