2014-10-16 59 views
0

我正在使用NancyFx作爲基礎框架的基於REST的webservice。然而,我的任務需要我使用Spring.Net進行依賴注入。我在C#方面經驗不足(我大部分都是在這個任務之前一直在處理Java代碼)還是Spring本身,而且我還沒有能夠找到很多關於使用Spring製作自定義引導程序的信息IoC容器,也沒有像Ninject或Unity這樣的預配置引導程序。如何配置NancyFx與Spring.net一起使用?

有沒有一種方法可以讓Nancy和Spring發揮出色,還是我會更好地迴歸微軟的MVC框架來完成我的任務?

非常感謝。

+0

你必須使用spring.net嗎?現在幾乎已經死了 - 一天... – Phill 2014-10-17 01:54:33

+0

@Phill很遺憾的是。我正在爲一個相當大的應用程序構建REST/MvC層的概念證明。這個應用程序使用了spring,並且很可能需要進行重寫以切換到另一種依賴注入方法。 它目前使用Web表單來表達它的視圖(我的項目主要是爲了找到這些替代方案),這就是爲什麼我確實有選擇選擇我的項目使用哪個Web框架的選項。 – Stip 2014-10-17 07:50:31

回答

1

Strip45,

不是很複雜,但是很有用。 Spring.Net是一個聲明式配置容器,TinyIoCContainer是一個Register/Resolver容器。也許第一眼看不出概念差異的問題,但一般情況下,註冊/解析器容器會自動填充,大多數情況下發現註冊類型。 要更改NancyFx IOC容器,你可能會得到來自:

NancyBootstrapperWithRequestContainerBase<TContainer> 

實現它的抽象和虛擬方法,這很容易,但是你需要配置60多個對象定義。這非常複雜,因爲如果在NancyFx的新版本中創建了新的可選依賴項,則不會收到通知。

我現在正在努力允許兩個容器一起工作,只在Spring.Net上託管NancyModules。任何具體的NancyFx基礎設施依賴關係仍然可以動態發現並在容器上註冊,就像過去一樣。一個建議:如果你使用同樣的策略,不會發送彈簧代理到TinyIoCContainer,它會在初始化時崩潰。

1

所以我通過結合Christian Horsdal和Luiz Carlos Faria的建議找到了解決方案。我現在已經設法通過Nancy注入了「Hello world」模塊。我最終做的是做一個DualContainer類,同時包含IApplicationContextTinyIoCContainer,並將它們實現爲NancyBootstrapperWithRequestContainerBase。對於大多數操作,我使用了TinyIoCContainer,只有在對象XML中存在模塊定義時才調用Spring容器。

我實現它的方式確實假設模塊是在其類名下注冊的,所以這是要考慮的事情。

的DualContainer類:

using Nancy.TinyIoc; 
using Spring.Context; 

namespace FORREST.WebService.General.Bootstrap 
{ 
public class DualContainer 
    { 
     public TinyIoCContainer TinyIoCContainer { get; set; } 
     public IApplicationContext ApplicationContext { get; set; } 

     public DualContainer GetChildContainer() 
     { 
      return new DualContainer 
      { 
       TinyIoCContainer = TinyIoCContainer.GetChildContainer(), 
       ApplicationContext = this.ApplicationContext 
      }; 
     } 
    } 
} 

彈簧對象定義(configSections用於數據庫配置,而不是用於該實施例):

<?xml version="1.0" encoding="utf-8" ?> 
    <objects xmlns="http://www.springframework.net" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"> 

     <object name="appConfigPropertyHolder" type="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer, Spring.Core"> 
     <property name="configSections"> 
      <value>appSettings</value> 
     </property> 
     </object> 

     <object id="HelloWorldSpringRestModule" type="FORREST.WebService.RESTApi.Modules.HelloWorldSpringRestModule"> 
     <property name="Message" value="Hello World!"/> 
     </object> 

    </objects> 

定製引導程序(而不是乾淨的解決方案最可能,但它對我有用):

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Reflection; 

using Nancy.Bootstrapper; 
using Nancy.TinyIoc; 
using Nancy; 
using Nancy.Diagnostics; 
using Spring.Context; 
using Spring.Context.Support; 

