0

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
}
4

1 に答える 1

0

usingブロックは実行が完了する前に破棄されるussため、null 参照の例外はここから発生します (両方の問題について)。

がシングルトンで、複数回使用できる場合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;
}
于 2012-12-07T16:40:47.317 に答える