AutoFac: Inject NULL values

2019-02-13 05:46发布

I want to use AutoFac to inject the current principal in the objects that need it. Suppose I have an object (AuthorizationValidator) that is performing security checks. It looks something like this:

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
     ...
  }
}

For my web application the AuthorizationValidator is registered and I use the following registration to inject the principal:

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

Other type of applications use the thread's principal or something similar. All object that require the principal get the proper principal injected.

If a call is made without authorization, then AutoFac raises an exception telling me that it cannot provide the IPrincipal object, because the factory returned null. In this case, an empty principal is fine and shouldn't raise an exception.

标签: c# null autofac
2条回答
SAY GOODBYE
2楼-- · 2019-02-13 06:16

In the Autofac documentation they recommend to use the Null Object pattern for such scenarios. You could create a NullPrincipal class that inherits from the IPrincipal interface with a private constructor that only exposes a readonly static field which provides the default instance. Then you can return this instance instead of null:

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

Of course you would have to update all places in your code where you are checking if the principal is null and check if it is equal to the NullPrincipal.Default instead.

查看更多
▲ chillily
3楼-- · 2019-02-13 06:33

To solve this problem, I have created the IPrincipalFactory interface that can obtain the current principal without going through 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();
}

For the ASP.NET application I would register the following object as IPrincipalFactory:

public class IAspNetPrincipalFactory : IPrincipalFactory
{
  public IPrincipal GetCurrentPrincipal() => HttpContext.Current?.User;
}

Although this works, I am not completely happy with this solution.

查看更多
登录 后发表回答