namespace FORREST.WebService.General.Bootstrap 
{ 
    /// <summary> 
    /// Class enabling the use of Spring injections in modules. 
    /// </summary> 
    public abstract class HybridNancyBootstrapperBase : NancyBootstrapperWithRequestContainerBase<DualContainer> 
    { 
     /// <summary> 
     /// Default assemblies that are ignored for autoregister 
     /// </summary> 
     public static IEnumerable<Func<Assembly, bool>> DefaultAutoRegisterIgnoredAssemblies = new Func<Assembly, bool>[] 
      { 
       asm => asm.FullName.StartsWith("Microsoft.", StringComparison.InvariantCulture), 
       asm => asm.FullName.StartsWith("System.", StringComparison.InvariantCulture), 
       asm => asm.FullName.StartsWith("System,", StringComparison.InvariantCulture), 
       asm => asm.FullName.StartsWith("CR_ExtUnitTest", StringComparison.InvariantCulture), 
       asm => asm.FullName.StartsWith("mscorlib,", StringComparison.InvariantCulture), 
       asm => asm.FullName.StartsWith("CR_VSTest", StringComparison.InvariantCulture), 
       asm => asm.FullName.StartsWith("DevExpress.CodeRush", StringComparison.InvariantCulture), 
       asm => asm.FullName.StartsWith("IronPython", StringComparison.InvariantCulture), 
       asm => asm.FullName.StartsWith("IronRuby", StringComparison.InvariantCulture), 
       asm => asm.FullName.StartsWith("xunit", StringComparison.InvariantCulture), 
       asm => asm.FullName.StartsWith("Nancy.Testing", StringComparison.InvariantCulture), 
       asm => asm.FullName.StartsWith("MonoDevelop.NUnit", StringComparison.InvariantCulture), 
       asm => asm.FullName.StartsWith("SMDiagnostics", StringComparison.InvariantCulture), 
       asm => asm.FullName.StartsWith("CppCodeProvider", StringComparison.InvariantCulture), 
       asm => asm.FullName.StartsWith("WebDev.WebHost40", StringComparison.InvariantCulture), 
      }; 

     /// <summary> 
     /// Gets the assemblies to ignore when autoregistering the application container 
     /// Return true from the delegate to ignore that particular assembly, returning true 
     /// does not mean the assembly *will* be included, a false from another delegate will 
     /// take precedence. 
     /// </summary> 
     protected virtual IEnumerable<Func<Assembly, bool>> AutoRegisterIgnoredAssemblies 
     { 
      get { return DefaultAutoRegisterIgnoredAssemblies; } 
     } 

     /// <summary> 
     /// Configures the container using AutoRegister followed by registration 
     /// of default INancyModuleCatalog and IRouteResolver. 
     /// </summary> 
     /// <param name="container">Container instance</param> 
     protected override void ConfigureApplicationContainer(DualContainer container) 
     { 
      AutoRegister(container, this.AutoRegisterIgnoredAssemblies); 
     } 

     /// <summary> 
     /// Resolve INancyEngine 
     /// </summary> 
     /// <returns>INancyEngine implementation</returns> 
     protected override sealed INancyEngine GetEngineInternal() 
     { 
      return this.ApplicationContainer.TinyIoCContainer.Resolve<INancyEngine>(); 
     } 

     /// <summary> 
     /// Create a default, unconfigured, container 
     /// </summary> 
     /// <returns>Container instance</returns> 
     protected override DualContainer GetApplicationContainer() 
     { 
      return new DualContainer 
      { 
       ApplicationContext = ContextRegistry.GetContext(), 
       TinyIoCContainer = new TinyIoCContainer() 
      };    
     } 

     /// <summary> 
     /// Register the bootstrapper's implemented types into the container. 
     /// This is necessary so a user can pass in a populated container but not have 
     /// to take the responsibility of registering things like INancyModuleCatalog manually. 
     /// </summary> 
     /// <param name="applicationContainer">Application container to register into</param> 
     protected override sealed void RegisterBootstrapperTypes(DualContainer applicationContainer) 
     { 
      applicationContainer.TinyIoCContainer.Register<INancyModuleCatalog>(this); 
     } 

