2016-03-29 12 views
2

ASP.NET 5アプリケーションで初期の「スーパーユーザー」を作成しようとしています。 MVC 6/EF7で最新のテンプレートファイルを使用する。ASP.NET 5 Startup.csのユーザーをAsyncでシードする方法

私はここに設定の例に従うことができます:

http://wildermuth.com/2015/3/17/A_Look_at_ASP_NET_5_Part_3_-_EF7

これは正常に動作します - 私は非同期メソッドを実行しようとするまで。

await _userManager.CreateAsync(user, "[email protected]!"); 

またはさらに:例えば

await _context.SaveChangesAsync(); 

同期方法は問題なく動作し、このコードは、同様Startup.cs Configure{...}の外に実行します。

アプリケーション開始時に「死の白いスクリーン」が表示されます。私は非同期なしですべてそれを行うだろうが、私はUserManagerがアイデンティティ3.0のCreate()を持っているとは思わない。

これは非同期プログラミングを理解していないのですか、それとも可能でしょうか?

EDIT:それを呼び出す

public void ConfigureServices(IServiceCollection services) 
{ 
... 
services.AddTransient<Seeder>(); 
... 
} 

ユーザーを作成しSeederクラスとメソッドを定義します:

public class Seeder 
    { 
     private ApplicationDbContext _context; 
     private UserManager<ApplicationUser> _userManager; 

     public Seeder(
      ApplicationDbContext context, 
      UserManager<ApplicationUser> userManager) 
     { 
      _context = context; 
      _userManager = userManager; 
     } 

     public async Task Seed() 
     { 
      await CreateUsersAsync(); 
     } 

     public async Task CreateUsersAsync() 
     { 
      var user = await _userManager.FindByEmailAsync("[email protected]"); 

      if (user == null) 
      { 
       var company = _context.Company.First(x => x.Name == "Acme Ltd"); 

       user = new ApplicationUser 
       { 
        UserName = "[email protected]", 
        Email = "[email protected]", 
        CreatedDate = DateTime.Now, 
        IsActive = true, 
        CompanyID = company.CompanyId 
       }; 

       await _userManager.CreateAsync(user, "[email protected]!!"); 

      } 
     } 
    } 

設定サービス全体の呼び出しを追加しました:

public async void Configure(Seeder seeder) 
{ 
... 
await seeder.Seed(); 
... 
} 

面白いのは、それは実際にユーザーを作成します - 単に続行しません。したがって、2回目にuser != nullが実行され、正常に実行されます。

+0

'_userManager.CreateAsnyc'メソッド呼び出し全体を共有してください。コントローラコードはどのように見えますか? –

+0

私はUserManagerの非同期呼び出しがメソッドが成功したかどうかを示すIdentityResultオブジェクトを返します。そのオブジェクトには、ユーザーを保持するResultプロパティがあります。 –

答えて

2

は、私は、デッドロックが署名

public async void Configure(Seeder seeder). 

それはvoidを返すのでにより、待望のタスクが死んでロックを作成し、呼び出し元に返されることはありませんが形成されるため、問題があると思います。あなたはそれを行うことができます。私はまだMVC 6で動作するように得ていない

public async Task Configure(Seeder seeder). 

、:(ので、私は何かが足りないかもしれないが、デッドロックが存在する理由です。

編集:あなたが設定の署名を変更することはできませんので

、タスクを入力し返すConfigureAsyncというメソッドを作成します。これで、あなたのユーザーマネージャーコードでいつもその内部に待っていて、ConfigureAsyncをConfigureから呼び出しますが、それを待っています。

ConfigureAsync.ConfigureAwait(false).Wait() 

ConfigureAwait(false)は、非同期メソッドが完了するのを待つ可能性のあるデッドロックを防ぐために使用されます。

全例:あなたがここにデッドロックに実行

public void Configure(Seeder seeder) 
{ 
    //Edited due to typo/bad syntax. 
    ConfigureAsync(seeder).Wait(); 
} 

public async Task ConfigureAsync(Seeder seeder) 
{ 
    //Now treat this like true async/await. 
    await seeder.Seed().ConfigureAwait(false); 
} 

場合は、おそらくあなたのシーダはちょうど同期すべきですか?私はASP.NETコンテキストでTask.Run()を使用することは避けています。なぜなら、これは非同期/待機の目的を、同期的に行われた場合に2つの要求スレッドを取り上げることによって完全に無効にするからです。

+0

私は 'Configure'が_Task_を返すとは思いません。私は 'xxx.Startup'型の 'Configure'メソッドに 'Void'の戻り値型が必要です。 'エラー。 – jidl

+0

@jidl void configureから非同期的に呼び出すのに役立つ解答を更新しました。基本的には非同期バージョンのconfigureが必要で、元のconfigureメソッドから同期的に呼び出す必要があります。 – davidallyoung

+0

これはうまくいっていますが、 '.Wait()'はコンパイルされません。私はそれを取り出し、'ConfigureAsync(シーダー)を使用しました.ConfigureAwait(false); '答えを編集し、私はそれをacceotよ - ありがとう! – jidl

1

同期インターフェイスを実装する必要がある場合もありますが、非同期APIのみを使用できます。完璧な解決策はありません。

このコードは一度しか呼び出されないため、パフォーマンスの問題は問題になりません。あなただけの非同期ブリッジの上に汚れた同期を行うことができます。

public void ConfigureServices(IServiceCollection services) 
{ 
    ConfigureServicesImpl(services).Wait(); //bridge 
} 

public async Task ConfigureServicesImpl(IServiceCollection services) 
{ 
    await ...; 
} 

あなたはConfigureAwait(false)またはTask.Run(() => ...).Wait()ようなデッドロックの保護を挿入する必要がある場合があります。

+0

ConfigureServicesを非同期タスクにすることはできませんか?それとも他の契約の実装部分ですか?これをまだ使用していないので、私は間違いなくその一部を欠いています。 – davidallyoung

+1

私はあなたがインターフェースを実装していると仮定します。その中であなたは立ち往生しています。非同期メソッドには、タスクの戻り値の型が必要です。呼び出し元が完了を待つことができないため、Async voidは機能しません。 – usr

+0

以下の私のコメントによると、私は 'Configure'が_Task_を返すとは思わないと思います。私の 'ConfigureServices'は' Configure'を直接呼び出すことはありません(DI目的のためにサービスを登録するのは私の理解ではありますか?)。 'Configure'はどこから呼び出されましたか? – jidl

関連する問題