C# AutoFac:注入空值

C# AutoFac:注入空值,c#,null,autofac,C#,Null,Autofac,我想使用AutoFac将当前主体注入到需要它的对象中。假设我有一个正在执行安全检查的对象(AuthorizationValidator)。它看起来像这样: public AuthorizationValidator : IAuthorizationValidator { public AuthorizationValidator(IDataAccess dataAccess, IPrincipal principal) { // Save injected objects

我想使用AutoFac将当前主体注入到需要它的对象中。假设我有一个正在执行安全检查的对象(
AuthorizationValidator
)。它看起来像这样:

public AuthorizationValidator : IAuthorizationValidator
{
  public AuthorizationValidator(IDataAccess dataAccess, IPrincipal principal)
  {
     // Save injected objects
     ...
  }

  public bool CheckPermission(Guid objectId, Action action)
  {
     // Check if we are authorized at all
     if (this.principal == null)
       return false;

     // Check the permission in the database
     ...
  }
}
对于我的web应用程序,已注册AuthorizationValidator,我使用以下注册来注入主体:

builder.Register<IPrincipal>((c, p) => HttpContext.Current?.User);
builder.Register((c,p)=>HttpContext.Current?User);
其他类型的应用程序使用线程的主体或类似的东西。所有需要主体的对象都会被注入适当的主体


如果调用未经授权,则AutoFac会引发异常,告诉我它无法提供
IPrincipal
对象,因为工厂返回了
null
。在这种情况下,空主体是可以的,不应该引发异常。

为了解决这个问题,我创建了
IPrincipalFactory
接口,该接口可以在不通过AutoFac的情况下获取当前主体:

public AuthorizationValidator : IAuthorizationValidator
{
  public AuthorizationValidator(IDataAccess dataAccess, IPrincipalFactory principalFactory)
  {
     // Save injected objects
     _dataAccess = dataAccess;
     _principal = principalFactory.GetCurrentPrincipal();
  }

  public bool CheckPermission(Guid objectId, Action action)
  {
     // Same as previous example
     ...
  }
}

public interface IPrincipalFactory
{
  IPrincipal GetCurrentPrincipal();
}
对于ASP.NET应用程序,我将以下对象注册为IPrincipalFactory:

public class IAspNetPrincipalFactory : IPrincipalFactory
{
  public IPrincipal GetCurrentPrincipal() => HttpContext.Current?.User;
}
虽然这是可行的,但我对这种解决方案并不完全满意。

在Autofac中,他们建议在这种情况下使用。您可以创建一个
NullPrincipal
类,该类继承自
IPrincipal
接口,并使用一个私有构造函数,该构造函数只公开一个提供默认实例的
readonly
字段。然后可以返回此实例,而不是null:

builder.Register<IPrincipal>((c, p) => HttpContext.Current?.User ?? NullPrincipal.Default);
builder.Register((c,p)=>HttpContext.Current?User??NullPrincipal.Default);

当然,您必须更新代码中检查主体是否为null的所有位置,并检查它是否等于
NullPrincipal.Default

我不知道Autofac内部是什么,但这可能会起作用:
builder.Register((c,p)=>(IPrincipal)HttpContext.Current?.User)一般来说,IoC框架不允许您故意注入null。这不仅仅是一个Autofac问题。会像我在回答中建议的那样是一个替代方案吗?虽然我最终使用了一个主体提供程序,如果它没有主体,则返回null,但我认为在大多数情况下,null对象模式可能更好,所以我将其标记为最佳答案。