     /// <summary> 
     /// Register the default implementations of internally used types into the container as singletons 
     /// </summary> 
     /// <param name="container">Container to register into</param> 
     /// <param name="typeRegistrations">Type registrations to register</param> 
     protected override sealed void RegisterTypes(DualContainer container, IEnumerable<TypeRegistration> typeRegistrations) 
     { 
      foreach (var typeRegistration in typeRegistrations) 
      { 
       switch (typeRegistration.Lifetime) 
       { 
        case Lifetime.Transient: 
         container.TinyIoCContainer.Register(typeRegistration.RegistrationType 
          , typeRegistration.ImplementationType).AsMultiInstance(); 
         break; 
        case Lifetime.Singleton: 
         container.TinyIoCContainer.Register(typeRegistration.RegistrationType 
          , typeRegistration.ImplementationType).AsSingleton(); 
         break; 
        case Lifetime.PerRequest: 
         throw new InvalidOperationException("Unable to directly register a per request lifetime."); 
        default: 
         throw new ArgumentOutOfRangeException(); 
       } 
      } 
     } 

     /// <summary> 
     /// Register the various collections into the container as singletons to later be resolved 
     /// by IEnumerable{Type} constructor dependencies. 
     /// </summary> 
     /// <param name="container">Container to register into</param> 
     /// <param name="collectionTypeRegistrations">Collection type registrations to register</param> 
     protected override sealed void RegisterCollectionTypes(DualContainer container, IEnumerable<CollectionTypeRegistration> collectionTypeRegistrations) 
     { 
      foreach (var collectionTypeRegistration in collectionTypeRegistrations) 
      { 
       switch (collectionTypeRegistration.Lifetime) 
       { 
        case Lifetime.Transient: 
         container.TinyIoCContainer.RegisterMultiple(collectionTypeRegistration.RegistrationType 
          , collectionTypeRegistration.ImplementationTypes).AsMultiInstance(); 
         break; 
        case Lifetime.Singleton: 
         container.TinyIoCContainer.RegisterMultiple(collectionTypeRegistration.RegistrationType 
          , collectionTypeRegistration.ImplementationTypes).AsSingleton(); 
         break; 
        case Lifetime.PerRequest: 
         throw new InvalidOperationException("Unable to directly register a per request lifetime."); 
        default: 
         throw new ArgumentOutOfRangeException(); 
       } 
      } 
     } 

     /// <summary> 
     /// Register the given module types into the container 
     /// </summary> 
     /// <param name="container">Container to register into</param> 
     /// <param name="moduleRegistrationTypes">NancyModule types</param> 
     protected override sealed void RegisterRequestContainerModules(DualContainer container, IEnumerable<ModuleRegistration> moduleRegistrationTypes) 
     { 
      foreach (var moduleRegistrationType in moduleRegistrationTypes) 
      { 
       container.TinyIoCContainer.Register(
        typeof(INancyModule), 
        moduleRegistrationType.ModuleType, 
        moduleRegistrationType.ModuleType.FullName). 
        AsSingleton(); 
       (container.ApplicationContext as IConfigurableApplicationContext).ObjectFactory. 
        RegisterResolvableDependency(moduleRegistrationType.ModuleType, 
        container.TinyIoCContainer.Resolve(moduleRegistrationType.ModuleType)); 
      } 
     } 

     /// <summary> 
     /// Register the given instances into the container 
     /// </summary> 
     /// <param name="container">Container to register into</param> 
     /// <param name="instanceRegistrations">Instance registration types</param> 
     protected override void RegisterInstances(DualContainer container, IEnumerable<InstanceRegistration> instanceRegistrations) 
     { 
      foreach (var instanceRegistration in instanceRegistrations) 
      { 
       container.TinyIoCContainer.Register(
        instanceRegistration.RegistrationType, 
        instanceRegistration.Implementation); 

       //Cast zodat het programmatisch kan worden gedaan 
       (container.ApplicationContext as IConfigurableApplicationContext).ObjectFactory.RegisterResolvableDependency(
        instanceRegistration.RegistrationType, 
        instanceRegistration.Implementation);    
      } 
     } 

     /// <summary> 
     /// Creates a per request child/nested container 
     /// </summary> 
     /// <returns>Request container instance</returns> 
     protected override sealed DualContainer CreateRequestContainer() 
     { 
      return this.ApplicationContainer.GetChildContainer(); 
     } 

     /// <summary> 
     /// Gets the diagnostics for initialisation 
     /// </summary> 
     /// <returns>IDiagnostics implementation</returns> 
     protected override IDiagnostics GetDiagnostics() 
     { 
      return this.ApplicationContainer.TinyIoCContainer.Resolve<IDiagnostics>(); 
     } 

