Blazor Server - 'Code Behind' pattern: OnInitializedAsync(): no suitable method found to override
Asked Answered
B

12

24

I have a Blazor (Server) application which runs perfectly fine, and which adheres to all rules set by Microsoft.CodeAnalysis.FxCopAnalyzers and StyleCop.Analyzers.

A heavily cut-down razor page is as follows:

@inherits OwningComponentBase<MyService>
@inject IModalService ModalService
@inject IJSRuntime JSRuntime

// UI code

@code
{
    private readonly CancellationTokenSource TokenSource = new CancellationTokenSource();
    ElementReference myElementReferenceName;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await this.myElementReferenceName.FocusAsync(this.JSRuntime);
    }

    protected override async Task OnInitializedAsync()
    {
        ....
    }

    public void Dispose()
    {
        this.TokenSource.Cancel();
    }

    protected void ShowModalEdit(object someObject)
    {
        .....
        Modal.Show<MyPage>("Edit", parameters);
    }
}

Note#1: I used @inherits OwningComponentBase<MyService> based on Daniel Roth's suggestion

Note#2: I am using the Chris Sainty's Modal component component

However, when I try to move all the code from the @code {...} section to a"Code Behind" partial class ("MyPage.razor.cs"), then I run into the following errors....

'MyPage' does not contain a definition for 'Service' and no accessible extension method 'Service' accepting .....

'MyPage.OnAfterRenderAsync(bool)': no suitable method found to override

'MyPage.OnInitializedAsync()': no suitable method found to override

The type 'MyPage' cannot be used as type parameter 'T' in the generic type or method 'IModalService.Show(string, ModalParameters, ModalOptions)'. There is no implicit reference conversion from 'MyPage' to 'Microsoft.AspNetCore.Components.ComponentBase'.

Suggestions?

Byer answered 26/11, 2019 at 12:43 Comment(5)
Show (the outline of) the CodeBehind class.Trumpery
Partial classes are only available in Core 3.1, what version are you on?Trumpery
I'm using Core 3.1 latest previewByer
inherit from ComponentBase is enough in code behindMoony
this is just crazy. It builds on my PC. It won't build on my mac. .net 6Quizzical
A
16

Your MyPage.razor.cs should inherit from ComponentBase class and your Mypage.razor should inherit from MyPage.razor.cs.

In your "code-behind" class you should use [Inject] attribute for every service you are injecting and make them at least protected properties to be able to use them in your razor components.

Below is an example from one of my testing apps, please note this uses .net-core 3.0, in 3.1 you can use partial classes.

Index.razor

@page "/"
@inherits IndexViewModel

<div class="row">
    <div class="col-md">

        @if (users == null)
        {
            <p><em>Hang on while we are getting data...</em></p>
        }
        else
        {
            <table class="table">
                <thead>
                    <tr>
                        <th class="text-danger">Id</th>
                        <th class="text-danger">Username</th>
                        <th class="text-danger">Email</th>
                        <th class="text-danger">FirstName</th>
                        <th class="text-danger">LastName</th>
                    </tr>
                </thead>
                <tbody>
                    @foreach (var user in users)
                    {
                        <tr>
                            <td>@user.Id</td>
                            <td>@user.Username</td>
                            <td>@user.Email</td>
                            <td>@user.FirstName</td>
                            <td>@user.LastName</td>
                        </tr>
                    }
                </tbody>
            </table>
        }
    </div>
</div>

IndexViewModel.cs

public class IndexViewModel : ComponentBase, IDisposable
{
    #region Private Members
    private readonly CancellationTokenSource cts = new CancellationTokenSource();
    private bool disposedValue = false; // To detect redundant calls

    [Inject]
    private IToastService ToastService { get; set; }
    #endregion

    #region Protected Members
    protected List<User> users;

    [Inject] IUsersService UsersService { get; set; }

    protected string ErrorMessage { get; set; }

    #endregion

    #region Constructor

    public IndexViewModel()
    {
        users = new List<User>();
    }

    #endregion

    #region Public Methods


    #endregion

    #region Private Methods

    protected override async Task OnInitializedAsync()
    {
        await GetUsers().ConfigureAwait(false);
    }

