首页 > 解决方案 > 如何从 C# 代码正确使用 Scoped 服务

问题描述

我使用 blazor 服务器端,因此尝试使用 AddScoped 而不是 AddSingleton,因为该对象是基于每个用户使用的。我尝试尽可能多地拆分剃须刀页面和 c# 代码,因为我发现这更干净。

我使用添加范围服务

Services.AddScoped<Services.ManageUserService>();

在 Startup 类的 ConfigureServices 函数中。

我现在的问题是从任何 .cs 文件(保存我的 .razor 页面的逻辑)正确访问服务

我试图做这样的注射:

[Inject]
public Services.ManageUserService manageUserService { get; set; }

然后使用(例如用户名)访问作用域对象:

manageUserService.User

这有效。我的问题是,如果我添加一个只在范围服务内运行一次的打印,它会在每次重新加载或更改页面时运行。

例如,假设我这样做:

public class ManageUserService
{
    public string User { get; private set; }

    private bool LoadedStartup = false;

    public ManageUserService() => SetupUser();

    private void SetupUser()
    {
        if (!LoadedStartup)
        {
            User = "me";
            LoadedStartup = true;
            System.Diagnostics.Debug.Print("User:" + User);
        }
    }
}

然后,我使用以下方法从多个 .cs 文件中访问该类:

[Inject]
public Services.ManageUserService manageUserService { get; set; }

打印“用户:我”应该只发生一次,因为锁定布尔LoadedStartup被更改,问题是每次注入发生时我都会得到打印(在更改页面等)

我究竟做错了什么?AddScoped() 不是假设为每个客户端添加一个“singelton”实例吗?我是否错误地访问它?

我找不到任何从分离的 .cs 和 .razor 页面中使用 AddScoped 的示例,只能直接从 .razor 页面中找到,然后使用@inject完成。

标签: c#razorserver-sideblazorinject

解决方案


我处于同样的情况:

1.- 添加范围服务:

Services.AddScoped<Services.ManageUserService>();

2.- 然后,为了让每个用户真正拥有一次范围内的实例,在 _Hosts.cshtml 中:

<app>
 <component type="typeof(App)" render-mode="Server" />
</app>

3.- 现在我自己发现的技巧,例如 App.razor 中的范围服务

@inject Examples.ViewModels.MainViewModel Main;
@inject Examples.ViewModels.ChildViewModel Child;
@inject Examples.ViewModels.LayoutViewModel Layout;
@inject Examples.ViewModels.TreeViewModel Tree;
@{

Child.Main = Main;
Tree.LayoutViewModel = Layout;
}

4.-如果你在构造函数中有类似的东西:

public class MainViewModel
{
  public static MainViewModel Instance;
  public MainViewModel()
  {
  Instance = this;
 }

}

您可以从代码中的任何位置访问您定义为服务的任何类。

 MainViewModel.Instance...

我在我的博客上发布了它:https ://expediteapps.net/2020/02/18/scoped-viewmodels-instanced-once-on-start/


推荐阅读