0

現在、私の ThingController のメソッドはすべて、リソースを識別する id パラメータを取ります。つまり、URL は /{controller}/{action}/{id} です。もちろん、すべてのメソッドが最初に行うことは、var thing = thingFactory.Get(id) です。現在、モノは、複数のユーザーとセッションで共有される、ライ​​ブでスレッドセーフなランタイム オブジェクトです。

だから私ができるようにしたいのは、DI フレームワークに id を使用してカスタム スコープ (「ライフスタイル?」) からモノをフェッチし、それを要求ごとのコントローラーに挿入させることです。その ID のものがまだ存在しない場合は、新しい Thing も作成する必要があります。

4

2 に答える 2

2

すべてのメソッドで「var thing = thingFactory.Get(id)」行を削除するためにコントローラーに Thing を挿入しようとしている場合は、ASP.NET MVC カスタム モデル バインダーを使用して、開始前に取得を実行できます。メソッドコード。

ルートが /{controller}/{action}/{id} のようになっている場合、id で値を検索します。

モデル バインディングにより、メソッド シグネチャは次のようになります。

public ActionResult SomeDetails(int id, Thing thing)
{

モデル バインディングと検証は、メソッド コードが実行される前に発生します。DefaultModelBinder は、FormCollection またはその他の非永続的なソースからのみクラスを設定します。

私がお勧めする秘訣は、ルックアップを実行する Thing クラスにカスタム モデル バインダー (IModelBinder) を提供することです。DefaultModelBinder から派生させ、IThingFactory を注入し、BindModel() をオーバーライドして、独自の方法でルックアップを行います。

public class ThingModelBinder : DefaultModelBinder
{
    IThingFactory ThingFactory;

    public ThingModelBinder(IThingFactory thingFactory)
    {
        this.IThingFactory = thingFactory;
    }

    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        Thing thing = new Thing();

        string id_string = controllerContext.RouteData.Values["id"].ToString();
        int id = 0;
        Int32.TryParse(id_string, out id);
        var thing = thingFactory.Get(id);

        return thing;
    }

    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
        {
            throw new ArgumentNullException("bindingContext");
        }

        // custom section
        object model = this.CreateModel(controllerContext, bindingContext, typeof(Thing));

        // set back to ModelBindingContext
        bindingContext.ModelMetadata.Model = model;

        // call base class version
        // this will use the overridden version of CreateModel() which calls the Repository
        // object model = BindComplexModel(controllerContext, bindingContext);

        return base.BindModel(controllerContext, bindingContext);

    }

次に、既にコンテナーを作成している global.asax Application_Start() でモデル バインダーを構成します。

    // Custom Model Binders
    System.Web.Mvc.ModelBinders.Binders.Add(
        typeof(MyCompany.Thing)
        , new MyMvcApplication.ModelBinders.ThingModelBinder(
            WindsorContainer.Resolve<IThingFactory>()
            )
        );

これにより、カスタム モデル バインダーが呼び出されます。

通常の方法で Windsor の依存関係を解決します。

これは、私が行った投稿に基づいています。

于 2012-04-27T23:21:35.973 に答える
1

私があなたを正しく理解していればThings、コンテナに登録されている固定数があり、指定された ID を持つものを返すファクトリが必要であり、2 回言うと毎回Get(1)同じものを取得し、別のものを取得します。ThingGet(2)

これを実現する方法の 1 つは、次のようなTyped Factory Facilityを使用することです。

// This is the thing factory - it will create the thing if it has not already 
// been created with the given ID - if it is already created it will return 
// that instance
public interface IThingFactory
{
    Thing Get(int id);
}

// This is the thing - it has an ID and a method that you
// can call that keeps track of how many times it has been
// called (so you can be sure it is the same instance)
public class Thing
{
    private int _count;

    public Thing(int id)
    {
        Id = id;
    }

    public int Id { get; private set; }

    public int HowManyCalls()
    {
        return Interlocked.Increment(ref _count);
    }
}

// This is a typed factory selector to manage selecting the component from
// the container by using the name ("Thing" followed by the ID)
public class GetThingComponentSelector : ITypedFactoryComponentSelector
{
    public TypedFactoryComponent SelectComponent(MethodInfo method, 
                                                 Type type, 
                                                 object[] arguments)
    {
        return new TypedFactoryComponent("Thing" + arguments[0],
                                         typeof(Thing),
                                         new Arguments(arguments));
    }
}

// .... In the installer ....

// Register each thing with a different name that matches the ID
// and register a custom component selector and the thing factory
container
    .AddFacility<TypedFactoryFacility>()
    .Register(
        Component
            .For<Thing>()
            .Named("Thing1"),
        Component
            .For<Thing>()
            .Named("Thing2"),
        Component
            .For<GetThingComponentSelector>(),
        Component
            .For<IThingFactory>()
            .AsFactory(c => c.SelectedWith<GetThingComponentSelector>()));

// ... Some demo code (you do not need to resolve the factory directly)

// Now resolve the same thing twice and then a different thing and make sure
// Windsor has handled the lifestyle
var thing = container.Resolve<IThingFactory>().Get(1);
Console.WriteLine("ID should be 1 and is " + thing.Id 
    + ". Calls should be 1 and is " + thing.HowManyCalls());

thing = container.Resolve<IThingFactory>().Get(1);
Console.WriteLine("ID should be 1 and is " + thing.Id 
    + ". Calls should be 2 and is " + thing.HowManyCalls());

thing = container.Resolve<IThingFactory>().Get(2);
Console.WriteLine("ID should be 2 and is " + thing.Id 
    + ". Calls should be 1 and is " + thing.HowManyCalls());

そこでは、コンテナー内で ID を「名前」として使用し、カスタム セレクターを使用して名前を検索していることがわかります。おそらく他にも方法はあると思いますが、あなたの質問に基づいて、うまくいけば少なくとも始められるはずです。

于 2012-04-23T17:48:39.610 に答える