将组件的依赖注入方法移动到 Blazor 服务器端中的分离 CS 库

Posted

技术标签:

【中文标题】将组件的依赖注入方法移动到 Blazor 服务器端中的分离 CS 库【英文标题】:Move component's Dependency Injected methods to separate CS library in Blazor Server-Side 【发布时间】:2021-05-30 22:36:46 【问题描述】:

希望在单独的 .cs 文件和/或单独的库中创建可重用的函数/方法。当然我知道怎么做,我的问题是我不知道在需要使用依赖注入元素的情况下怎么做。 例如,下面是一个获取用户属性的非常简单的函数:

[Inject]
public UserManager<IdentityUser> UserManager  get; set; 

public async Task<string> GetUserId(string emailName)

    var user = await userManager.FindByNameAsync(emailName);
    if (user == null)
        return null;
    return user.Id;

这适用于每个剃须刀文件/组件,如果(!)组件已初始化。如果没有,注入的服务也没有初始化并得到一个空异常错误。

我不想将此代码-sn-p 重写/复制到我想使用的每个组件中,所以我想为它创建一个类或库。正确的方法应该是什么?最好的办法是我可以将这些函数移到单独的类库或 Razor 类库中。

更新:

@Nkosi 提供了完美的解决方案,但我想向前思考一点。 之前的代码示例非常小,那么如果我的自定义方法需要 2-3-4 或更多 DI 怎么办?例如(在 Razor 组件中):

[Inject]
public UserManager<IdentityUser> UserManager  get; set; 
[Inject]
public SignInManager<IdentityUser> SignInManager  get; init; 
[Inject]
public IJSRuntime jsRuntime  get; init; 
[Inject]
public CookieAuthenticationOptions cookieAuthenticationOptions  get; set; 
[Inject]
public IOptionsMonitor<CookieAuthenticationOptions> c_options  get; set; 


public async Task<string> GetUserWithOtherStuff(string email, string psw)

    cookieAuthenticationOptions = c_options.Get("schema");
    var user = await UserManager.FindByNameAsync(email);
    var valid = await SignInManager.UserManager.CheckPasswordAsync(user, psw);
    // etc..

    return something;

【问题讨论】:

如果您有那么多依赖项要注入,那么您首先要处理更多的设计问题。这通常被视为您的类/组件做得太多并违反单一责任原则的代码味道。 我的回答中提供的相同方法仍然可以应用于这种情况。您最终将有更多的依赖项注入您的服务(但是,请注意我之前的评论)。它甚至会简化您的组件,因为所有这些额外的依赖项都将聚合到新的抽象中。 你说得对,一般都用几个,但尽量找个极端的例子....谢谢,试着和他们一起玩一下。 【参考方案1】:

将其移至单独的类/库

public interface IUserService 
    Task<string> GetUserId(string emailName);


public class UserService : IUserService 
    private readonly UserManager<IdentityUser> userManager;
    
    public UserService(UserManager<IdentityUser> userManager) 
        this.userManager = userManager;
    

    public async Task<string> GetUserId(string emailName) 
        var user = await userManager.FindByNameAsync(emailName);
        if (user == null)
            return null;
        return user.Id;
    
    

并在需要的地方注入封装的服务

[Inject]
public IUserService  UserService  get; set; 

确保在服务集合中注册了所有必要的依赖项。

可以做一个扩展方法来对需要的依赖注册进行分组

public static IServiceCollection AddUserServices(this IServiceCollection services) 
    services
        .AddScoped<IUserService, UserService>()
        .AddIdentity<.....>()
        //... add what is needed for this library library to function

    return services;

并在需要时调用/重用

//...

services.AddUserServices();

//...

【讨论】:

【参考方案2】:

小心像 UserManager 这样的常见注入。

如果它们被注入到多个其他服务中,而这些服务又被注入到同一个页面中,那么您最终可能会遇到线程异常导致页面崩溃。

例如,在市场页面中,您可能有一项服务来查找当前用户的现有资金,另一项服务检查用户添加的项目,以及其他几项都依赖于了解当前用户的身份证。

如果您只是愉快地将访问 UserManager 的自定义服务注入到许多嵌套组件中,那么您可能会像我第一次学习 Blazor 时那样感到悲痛。

【讨论】:

感谢您的建议,尽量记住。我还没有遇到过这个问题,现在我尝试将这些东西组织到一个主要的服务中。 是的,我也没有这个问题了。自从我让 Blazor 崩溃以来已经有一段时间了,除了空引用或数据库查询问题。

以上是关于将组件的依赖注入方法移动到 Blazor 服务器端中的分离 CS 库的主要内容,如果未能解决你的问题,请参考以下文章

Blazor 中的依赖注入与 Razor 组件

Blazor University (52)依赖注入 —— 拥有多个依赖项:正确的方式

如何将 Blazor 中的所有注册服务添加到 Simple Injector?

Blazor 的依赖注入问题

将服务器端 Blazor 添加到现有 MVC Core 应用程序

Blazor University (48)依赖注入 —— Scoped 依赖