    private async Task GetUsers()
    {
        try
        {
            await foreach (var user in UsersService.GetAllUsers(cts.Token))
            {
                users.Add(user);
                StateHasChanged();
            }
        }
        catch (OperationCanceledException)
        {
            ShowErrorMessage($"{ nameof(GetUsers) } was canceled at user's request.", "Canceled");
        }

        catch (Exception ex)
        {
            // TODO: Log the exception and filter the exception messages which are displayed to users.
            ShowErrorMessage(ex.Message);
        }
    }

    private void ShowErrorMessage(string message, string heading ="")
    {
        //ErrorMessage = message;
        //StateHasChanged();
        ToastService.ShowError(message, heading);
    }

    private void ShowSuccessMessage(string message, string heading = "")
    {
        ToastService.ShowSuccess(message, heading);
    }

    protected void Cancel()
    {
        cts.Cancel();
    }
    #endregion

    #region IDisposable Support

    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                cts.Dispose();
            }

            disposedValue = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        // TODO: uncomment the following line if the finalizer is overridden above.
        // GC.SuppressFinalize(this);
    }
    #endregion
}
Apomixis answered 26/11, 2019 at 13:14 Comment(6)
Also, not sure about using .ConfigureAwait(false) on the UI thread in the method OnInitializedAsync()Byer
As an aside: ...why is it these guys neglect something so important as the inheritance chain?Maudiemaudlin
The reason mine was saying it couldn't find the methods, no method to override, etc. is because I had not corrected the namespace to be the same as the .razor view.Maudiemaudlin
@Maudiemaudlin how are you suppose to know what namespace your razor view is, when you look at it there is no mention of any namespace?Cerda
@Paul: by default use the directory structureMaudiemaudlin
This worked for me except for I did not need to add any inheritance to the .razor page. I only needed to have the razor.cs file inherit from CompnentBase . This may be because I am using .NET 5 instead of the .NET core 3.x as in the question.Sherylsheryle
H
18

TLDR

Make sure the namespace in your razor.cs file is correct

Longer explanation

In my case, I got this error when I put the class in the wrong namespace. The page.razor.cs file was in the same directory as the page.razor file and it contained a partial class as accepted by the October 2019 update.

However, even though the files were located in path/to/dir, page.razor.cs had a namespace of path.to.another.dir, which led to this error being thrown. Simply changing the namespace to path.to.dir fixed this error for me!

Hortensiahorter answered 19/5, 2021 at 7:9 Comment(5)
This was the case for me. I use project names such as OfficeReports.Api and then name spaces like OfficeReports.Api.Pages. Turns out this naming approach is incompatible with the way VS uses the Project Name + the folder structure to automatically create name spaces for the Razor pages. If I use OfficeReportsApi as my project name, resulting in OfficeReportsApi.Pages, the name spaces automatically resolve as expected and having the C# class inherit from ComponentBase is unnecessary.Sherylsheryle
This has had me tearing what little hair I have left out. I created a page.razor and page.razor.cs file in a folder folder1. That got checked into source control, and all worked. Then the folder got renamed to Folder1, the name spaces adjusted accordingly automatically. However the rename didn't take in source control for some now unknown reason, so it remained folder1. It worked on my PC, but not on my colleagues as he had folder1 but the namespace was Folder1.Warthman
Believe it or not, this was the solution for me. I moved few Razor components from one folder to another and it did not update the namespace automatically. I had to make the changes manually and the error went away. Thanks.Carboniferous
Wow, thanks for this. My components were all moved into a folder under the Pages folder and the namespace didn't change to match the new location. It caused my code-behind to not be found by razor.Kiernan
I renamed the folder, and it didn't update the namespace. This worksRotarian
A
16

Your MyPage.razor.cs should inherit from ComponentBase class and your Mypage.razor should inherit from MyPage.razor.cs.

In your "code-behind" class you should use [Inject] attribute for every service you are injecting and make them at least protected properties to be able to use them in your razor components.

Below is an example from one of my testing apps, please note this uses .net-core 3.0, in 3.1 you can use partial classes.

Index.razor

@page "/"
@inherits IndexViewModel

