1

初めての実際の MVC4 アプリケーションを作成していますが、次の問題が発生しました。

「ユーザー」クラスのモデルがあります。そのデータは、Web サービスへの非同期呼び出しによって取得されます。

public sealed class AdminDMSEntities
{
    public List<User> UserList { get; private set; }

    public AdminDMSEntities()
    {
        this.UserList = new List<User>(0);
        ServiceClient client = new ServiceClient();
        client.GetUsersCompleted += (s, e) => 
        {
            if (e.Result == null)
                throw new ArgumentNullException("No users were retrieved");

            UserList = new List<User>(0);
            e.Result.ForEach(w => this.UserList.Add(new User(w.Guid, w.TrusteeType, w.Username, w.Email, w.LastLogin, w.PasswordChanged, w.IsUsingTempPassword)));               
        };

        client.GetUsersAsync();
    }        
}

DbContext から派生したクラスを使用するので、このクラスを使用するつもりです (Entity Framework を使用できない場合)。これまでのところ、クラスにはユーザーしかいません。

私は次のように UsersController で tis クラスを使用しています:

public class UsersController : Controller
{
    private AdminDMSEntities adminEntities = new AdminDMSEntities();
    //
    // GET: /User/

    public ActionResult Index()
    {
        return View(adminEntities.UserList);
    }
}

問題は、コントローラーが非同期呼び出しの完了を待機しておらず、ユーザーが適切に入力される前に UserList をビューに渡すため、InvalidOperationException が発生することです。

当分の間、呼び出しを同期させることができますが、後で非同期呼び出しを使用することを余儀なくされる可能性が非常に高いため、UserList が渡される前にコントローラーが非同期呼び出しが完了するのを待機するようにする方法を知りたいです。表示するには...

前もって感謝します

編集: 以下にリストされているように、AsyncController を使用してアプローチを試みましたが、現在、これを AdminDMS エンティティ クラスに追加しています。

public static async Task<AdminDMSEntities> AdminDMSEntitiesAsync()
    {
        AdminDMSEntities result = null;
        Task<AdminDMSEntities> getUsersAsyncTask = Task.Factory.StartNew(() => new AdminDMSEntities());
        await getUsersAsyncTask;
        return result;
    }

そして、これはコントローラーへの変更です:

public class UsersController : AsyncController
{
    private AdminDMSEntities adminEntities = null;
    //
    // GET: /User/

    public async Task<ActionResult> Index()
    {
        if (adminEntities == null)
        {
            adminEntities = await AdminDMSEntities.AdminDMSEntitiesAsync();
        }
        return View(adminEntities.UserList);
    }
}

その結果、adminEntities にはクラスのインスタンスが含まれていますが、リストにはユーザーがありません (11 あるはずです)。

EDIT2: 新しいタスクを作成することは正しいことではないと言われたので、コードから AdminDMSEntities クラスを削除する最初の提案されたアプローチを使用しました。私を助けてくれたダーリンに感謝します:)

4

1 に答える 1

1

を使用できますasynchronous controller。アイデアは、コントローラーをAsyncControllerクラスではなくクラスから派生させることControllerです。このクラスは、非同期操作を実行できるメソッドを提供します。

例えば:

public class MyController: AsyncController
{
    public void IndexAsync()
    {
        AsyncManager.OutstandingOperations.Increment();
        var client = new SomeClient();
        client.GetUsersCompleted += (s, e) => 
        {
            UserList = new List<User>();
            AsyncManager.Parameters["users"] = e.Result.Select(
                w => new User(
                    w.Guid, 
                    w.TrusteeType, 
                    w.Username, 
                    w.Email, 
                    w.LastLogin, 
                    w.PasswordChanged, 
                    w.IsUsingTempPassword
                )
            )
            .ToList();
            AsyncManager.OutstandingOperations.Decrement();            
        };
        client.GetUsersAsync();
    }

    public ActionResult IndexCompleted(IEnumerable<User> users)
    {
        return View(users);
    }
}

.NET 4.5 を使用している場合は、新しいasyncキーワードを利用して、非同期コードをさらに簡素化することもできます。これは、データ アクセス レイヤーを新しいパターンにリファクタリングする (つまり、タスクを返す) 場合に可能です。

public class MyController: AsyncController
{
    public async Task<ActionResult> Index()
    {
        var client = new SomeClient();
        var users = await client.GetUsersAsync().Select(
            w => new User(
                w.Guid, 
                w.TrusteeType, 
                w.Username, 
                w.Email, 
                w.LastLogin, 
                w.PasswordChanged, 
                w.IsUsingTempPassword
            )
        )
        .ToList();
        return View(users);
    }
}
于 2013-04-22T09:08:05.263 に答える