2009-05-18 21 views
16

現在、私はのHttpContextから、現在のユーザー名を取得し、サービスの方法でそれを使用するアクションにそれを渡すのActionFilterを持っています。例:ASP.NET MVC:のHttpContextと依存性注入

Service.DoSomething(userName); 

私は今、アクションレベルではなくコントローラのコンストラクタレベルでこれを行う理由があります。現在、構造マップを使用してコントローラを作成し、サービスを注入しています。私のようなもので探しています:これは私はそれを使用してきた最初のプロジェクトであると言わ

public interface IUserProvider 
{ 
    string UserName { get; } 
} 

public class HttpContextUserProvider : IUserProvider 
{ 
    private HttpContext context; 

    public HttpContextUserProvider(HttpContext context) 
    { 
     this.context = context; 
    } 

    public string UserName 
    { 
     get 
     { 
      return context.User.Identity.Name; 
     } 
    } 
} 

は、私のIoC fooは本当に弱いです。

だから私の質問は、私はHttpContextUserProviderのコンストラクタでのHttpContextに渡す構造マップを伝えることができるか...でしょうか?これはちょっと変わったようです...私はHttpContextの考え方がわかりません。

答えて

8

インターフェイスの抽象的なHttpContext.Currentが必要です。必要なメソッドだけを公開してください。GetUserName()は、HttpContext.Current.User.Identity.Nameを例えば実装、。可能な限り薄いことを確認してください。

これはHTTPをあざけることで、プロバイダをテストすることができます。その抽象化を取り、あなたの他のプロバイダクラスに注入しますコンテキスト抽象化。副次的なメリットとして、HttpContext抽象化を使って他の面白いことを行うことができます。それを再利用してください。バッグなどにジェネリックタイプのパラメータを追加する

+0

「ジェネリックタイプのパラメータをバッグに追加する」とはどういう意味ですか?興味をそそられるように聞こえる。 –

+4

は、セッションの上に強い型付きのラッパーを提供しています –

+3

サンプルコード/リンクがありますか?これは面白いようです_私はちょっと新しいDIですので、これを正しく理解していないので、助言やアドバイスをいただければ幸いです... – Haroon

2

は、たぶん私は何かを残しますが、上記の答えは私のために動作しません(以降削除されている - それはしかし、まだ便利な答えだった - それは、コンストラクタの引数を渡すためにSMを伝える方法を示しました)。代わりに私が行う場合:

ObjectFactory.Initialize(x => 
{ 
    x.BuildInstancesOf<HttpContext>() 
     .TheDefault.Is.ConstructedBy(() => HttpContext.Current); 
    x.ForRequestedType<IUserProvider>() 
     .TheDefault.Is.OfConcreteType<HttpContextUserProvider>(); 
}); 

私はそれが動作するようになる。私が発見した後にこれをやった:http://codebetter.com/blogs/jeremy.miller/archive/2008/03/20/if-you-need-something-in-structuremap-but-you-can-t-build-it-with-new.aspx


編集:ブラッドの答えに

おかげで、私は私がのHttpContextに優れたハンドルを持ってを考える。彼の答えは間違いなく機能しますが、クラス内でHttpContext.Currentを呼び出すのが好きではないかどうかはわかりません(依存関係は隠れているようですが、私はこのようなことについては熟知していません)。

上記のコードは、私の知る限りのHttpContextを注入するために働く必要があります。 Matt Hinzeは、HttpContextから必要なものがすべてUser.Identity.Nameである必要がある場合、私のデザインは明示的に(HttpContextの周囲にIが必要なものだけを公開するようにする)必要があるという点を追加しました。これは良い考えだと思う。ユーザー名を:

事は、私はちょっと文字列のみに依存する必要が本当に私のサービスを実現して昼食を超えています。それがIUserProviderに依存することは、あまり価値がないかもしれません。だから私はそれがHttpContextに依存することを望んでいないことを知っている、私は必要なすべてが文字列(userName)であることを知っている - 私はこの接続を作るために十分なStructureMap fooを学ぶことができるかどうかを確認する必要があります。 (*)。

+0

コンストラクタがHttpContextの依存関係を持つとき、IoCはHttpContext.Currentのインスタンスを渡します。コンストラクタにIUserProviderの依存関係がある場合、IoCはHttpContextUserProviderの新しいインスタンスをインスタンス化し、コンストラクタに渡します。 –

+0

StructureMapインターフェイスが正しく読み取ります。私の混乱は、私は2つの部分で考える:1)ForRequestedTypeをたった今使用したことがある - 代わりにBuildInstancesOfをいつ壊すべきかを私は知っているだろうか(私はおそらくこれをグーグルにすることができる - 簡単な質問)2)そのStructureMapはHttpContext.Currentを取得する方法を知っていますか?私は、HttpContextがちょっと混乱させて、どこでも魔法のように浮かんでいるようだと思います。私はそれを得るために行くことができる単一の源について考えることはできません。他のすべてがより明確な情報源を持っているからです。 – anonymous

+0

確かに私の解決策はうまくいかず、ハードコアエラーでさえ、内部例外はJITの制限について何か言いました... wow – sirrocco

3

なぜあなたは気にしないのですか?HttpContext.CurrentをHttpContextUserProviderで直接使用しているようですが、これは正しいことです。別のHttpContextに置き換えることは決してありません...

+0

Yah ...私は* HttpContextを取得するとは思わない。私はコンストラクタ経由で何かを渡すことに慣れていたと思いますが、HttpContextはグローバルに存在するようです。 – anonymous

+0

さて、戻り値HttpContext.Current.User.Identity.Name;それは動作します。私はちょっとここでの取り込みが遅いと思うが、現在のHttpContextを見つける方法を知っている責任を持っているHttpContextの静的プロパティを更新している。唯一の欠点は、静的なプロパティや型を渡すことができないので、コンストラクタインジェクションを介してHttpContextに依存することは明白ではありませんか?あなたはHttpContext.Currentを返すIHttpContextProviderのようなラッパーを作ることができます。そして、何かがHttpContextに依存することを知っていますか?それともダムなの? – anonymous

+0

HttpContextを、Webを参照していないサービスレイヤーにどのように注入しますか?これは、レコード/データセットが現在のユーザーに依存するユースケースのシナリオでしょうか? (asp.net mvc2)... – Haroon

9

HttpContextUserProviderの代わりにHttpContextBaseを使用する必要があります。これはデフォルトのHttpContextという抽象概念であり、モックを作成し、UnitTestsを記述し、依存関係を注入することができます。

public class SomethingWithDependenciesOnContext 
{ 
    public SomethingWithDependenciesOnContext(HttpContextBase context) { 
     ... 
    } 

    public string UserName 
    { 
     get {return context.User.Identity.Name;} 
    } 
} 

ObjectFactory.Initialize(x => 
      x.For<HttpContextBase>() 
      .HybridHttpOrThreadLocalScoped() 
      .Use(() => new HttpContextWrapper(HttpContext.Current));