2014-10-16 4 views
0

NancyFx를 기본 프레임 워크로 사용하는 REST 기반 웹 서비스를 개발하고 있습니다. 그러나, 나의 임무는 Spring.Net을 의존성 주입에 사용하도록 요구한다. 나는 C# (이 과제 이전에 주로 자바 코드로 작업 해왔다.) 또는 Spring 자체를 아직 경험하지 못했으며 Spring을 사용하여 커스텀 부트 스트 래퍼를 만드는 것에 관한 많은 정보를 찾을 수 없었다. IoC 컨테이너 또는 Ninject 또는 Unity와 같은 사전 구성된 부트 스트랩퍼가 없습니다.Spring.net에서 작동하도록 NancyFx를 구성하려면 어떻게해야합니까?

낸시와 스프링을 멋지게 만들 수있는 좋은 방법이 있습니까? 아니면 과제에 대한 Microsoft의 MVC 프레임 워크로 돌아가는 것이 나을 것입니까?

미리 감사드립니다.

+0

spring.net을 사용해야합니까? 그것은 지금 꽤 많이 죽었습니다. ... – Phill

+0

@Phill 슬프게도 그렇습니다. 나는 상당히 큰 어플리케이션에서 REST/MvC 레이어에 대한 개념 증명을 구축하고 있습니다. 이 응용 프로그램은 spring을 사용하며 대부분의 경우 종속성 주입의 다른 방법으로 전환하기 위해 다시 작성해야합니다. 현재 웹 양식을 사용하고 있습니다. (내 프로젝트는 주로 이러한 대안을 찾기 위해 고안되었습니다.) 그래서 내 프로젝트에 사용할 웹 프레임 워크를 선택할 수있는 옵션이 있습니다. – Stip

답변

1

스트립 45,

은 그리 복잡하지는 않지만 수월합니다. Spring.Net은 선언적 구성 컨테이너이고 TinyIoCContainer는 Register/Resolver 컨테이너입니다. 처음에는 개념의 차이에 대한 문제점을 볼 수 없지만 일반적으로 레지스터/유형 컨테이너를 등록하는 대부분의 경우 자동으로 채워집니다. 그 추상적이고 가상 메소드를 구현

NancyBootstrapperWithRequestContainerBase<TContainer> 

, 쉽게,하지만 당신은 더 많은 다음 60 개체 정의를 구성해야합니다 은 당신이 유도 할 수있다 NancyFx IOC의 컨테이너를 변경합니다. NancyFx의 새 릴리스에서 새로운 선택적 종속성을 만들면 그에 대한 알림을받지 않기 때문에 매우 복잡합니다.

저는 이제 양쪽 컨테이너에서 Spring.Net에서만 NancyModules을 호스팅 할 수 있도록 작업하고 있습니다. NancyFx 인프라 종속성은 여전히 ​​동적으로 발견되어 과거와 마찬가지로 컨테이너에 등록됩니다.

하나의 조언 : 나와 같은 전략을 사용하고 TinyIoCContainer에 스프링 프록시를 보내지 않으면 초기화시 충돌이 발생합니다.

0

이제 가장 좋은 방법은 bit of documentation을 읽고 Nancy Github organization에있는 다른 컨테이너 관련 부트 스트 래퍼 중 하나에서 영감을 얻는 것입니다. Ninject one. 구현을 확인하려면 새 부트 스트 래퍼에 대해 the tests NancyBootstrapperBase을 실행할 수 있습니다.

장래에 부트 스트 래퍼에 대한 요구 사항에 대한 더 나은 사양을 갖기를 바랍니다.

1

그래서 Christian Horsdal과 Luiz Carlos Faria의 제안을 결합하여 해결책을 찾았습니다. 낸시를 통해 작동하는 "Hello world"모듈을 주입 할 수있게되었습니다. 내가 마지막으로 수행 한 작업은 IApplicationContextTinyIoCContainer이 포함 된 DualContainer 클래스를 만들고이를 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); 
     }   
    } 
} 

그리고 마지막으로 액츄에이터 알 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; 
     } 
    } 
} 

도움 주셔서 감사합니다!