2017-04-21 87 views
0

我有一个名为IXmlStrategy的接口已声明的另一个接口是这样的:使用DI与ninject当接口具有其他接口签名

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()); 

不过,我得到一个运行时错误,因为国际奥委会不知道如何解决它的依赖性:

{“Message”:“发生错误。”,“ExceptionMessage”:“发生错误时试图创建一个类型为'IpdController'的控制器。确保控制器有一个无参数公共构造函数。“,”ExceptionType“:”System.InvalidOperationException“,”StackTrace“:”在System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage请求,HttpControllerDescriptor controllerDescriptor,Type控制器类型)在System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage请求)\ r \ n在System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()“,”InnerException“:{”Message“ :“发生错误”,“ExceptionMessage”:“使用从IXmlStrategy到XmlStrategy的绑定激活IXmlStrategy时出错\ r \ n没有构造函数可用于创建实现类型的实例。\ r \ n \ r \ n激活路径:\ r \ n 3)将依赖项IXmlStrategy注入到类型为IpdCommands \ r \ n的构造函数的参数xmlStrategy中2)将依赖项IIpdCommands注入到类型为IpdController的构造函数的参数ipdCommands中\ r \ n 1)请求IpdController \ r \ n \ r \ nSuggesti ons:\ r \ n 1)确保实现类型具有公共构造函数。\ r \ n 2)如果已经实现了Singleton模式,请使用与InSingletonScope()绑定。\ r \ n“,”ExceptionType“ :Ninject.Activation.Activation.Context.ResolveInternal(对象作用域)\ n \ Ninject.Activation上的“Ninject.ActivationException”,“StackTrace”:“at Ninject.Activation.Providers.StandardProvider.Create(IContext context)\ r \ n System.Linq.Enumerable.WhereSelectArrayIterator中的System.Linq.Enumerable.WhereSelectEnumerableIterator 2.MoveNext()\r\n at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable 1源())上的.Context.Resolve()\ r \ n Ninject.Activation.Providers.StandardProvider.Create(IContext context)\ r \ n at Ninject.Activation.Context.ResolveInternal(Object scope)\ r \ n at Ninject.Activation.Context.Resolve()\ r \ n at System。 Linq.Enumerable.WhereSelectEnumerableIterator 2.MoveNext()\r\n at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable 1来源)\ r \ n在System.Linq.Enumerable.Whe在Ninject.Activation.Providers.StandardProvider.Create(IContext上下文)中的\ r \ n \ n在Ninject.Activation.Context.ResolveInternal(对象作用域)\ r \ n中重新选择阵列查询器1..ctor(IEnumerable 1 source)\r\n at System.Linq.Enumerable.ToArray[TSource](IEnumerable 1个源代码)\ r \ n在System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(System.Linq.Enumerable.WhereSelectEnumerableIterator 2.MoveNext()\r\n at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable 1源)Ninject.Activation.Context.Resolve()\ r \ n(HttpRequestMessage请求,类型controllerType,Func '1 &活化剂)\ r \ n在System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage请求,HttpControllerDescriptor controllerDescriptor,类型controllerType)“}}

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

/// <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,但我不知道如何。有谁知道如何让Ninject通过IXmlStrategy.IGetPersonNameXmlStrategy解决依赖性问题?

回答

1

我希望有很多策略接口,我想把它们全部放在一次接口中,所以我不必注入10-20个IXmlStrategy变体。

不要这样做。你在做什么被描述为一个代码味道here

服务抽象不应该在他们的定义

在你的情况暴露其他服务的抽象,您IXmlStrategy服务抽象暴露从IGetPersonNameXmlStrategy抽象其定义。

把它们全部放在一次界面中,所以我不必注入10-20个IXmlStrategy变体。

这是违规的Interface Segregation Principle(ISP)。 ISP声明:

没有客户端应该被迫依赖它不使用的方法。

拥有如此广泛的接口会造成几件事情:

  • 接口将继续增长,这迫使你更新现有的实现也是如此。
  • 它使单元测试变得复杂,因为它不清楚被测试类所使用的依赖关系。
  • 当您不断向该接口添加服务时,该接口将成为Service Locator的一种形式。

相反,您应该让消费者依赖它所需的服务。不是抽象的抽象。在您的具体情况下,将IGetPersonNameXmlStrategy直接注入需要它的客户。

您拥有此类服务定位器类抽象的最可能原因是您违反了Single Responsibility Principle(SRP)。这一原则规定,班级应该专注于一项特定的工作,只有一项要求应该导致他们改变。当一个类有很多依赖关系时,这是SRP被违反的一个很好的指示。

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

而是应该进行重构。例如,您可以将您拥有的单一方法中的所有代码提取到它自己的类中。这给你留下了一个可以注入原始类的依赖关系。当你用所有方法做这件事时,你甚至可能完全删除原来的类,因为它现在可能已经失去了意义。

+1

嘿,我结束了重构该类,以便调用Soap服务和反序列化xml字符串到对象是在两个分开的类。我知道太多的接口注入是代码味道。还是要谢谢你的帮助。 –