c# - Blazor 组件之间注入(inject)的单例服务是不同的 [.NET 6]

标签 c# blazor webassembly .net-6.0

在 Blazor 6.0 WASM Web 客户端上

看来 IOC 容器正在返回我的单例服务 NodeService 的不同实例。我通过在 NodeService 构造函数中生成一个随机数,然后从使用该服务的不同类检查该随机数的值,得出了这个结论。

程序.cs

using BlazorDraggableDemo;
using BlazorDraggableDemo.Factories;
using BlazorDraggableDemo.Services;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");



builder.Services.AddSingleton<MouseService>();
builder.Services.AddSingleton<IMouseService>(ff => ff.GetRequiredService<MouseService>());
builder.Services.AddSingleton<INodeService, NodeService>();
builder.Services.AddSingleton<INodeServiceRequestMessageFactory, NodeServiceRequestMessageFactory>();
builder.Services.AddHttpClient<INodeService, NodeService>(client =>
{
    client.BaseAddress = new Uri("http://localhost:7071");
});



await builder.Build().RunAsync();

Playground .razor

@inject MouseService mouseSrv;
@inject INodeService nodeService;

<div class="row mt-2">
    <div class="col">
        <button @onclick="AddNode">Add Node</button>
        <button @onclick="SaveNodes">Save</button>
        <button @onclick="AddConnector">Add Connector</button>
        <svg class="bg-light" width="100%" height="500" xmlns="http://www.w3.org/2000/svg"
            @onmousemove=@(e => mouseSrv.FireMove(this, e))
            @onmouseup=@(e => mouseSrv.FireUp(this, e))
            @onmouseleave=@(e => mouseSrv.FireLeave(this, e))>

            @foreach(var node in nodes)
            {
                <Draggable Circle=@node>
                <circle r="15" fill="#04dcff" stroke="#fff" />
                </Draggable>
            }
            @foreach(var connector in connectors)
            {
                <ConnectorComponent Line=connector />
            }
        </svg>
    </div>
</div>

@code {
    public List<Node>? nodes;
    public List<Connector>? connectors;
    int serviceIntance = 0;
    protected override async Task OnInitializedAsync()
    {
        nodes = new List<Node>();
        connectors = new List<Connector>();
        
        try
        {
            await nodeService.LoadNodes();
            nodes = nodeService.GetNodes();
            connectors = nodeService.GetConnectors();
            serviceIntance = nodeService.getInstance();
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine(ex.Message);
        }

        Console.WriteLine("Got Stuff?");
    }

    public async Task SaveNodes()
    {
        await nodeService.SaveNodes();
    }

    private async Task AddNode()
    {
        var lastShape = nodes.LastOrDefault();
        double x = lastShape != null ? lastShape.XCoord + 15 : 0;
        double y = lastShape != null ? lastShape.YCoord : 0;
        await nodeService.CreateNode(x, y, "nodes");
    }

    private async Task AddConnector()
    {
        var startnode = nodes[0];
        var endNode = nodes[1];
        await nodeService.AddConnector(startnode, endNode);
        Console.WriteLine("We Here");
    }
}

ConnectorComponent.razor

@inject INodeService nodeService;

<path d="M @startNode.XCoord @startNode.XCoord C @Line.StartBezierXCoord @Line.StartBezierYCoord, @Line.EndBezierXCoord @Line.EndBezierYCoord, @endNode.XCoord @endNode.YCoord" stroke="rgb(108, 117, 125)" stroke-width="1.5" fill="transparent" style="pointer-events:none !important;" />

@code {
    [Parameter] public Connector Line  { get; set; }
    public Node startNode;
    public Node endNode;
    int serviceInstance;

    protected override void OnParametersSet() {
        var nodes = nodeService.GetNodes();
        serviceInstance = nodeService.getInstance();
        startNode = nodes.First(node => node.Id.Equals(Line.StartNodeId));
        endNode = nodes.First(node => node.Id.Equals(Line.EndNodeId));
        base.OnParametersSet();
    }
}

NodeService.cs

using BlazorDraggableDemo.Models;
using Microsoft.AspNetCore.Components.Web;
using System.Net.Http.Json;
using System.Net.Http;
using BlazorDraggableDemo.Factories;
using BlazorDraggableDemo.DTOs;
using System.Text.Json;

namespace BlazorDraggableDemo.Services
{
    public interface INodeService
    {
        public Task LoadNodes();
        public List<Node> GetNodes();
        public Task SaveNodes();
        public Task AddConnector(Node startNode, Node endNode);
        public void SaveConnectors();
        public Task CreateNode(double xCoord, double yCoord, string solutionId);
        public List<Connector> GetConnectors();
        public int getInstance();
    }

