所以我通過結合Christian Horsdal和Luiz Carlos Faria的建議找到了解決方案。我現在已經設法通過Nancy注入了「Hello world」模塊。我最終做的是做一個DualContainer
類,同時包含IApplicationContext
和TinyIoCContainer
,並將它們實現爲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;
}
}
}
感謝您的幫助!
你必須使用spring.net嗎?現在幾乎已經死了 - 一天... – Phill 2014-10-17 01:54:33
@Phill很遺憾的是。我正在爲一個相當大的應用程序構建REST/MvC層的概念證明。這個應用程序使用了spring,並且很可能需要進行重寫以切換到另一種依賴注入方法。 它目前使用Web表單來表達它的視圖(我的項目主要是爲了找到這些替代方案),這就是爲什麼我確實有選擇選擇我的項目使用哪個Web框架的選項。 – Stip 2014-10-17 07:50:31