繁体   English   中英

当接口具有其他接口的签名时,将DI与ninject一起使用

[英]Using DI with ninject when interface has signature of other interfaces

我有一个名为IXmlStrategy的接口,它已经声明了另一个接口,如下所示:

namespace IceServices.Business.Interfaces.Strategies
{
    public interface IXmlStrategy
    {
        IGetPersonNameXmlStrategy GetPersonNameXmlStrategy { get; }
    }
}

我希望会有许多策略接口,并且我想将所有接口都放在一个接口中,因此不必注入10-20个IXmlStrategy变体。

这是我使用DI的课程:

using System.Linq;
using IceServices.Business.Interfaces.Commands;
using IceServices.Business.Interfaces.Configurations;
using IceServices.Business.Interfaces.Deserializers;
using IceServices.Business.Interfaces.Mappers;
using IceServices.Business.Interfaces.Services;
using IceServices.Business.Interfaces.Strategies;
using IceServices.DomainObjects.ResponseObjects;

namespace IceServices.Business.Commands
{
    public class IpdCommands : IIpdCommands
    {
        private readonly ISoapService _soapService;
        private readonly IUrlConfigurations _urlConfigurations;
        private readonly IXmlDeserializer _xmlDeserializer;
        private readonly IDomainObjectMapper _domainObjectMapper;
        private readonly IXmlStrategy _xmlStrategy;

        public IpdCommands(ISoapService soapService, IUrlConfigurations urlConfigurations, IXmlDeserializer xmlDeserializer, IDomainObjectMapper domainObjectMapper, IXmlStrategy xmlStrategy)
        {
            _soapService = soapService;
            _urlConfigurations = urlConfigurations;
            _xmlDeserializer = xmlDeserializer;
            _domainObjectMapper = domainObjectMapper;
            _xmlStrategy = xmlStrategy;
        }

        public PersonNameResponse GetPersonName(int id)
        {
            var webServiceXmlString = _xmlStrategy.GetPersonNameXmlStrategy.GetXml(id.ToString());
            var listOfProperties = typeof(PersonNameResponse).GetProperties().Select(expr => expr.Name);

            var xmlStringResponse = _soapService.CallWebService(_urlConfigurations.GetPersonFirstname, webServiceXmlString);
            var stringArrayOfProperties = listOfProperties as string[] ?? listOfProperties.ToArray();
            var dictionaryData = _xmlDeserializer.DeserializeXmlToDictionary(stringArrayOfProperties, xmlStringResponse);
            return _domainObjectMapper.MapDictionaryToObject<PersonNameResponse>(dictionaryData, stringArrayOfProperties);
        }
    }
}

如您所见,我正在像这样调用GetPersonNameXmlStrategy.GetXml(id):

  var webServiceXmlString = _xmlStrategy.GetPersonNameXmlStrategy.GetXml(id.ToString());

但是我收到一个运行时错误,因为IOC不了解如何解决它的依赖关系:

