Search code examples
asp.net-core.net-coredependency-injectionblazorblazor-webassembly

Blazor component @inject not working while dependency registered in client project program.cs file


I have created a very simple Blazor application, which have BlazorTestApp and BlazorTestApp.Client. I want to inject HttpClient in the BlazortestApp.Client>Pages>Counter.razor.

Following is the simplified version, and I have used HttpClient as an example, but in real scenario, I want to have my own object to be injected.

@page "/counter"
@rendermode InteractiveAuto
@inject HttpClient Http

<h1>HttpClient test</h1>

<button class="btn btn-primary" @onclick="GetData">Get Data</button>

@code {

    private async Task GetData()
    {
        var url = "https://jsonplaceholder.typicode.com/users/1";
        using HttpResponseMessage response = await Http.GetAsync(url);
        var json = await response.Content.ReadAsStringAsync();
        Console.WriteLine(json);
    }

}

I registered the the dependency in the BlazorTestApp.Client>Program.cs

using Microsoft.AspNetCore.Components.WebAssembly.Hosting;

var builder = WebAssemblyHostBuilder.CreateDefault(args);
//Registering the HttpClient Dependency
builder.Services.AddScoped(sp => new HttpClient());

await builder.Build().RunAsync();

When I navigate to that page, I am getting following exception.

System.InvalidOperationException: Cannot provide a value for property 'Http' on type 'BlozorTestApp.Client.Pages.Counter'. There is no registered service of type 'System.Net.Http.HttpClient'.
   at Microsoft.AspNetCore.Components.ComponentFactory.<>c__DisplayClass9_0.<CreatePropertyInjector>g__Initialize|1(IServiceProvider serviceProvider, IComponent component)
   at Microsoft.AspNetCore.Components.ComponentFactory.InstantiateComponent(IServiceProvider serviceProvider, Type componentType, IComponentRenderMode callerSpecifiedRenderMode, Nullable`1 parentComponentId)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.InstantiateChildComponentOnFrame(RenderTreeFrame[] frames, Int32 frameIndex, Int32 parentComponentId)
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewComponentFrame(DiffContext& diffContext, Int32 frameIndex)
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewSubtree(DiffContext& diffContext, Int32 frameIndex)
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InsertNewFrame(DiffContext& diffContext, Int32 newFrameIndex)
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(DiffContext& diffContext, Int32 oldStartIndex, Int32 oldEndIndexExcl, Int32 newStartIndex, Int32 newEndIndexExcl)
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.ComputeDiff(Renderer renderer, RenderBatchBuilder batchBuilder, Int32 componentId, ArrayRange`1 oldTree, ArrayRange`1 newTree)
   at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment, Exception& renderFragmentException)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.AddToRenderQueue(Int32 componentId, RenderFragment renderFragment)
   at Microsoft.AspNetCore.Components.ComponentBase.StateHasChanged()
   at Microsoft.AspNetCore.Components.ComponentBase.CallOnParametersSetAsync()
   at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
   at Microsoft.AspNetCore.Components.Rendering.ComponentState.SetDirectParameters(ParameterView parameters)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderRootComponentAsync(Int32 componentId, ParameterView initialParameters)
   at Microsoft.AspNetCore.Components.HtmlRendering.Infrastructure.StaticHtmlRenderer.BeginRenderingComponent(IComponent component, ParameterView initialParameters)
   at Microsoft.AspNetCore.Components.Endpoints.EndpointHtmlRenderer.RenderEndpointComponent(HttpContext httpContext, Type rootComponentType, ParameterView parameters, Boolean waitForQuiescence)
   at Microsoft.AspNetCore.Components.Endpoints.RazorComponentEndpointInvoker.RenderComponentCore(HttpContext context)
   at Microsoft.AspNetCore.Components.Endpoints.RazorComponentEndpointInvoker.RenderComponentCore(HttpContext context)
   at Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext.<>c.<<InvokeAsync>b__10_0>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

If I do the dependency registration in BlazorTestApp>Program.cs then it works.

My question is, as this is a client-side (InteractiveAuto or InteractiveWebAssembly) component, can we not have this dependency registration only in BlazorTestApp.Client>program.cs


Solution

  • I encountered similar issue. In my case the method was executing twice, the first time from the server project then from the client project.

    Change this

    @rendermode InteractiveAuto
    

    to this:

    @rendermode @(new InteractiveAutoRenderMode(prerender: false))