C# と SQLite を使用して Windows ストア アプリから WinRt クラス ライブラリを呼び出す WinRt で作業しています...オブジェクトが予期しないときに null 参照エラーを返しています...
データファイルが存在するかどうかを確認し、次にユーザーが現在ログインしているユーザーであるかどうかを確認することにより、現在のユーザーが既にログインしているかどうかを確認するログオンサービスを実装しようとしています...
ユーザーは ID を入力してログオン ボタンをクリックするだけです。SQLite データベースをラップする DataService オブジェクトを作成し、UserStartupService に「注入」します。
UserStartupService は依存性注入、シングルトンを使用し、IDisposable を実装します。
問題 1) ユーザーがログオン ボタンを 2 回クリックすると、UserStartupService オブジェクト コンストラクターが実行されず、内部オブジェクトが使用されると、using ブロックを終了した後に dispose メソッドを実行しても、null 参照エラーがスローされます。ログオン ボタンを非アクティブ化します。これはせいぜいクルーゲの修正です。新しいユーザーが新しいユーザーとしてログインするには、プログラムを終了する必要があります。(元のコードは IAsyncOperationWithProgress を実装していませんでしたが、それは問題ではありません...)
問題 2) IAsyncOperationWithProgress を実装して進行状況を UI に中継しようとしていますが、行で _dataFeedService を使用しようとするとすぐに null 参照エラーが発生します。
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
}