Autofac - HttpContext が利用できないため、要求の有効期間スコープを作成できません - 非同期コードが原因ですか?

2014 年 11 月 20 日更新: Autofac.Mvc5 のリリースでは この質問がリリースされて以来、AutofacDependencyResolver.Current の実装は HttpContext の必要性を取り除くために更新されました .この問題に遭遇し、この回答を見つけた場合、Autofac.Mvc5 の新しいバージョンに更新することで、問題を簡単に解決できる可能性があります。 .ただし、元の質問者が問題を抱えていた理由を人々が理解できるように、元の回答はそのまま残します。

元の回答は次のとおりです:

AutofacDependencyResolver.Current HttpContext が必要です .

コードを見ていく AutofacDependencyResolver.Current 次のようになります:

public static AutofacDependencyResolver Current
{
  get
  {
    return DependencyResolver.Current.GetService<AutofacDependencyResolver>();
  }
}

もちろん、現在の依存関係リゾルバーが AutofacDependencyResolver その後、解決を試みます...

public object GetService(Type serviceType)
{
  return RequestLifetimeScope.ResolveOptional(serviceType);
}

RequestLifetimeScopeProvider からライフタイム スコープを取得する ...

public ILifetimeScope GetLifetimeScope(Action<ContainerBuilder> configurationAction)
{
  if (HttpContext.Current == null)
  {
    throw new InvalidOperationException("...");
  }

  // ...and your code is probably dying right there so I won't
  // include the rest of the source.
}

依存関係リゾルバーを動的にラップ/プロキシして計測する Glimpse などのツールをサポートするには、そのように動作する必要があります。そのため、 DependencyResolver.Current as AutofacDependencyResolver をキャストすることはできません .

Autofac.Integration.Mvc.AutofacDependencyResolver を使用するほとんどすべて HttpContext が必要です .

そのため、このエラーが発生し続けます。 登録されている依存関係がなくても構いません InstancePerHttpRequest - AutofacDependencyResolver まだウェブ コンテキストが必要です。

これが問題にならなかった他のワークフロー アプリは、MVC アプリか、常に Web コンテキストが存在するものだったと思います。

おすすめの方法は次のとおりです:

  • Web コンテキスト外でコンポーネントを使用する必要があり、WebApi を使用している場合は、Autofac.Integration.WebApi.AutofacWebApiDependencyResolver を使用してください .
  • WCF を使用している場合は、標準の AutofacHostFactory.Container を使用してください 依存関係を解決するためのホスト ファクトリの実装。 (WCF はシングルトン ホストの可能性などで少し奇妙です。そのため、「リクエストごと」はそれほど単純ではありません。)
  • テクノロジーに「依存しない」ものが必要な場合は、CommonServiceLocator を検討してください。 Autofac の実装。リクエストの有効期間は作成されませんが、問題が解決する場合があります。

これらのことを正し、いわばネイティブの生息地の外でさまざまなリゾルバーを使用しようとしない場合、問題に遭遇することはありません.

できます かなり安全に InstancePerApiRequest を使用してください と InstancePerHttpRequest サービス登録で交換可能。 これらの拡張機能はどちらも同じライフタイム スコープ タグを使用するため、MVC Web リクエストと Web API リクエストの概念は、1 つのケースの基になるライフタイム スコープが HttpContext に基づいている場合でも同様に扱うことができます。 もう 1 つは IDependencyScope に基づいています。 .したがって、アプリ/アプリの種類間で登録モジュールを仮想的に共有することができ、それは正しいことを行うはずです.

元の Autofac コンテナが必要な場合は、独自のリファレンスを保存してください。 Autofac が何らかの理由でそのコンテナーを返すと仮定するのではなく、何らかの理由で後で取得する必要がある場合は、アプリケーション コンテナーへの参照を保存する必要がある場合があります。

public static class ApplicationContainer
{
  public static IContainer Container { get; set; }
}

// And then when you build your resolvers...
var container = builder.Build();
GlobalConfiguration.Configuration.DependencyResolver =
  new AutofacWebApiDependencyResolver(container);
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
ApplicationContainer.Container = container;

これにより、今後のトラブルを大幅に軽減できます。


私の仮定:

<オール>
  • MVC プロジェクトとは別の Thread/AppDomain でワークフロー プロジェクトを実行しています。
  • IUserRepo HttpContext に依存しています
  • 私の仮定が正しければ、ワークフロー プロジェクトは HttpContext.Current について何も知らないでしょう。 .

    WindowsWorkflow プロジェクトは常に実行されます (正しく理解していれば、実際にはこの技術では機能しませんでした)。 MVC は HTTP リクエストに基づいています。 HttpContext.Current リクエストがある場合にのみ設定されます。リクエストがない場合、この変数は null です。リクエストがないのに、Workflow インスタンスが HttpContext にアクセスしようとするとどうなりますか ?正しい - null 参照例外。または、あなたの場合、依存関係解決の例外です。

    あなたがしなければならないこと:

    <オール>
  • コンテナー登録をモジュール (すべてのドメイン クラスのドメイン モジュール) に分離します。次に、MVC モジュール:User.Current などのすべての MVC 仕様 または HttpContext.Current .そして、すべてのワークフロー固有の実装を含むワークフロー モジュール (必要な場合)。
  • ワークフローの初期化時に、ドメインとワークフロー モジュールを含む autofac コンテナーを作成し、MVC の依存関係を除外します。 MVC コンテナーの場合 - ワークフロー モジュールなしで作成します。
  • IUserRepo の場合 HttpContext に依存しない実装を作成します。これがおそらく最も問題になるでしょう。
  • Azure での Quartz.Net の実行についても同様のことを行いました。これについては、私のブログ投稿 (http://tech.trailmax.info/2013/07/quartz-net-in-azure-with-autofac-smoothness/) を参照してください。この投稿は直接的には役に立ちませんが、autofac モジュールを分割する理由を説明します。

    コメントに従って更新: WebApi は、ここで多くのことを明確にします。 WebApi リクエストは、MVC リクエストと同じパイプラインを通過しません。また、WebApi コントローラーは HttpContext にアクセスできません。この回答を参照してください。

    ここで、wepApi コントローラーで行っていることによっては、IUserRepo を変更したい場合があります。 MVC と WebApi の両方で動作できるように実装します。