     /// <summary> 
     /// Gets all registered startup tasks 
     /// </summary> 
     /// <returns>An <see cref="IEnumerable{T}"/> instance containing <see cref="IApplicationStartup"/> instances. </returns> 
     protected override IEnumerable<IApplicationStartup> GetApplicationStartupTasks() 
     { 
      return this.ApplicationContainer.TinyIoCContainer.ResolveAll<IApplicationStartup>(false); 
     } 

     /// <summary> 
     /// Gets all registered request startup tasks 
     /// </summary> 
     /// <returns>An <see cref="IEnumerable{T}"/> instance containing <see cref="IRequestStartup"/> instances.</returns> 
     protected override IEnumerable<IRequestStartup> RegisterAndGetRequestStartupTasks(DualContainer container, Type[] requestStartupTypes) 
     { 
      container.TinyIoCContainer.RegisterMultiple(typeof(IRequestStartup), requestStartupTypes); 
      return container.TinyIoCContainer.ResolveAll<IRequestStartup>(false); 
     } 

     /// <summary> 
     /// Gets all registered application registration tasks 
     /// </summary> 
     /// <returns>An <see cref="IEnumerable{T}"/> instance containing <see cref="IRegistrations"/> instances.</returns> 
     protected override IEnumerable<IRegistrations> GetRegistrationTasks() 
     { 
      return this.ApplicationContainer.TinyIoCContainer.ResolveAll<IRegistrations>(false); 
     } 

     /// <summary> 
     /// Retrieve all module instances from the container 
     /// </summary> 
     /// <param name="container">Container to use</param> 
     /// <returns>Collection of NancyModule instances</returns> 
     protected override sealed IEnumerable<INancyModule> GetAllModules(DualContainer container) 
     { 
      var nancyModules = container.TinyIoCContainer.ResolveAll<INancyModule>(false); 
      return nancyModules; 
     } 

     /// <summary> 
     /// Retreive a specific module instance from the container 
     /// </summary> 
     /// <param name="container">Container to use</param> 
     /// <param name="moduleType">Type of the module</param> 
     /// <returns>NancyModule instance</returns> 
     protected override sealed INancyModule GetModule(DualContainer container, Type moduleType) 
     { 
      INancyModule module; 
      try 
      { 
       module = (INancyModule) container.ApplicationContext.GetObject(moduleType.Name, moduleType); 
      } 
       //Niet geregistreerd in Spring, gebruik TinyIoCContainer om op te halen 
      catch (Spring.Objects.Factory.NoSuchObjectDefinitionException) 
      { 
       System.Diagnostics.Debug.WriteLine("Laad " + moduleType.Name + " uit TinyIoC in plaats van Spring"); 
       container.TinyIoCContainer.Register(typeof(INancyModule), moduleType); 
       module = container.TinyIoCContainer.Resolve<INancyModule>(); 
      }    
      return module; 
     } 

     /// <summary> 
     /// Executes auto registation with the given container. 
     /// </summary> 
     /// <param name="container">Container instance</param> 
     private static void AutoRegister(DualContainer container, IEnumerable<Func<Assembly, bool>> ignoredAssemblies) 
     { 
      var assembly = typeof(NancyEngine).Assembly; 
      container.TinyIoCContainer.AutoRegister(AppDomain.CurrentDomain.GetAssemblies() 
       .Where(a => !ignoredAssemblies.Any(ia => ia(a))) 
       , DuplicateImplementationActions.RegisterMultiple, t => t.Assembly != assembly); 
     }   
    } 
} 

最後,執行al NancyModule:

using FORREST.WebService.General; 
using FORREST.WebService.General.Modules; 
using Nancy; 
using Newtonsoft.Json; 

namespace FORREST.WebService.RESTApi.Modules 
{ 
    public class HelloWorldSpringRestModule : NancyModule 
    { 
     public string Message { get; set; } 
     public string Route_Base 
     { 
      get { return Configuratie.Api_Root + "/Hello"; } 
     } 

     public HelloWorldSpringRestModule() 
     { 
      Get[Route_Base] = HelloSpring; 
     } 

     protected internal Response HelloSpring(dynamic parameters) 
     { 
      var _response = (Response)(JsonConvert.SerializeObject(Message)); 
      return _response; 
     } 
    } 
} 

感謝您的幫助!

相關問題