Using Castle Windsor child containers to resolve a type with a specific instance

自闭症网瘾萝莉.ら 提交于 2019-12-21 05:41:15

问题


I'm currently using Castle Windsor's child container functionality to override the registration of a particular type with a specific instance in a factory method. I am using the child containers purely so that the registration is temporary for a single resolution - in other words, I don't want the registration to affect all resolutions for that type.

Perhaps some code will explain what I mean.

I have a Func which acts as a factory Func<IReportCategory, IReportCategoryViewModel> - I give it an implementation of an IReportCategory and it returns a new instance of an IReportCategoryViewModel. (IReportCategoryViewModel has a dependency on IReportCategory).

This is registered with Castle Windsor as follows:

        container.Register(
            Component.For<Func<IReportCategory, IReportCategoryViewModel>>().Instance(
                category => ResolveCategoryViewModelFactory(container, category)));

Where ResolveCategoryViewModelFactory is implemented as follows:

    private CategoryViewModel ResolveCategoryViewModelFactory(IWindsorContainer container, IReportCategory category)
    {
        using (IWindsorContainer childContainer = new WindsorContainer())
        {
            childContainer.Register(Component.For<IReportCategory>().Instance(category));
            container.AddChildContainer(childContainer);

            return childContainer.Resolve<IReportCategoryViewModel>();
        }
    }

What the above method achieves is the resolution of IReportCategoryViewModel, injecting the specific instance of IReportCategory as a dependency. If IReportCategoryViewModel has other dependencies that need satisfying, then these get automatically injected by the container.

I can subsequently use the Func as follows:

public class Test
{
    private readonly Func<IReportCategory, IReportCategoryViewModel> factory;

    public Test(Func<IReportCategory, IReportCategoryViewModel> factory)
    {
        this.factory = factory;
    }

    public void ResolveTest()
    {
        // Create a category (note: this would probably be resolved from the container in some way)
        IReportCategory category = new ReportCategory();

        // Call into the factory to resolve the view model
        IReportCategoryViewModel vm = factory(category);
    }
    ...

Question: Does this seem like a suitable thing to do? From the impression I get, child containers are not recommended in Castle Windsor - is there another way of achieving the same result?

Thanks for your help.


回答1:


Absolutely there are better ways to go, and the code you're using right now has a bug - it will try to release all the component instances you're resolving when you dispose of the child container, therefore they might be unusable (disposed) before you even get a chance to use them.

If I understand your explanation correctly it feels like a job for typed factories.




回答2:


Following Krzysztof's advice to use Typed Factories, here is how I implemented the above functionality. It is far more simpler than using child containers!

Firstly, create a factory interface which defines the signature of the factory method:

public interface ICategoryViewModelFactory
{
    CategoryViewModel Create(ReportCategory category);
} 

Next, ensure the TypedFactoryFacility is enabled in the container:

container.AddFacility<TypedFactoryFacility>();

Finally, register the factory interface with the container:

container.Register(
    Component.For<ICategoryViewModelFactory>()
        .AsFactory());

Now you can inject ICategoryViewModelFactory into your classes, and call the Create() method to create a new instance of CategoryViewModel:

public class SomeClass
{
    public SomeClass(ICategoryViewModelFactory categoryViewModelFactory)
    {
        // This would probably be resolved by the container (it's like this for the example)
        ReportCategory category = new ReportCategory();

        // Get Windsor to resolve the view model using the factory
        ReportCategoryViewModel vm = categoryViewModelFactory.Create(category);

        ....

Warning: The parameter name in the factory method needs to match the parameter name of the constructor of the object the factory creates. In the above example, the factory interface defines the method:

CategoryViewModel Create(ReportCategory category)

The constructor for CategoryViewModel must also have the parameter named "category":

public CategoryViewModel(ReportCategory category)

This is because the factory method is the equivalent of the following:

container.Resolve<CategoryViewModel>(new { category = paramPassedIntoFactoryMethod });


来源:https://stackoverflow.com/questions/8053092/using-castle-windsor-child-containers-to-resolve-a-type-with-a-specific-instance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!