简体   繁体   English

如何使用Castle Windsor的基本接口注册服务工厂模式

[英]How to register Service Factory Pattern using base interface with Castle Windsor

I am running into an issue and i can't figure out how to solve for it. 我遇到了一个问题,我不知道该如何解决。 I basically have a factory pattern set up as such: 我基本上设置了这样的工厂模式:

This is my base interface 这是我的基本界面

public interface IReportedIssueManager
{
    Task<BaseManagerResponse> ManageRequest(ReportedIssueRequest request);
}

And then I have a factory class which will handle which service to return based on a certain type (createReportedXIssueManager, or createReportedYIssueManager, or createReportedZIssueManager). 然后,我有一个工厂类,该类将处理基于某种类型(createReportedXIssueManager或createReportedYIssueManager或createReportedZIssueManager)返回的服务。 In my controller I would create an instance of this class and call this method and pass through a type: 在我的控制器中,我将创建此类的实例,并调用此方法并传递一个类型:

public class ReportedIssueFactory : IReportedIssueFactory
    {
        private readonly ICreateReportedXIssueManager createReportedXIssueManager;
        private readonly ICreateReportedYIssueManager createReportedYIssueManager;
        private readonly ICreateReportedZIssueManager createReportedZIssueManager;

        public ReportedIssueFactory(
            ICreateReportedXIssueManager createReportedXIssueManager,
            ICreateReportedYIssueManager createReportedYIssueManager,
            ICreateReportedZIssueManager createReportedZIssueManager)
        {
            this.createReportedXIssueManager = createReportedXIssueManager;
            this.createReportedYIssueManager= createReportedYIssueManager;
            this.createReportedZIssueManager= createReportedZIssueManager;
        }

        public async Task<IReportedIssueManager> ReportIssue(int issueTypeId)
        {
            var issueType = (IssueType)issueTypeId;
            switch(issueType)
            {
                case IssueType.Listing:
                    return createReportedXIssueManager;
                case IssueType.Post:
                    return createReportedYIssueManager;
                case IssueType.User:
                    return createReportedZIssueManager;
                default:
                    throw new ValidationException(ReportedIssuesServiceResources.UnknownIssueType);
            }
        }
    }

and each of those services are set up as such: 这些服务均按以下方式设置:

public interface ICreateReportedXIssueManager : IReportedIssueManager
    {
        Task<BaseManagerResponse> ManageRequest(CreateReportedXIssueRequest request);
    }

and 

public interface ICreateReportedYIssueManager : IReportedIssueManager
    {
        Task<BaseManagerResponse> ManageRequest(CreateReportedYIssueRequest request);
    }

and 

public interface ICreateReportedZIssueManager : IReportedIssueManager
    {
        Task<BaseManagerResponse> ManageRequest(CreateReportedZIssueRequest request);
    }

and finally in my controller i would call something like this: 最后在我的控制器中,我会这样调用:

var manager = await _reportedIssueFactory.ReportIssue(IssueTypeId);
var response = await manager.ManageRequest(request);

My problem is that since this is a factory pattern, i think Windsor expects a service of the same name as the base interface? 我的问题是,由于这是工厂模式,因此我认为Windsor希望提供与基本接口同名的服务?

I get the following error: 我收到以下错误:

No component for supporting the service System.Threading.Tasks.Task`1[[.....ReportedIssues.IReportedIssueManager]] 没有支持服务System.Threading.Tasks.Task`1 [[..... ReportedIssues.IReportedIssueManager]]的组件

Does anyone know how to properly register to Windsor in this case? 在这种情况下,有人知道如何正确向温莎注册吗? Any help greatly appreciated, thanks! 任何帮助,不胜感激,谢谢!

Based on the error message, you're trying to inject Task<IReportedIssueManager> instead of your factory. 根据错误消息,您尝试注入Task<IReportedIssueManager>而不是工厂。 That might be all you need to know. 那可能就是您所需要知道的。

You also don't need to have a "base interface" and then another interface for each implementation. 您也不需要为每个实现都拥有一个“基本接口”和另一个接口。 The point of the one interface is that it can have multiple implementations. 一个接口的要点是它可以具有多个实现。 If we have multiple implementations of the one interface, then declaring inherited interfaces, one per implementation, is redundant. 如果我们有一个接口的多个实现,则声明继承的接口(每个实现一个)是多余的。

In other words, whatever your factory returns will be an implementation of IReportedIssueManager cast as IReportedIssueManager . 换句话说,无论您的工厂返回什么,都是将IReportedIssueManagerIReportedIssueManager Downstream code won't know whether it also implements ICreateReportedXIssueManager , ICreateReportedYIssueManager , or ICreateReportedZIssueManager . 下游代码不知道它是否也实现ICreateReportedXIssueManagerICreateReportedYIssueManagerICreateReportedZIssueManager There might be no reason at all for those interfaces to exist. 这些接口可能根本没有理由存在。 Even if there is a reason, it's not relevant here if the caller expects and receives IReportedIssueManager . 即使有原因,如果调用方期望并接收IReportedIssueManager ,则此处也不相关。


Windsor provides a way to create a factory. 温莎提供了一种创建工厂的方法。 It's not much more concise, but it does result in resolving everything from the container each time it's created. 它不是很简洁,但是确实会在每次创建容器时解决容器中的所有问题。

