【问题标题】:Blazor Server - 'Code Behind' pattern: OnInitializedAsync(): no suitable method found to overrideBlazor 服务器 - “代码隐藏”模式:OnInitializedAsync():找不到合适的方法来覆盖
【发布时间】:2020-03-21 21:21:36
【问题描述】:

我有一个运行良好的 Blazor(服务器)应用程序,它遵守 Microsoft.CodeAnalysis.FxCopAnalyzersStyleCop.Analyzers 设置的所有规则。

一个大幅缩减的剃须刀页面如下:

@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);
    }
}

注意#1:我使用基于Daniel Roth's suggestion@inherits OwningComponentBase&lt;MyService&gt;

注意#2:我正在使用Chris Sainty's Modal component 组件

但是,当我尝试将所有代码从 @code {...} 部分移动到“代码隐藏”部分类(“MyPage.razor.cs”)时,我遇到了以下错误......

“我的页面”不包含“服务”的定义,并且无法访问 扩展方法“服务”接受.....

'MyPage.OnAfterRenderAsync(bool)': 找不到合适的方法来覆盖

'MyPage.OnInitializedAsync()': 找不到合适的方法来覆盖

类型“MyPage”不能用作泛型中的类型参数“T” 类型或方法 'IModalService.Show(string, ModalParameters, 模态选项)'。没有隐式引用转换 'MyPage' 到 'Microsoft.AspNetCore.Components.ComponentBase'。

建议?

【问题讨论】:

  • 显示(大纲)CodeBehind 类。
  • 部分课程是only available in Core 3.1,你用的是什么版本?
  • 我正在使用 Core 3.1 最新预览版
  • 从 ComponentBase 继承在后面的代码中就足够了

标签: code-behind blazor blazor-server-side


【解决方案1】:

您的 MyPage.razor.cs 应该继承自 ComponentBase 类,而您的 Mypage.razor 应该继承自 MyPage.razor.cs

在您的“代码隐藏”类中,您应该为要注入的每个服务使用[Inject] 属性,并使它们至少具有protected 属性,以便能够在您的剃须刀组件中使用它们。

以下是我的一个测试应用程序的示例,请注意这使用 .net-core 3.0,在 3.1 中您可以使用部分类。

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
}

【讨论】:

  • 另外,不确定在方法OnInitializedAsync()的UI线程上使用.ConfigureAwait(false)
  • 顺便说一句:......为什么这些人忽略了继承链这样重要的东西?
  • 我之所以说它找不到方法、没有方法可以覆盖等是因为我没有将命名空间更正为与 .razor相同> 查看。
  • @IAbstract 你怎么知道你的剃刀视图是什么命名空间,当你看它时没有提到任何命名空间?
  • @Paul: 默认使用目录结构
【解决方案2】:

TLDR

确保razor.cs 文件中的命名空间正确

更长的解释

在我的例子中,当我将类放在错误的命名空间中时,我得到了这个错误。 page.razor.cs 文件与page.razor 文件位于同一目录中,它包含一个部分类as accepted by the October 2019 update

但是,即使文件位于 path/to/dir 中,page.razor.cs 的命名空间为 path.to.another.dir,这也会导致引发此错误。只需将命名空间更改为 path.to.dir 即可为我修复此错误!

【讨论】:

  • 这就是我的情况。我使用诸如OfficeReports.Api 之类的项目名称,然后使用诸如OfficeReports.Api.Pages 之类的命名空间。事实证明,这种命名方法与 VS 使用项目名称 + 文件夹结构自动为 Razor 页面创建命名空间的方式不兼容。如果我使用OfficeReportsApi 作为我的项目名称,导致OfficeReportsApi.Pages,则名称空间会按预期自动解析,并且不需要从ComponentBase 继承C# 类。
【解决方案3】:

当我使用部分类方法并尝试构建 Identity 时遇到此错误。我改成基类方法就解决了。

我使用的部分类 添加组件后说 MyComponent,添加一个类 MyComponent.razor.cs 用于注入服务 使用

[注入] 公共建筑服务服务{得到;放; }

基类方法

添加一个组件后说MyComponent,添加一个类MyComponent.razor.cs 更改类名并使其继承自componentBase MyComponentBase : 组件库

并将其放在 MyComponent.razor 的顶部

@inherits MyComponentBase

使用受保护的关键字使您的方法可访问

【讨论】:

  • 这对于实际上解释如何执行此操作的公认答案将是一个很好的评论。
  • 在 ComponentBase 的代码隐藏文件 (view.razor.cs) 中显式指定继承修复了它。我想指出,这个问题只是一个 Intellisense 问题,因为程序编译并正常工作。此行为不同于 WPF 和部分类的其余 c#,在该部分类中,可以选择重述继承。事实上,ReSharper 在将“:ComponentBase”添加为“已在其他部分中指定”时会发出警告
【解决方案4】:

以上几点都非常正确。 FWIW,只是为了添加一个我在这个问题上发现的奇怪的东西;我无法让那个错误消失。一切都被宣布为应有的样子。一旦你排除了所有潜在的编码问题,我发现退出 VS,重新进入并重建可以清除它。这几乎就像 VS 就是不会放过那个错误。

【讨论】:

    【解决方案5】:

    花了两天时间清理、重建……结果是剪切和粘贴错误。我从另一个类似的类中复制了剃刀文件,并错误地将其留在了顶部:

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

    'Person' 是错误的类,它不是由任何包含语句定义的。出于某种奇怪的原因,唯一的错误是“OnInitialized() 没有找到要覆盖的方法。”

    【讨论】:

      【解决方案6】:

      我在升级到 6.0 时发现了这一点。我不得不从使用基类切换到使用部分类!

      【讨论】:

        猜你喜欢
        • 2021-10-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多