<div class="row">
    <div class="col-md">

        @if (users == null)
        {
            <p><em>Hang on while we are getting data...</em></p>
        }
        else
        {
            <table class="table">
                <thead>
                    <tr>
                        <th class="text-danger">Id</th>
                        <th class="text-danger">Username</th>
                        <th class="text-danger">Email</th>
                        <th class="text-danger">FirstName</th>
                        <th class="text-danger">LastName</th>
                    </tr>
                </thead>
                <tbody>
                    @foreach (var user in users)
                    {
                        <tr>
                            <td>@user.Id</td>
                            <td>@user.Username</td>
                            <td>@user.Email</td>
                            <td>@user.FirstName</td>
                            <td>@user.LastName</td>
                        </tr>
                    }
                </tbody>
            </table>
        }
    </div>
</div>

IndexViewModel.cs

public class IndexViewModel : ComponentBase, IDisposable
{
    #region Private Members
    private readonly CancellationTokenSource cts = new CancellationTokenSource();
    private bool disposedValue = false; // To detect redundant calls

    [Inject]
    private IToastService ToastService { get; set; }
    #endregion

    #region Protected Members
    protected List<User> users;

    [Inject] IUsersService UsersService { get; set; }

    protected string ErrorMessage { get; set; }

    #endregion

    #region Constructor

    public IndexViewModel()
    {
        users = new List<User>();
    }

    #endregion

    #region Public Methods


    #endregion

    #region Private Methods

    protected override async Task OnInitializedAsync()
    {
        await GetUsers().ConfigureAwait(false);
    }

    private async Task GetUsers()
    {
        try
        {
            await foreach (var user in UsersService.GetAllUsers(cts.Token))
            {
                users.Add(user);
                StateHasChanged();
            }
        }
        catch (OperationCanceledException)
        {
            ShowErrorMessage($"{ nameof(GetUsers) } was canceled at user's request.", "Canceled");
        }

        catch (Exception ex)
        {
            // TODO: Log the exception and filter the exception messages which are displayed to users.
            ShowErrorMessage(ex.Message);
        }
    }

    private void ShowErrorMessage(string message, string heading ="")
    {
        //ErrorMessage = message;
        //StateHasChanged();
        ToastService.ShowError(message, heading);
    }

    private void ShowSuccessMessage(string message, string heading = "")
    {
        ToastService.ShowSuccess(message, heading);
    }

    protected void Cancel()
    {
        cts.Cancel();
    }
    #endregion

    #region IDisposable Support

    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                cts.Dispose();
            }

            disposedValue = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        // TODO: uncomment the following line if the finalizer is overridden above.
        // GC.SuppressFinalize(this);
    }
    #endregion
}
Apomixis answered 26/11, 2019 at 13:14 Comment(6)
Also, not sure about using .ConfigureAwait(false) on the UI thread in the method OnInitializedAsync()Byer
As an aside: ...why is it these guys neglect something so important as the inheritance chain?Maudiemaudlin
The reason mine was saying it couldn't find the methods, no method to override, etc. is because I had not corrected the namespace to be the same as the .razor view.Maudiemaudlin
@Maudiemaudlin how are you suppose to know what namespace your razor view is, when you look at it there is no mention of any namespace?Cerda
@Paul: by default use the directory structureMaudiemaudlin
This worked for me except for I did not need to add any inheritance to the .razor page. I only needed to have the razor.cs file inherit from CompnentBase . This may be because I am using .NET 5 instead of the .NET core 3.x as in the question.Sherylsheryle
A
7

I came across this error when I used partial class approach, and I was trying to scaffold Identity. I changed to base class approach it was resolved.

Partial class I was using after adding a component say MyComponent, I added a class to MyComponent.razor.cs for injecting services:

public BuildingServices Services { get; set; }

For base class approach after adding MyComponent, I added a class to MyComponent.razor.cs change the class name and make it inherit from componentBase:

MyComponentBase : ComponentBase

And I placed this at the top of MyComponent.razor:

@inherits MyComponentBase

Use protected keyword to make your methods accessible.