First, regardless of how you implement the factory there's no reason for it to be asynchronous. 首先,无论您如何实现工厂,都没有理由使其异步。 It's just creating an object. 它只是创建一个对象。 Async is for longer-running I/O processes where the thread can be freed up to do something else while some response is pending. 异步用于运行时间较长的I / O进程,在该进程中,可以在某些响应挂起时释放线程以执行其他操作。 Here's a synchronous interface: 这是一个同步接口:

public interface IReportedIssueFactory
{
    // I used the enum here, but you could use the int instead.
    IReportedIssueManager CreateIssueManager(IssueType issueType);
}

In your dependency registration, add the TypedFactoryFacility to your container: 在依赖项注册中,将TypedFactoryFacility添加到您的容器中:

container.AddFacility<TypedFactoryFacility>();

Then register all of the implementations of IReportedIssueManager , giving them names (which will be important later.) Since the point is that they all implement IReportedIssueManager , for the purpose of this factory it doesn't matter if those classes implement other interfaces. 然后注册IReportedIssueManager所有实现,并为其指定名称(稍后将很重要。)由于要点是它们都实现了IReportedIssueManager ,对于本工厂而言,这些类是否实现其他接口并不重要。 Register them according to their concrete types. 根据其具体类型进行注册。

For this example I'm using the names of types to name the dependencies just because it avoids adding a "magic string" constant. 对于此示例,我使用类型的名称来命名依赖关系,只是因为它避免添加“魔术字符串”常量。 The actual names can be whatever you choose, but they're not important except that you use them elsewhere. 实际名称可以是您选择的任何名称,但是除了在其他地方使用它们之外,它们并不重要。

container.Register(
    Component.For<IReportedIssueManager, CreateReportedXIssueManager>()
        .Named(typeof(CreateReportedXIssueManager).FullName),
    Component.For<IReportedIssueManager, CreateReportedYIssueManager>()
        .Named(typeof(CreateReportedYIssueManager).FullName),
    Component.For<IReportedIssueManager, CreateReportedZIssueManager>()
        .Named(typeof(CreateReportedZIssueManager).FullName)
);

Next, create a class which will take an input (in this case the issueTypeId ) and return the name of the correct dependency: 接下来,创建一个将接受输入的类(在本例中为issueTypeId ),并返回正确依赖项的名称

public class IssueManagerSelector : DefaultTypedFactoryComponentSelector
{

    protected override string GetComponentName(MethodInfo method, object[] arguments)
    {
        var issueType = (IssueType)arguments[0];
        switch (issueType)
        {
            case IssueType.Listing:
                {
                    return typeof(CreateReportedXIssueManager).FullName;
                }
            case IssueType.Post:
                {
                    return typeof(CreateReportedYIssueManager).FullName;
                }
            case IssueType.User:
                {
                    return typeof(CreateReportedZIssueManager).FullName;
                }
            default:
                // So I didn't have to create an exception type as I tested.
                throw new Exception("Unknown type");
        }
    }
}

Finally, register the following with your container: 最后,在您的容器中注册以下内容:

container.Register(Component.For<IReportedIssueFactory>()
    .AsFactory(new IssueManagerSelector()));

You don't need to actually create an implementation of IReportedIssueFactory . 您不需要实际创建IReportedIssueFactory的实现。 You can just inject the interface and Windsor supplies the implementation. 您只需注入接口,Windsor即可提供实现。

It will do the following: - When you call CreateIssueManager it will pass your IssueType argument to the GetComponentName method of IssueManagerSelector . 它将执行以下操作: -当你调用CreateIssueManager将您传递IssueType参数传递给GetComponentName的方法IssueManagerSelector - That method will select a component name and return it. -该方法将选择一个组件名称并返回它。 - The factory will then resolve the component with that name and return it. -工厂随后将解析具有该名称的组件并将其返回。

The factory works by convention. 这家工厂按惯例工作。 Windsor assumes that a factory interface method that returns something is the "create" method. Windsor假定返回某些内容的工厂接口方法是“ create”方法。 That's why we didn't need to give it a particular name. 这就是为什么我们不需要给它起一个特定的名字的原因。

Here's a unit test to ensure that it works as expected: 这是一个单元测试,以确保它能按预期工作:

[TestMethod]
public void WindsorFactoryTest()
{
    var container = new WindsorContainer();
    container.AddFacility<TypedFactoryFacility>();
    container.Register(
        Component.For<IReportedIssueManager, CreateReportedXIssueManager>()
            .Named(typeof(CreateReportedXIssueManager).FullName),
        Component.For<IReportedIssueManager, CreateReportedYIssueManager>()
            .Named(typeof(CreateReportedYIssueManager).FullName),
        Component.For<IReportedIssueManager, CreateReportedZIssueManager>()
            .Named(typeof(CreateReportedZIssueManager).FullName)
    );
    container.Register(Component.For<IReportedIssueFactory>()
        .AsFactory(new IssueManagerSelector()));

    var factory = container.Resolve<IReportedIssueFactory>();
    Assert.IsInstanceOfType(factory.CreateIssueManager(IssueType.Listing), typeof(CreateReportedXIssueManager));
    Assert.IsInstanceOfType(factory.CreateIssueManager(IssueType.Post), typeof(CreateReportedYIssueManager));
    Assert.IsInstanceOfType(factory.CreateIssueManager(IssueType.User), typeof(CreateReportedZIssueManager));

}

Finally, here is Windsor's documentation . 最后,这是Windsor的文档

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM