如何配置NancyFx以使用Spring.net?

时间:2014-10-16 12:24:19

标签: c# spring.net nancy

我正在使用基于REST的Web服务,使用NancyFx作为底层框架。但是,我的任务要求我使用Spring.Net进行依赖注入。我对C#(我在这个任务之前大部分都在研究Java代码)或Spring本身都没有太多的经验,而且我还没有找到很多关于使用Spring制作自定义引导程序的信息。 IoC容器,也没有像Ninject或Unity那样的预配置引导程序。

是否有一种很好的方法可以让Nancy和Spring玩得很好,或者我最好还是回到微软的MVC框架来完成我的工作?

提前多多感谢。

3 个答案:

答案 0 :(得分:1)

Strip45,

不是很复杂,但是很健康。 Spring.Net是一个声明性配置容器,TinyIoCContainer是一个Register / Resolver容器。也许初看起来你看不出概念差异的问题,但一般来说,寄存器/解析器容器会自动填充,大多数情况下会发现注册它们的类型。 要更改NancyFx IoC容器,您可以从:

NancyBootstrapperWithRequestContainerBase<TContainer>

实现其抽象和虚拟方法很简单,但您需要配置超过60个对象定义。这非常复杂,因为如果在NancyFx的新版本中他们创建了一个新的可选依赖项,您将不会收到通知。

我现在正努力允许两个容器一起工作,只在Spring.Net上托管NancyModules。任何特定的NancyFx基础结构依赖关系仍然可以动态发现并像过去一样在容器上注册。

一个建议:如果你使用相同的策略,不向TinyIoCContainer发送弹簧代理,它会在初始化时崩溃。

答案 1 :(得分:1)

所以我通过结合Christian Horsdal和Luiz Carlos Faria的建议找到了解决方案。我现在已经成功地注入了一个工作注射&#34; Hello world&#34;模块通过南希。我最终做的是制作一个包含DualContainerIApplicationContext的{​​{1}}课程,并将其实施为TinyIoCContainer。我在大多数操作中使用了TinyIoCContainer,只有在对象XML中有模块定义时才调用Spring容器。

我实现它的方式确实假设模块在其类名下注册,所以这是需要考虑的事情。

DualContainer类:

NancyBootstrapperWithRequestContainerBase

Spring对象定义(configSections用于数据库配置,不用于此示例):

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
            };
        }
    }
}

自定义引导程序(最不可能是最干净的解决方案,但它对我有用):

 <?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>

最后,实际的NancyModule:

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

感谢帮助人员!

答案 2 :(得分:0)

现在最好的办法是阅读bit of documentation,然后从Nancy Github organization找到的其他容器特定引导程序中汲取灵感 - 例如Ninject one。 要验证实现,您可以对新的引导程序运行the tests NancyBootstrapperBase

希望将来我们会有更好的规范来满足bootstrappers的要求。