SPRNET-1510 change SpringWebApiDependencyResolver to properly accept sep. config sources for child/nested contexts
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<objects xmlns="http://www.springframework.net">
|
||||
|
||||
<object type="Spring.Mvc4QuickStart.Controllers.SuffixNestedController, Spring.Mvc4QuickStart" singleton="false" >
|
||||
<property name="Suffix" value="***This message comes from a child Spring.NET context!***" />
|
||||
</object>
|
||||
|
||||
</objects>
|
||||
@@ -1,17 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<objects xmlns="http://www.springframework.net">
|
||||
<objects xmlns="http://www.springframework.net" default-autowire="constructor">
|
||||
|
||||
<object type="Spring.Mvc4QuickStart.Controllers.HomeController, Spring.Mvc4QuickStart" singleton="false" >
|
||||
<property name="Message" value="Welcome to ASP.NET MVC4 powered by Spring.NET!" />
|
||||
</object>
|
||||
|
||||
<object type="Spring.Mvc4QuickStart.Controllers.CountController, Spring.Mvc4QuickStart" singleton="false" />
|
||||
|
||||
<object type="Spring.Mvc4QuickStart.Controllers.SuffixController, Spring.Mvc4QuickStart" singleton="false" >
|
||||
<property name="Suffix" value="_Spring.NET_was_Here!" />
|
||||
</object>
|
||||
|
||||
<object type="Spring.Mvc4QuickStart.Controllers.OdataController, Spring.Mvc4QuickStart" singleton="false" />
|
||||
|
||||
|
||||
|
||||
<!--intentionally do NOT register the AccountController or the ValuesController with the container; demonstrates that the underlying
|
||||
default controller factory will properly (attempt to!) resolve all controllers not registered with Spring.NET
|
||||
using its default controller resolution behavoir-->
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<objects xmlns="http://www.springframework.net" default-autowire="constructor">
|
||||
|
||||
<!-- this obj is defined as a singleton and given an initial value for Count of 0
|
||||
so it can be easily verified as being instantiated only once by the ApplicationContext
|
||||
no matter how many child contexts are instatiated as part of WebAPI calls -->
|
||||
<object type="Spring.Mvc4QuickStart.Counter, Spring.Mvc4QuickStart">
|
||||
<property name="Count" value="0" />
|
||||
</object>
|
||||
|
||||
</objects>
|
||||
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
|
||||
namespace Spring.Mvc4QuickStart.Controllers
|
||||
{
|
||||
public class CountController : Controller
|
||||
{
|
||||
private readonly Counter _counter;
|
||||
|
||||
public CountController(Counter counter)
|
||||
{
|
||||
_counter = counter;
|
||||
}
|
||||
|
||||
public ActionResult Index()
|
||||
{
|
||||
ViewBag.Message = _counter.Count;
|
||||
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ namespace Spring.Mvc4QuickStart.Controllers
|
||||
[Queryable]
|
||||
public IQueryable<SampleDataItem> Get()
|
||||
{
|
||||
var campaigns = new[]
|
||||
var dataItems = new[]
|
||||
{
|
||||
new SampleDataItem { SomeProperty = 1 },
|
||||
new SampleDataItem { SomeProperty = 2 },
|
||||
@@ -25,7 +25,7 @@ namespace Spring.Mvc4QuickStart.Controllers
|
||||
new SampleDataItem { SomeProperty = 4 },
|
||||
};
|
||||
|
||||
return campaigns.AsQueryable();
|
||||
return dataItems.AsQueryable();
|
||||
}
|
||||
|
||||
// POST /api/odata
|
||||
|
||||
@@ -7,29 +7,29 @@ namespace Spring.Mvc4QuickStart.Controllers
|
||||
{
|
||||
public string Suffix { get; set; }
|
||||
|
||||
// GET /api/values
|
||||
// GET /api/suffix
|
||||
public IEnumerable<string> Get()
|
||||
{
|
||||
return new string[] { string.Format("value1{0}", Suffix), string.Format("value2{0}", Suffix) };
|
||||
return new string[] { string.Format("value1_{0}", Suffix), string.Format("value2_{0}", Suffix) };
|
||||
}
|
||||
|
||||
// GET /api/values/5
|
||||
// GET /api/suffix/5
|
||||
public string Get(int id)
|
||||
{
|
||||
return string.Format("value{0}", Suffix);
|
||||
return string.Format("value{0}_{1}", Suffix, id);
|
||||
}
|
||||
|
||||
// POST /api/values
|
||||
// POST /api/suffix
|
||||
public void Post(string value)
|
||||
{
|
||||
}
|
||||
|
||||
// PUT /api/values/5
|
||||
// PUT /api/suffix/5
|
||||
public void Put(int id, string value)
|
||||
{
|
||||
}
|
||||
|
||||
// DELETE /api/values/5
|
||||
// DELETE /api/suffix/5
|
||||
public void Delete(int id)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Web.Http;
|
||||
|
||||
namespace Spring.Mvc4QuickStart.Controllers
|
||||
{
|
||||
public class SuffixNestedController : ApiController
|
||||
{
|
||||
//same public API as SuffixController, only here so that its config can be shown to
|
||||
// be properly read out of a separate 'child' config file
|
||||
|
||||
public string Suffix { get; set; }
|
||||
|
||||
// GET /api/suffixnested
|
||||
public IEnumerable<string> Get()
|
||||
{
|
||||
return new string[] { string.Format("value1_{0}", Suffix), string.Format("value2_{0}", Suffix) };
|
||||
}
|
||||
|
||||
// GET /api/suffixnested/5
|
||||
public string Get(int id)
|
||||
{
|
||||
return string.Format("value{0}_{1}", Suffix, id);
|
||||
}
|
||||
|
||||
// POST /api/suffixnested
|
||||
public void Post(string value)
|
||||
{
|
||||
}
|
||||
|
||||
// PUT /api/suffixnested/5
|
||||
public void Put(int id, string value)
|
||||
{
|
||||
}
|
||||
|
||||
// DELETE /api/suffixnested/5
|
||||
public void Delete(int id)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Spring.Mvc4QuickStart
|
||||
{
|
||||
//intended to be instantiated as a singleton by the parent ApplicationContext so that it can keep track of its hit-count
|
||||
// as the page is visited (NOTE: this impl. is for demo purposes only and is obviously NOT threadsafe!)
|
||||
public class Counter
|
||||
{
|
||||
private int _count;
|
||||
public int Count
|
||||
{
|
||||
get { return _count++; }
|
||||
set { _count = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,5 +23,23 @@ namespace Spring.Mvc4QuickStart
|
||||
RouteConfig.RegisterRoutes(RouteTable.Routes);
|
||||
BundleConfig.RegisterBundles(BundleTable.Bundles);
|
||||
}
|
||||
|
||||
protected override System.Web.Http.Dependencies.IDependencyResolver BuildWebApiDependencyResolver()
|
||||
{
|
||||
//get the 'default' resolver, populated from the 'main' config metadata
|
||||
var resolver = base.BuildWebApiDependencyResolver();
|
||||
|
||||
//check if its castable to a SpringWebApiDependencyResolver
|
||||
var springResolver = resolver as SpringWebApiDependencyResolver;
|
||||
|
||||
//if it is, add additional config sources as needed
|
||||
if (springResolver != null)
|
||||
{
|
||||
springResolver.AddChildApplicationContextConfigurationLocation("file://~/Config/child_controllers.xml");
|
||||
}
|
||||
|
||||
//return the fully-configured resolver
|
||||
return resolver;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,12 +121,15 @@
|
||||
<Compile Include="App_Start\FilterConfig.cs" />
|
||||
<Compile Include="App_Start\RouteConfig.cs" />
|
||||
<Compile Include="Controllers\AccountController.cs" />
|
||||
<Compile Include="Controllers\CountController.cs" />
|
||||
<Compile Include="Controllers\SuffixNestedController.cs" />
|
||||
<Compile Include="Controllers\HomeController.cs" />
|
||||
<Compile Include="Controllers\OdataController.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controllers\ValuesController.cs" />
|
||||
<Compile Include="Controllers\SuffixController.cs" />
|
||||
<Compile Include="Counter.cs" />
|
||||
<Compile Include="Global.asax.cs">
|
||||
<DependentUpon>Global.asax</DependentUpon>
|
||||
</Compile>
|
||||
@@ -137,6 +140,12 @@
|
||||
<Content Include="Config\controllers.xml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Config\child_controllers.xml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Config\objects.xml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Content\themes\base\images\ui-bg_flat_0_aaaaaa_40x100.png" />
|
||||
<Content Include="Content\themes\base\images\ui-bg_flat_75_ffffff_40x100.png" />
|
||||
<Content Include="Content\themes\base\images\ui-bg_glass_55_fbf9ee_1x400.png" />
|
||||
@@ -228,6 +237,9 @@
|
||||
<ItemGroup>
|
||||
<Content Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\Count\Index.cshtml" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
<p>Singleton Counter object is keeping track of requests for this page.</p>
|
||||
<h2>Current Count: @ViewBag.Message</h2>
|
||||
@@ -14,6 +14,7 @@
|
||||
<spring>
|
||||
<context>
|
||||
<resource uri="file://~/Config/controllers.xml"/>
|
||||
<resource uri="file://~/Config/objects.xml"/>
|
||||
</context>
|
||||
</spring>
|
||||
<connectionStrings>
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace Spring.Web.Mvc
|
||||
/// Defaults to using the root (default) Application Context.
|
||||
/// </remarks>
|
||||
/// <value>The name of the application context.</value>
|
||||
public static string ApplicationContextName { get; set; }
|
||||
public string ApplicationContextName { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Http.Dependencies;
|
||||
using System.Web.Http.Services;
|
||||
using Spring.Context;
|
||||
using Spring.Context.Support;
|
||||
using Spring.Core.IO;
|
||||
|
||||
|
||||
namespace Spring.Web.Mvc
|
||||
@@ -38,16 +40,28 @@ namespace Spring.Web.Mvc
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public virtual IDependencyScope BeginScope()
|
||||
{
|
||||
var abstractXmlApplicationContext = ApplicationContext as AbstractXmlApplicationContext;
|
||||
|
||||
if (abstractXmlApplicationContext != null)
|
||||
if (HasApplicationContext && (HasChildApplicationContextConfigurationLocations || HasChildApplicationContextConfigurationResources))
|
||||
{
|
||||
var locations = abstractXmlApplicationContext.ConfigurationLocations;
|
||||
var resources = abstractXmlApplicationContext.ConfigurationResources;
|
||||
string[] configurationLocations = null;
|
||||
if (HasChildApplicationContextConfigurationLocations)
|
||||
{
|
||||
configurationLocations = ChildApplicationContextConfigurationLocations.ToArray();
|
||||
}
|
||||
|
||||
var args = new MvcApplicationContextArgs(string.Format("child_of_{0}", ApplicationContext.Name), ApplicationContext, locations, resources, false);
|
||||
IResource[] configurationResources = null;
|
||||
if (HasChildApplicationContextConfigurationResources)
|
||||
{
|
||||
configurationResources = ChildApplicationContextConfigurationResources.ToArray();
|
||||
}
|
||||
|
||||
var childContextName = string.Format("child_of_{0}", ApplicationContext.Name);
|
||||
var args = new MvcApplicationContextArgs(childContextName, ApplicationContext, configurationLocations, configurationResources, false);
|
||||
|
||||
var childContext = new MvcApplicationContext(args);
|
||||
var newResolver = new SpringWebApiDependencyResolver(childContext) { ApplicationContextName = childContextName };
|
||||
|
||||
RegisterContextIfNeeded(childContext);
|
||||
|
||||
var newResolver = new SpringWebApiDependencyResolver(new MvcApplicationContext(args));
|
||||
return newResolver;
|
||||
}
|
||||
else
|
||||
@@ -55,5 +69,76 @@ namespace Spring.Web.Mvc
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterContextIfNeeded(IApplicationContext childContext)
|
||||
{
|
||||
if (!ContextRegistry.IsContextRegistered(childContext.Name))
|
||||
{
|
||||
ContextRegistry.RegisterContext(childContext);
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasChildApplicationContextConfigurationResources
|
||||
{
|
||||
get
|
||||
{
|
||||
return ChildApplicationContextConfigurationResources != null &&
|
||||
ChildApplicationContextConfigurationResources.Count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasChildApplicationContextConfigurationLocations
|
||||
{
|
||||
get
|
||||
{
|
||||
return ChildApplicationContextConfigurationLocations != null &&
|
||||
ChildApplicationContextConfigurationLocations.Count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasApplicationContext
|
||||
{
|
||||
get { return ApplicationContext != null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the child configuration locations.
|
||||
/// </summary>
|
||||
/// <value>The child configuration locations.</value>
|
||||
public virtual IList<string> ChildApplicationContextConfigurationLocations { protected get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the child configuration resources.
|
||||
/// </summary>
|
||||
/// <value>The child configuration resources.</value>
|
||||
public virtual IList<IResource> ChildApplicationContextConfigurationResources { protected get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds the child configuration resource.
|
||||
/// </summary>
|
||||
/// <param name="resource">The resource.</param>
|
||||
public virtual void AddChildApplicationContextConfigurationResource(IResource resource)
|
||||
{
|
||||
if (null == ChildApplicationContextConfigurationResources)
|
||||
{
|
||||
ChildApplicationContextConfigurationResources = new List<IResource>();
|
||||
}
|
||||
|
||||
ChildApplicationContextConfigurationResources.Add(resource);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the child configuration location.
|
||||
/// </summary>
|
||||
/// <param name="location">The location.</param>
|
||||
public virtual void AddChildApplicationContextConfigurationLocation(string location)
|
||||
{
|
||||
if (null == ChildApplicationContextConfigurationLocations)
|
||||
{
|
||||
ChildApplicationContextConfigurationLocations = new List<string>();
|
||||
}
|
||||
|
||||
ChildApplicationContextConfigurationLocations.Add(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,10 +29,6 @@ using Spring.Web.Mvc.Tests.Controllers;
|
||||
|
||||
namespace Spring.Web.Mvc.Tests
|
||||
{
|
||||
// internal class MockContext : HttpContextBase
|
||||
// {
|
||||
// }
|
||||
|
||||
[TestFixture]
|
||||
public class SpringMvcDependencyResolverTests
|
||||
{
|
||||
|
||||
@@ -67,9 +67,7 @@
|
||||
<Compile Include="..\Spring.Web.Mvc3.Tests\Controllers\SecondContainerRegisteredController.cs">
|
||||
<Link>Controllers\SecondContainerRegisteredController.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Spring.Web.Mvc3.Tests\SpringMvcDependencyResolverTests.cs">
|
||||
<Link>SpringMvcDependencyResolverTests.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="SpringMvcDependencyResolverTests.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Spring\Spring.Core\Spring.Core.2010.csproj">
|
||||
@@ -78,7 +76,7 @@
|
||||
<Private>True</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\src\Spring\Spring.Web.Mvc4\Spring.Web.Mvc4.2010.csproj">
|
||||
<Project>{904C97E0-3667-4D12-A55F-6CC2E6F68A0A}</Project>
|
||||
<Project>{CB351EB2-049D-40BE-BB09-1CE4ED68FE67}</Project>
|
||||
<Name>Spring.Web.Mvc4.2010</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
<include name="**/*.cs" />
|
||||
<include name="../CommonAssemblyInfo.cs" />
|
||||
<include name="../Spring.Web.Mvc3.Tests/**/*.cs" />
|
||||
<include name="../Spring.Web.Mvc4.Tests/**/*.cs" />
|
||||
<exclude name="../Spring.Web.Mvc3.Tests/**/SpringMvcDependencyResolverTests.cs" />
|
||||
</sources>
|
||||
<resources prefix="Spring" dynamicprefix="true" failonempty="true">
|
||||
<include name="../Spring.Web.Mvc3.Tests/**/*.resx" />
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright © 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using NUnit.Framework;
|
||||
using Spring.Context.Support;
|
||||
using Spring.Web.Mvc.Tests.Controllers;
|
||||
|
||||
namespace Spring.Web.Mvc.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class SpringMvcDependencyResolverTests
|
||||
{
|
||||
#region Setup/Teardown
|
||||
|
||||
[SetUp]
|
||||
public void _TestSetup()
|
||||
{
|
||||
ContextRegistry.Clear();
|
||||
_context = new MvcApplicationContext("file://objectsMvc.xml");
|
||||
_mvcNamedContext = new MvcApplicationContext("named", false, "file://namedContextObjectsMvc.xml");
|
||||
|
||||
ContextRegistry.RegisterContext(_context);
|
||||
ContextRegistry.RegisterContext(_mvcNamedContext);
|
||||
|
||||
_resolver = new SpringMvcDependencyResolver(_context);
|
||||
|
||||
_resolver.ApplicationContextName = string.Empty;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private MvcApplicationContext _context;
|
||||
private MvcApplicationContext _mvcNamedContext;
|
||||
private SpringMvcDependencyResolver _resolver;
|
||||
|
||||
[Test]
|
||||
public void CanUseNamedContextToResolveType()
|
||||
{
|
||||
_resolver.ApplicationContextName = "named";
|
||||
var service = _resolver.GetService(typeof (NamedContextController));
|
||||
|
||||
Assert.NotNull(service);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanUseUnnamedContextToResolveType()
|
||||
{
|
||||
Assume.That(_resolver.ApplicationContextName, Is.Empty, "Resolver should not have a named-context set for this test!");
|
||||
|
||||
var service = _resolver.GetService<FirstContainerRegisteredController>();
|
||||
Assert.NotNull(service);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequestForNullTypeReturnsNull()
|
||||
{
|
||||
var service = _resolver.GetService(null);
|
||||
Assert.That(service, Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanReturnCollectionOfTypes()
|
||||
{
|
||||
var services = _resolver.GetServices<FirstContainerRegisteredController>();
|
||||
Assert.That(services.Count(), Is.EqualTo(2));
|
||||
|
||||
foreach (var service in services)
|
||||
{
|
||||
Assert.That(service, Is.TypeOf(typeof(FirstContainerRegisteredController)), "Service Returned was not of the expected Type.");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequestForSingleInstanceOfMultiplyRegisteredTypeReturnsFirstDefinition()
|
||||
{
|
||||
var service = _resolver.GetService<FirstContainerRegisteredController>();
|
||||
Assert.That(service.TestValue, Is.EqualTo("First Definition of Type"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequestForSingleUndefinedTypeReturnsNull()
|
||||
{
|
||||
var service = _resolver.GetService<NotInContainerController>();
|
||||
Assert.That(service, Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequestForCollectionOfUndefinedTypesReturnsEmptyCollection()
|
||||
{
|
||||
var services = _resolver.GetServices<NotInContainerController>();
|
||||
Assert.That(services, Is.Empty);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user