    public class NodeService : INodeService
    {
        private readonly HttpClient _httpClient;
        private readonly INodeServiceRequestMessageFactory _nodeServiceRequestMessageFactory;
        private readonly int instance;
        public NodeService(HttpClient httpClient, INodeServiceRequestMessageFactory nodeServiceRequestMessageFactory)
        {
            _httpClient = httpClient;
            _nodeServiceRequestMessageFactory = nodeServiceRequestMessageFactory;
            var rand = new Random();
            instance = rand.Next(0, 100);
        }
        public List<Node> Nodes = new List<Node>();
        public List<Connector> Connectors = new List<Connector>();

        public async Task LoadNodes()
        {
            try
            {
                var nodes = await _httpClient.GetFromJsonAsync<List<Node>>("api/getnodes");
                if (nodes != null)
                {
                    Nodes = nodes;
                }
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine(ex.Message);
            }
        }

        public List<Node> GetNodes()
        {
            return Nodes;
        }

        public async Task SaveNodes()
        {
            try
            {
                var response = await _httpClient.PostAsJsonAsync<UpsertNodesRequestMessage>("api/upsertNodes", new UpsertNodesRequestMessage()
                {
                    Nodes = Nodes.ToList()
                });
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine(ex.Message);
            }
        }

        public async Task AddConnector(Node startNode, Node endNode)
        {
            try
            {
                var response = await _httpClient.PostAsJsonAsync("api/AddConnector", new AddConnectorRequestMessage()
                {
                    StartNode = startNode,
                    EndNode = endNode
                });
                var responseMessage = await response.Content.ReadAsStringAsync();
                var connector = JsonSerializer.Deserialize<Connector>(responseMessage);
                Connectors.Add(connector);
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine(ex.Message);
            }
        }
        public void SaveConnectors()
        {

        }

        public List<Connector> GetConnectors()
        {
            return Connectors;
        }
        public async Task CreateNode(double xCoord, double yCoord, string solutionId)
        {
            try
            {
                var response = await _httpClient.PostAsJsonAsync<CreateNodeRequestMessage>("api/CreateNode", new CreateNodeRequestMessage()
                {
                    XCoord = xCoord,
                    YCoord = yCoord,
                    SolutionId = solutionId
                });
                var responseMessage = await response.Content.ReadAsStringAsync();
                var node = JsonSerializer.Deserialize<Node>(responseMessage);
                Nodes.Add(node);
                
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine(ex.Message);
            }
        }

        public int getInstance()
        {
            return instance;
        }
    }
}

当我从 ComponentA 检查 nodeService.instance 的值时,它出现在 84 当我从 ComponentB 检查值时,它出现在 84出现在12。我对单例的理解是,单例服务的单个实例应该跨用户的应用程序实例。从任一组件引用时,nodeService.instance 的值不应该相同吗?

最佳答案

添加@Mister Magoo关于将 transient /作用域服务注入(inject)单例的答案。我刚刚尝试将 HttpClient 注入(inject)到单例中,然后当我尝试注入(inject)单例时出现运行时错误。

Unhandled exception rendering component: Cannot consume scoped service 'System.Net.Http.HttpClient' from singleton 'IComp'.

builder.Services.AddHttpClient(),实际上是将IHttpClientFactory注册为服务。所以你应该注入(inject)它,然后在需要时创建客户端。这可能是您的问题,但我实际上无法重现您的结果。

public interface IComp
{
    int num { get; set; }
}
public class myComp : IComp
{
    public int num { get; set; }

    private readonly IHttpClientFactory _clientFactory;
    public myComp(IHttpClientFactory clientFactory)
    {
        _clientFactory = clientFactory;
        var rand = new Random();
        num = rand.Next(0, 100);
    }

    public async Task<string> GetSomething()
    {
        // edit, removed the using on client
        var client = _clientFactory.CreateClient();
        return await client.GetStringAsync("http://some-url");
    }
}

关于c# - Blazor 组件之间注入(inject)的单例服务是不同的 [.NET 6],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71260618/

相关文章:

blazor - 在 Blazor 服务器端使用 CancellationTokenSource 去抖动实现

c++ - 在 WASM 中访问当前 URL (c/c++)

c# - 无法部署新的 SharePoint 网站模板程序集版本

c# - 由于Windows系统崩溃,C#解决方案和源文件已损坏

c# - 如何使用 VSIX 扩展实现控制台应用程序

c# - 在 C# 中解析带有标题的 CSV 文件

error-handling - 有没有办法全局捕获 Blazor 单页应用程序中所有未处理的错误?

c# - 仅更改所选 div 的类

clang - 如何在wasm中更改导入模块名称 "env"?

rust - 调用从 Wasmtime 返回字符串的 WASM 函数