Search code examples
c#taskreturn-typeblazor

Blazor Task With Wrong Return Type


I am getting the error

Task> __generated__Index.SearchFilms(string)' has the wrong return type

On my code below and I don't know why. The line in question is

 <BlazoredTypeahead SearchMethod="SearchFilms"

Code:

@page "/"

@using Blazored.Typeahead

<BlazoredTypeahead SearchMethod="SearchFilms"
                   @bind-Value="SelectedFilm">
    <SelectedTemplate>
        @context.Title
    </SelectedTemplate>
    <ResultTemplate>
        @context.Title (@context.Year)
    </ResultTemplate>
</BlazoredTypeahead>

@if (SelectedFilm != null)
{
    <p>Selected Film is: @SelectedFilm.Title</p>
}



@code {

    private List<Film> Films;
    private Film SelectedFilm;

    protected override void OnInitialized()
    {
        Films = new List<Film> {
            new Film("The Matrix", 1999),
            new Film("Hackers", 1995),
            new Film("War Games", 1983) };
    }

    private async  Task<List<Film>> SearchFilms(string searchText)
    {
        return await Task.FromResult(Films.Where(x => x.Title.ToLower().Contains(searchText.ToLower())).ToList());
    }

    class Film
    {
        public string Title { get; set; }
        public int Year { get; set; }

        public Film(string title, int year)
        {
            Title = title;
            Year = year;
        }
    }

}

Solution

  • Introduction

    On BlazoredTypeahead the SearchMethod is async because this delegate is intended to call backend for data and we can't block the UI thread waiting for result. Typically:

    private async  Task<IEnumerable<Film>> SearchFilms(string searchText)
    {
        try
        {
           var result = await BackendService.SearchFilms(searchText);
           return result;
        } 
        catch ( ... )
        {
             UiShowError( ... )
             return empty_list;
        }
    }
    

    But in your case, no backend operations are involved and your whole method is sync. Then, compiler will raise warning because they are not any async operation into your method.

    Also, quoting docs:

    You must provide a method which has the following signature Task<IEnumerable<T> MethodName(string searchText), to the SearchMethod parameter.

    Solution

    One easy and readable solution is to make an async call in your method:

    private async  Task<IEnumerable<Film>> SearchFilms(string searchText)
    {
        var result = Films
                     .Where(x => x.Title.ToLower().Contains(searchText.ToLower()))
                     .ToList();
        await Task.CompletedTask;  // avoid warning (*1)
        return result;
    }
    

    But they are other more ways to do it: you can micro-optimized and avoid async and convert result into a task, see aguas's answer.

    (*1) Also you can avoid warning writing #pragma warning disable CS1998 above the method (thanks @Henk Holterman )