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

10,072

Solution 1

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
}

Solution 2

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!

Solution 3

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

partial class I was using after adding a component say MyComponent, add a class MyComponent.razor.cs for injecting services use

[Inject] public BuildingServices Services { get; set; }

for base class approach

after adding a component say MyComponent, add a class MyComponent.razor.cs change the class name and make it inherit from componentBase MyComponentBase : ComponentBase

and place this at the top of MyComponent.razor

@inherits MyComponentBase

Use protected keyword to make your methods accessible

Share:
10,072
DrGriff
Author by

DrGriff

Updated on July 15, 2022

Comments

  • DrGriff
    DrGriff almost 2 years

    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?

  • DrGriff
    DrGriff over 4 years
    Also, not sure about using .ConfigureAwait(false) on the UI thread in the method OnInitializedAsync()
  • IAbstract
    IAbstract over 3 years
    As an aside: ...why is it these guys neglect something so important as the inheritance chain?
  • IAbstract
    IAbstract over 3 years
    This would be a great comment for the accepted answer that actually explains how to do this.
  • IAbstract
    IAbstract over 3 years
    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.
  • Paul
    Paul over 3 years
    @IAbstract how are you suppose to know what namespace your razor view is, when you look at it there is no mention of any namespace?
  • IAbstract
    IAbstract over 3 years
    @Paul: by default use the directory structure
  • user1221237
    user1221237 about 3 years
    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"
  • Tyson Gibby
    Tyson Gibby over 2 years
    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.
  • Tyson Gibby
    Tyson Gibby over 2 years
    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.