使用Autofac访问单例时出现Null引用异常

时间:2016-03-19 19:49:53

标签: c# asp.net-mvc autofac

尝试从ASP.NET MVC Controller Action访问单例类时,我得到空引用异常。我使用Autofac作为IoC容器。

以下是代码:

注册依赖项方法:

public static void RegisterDependencies()
    {
        var builder = new ContainerBuilder();
        const string nameOrConnectionString = "name=DefaultConnection";
        builder.RegisterApiControllers(typeof(WebApiConfig).Assembly);
        builder.RegisterControllers(typeof(MvcApplication).Assembly);
        builder.RegisterModule<AutofacWebTypesModule>();

        builder.RegisterGeneric(typeof(EntityRepository<>)).As(typeof(IRepository<>)).InstancePerLifetimeScope();
        builder.RegisterGeneric(typeof(Service<>)).As(typeof(IService<>)).InstancePerLifetimeScope();
        builder.RegisterType(typeof(UnitOfWork)).As(typeof(IUnitOfWork)).InstancePerLifetimeScope();
        builder.Register<IEntitiesContext>(b =>
        {
            var logger = b.Resolve<ILogger>();
            var context = new InterfaceContext(nameOrConnectionString, logger);
            return context;
        }).InstancePerRequest();
        builder.Register(b => NLogLogger.Instance).SingleInstance();
        builder.Register(b => UserControlHelper.Instance).SingleInstance();
        builder.RegisterModule(new IdentityModule());

        var container = builder.Build();
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
        GlobalConfiguration.Configuration.DependencyResolver =
             new AutofacWebApiDependencyResolver(container);
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    }

UserControlHelper类:

public class UserControlHelper
{
    private static volatile UserControlHelper _instance;
    private static readonly object SyncRoot = new object();

    private static IService<Administrator> _service;
    private static IService<Customer> _customerService;


    private UserControlHelper() { }

    private UserControlHelper(IService<Administrator> service, IService<Customer> customerService)
    {
        _service = service;
        _customerService = customerService;
    }

    public static UserControlHelper Instance
    {
        get
        {
            if (_instance == null)
            {
                lock (SyncRoot)
                {
                    if (_instance == null)
                        _instance = new UserControlHelper(_service, _customerService);
                }
            }

            return _instance;
        }
    }

    public static string GetUserData(int userId, string type)
    {
        var getImage = _service.GetByIdAsync(userId);

        switch (type)
        {
            case "Image":
                {
                    return getImage.GetAwaiter().GetResult().Image;
                }
            case "Name":
                {
                    return getImage.GetAwaiter().GetResult().FullName;
                }
            case "Email":
                {
                    return getImage.GetAwaiter().GetResult().Email;
                }

            case "AllUsers":
                {
                    return _customerService.GetCountAsync(userId).GetAwaiter().GetResult().ToString();
                }

            default:
                return "No Data";
        }
    }
}

我这样称呼它:

  

ViewBag.FullName = UserControlHelper.GetUserData(UserId,“Name”);

1 个答案:

答案 0 :(得分:3)

您的_service变量始终为null。因此,您可能会获得null引用。

private static IService<Administrator> _service;

此变量从不实例化(手动或通过Autofac)

当你调用你的方法时,这是可能导致空引用的代码。

    var getImage = _service.GetByIdAsync(userId);

因为_service为空

对于所有正在完成的Autofac连线,我们没有向Autofac指示此类需要自动实例化的地方。该类似乎不是控制器(MVC或API)或对控制器的任何依赖。

此外,静态_service变量对Autofac没有帮助。

要解决这个问题,您可能想要根据控制器或更好的方式重新考虑这个类,一个依赖(构造函数参数)到一个控制器,使用_service和变量这样的变量而不是静态变量,其中Autofac不能帮助你。

这样,当控制器由Autofac实例化时,它会自动创建一个&#39; UserControlHelper&#39;的实例。对你而言。

回答你的评论(你需要一个UserControlHelper单身):

  1. 您可以利用Autofac进行此操作。
  2. 我们将此类作为控制器的构造函数参数。
  3. 让Autofac知道将其实例化为单身人士。

    public class MyController: Controller
    {
     public MyController(UserControlHelper helper)
     {
      ViewBag.FullName = helper.GetUserData(UserId, "Name");
     }
    }
    
  4. 当您使用Autofac注册此课程时,您可以执行以下操作:

    build.RegisterType<UserControlHelper>().SingleInstance();
    

    这意味着你必须删除Instance变量和类中任何类似singleton的逻辑。并且还将静态方法转换为实例方法。并将构造函数转换为公共构造函数。

    最好让Autofac / frameworks完成Singletons /其他此类功能的繁重工作。 (懒惰变量是另一种这样的工具)

    我们可以专注于保持您的课程与业务逻辑相关。

    如果你真的想自己做单例实现,你仍然可以用autofac注册它:

    builder.RegisterInstance<UserControlHelper>(singletonInstanceYouConstructed);
    

    但总的来说,我发现让Autofac管理整个生命周期管理会更简单。