【问题标题】:Null Reference exception when accessing a singleton with Autofac使用 Autofac 访问单例时出现空引用异常
【发布时间】:2016-07-06 12:09:36
【问题描述】:

尝试从我的 ASP.NET MVC 控制器操作访问单例类时出现空引用异常。我使用 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");

【问题讨论】:

    标签: c# asp.net-mvc autofac


    【解决方案1】:

    您的 _service 变量将一直为空。因此,您可能会得到空参考。

    private static IService<Administrator> _service;
    

    这个变量永远不会被实例化(手动或通过 Autofac)

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

        var getImage = _service.GetByIdAsync(userId);
    

    因为_service 为空

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

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

    为了解决这个问题,你可能想从控制器或更好的控制器的角度重新考虑这个类,对控制器的依赖(构造函数参数),使用 _service 和这样的变量作为实例变量而不是静态变量,而 Autofac 不能对你有很大帮助。

    这样,当控制器被 Autofac 实例化时,它会自动为你创建一个 'UserControlHelper' 的实例。

    回答您的评论(您需要一个单例 UserControlHelper):

    1. 您可以为此利用 Autofac。
    2. 我们将使此类成为控​​制器的构造函数参数。
    3. 并让 Autofac 知道将其实例化为单例。

      public class MyController: Controller
      {
       public MyController(UserControlHelper helper)
       {
        ViewBag.FullName = helper.GetUserData(UserId, "Name");
       }
      }
      

    当你用 Autofac 注册这个类时,你可以这样做:

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

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

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

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

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

    builder.RegisterInstance<UserControlHelper>(singletonInstanceYouConstructed);
    

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

    【讨论】:

    • 感谢您的回答。实际上我想让 UserControl Helper 类只实例化一次,我认为我应该实现单例。你能用代码告诉我如何实现这一点吗?或使用autofac?用 autofac 注册这个类有意义吗?
    • @Anony 我已编辑我的答案以在评论中回答您的问题
    • 感谢您的评论。有效!。但它只有在我设置 InstancePerLifetimeScope() 而不是单个实例时才有效。只要我实现单例,它会引起任何担忧吗?
    猜你喜欢
    • 2020-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-30
    • 2015-03-22
    • 1970-01-01
    相关资源
    最近更新 更多