Home > Mobile >  Blazor Webassembly EditForm works on IISExpress but has Problem on IIS
Blazor Webassembly EditForm works on IISExpress but has Problem on IIS

Time:09-15

I have a Blazor Webassembly Project that works fine on iisexpress (visual studio 2019). But when I deploy it on IIS, I can't see the login page due to this errors:

crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] Unhandled exception rendering component: The provided expression contains a PropertyExpression which is not supported. FieldIdentifier only supports simple member accessors (fields, properties) of an object. System.ArgumentException: The provided expression contains a PropertyExpression which is not supported. FieldIdentifier only supports simple member accessors (fields, properties) of an object. at Microsoft.AspNetCore.Components.Forms.FieldIdentifier.ParseAccessor[String](Expression1 , Object& , String& ) at Microsoft.AspNetCore.Components.Forms.FieldIdentifier.Create[String](Expression1 ) at Microsoft.AspNetCore.Components.Forms.InputBase1[[System.String, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].SetParametersAsync(ParameterView ) at Microsoft.AspNetCore.Components.Rendering.ComponentState.SetDirectParameters(ParameterView ) at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewComponentFrame(DiffContext& , Int32 ) at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewSubtree(DiffContext& , Int32 ) at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InsertNewFrame(DiffContext& , Int32 ) at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InsertNewFrame(DiffContext& , Int32 ) at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(DiffContext& , Int32 , Int32 , Int32 , Int32 ) at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.ComputeDiff(Renderer , RenderBatchBuilder , Int32 , ArrayRange1 , ArrayRange`1 ) at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder , RenderFragment ) at Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderInExistingBatch(RenderQueueEntry ) at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()

crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] Unhandled exception rendering component: No element is currently associated with component 13 Error: No element is currently associated with component 13 at e.updateComponent (https://localhost/_framework/blazor.webassembly.js:1:31703) at t.renderBatch (https://localhost/_framework/blazor.webassembly.js:1:12134) at window.Blazor._internal.renderBatch (https://localhost/_framework/blazor.webassembly.js:1:61913) at Object.w [as invokeJSFromDotNet] (https://localhost/_framework/blazor.webassembly.js:1:64435) at _mono_wasm_invoke_js_blazor (https://localhost/_framework/dotnet.5.0.12.js:1:190800) at wasm_invoke_iiiiii (wasm://wasm/00aba242:wasm-function[5611]:0xdda7f) at ves_pinvoke_method (wasm://wasm/00aba242:wasm-function[5708]:0xdfb62) at interp_exec_method (wasm://wasm/00aba242:wasm-function[2155]:0x44c08) at interp_runtime_invoke (wasm://wasm/00aba242:wasm-function[7862]:0x12efff) at mono_jit_runtime_invoke (wasm://wasm/00aba242:wasm-function[7347]:0x118e5f)

. when I replace the EditForm with pure HTML inputs, everything is OK! here is my EditForm:

  <EditForm Model="request" OnValidSubmit="OnValid" style="max-width:500px;">
                <DataAnnotationsValidator />
                <ValidationSummary />
                <div >
                    <InputText  @bind-Value="request.Username" placeholder="نام کاربری"></InputText>

                    <div >
                        <span ></span>
                    </div>
                </div>
                <div >
                    <InputText type="password"  @bind-Value="request.Password" placeholder="رمز عبور"></InputText>

                    <div >
                        <span ></span>
                    </div>
                </div>
                <div >

                    <!-- /.col -->
                    <div >
                        <button  disabled="@isDisabled">ورود</button>
                    </div>
                    <div >
                        <img src="dist/img/allin-logo.png" width="140" height="100" />
                    </div>
                    <!-- /.col -->
                </div>
            
            </EditForm>

and here is the code behind:

[Inject]
    public IAccountService accountService { get; set; }

    [Inject]
    public NavigationManager navigationManager { get; set; }
    public AuthenticationRequest request { get; set; }

    private string message { get; set; }
    private bool isDisabled { get; set; }

    public Login()
    {
        
        request = new AuthenticationRequest();
      
        message = string.Empty;
        isDisabled = false;
      

    }


    private async void OnValid()
    {
        isDisabled = true;

        var result = await accountService.LoginAsync(request);

        if (result)
        {
            navigationManager.NavigateTo("/");
        }
        else
        {
            isDisabled = false;
            message = "نام کاربری یا رمز عبور اشتباه است";
        }


    }

what should I do?!

Update: changing void OnValid() to Task OnValid() didn't solve the problem.

CodePudding user response:

Blazor Webassembly runs completely on the browser. The server version or edition plays no role at all. There's nothing wrong with either IIS or IIS Express.

The bug is using async void instead of async Task. Methods with the async void signature can't be awaited.

To fix it, change async void OnValid to async Task OnValid or even better, async Task OnValidAsync:

    <EditForm Model="request" OnValidSubmit="OnValid" style="max-width:500px;">
    </EditForm>

@code {
    private async Task OnValidAsync()
    {
        isDisabled = true;

        var result = await accountService.LoginAsync(request);
        ...

    }
}

The async void signature is only meant for asynchronous event handlers in desktop applications (WinForms, WPF). These frameworks were created before Task was introduced and don't know how to await asynchronous methods.

Asynchronous methods that return no results should use the async Task signature. Methods that return a value use async Task<T>.

Blazor on the other hand was built with asynchronous operations baked in. All Blazor examples use async Task instead. For example :

@page "/set-params-async/{Param?}"

<p>@message</p>

@code {
    private string message = "Not set";

    [Parameter]
    public string? Param { get; set; }

    public override async Task SetParametersAsync(ParameterView parameters)
    {
        if (parameters.TryGetValue<string>(nameof(Param), out var value))
        {
            if (value is null)
            {
                message = "The value of 'Param' is null.";
            }
            else
            {
                message = $"The value of 'Param' is {value}.";
            }
        }

        await base.SetParametersAsync(parameters);
    }
}

CodePudding user response:

There was a mismatch between sdk versions. project was built with .net 5.0 but .net runtime was .net 6.0.1 . By uninstalling .net 6, everything works fine! Thank you for your helps!

CodePudding user response:

Change this:

<div >
   <button  
                                        disabled="@isDisabled">ورود</button>
</div>

To:

 <div >
      <button type="submit"  
             disabled="@isDisabled">ورود</button>
    </div>

You can't control the value of the isDisabled field from the OnValid method as the "Submit" button is disabled. In other words, clicking on the "Submit" button does not trigger the call back OnValid

Here's how you can do that:

<EditForm EditContext="@EditContext" OnValidSubmit="OnValid" style="max-width:500px;">

</EditForm>

@code
{
       private EditContext EditContext;
       private AuthenticationRequest request = new AuthenticationRequest();
       protected string Disabled { get; set; } = "disabled";

      protected override void OnInitialized()
      {
            EditContext = new EditContext(request);
            EditContext.OnFieldChanged  = EditContext_OnFieldChanged;

      }

     // Note: The OnFieldChanged event is raised for each field in the model
        private void EditContext_OnFieldChanged(object sender, 
                                                FieldChangedEventArgs e)
        {
            SetSaveDisabledStatus(e);

        }

      private void SetSaveDisabledStatus(FieldChangedEventArgs e)
        {
            // Each time a field changes this code is executed. 
            // EditContext.Validate() returns true if
            // validation succeeded; that is, both fields pass validation, in 
            // which case we assign the value null
            // to the property Disabled, and thus enabling the Submit button.
            if (EditContext.Validate())
            {
                Disabled = null;
            }
            else
            {
                Disabled = "disabled";
            }
        }
       
       private async TaskOnValid()
      {
        
        var result = await accountService.LoginAsync(request);

        if (result)
        {
            navigationManager.NavigateTo("/");
        }
        else
        {
           Disabled = "disabled";
            message = "نام کاربری یا رمز عبور اشتباه است";
        }


    }

}

Pay attention to Disabled (instead of the boolean isDisabled you're using)

  • Related