{“ Message”:“发生错误。”,“ ExceptionMessage”:“尝试创建类型为'IpdController'的控制器时发生错误。请确保该控制器具有无参数的公共构造函数。”,“ ExceptionType”: System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create上的“ System.InvalidOperationException”,“ StackTrace”:“(System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(httpRequestMessage request,HttpControllerDescriptor controllerDescriptor,type controllerType)\\ r \\ n HttpRequestMessage请求)\\ r \\ n位于System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()“,” InnerException“:{” Message“:”发生了错误。“,” ExceptionMessage“:”激活IXmlStrategy时出错使用从IXmlStrategy到XmlStrategy的绑定\\ r \\ n没有构造函数可用于创建实现类型的实例。\\ r \\ n \\ r \\ n激活路径:\\ r \\ n 3)将依赖项IXmlStrategy注入参数ipStrategy类型的构造函数的xmlStrategy \\ r \\ n 2)注入de 将ImpdCommands插入IpdController类型的构造函数的参数ipdCommands中\\ r \\ n 1)请求IpdController \\ r \\ n \\ r \\ n建议:\\ r \\ n 1)确保实现类型具有公共构造函数。\\ r \\ n 2)如果您已经实现了Singleton模式,请改为使用InSingletonScope()进行绑定。\\ r \\ n“,” ExceptionType“:” Ninject.ActivationException“,” StackTrace“:”在Ninject.Activation.Providers.StandardProvider.Create(IContext) context)\\ r \\ n在Ninject.Activation.Context.ResolveInternal(对象范围)\\ r \\ n在Ninject.Activation.Context.Resolve()\\ r \\ n在System.Linq.Enumerable.WhereSelectEnumerableIterator 2.MoveNext()\\r\\n at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable 1源)\\ r \\ n,位于System.Linq.Enumerable.WhereSelectArrayIterator 2.MoveNext()\\r\\n at System.Linq.Buffer 1..ctor (IEnumerable 1 source)\\r\\n at System.Linq.Enumerable.ToArray[TSource](IEnumerable 1源)\\ r \\ n在Ninject.Activation.Providers.StandardProvider.Create(IContext上下文)\\ r \\ n在Ninject。激活 ion.Context.ResolveInternal(对象作用域)\\ r \\ n在Ninject.Activation.Context.Resolve()\\ r \\ n在System.Linq.Enumerable.WhereSelectEnumerableIterator 2.MoveNext()\\r\\n at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable 1源)\\ r \\ n在System.Linq.Enumerable.WhereSelectArrayIterator 2.MoveNext()\\r\\n at System.Linq.Buffer 1. 2.MoveNext()\\r\\n at System.Linq.Buffer 。ctor(IEnumerable 1 source)\\r\\n at System.Linq.Enumerable.ToArray[TSource](IEnumerable 1源)\\ r \\ n在Ninject.Activation.Providers.StandardProvider.Create(IContext上下文)\\ r \\ n在Ninject.Activation.Context.ResolveInternal(对象范围) \\ r \\ n在Ninject.Activation.Context.Resolve()\\ r \\ n在System.Linq.Enumerable.WhereSelectEnumerableIterator 2.MoveNext()\\r\\n at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable 1 source )\\ r \\ n在System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage请求,类型controllerType,Func`1&激活器)\\ r \\ n在System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpReq uestMessage请求,HttpControllerDescriptor controllerDescriptor,类型controllerType)“}}

这是我在Ninject.WebCommon中的IOC设置:

/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
    kernel.Bind<IIpdCommands>().To<IpdCommands>();
    kernel.Bind<IUrlConfigurations>().To<UrlConfigurations>();
    kernel.Bind<IXmlDeserializer>().To<XmlDeserializer>();
    kernel.Bind<IXmlDocumentFactory>().To<XmlDocumentFactory>();
    kernel.Bind<IDomainObjectMapper>().To<DomainObjectMapper>();
    kernel.Bind<ISoapService>().To<SoapService>();

    kernel.Bind<IXmlStrategy>().To<XmlStrategy>();
    kernel.Bind<IGetPersonNameXmlStrategy>().To<GetPersonNameXmlStrategy>();
}  

我需要更改IGetPersonNameXmlStrategy绑定的工作方式,但不确定如何。 有谁知道我怎样才能通过IXmlStrategy.IGetPersonNameXmlStrategy来解决Ninject问题?

我希望会有许多策略接口,并且我想将所有接口都放在一个接口中,因此不必注入10-20个IXmlStrategy变体。

不要这样 您在做什么在这里被描述为代码气味:

服务抽象不应在其定义中公开其他服务抽象

对于您的情况,您的IXmlStrategy服务抽象从其定义中公开IGetPersonNameXmlStrategy抽象。

将它们全部放入一个接口中,这样我就不必注入10-20个IXmlStrategy变体。

这是违反接口隔离原则 (ISP)的行为。 ISP指出:

不应强迫任何客户端依赖其不使用的方法。

具有如此宽的界面将导致以下几点:

  • 该界面将保持增长,这迫使您也必须更新现有的实现。
  • 它使单元测试复杂化,因为不清楚测试中的类使用什么依赖项。
  • 当您继续向该接口添加服务时,该接口将成为Service Locator的一种形式。

相反,您应该简单地让使用者依赖于它所需要的服务。 不在抽象之上。 在您的特定情况下,将IGetPersonNameXmlStrategy直接注入需要它的使用者。

您具有类似服务定位符的抽象的最可能原因是因为您违反了单一职责原则 (SRP)。 这项原则规定,班级应专注于一项特定的工作,只有一项要求才能使他们发生变化。 当一个类具有许多依赖关系时,就很好地表明违反了SRP。

违反SRP的类倾向于具有许多依赖项的构造函数。 这称为构造函数过度注入。 但是,构造函数过度注入是一种症状。 您可以通过对依赖项进行分组来解决注入过多问题,但这不能解决根本原因。 根本问题是该类过于复杂,将这些依赖项组合在一起无法解决该问题。

相反,应该进行重构。 例如,您可以将单个方法中拥有的所有代码提取到其自己的类中。 这样就只剩下一种可以注入到原始类中的依赖项。 当使用所有方法执行此操作时,您甚至可以完全删除原始类,因为它现在可能已失去其含义。

暂无
暂无

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

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