.NET Core WebAPI 依赖注入解析 null

Luk*_*988 10 c# authentication dependency-injection asp.net-web-api .net-core

我将 .NET Core WebAPI 与依赖项注入和多个身份验证模式(http 基本、访问密钥、JWT)结合使用。我注入了一些需要一些经过身份验证的用户数据的业务服务。如果用户通过任何 auth 中间件进行身份验证,DI 工作正常。如果用户未通过身份验证,DI 将无法解析某些服务。我需要 DI 返回null

这怎么可能?下面的代码将导致异常,null不允许作为结果。

services.AddTransient<IMasterRepository>(serviceProvider =>
        {
            var _serviceFactory = new RepositoriesFactory(Configuration);

            if (!Authenticated)
            {
                return null;
            }

            return _serviceFactory.CreateMasterRepository();
        });
Run Code Online (Sandbox Code Playgroud)

另外,我无法在身份验证中间件中返回 401,因为另一个中间件可能会成功(expl:无法在 http 基本身份验证中间件中返回 401,因为下一个 JWT 可能会成功)

此外,我无法在所有身份验证中间件之后添加“需要身份验证”检查,因为某些控制器是公共的(不需要身份验证/依赖项注入)。

有什么建议吗?谢谢!

Nko*_*osi 5

默认 DI 框架在设计上不允许工厂委托返回 null。

通过创建从接口派生的 NullObject 来考虑空对象模式

public class NullRepository : IMasterRepository {
    public static readonly IMasterRepository Empty = new NullRepository();

    public NullRepository () { }

    //...implement members that do nothing and may return empty collections.
}
Run Code Online (Sandbox Code Playgroud)

调用时不执行任何操作。

services.AddTransient<IMasterRepository>(serviceProvider => {
    IMasterRepository result = NullRepository.Empty;
    var _serviceFactory = new RepositoriesFactory(Configuration);
    if (Authenticated) {
        result = _serviceFactory.CreateMasterRepository();
    }
    return result;
});
Run Code Online (Sandbox Code Playgroud)

检查 null 现在变为

//ctor
public SomeClass(IMasterRepository repository) {

    if(repository == NullRepository.Empty)
        //...throw

    //...
}
Run Code Online (Sandbox Code Playgroud)


Mat*_*int 5

有没有在任何问题登记的执行情况null。只有解决了才会有问题。

换句话说,如果您注册:

services.AddTransient<IMasterRepository>(provider => null);
Run Code Online (Sandbox Code Playgroud)

然后尝试:

private readonly IMasterRepository _repository;

public SomeController(IMasterRepository repository)
{
    _repository = repository;
}
Run Code Online (Sandbox Code Playgroud)

您将InvalidOperationException在运行时收到一个类似以下内容的消息:

尝试激活“MyApp.Controllers.SomeController”时无法解析“MyApp.IMasterRepository”类型的服务

但是,有一个简单的解决方法。不是注入接口,而是注入该接口的一个IEnumerable

private readonly IMasterRepository _repository;

public SomeController(IEnumerable<IMasterRepository> repositories)
{
    _repository = repositories.First();  // (using System.Linq)
}
Run Code Online (Sandbox Code Playgroud)

您可能认为它应该是FirstOrDefault,但是确实会有一个包含null您注册的项目。

这种方法之所以有效,是因为 ASP.Net Core 中的 DI 支持注册给定类型的多个实现,null并且在注册时不区分和 对象实例。

请记住,即使这样可行,也不建议这样做,因为现在该_repository变量可能为空,并且每次访问时都必须使用空检查。例如:if (_repository != null) { _repository.DoSomething(); }_repository?.DoSomething();。大多数人不希望编写那样的代码。

这涵盖了问题的 DI 部分。但是,如果问题确实出在 auth 上,那么ste-fu 的回答描述了一种更合适的方法。

  • 我不能看这个:o,如果我在代码库中看到这个,我会停止我正在做的事情并重构它。 (2认同)