3

私の Web API プロジェクトには、現在の要求を必要とする依存関係があります。

コードは以下のとおりです。

public interface IResourceLinker {
  Uri Link(string routeName, object routeValues);
}

public class ResourceLinker : IResourceLinker {
  private readonly HttpRequestMessage _request;

  public ResourceLinker(HttpRequestMessage request) {
    _request = request;
  }

  public Uri Link(string routeName, object routeValues) {
    return new Uri(_request.GetUrlHelper()
        .Link(routeName, routeValues));
  }
}

public class TestController : ApiController {
  private IResourceLinker _resourceLinker;

  public TestController(IResourceLinker resourceLinker) {
    _resourceLinker = resourceLinker
  }

  public Test Get() {
    var url = _resourceLinker.Link("routeName", routeValues);

    // etc.
  }
}

Simple Injector を使用して、実行時に現在のリクエストをコンテナーに注入することは可能ですか?

私は次のことを試しました:

public class InjectRequestHandler : DelegatingHandler
{
  protected override Task<HttpResponseMessage> SendAsync(
    HttpRequestMessage request, CancellationToken cancellationToken)
  {
    InjectRequest(request);
    return base.SendAsync(request, cancellationToken);
  }

  public static void InjectCurrentRequestIntoContainer(
    HttpRequestMessage request)
  {
    var resolver = (SimpleInjectorDependencyResolver)
      request.GetDependencyScope();
    resolver.Container.Register(() => request);
  }
}

しかし、次のエラーを受け取りました

GetInstance、GetAllInstances、および Verify を最初に呼び出した後は、コンテナーを変更できません。

実行時に現在のリクエストをコンテナに挿入する方法はありますか?

4

1 に答える 1

5

コンテナーは、登録フェーズの後、すべての登録をブロックします。これにより、コンテナの使用が登録と解決の 2 つのフェーズに分割されます。これを行うコンテナーは Simple Injector だけではありません。たとえば、Autofacは、構成フェーズの最後のステップとしてメソッドをContainerBuilder使用してコンテナを構築するを使用してユーザーが登録できるようにすることで、これをさらに明示的に行います。Build

Simple Injector は主に、アプリケーションの存続期間中に後で登録を行うと、競合状態などのあらゆる種類の問題のある動作に簡単につながる可能性があるため、これを許可しません。また、DI を適用するときは登録を集中化するように努める必要がありますが、登録がアプリケーション全体に分散しているため、DI 構成を理解するのがはるかに難しくなります。副作用として、この設計により、コンテナーのハッピー パスにロックがないため、マルチスレッド シナリオでコンテナーが線形のパフォーマンス特性を持つことができます。

Simple Injector では、イベントを使用してジャストインタイムの登録が可能ですResolveUnregisteredTypeが、これはあなたの場合には適していません。

問題は、実行時にのみ認識されるオブジェクトをオブジェクト グラフに挿入することです。一般に、実行時の依存関係はメソッド引数を介して渡す必要がありますが、コンパイル時/構成時の依存関係はコンストラクターを介して渡す必要があるため、これは最善の方法ではない可能性があります。

HttpRequestMessageしかし、コンストラクタ引数として を渡すことが正しいと確信している場合は、リクエストの存続期間中にこのメッセージをキャッシュし、そのキャッシュされたインスタンスを返すことを許可する登録を行う必要があります。

これは次のようになります。

// using SimpleInjector.Advanced; // for IsVerifying()

container.Register<HttpRequestMessage>(() =>
{
    var context = HttpContext.Current;

    if (context == null && container.IsVerifying())
        return new HttpRequestMessage();

    object message = context.Items["__message"];
    return (HttpRequestMessage)message;
});

この登録により、辞書HttpRequestMessageにキャッシュされているが取得されます。検証中 ( を呼び出すとき)HttpContext.Itemsにこの登録が機能することを許可する追加のチェックがあります。ただし、コンテナーの検証に関心がない場合 (通常は実際に確認する必要があります)、次のように最小化できます。container.Verify()HttpContext.Current

container.Register<HttpRequestMessage>(() =>
    (HttpRequestMessage)HttpContext.Current.Items["__message"]);

この登録では、コントローラーを取得するために が呼び出される前にHttpRequestMessageインスタンスをキャッシュするだけで済みます。 container.GetInstance

public static void InjectCurrentRequestIntoContainer(
    HttpRequestMessage request)
{
    HttpContext.Current.Items["__message"] = request;
}

アップデート

Web API 統合パッケージには、現在の要求のGetCurrentHttpRequestMessage取得を可能にする拡張メソッドが含まれています。HttpRequestMessageWeb API 統合 Wiki ページでは、この拡張メソッドの使用方法について説明しています

于 2013-07-15T09:15:37.557 に答える