2016-03-19 102 views
0

當我嘗試從ASP.NET MVC Controller Action訪問單例類時,出現空引用異常。我使用Autofac作爲IoC容器。當使用Autofac訪問單例時出現空引用異常

下面是代碼:

註冊依賴性方法:

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」);

回答

3

您的_service變量將一直爲空。因此你可能會得到null引用。

private static IService<Administrator> _service; 

這個變量從不實例(手動或通過Autofac)

當你罵你的方法,這是一個可能會導致空引用代碼。

var getImage = _service.GetByIdAsync(userId); 

因爲_service爲空

對於所有Autofac wireup正在做,還有我們指示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(); 

這意味着你必須刪除實例變量,並在類中的任何單身般的邏輯。並且將靜態方法轉換爲實例方法。並將構造函數轉換爲公共函數。

最好讓Autofac /框架做單身/其他功能的咕嚕聲。 (懶惰變量是另一個這樣的工具)

我們可以專注於保持您的類與業務邏輯相關。

如果你真的想自己做單的實現,你仍然可以autofac註冊爲:

builder.RegisterInstance<UserControlHelper>(singletonInstanceYouConstructed); 

但總的來說,我發現它更簡單,讓Autofac管理整個生命週期管理。

+0

感謝您的回答。其實我想讓UserControl Helper類僅實例化一次,我想我應該實現單例。你能告訴我用代碼我怎麼能做到這一點?或使用autofac?用autofac註冊這個類是否有意義? – Anony

+0

@Anony我編輯了我的回答,在評論中回答你的問題 –

+0

感謝您的評論。有效!。但它只適用於我設置InstancePerLifetimeScope()而不是單個實例。只要即時通信實施單身人士,是否會引起任何關注? – Anony