Anglo answered 29/8, 2020 at 11:41 Comment(2)
This would be a great comment for the accepted answer that actually explains how to do this.Maudiemaudlin
Explicitly specifying the inheritance in the code behind file (view.razor.cs) from ComponentBase fixed it. I would like to point out that the problem was only an Intellisense issue as the program compiled and worked correctly. This behavior is different than WPF and the rest of c# for a partial class where it is optional to restate the inheritance. In fact ReSharper gives a warning when adding ": ComponentBase " as "already specified in other parts"Zeta
B
1

All the above points are very true. FWIW, and just to add a weird thing that I was finding with this issue; I could not get that error to go away. Everything was declared as it should be. Once you have ruled out all potential coding issues, I have found exiting VS, coming back in, and rebuilding clears it up. It is almost like VS just will not let go of that error.

Brothers answered 1/10, 2021 at 13:5 Comment(0)
A
0

It took two days of cleaning, rebuilding, ... and it turned out to be a cut and paste error. I copied the razor file from another, similar class, and left this at the top by mistake:

@inject Microsoft.Extensions.Localization.IStringLocalizer<Person> localizer

'Person' was the wrong class, it wasn't defined by any of the include statements. For some strange reason the only error was "OnInitialized() No method found to override."

Althaalthea answered 16/11, 2021 at 22:44 Comment(0)
M
0

I found this when upgrading to 6.0. I had to switch from using base classes to using partial classes!

Moorefield answered 10/1, 2022 at 19:3 Comment(0)
O
0

What did the trick for me was dragging the .razor file into Shared folder and dragging it back to the original folder. As per spmoran-blazor's answer on GitHub

Overscrupulous answered 2/5, 2023 at 21:54 Comment(0)
T
0

It's the type of error that can have multiple cause. In my case it was so weird that I thought what I had changed recently and it was an install of more recent .Net 7 SDK. I desinstalled it leaving the original .NET installed with VS 2022 and everything now compiles instead of 69 error of this kind.

Trueblue answered 27/5, 2023 at 14:2 Comment(0)
K
0

MyComponent.razor file:

<h1>@Message</h1>

MyComponent.razor.cs file:

using Microsoft.AspNetCore.Components;

namespace MyProject.Client.Shared;

public class MyComponent : ComponentBase
{
    string Message = "Hello";
}

somtime visual studio steel show error in Error List window. for making sure you have error or not build the blazor project.

Kirsti answered 8/6, 2023 at 15:22 Comment(0)
T
0

I have Blazor .net 7 VS 2022. I got same issues, I Created new folder and copied all files one by one into new folder(Here namespace is updated) and issues resolved. Thank you, Eugine.

Trier answered 8/9, 2023 at 21:56 Comment(0)
L
0

I had the same issue when using MAUI Blazor Hybrid project.Partial class approach was working in one component and was not working on the one I recently added. I could not find any issues with code, therefore, I finally restarted Visual Studio Professional 2022 (17.9.4). Once Visual Studio reopened, error went away.

Losing answered 8/4, 2024 at 21:13 Comment(0)
W
0

My error came up slightly different, but because this thread on Stack overflow is the #1 listing in the search engines on it, I'm posting my error to help the next fellow...

My error message that only came up on azure, not in visual studio was,

OnInitializedAsync error ExpectedStartOfValueNotFound, \u003C Path: $ | LineNumber: 0 | BytePositionInLine: 0."

What I discovered that I had done was pretty silly. When I initially setup the OnInitialized method, I used the non-async version. The moment I put in a line into the method to perform an awaited command, visual studio plugged in the async into the method signature line.

I hadn't put in the proper method OnInitialized'Async' method as part of the call and of course, the compiler doesn't throw and error because the method was still returning void, which is legal. But Azure did not like it and throws the error message into the logs as mentioned above. Why Visual Studio doesn't catch this, I'm unsure why.

So watch out when setting up your lifecycle calls for a blazor page. The minute you perform an awaited call, you need to ensure you call the proper lifecycle method, or you will waste hours like I've just done to find a really silly error.

//old code
protected override async void OnInitialized()

//proper code
protected override async Task OnInitializedAsync()
Warhead answered 15/4, 2024 at 15:56 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.