2012-12-07 16 views
0

我正在WinRt中使用C#和SQLite從Windows應用程序調用WinRt類庫...對象在意外的時間返回空引用錯誤...WinRt C#空異常 - 使用IAsyncOperationWithProgress的對象範圍問題

我試圖執行登錄服務,通過檢查數據文件是否存在來檢查當前用戶是否已登錄,然後檢查用戶是否是當前登錄用戶...

用戶只需輸入他們的ID並點擊登錄按鈕即可。它創建一個包裝SQLite數據庫的DataService對象,然後「注入」UserStartupService。

UserStartupService使用依賴注入,單例並實現IDisposable。

問題1)如果用戶第二次單擊登錄按鈕,UserStartupService對象構造函數不會運行,並且在使用內部對象時,即使它在退出using塊後通過dispose方法運行,它們仍會拋出null引用錯誤,這迫使我停用登錄按鈕,這是一個最好的解決方案。新用戶必須退出程序才能以新用戶身份登錄。 (原始代碼沒有實現IAsyncOperationWithProgress,但這應該沒關係......)

問題2)我現在試圖實現IAsyncOperationWithProgress將進度中繼到UI,並且它立即獲得null引用錯誤嘗試使用_dataFeedService就行:

var json = await _dataFeedService.ValidateUser(userId);

即使它運行在using語句的頂部構造預期...

我覺得這是我失蹤這裏範圍/線程問題。也許一些明顯的...

任何想法?謝謝!

// logon button pressed... 
private void LogOn_Click(object sender, RoutedEventArgs e) 
{ 
    // Create database service for DI 
    DataService _dataService = new DataService("MyData.sqlite"); 

    // using statement for scope control 
    using (UserStartupService uss = UserStartupService.GetInstance(_dataService)) 
    { 
     // progress bar... 
     CurrentProgress.Visibility = Windows.UI.Xaml.Visibility.Visible; 

     // create op and call... 
     IAsyncOperationWithProgress<string, int> op; 
     op = uss.SetUpUser(txtUserId.Text); 

     op.Progress = (info, progress) => 
     { 
      CurrentProgress.Value = progress; 
     }; 

     op.Completed = (info, status) => 
     { 
      var results = info.GetResults(); 
      // when completed... 
      if (status == AsyncStatus.Completed) 
      { 
       txtMessage.Text = "Current user data already loaded..."; 
       CurrentProgress.Value = 100; 
      } // if cancelled... 
      else if (status == AsyncStatus.Canceled) 
      { 
       // Operation canceled - not implemented... 
      } 
     }; 
    } 
    btnLogon.IsEnabled = false; 
} 


public sealed class UserStartupService : IDisposable 
{ 
    #region properties 

    // services 
    private static DataService _dataService; 
    private static DataFeedService _dataFeedService; 
    private static SqliteService _sqlMAFService; 
    private static SerialiseDeserialiseService _serializeService; 

    private string _token = String.Empty; 

    #endregion properties 

    #region constructors with DI and singleton pattern 

    // use this code to implement singleton patter... 
    // private constructor = can't instance without GetInstance... 
    private UserStartupService(DataService dataService) 
    { 
     // guard clause... 
     if (dataService == null) 
     { 
      throw new ArgumentNullException("DataService"); 
     } 
     _dataService = dataService; 
     _dataFeedService = new DataFeedService(); 
     _sqlMAFService = new SqliteService(_dataService); 
     _serializeService = new SerialiseDeserialiseService(); 
    } 

    // implement singleton 
    public static UserStartupService GetInstance(DataService dataService) 
    { 
     _dataService = dataService; 
     return MyNestedSingletonClass.singleton; 
    } 

    class MyNestedSingletonClass 
    { 
     internal static readonly UserStartupService singleton = new UserStartupService(_dataService); 

     static MyNestedSingletonClass() { } 
    } 

    #endregion constructors with DI and singleton pattern 

    public IAsyncOperationWithProgress<string, int> SetUpUser(string userId) 
    { 
     return AsyncInfo.Run<string, int>((token, progress) => 
      Task.Run<string>(async() => 
      { 
       progress.Report(1); 

       try 
       { 
        // validate user against server REST feed and get token 
        var json = await _dataFeedService.ValidateUser(userId); 

                 // ... it never gets here due to _dataFeedService null exception 
        // ...more code ... never gets here... 


       } 
       catch (Exception ex) 
       { 
        return ex.Message; 
       } 

       progress.Report(100); 

       return ""; 
      }, token)); 
    } 

    #region implement IDisposable 
    public void Dispose() 
    { 
     _serializeService = null; 
     _sqlMAFService.Dispose(); 
     _sqlMAFService = null; 
     _dataFeedService.Dispose(); 
     _dataFeedService = null; 
     _dataService.CloseConnection(); 
     _dataService = null; 
    } 
    #endregion implement IDisposable 
} 

回答

0

它執行完畢之前,因此,這就是你的空引用異常是從(兩個問題)來的using塊將處置uss

如果UserStartupService是單身人士,並且可以多次使用,那麼請不要處理它。

此外,我會建議使用await,而不是回調(它通常是簡單的),所以這樣的事情應該工作:

private async void LogOn_Click(object sender, RoutedEventArgs e) 
{ 
    btnLogon.IsEnabled = false; 

    // Create database service for DI 
    DataService _dataService = new DataService("MyData.sqlite"); 

    var uss = UserStartupService.GetInstance(_dataService); 

    // progress bar... 
    CurrentProgress.Visibility = Windows.UI.Xaml.Visibility.Visible; 

    // create op and call... 
    var op = uss.SetUpUser(txtUserId.Text) 
     .AsTask(progress => { CurrentProgress.Value = progress; }); 
    var result = await op; 

    txtMessage.Text = "Current user data already loaded..."; 
    CurrentProgress.Value = 100; 

    btnLogon.IsEnabled = true; 
} 
+0

THX快速回復。對處置的好建議。我正在實施你的建議,看看它的其餘部分如何。我會告訴你。 – CodeChops