diff --git a/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Config/child_controllers.xml b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Config/child_controllers.xml new file mode 100644 index 00000000..4030b1a6 --- /dev/null +++ b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Config/child_controllers.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Config/controllers.xml b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Config/controllers.xml index c1c07df0..527dc473 100644 --- a/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Config/controllers.xml +++ b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Config/controllers.xml @@ -1,17 +1,19 @@  - + + + - + diff --git a/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Config/objects.xml b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Config/objects.xml new file mode 100644 index 00000000..b10b9d55 --- /dev/null +++ b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Config/objects.xml @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Controllers/CountController.cs b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Controllers/CountController.cs new file mode 100644 index 00000000..be4c79b2 --- /dev/null +++ b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Controllers/CountController.cs @@ -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(); + } + } +} diff --git a/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Controllers/OdataController.cs b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Controllers/OdataController.cs index 3dd59378..b31dc4f5 100644 --- a/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Controllers/OdataController.cs +++ b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Controllers/OdataController.cs @@ -17,7 +17,7 @@ namespace Spring.Mvc4QuickStart.Controllers [Queryable] public IQueryable 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 diff --git a/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Controllers/SuffixController.cs b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Controllers/SuffixController.cs index eb27e16b..0a0adee3 100644 --- a/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Controllers/SuffixController.cs +++ b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Controllers/SuffixController.cs @@ -7,29 +7,29 @@ namespace Spring.Mvc4QuickStart.Controllers { public string Suffix { get; set; } - // GET /api/values + // GET /api/suffix public IEnumerable 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) { } diff --git a/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Controllers/SuffixNestedController.cs b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Controllers/SuffixNestedController.cs new file mode 100644 index 00000000..4d726ef7 --- /dev/null +++ b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Controllers/SuffixNestedController.cs @@ -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 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) + { + } + } + +} \ No newline at end of file diff --git a/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Counter.cs b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Counter.cs new file mode 100644 index 00000000..d302f55e --- /dev/null +++ b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Counter.cs @@ -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; } + } + } +} \ No newline at end of file diff --git a/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Global.asax.cs b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Global.asax.cs index 8d26bf38..1b4b21d2 100644 --- a/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Global.asax.cs +++ b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Global.asax.cs @@ -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; + } } } \ No newline at end of file diff --git a/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart.csproj b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart.csproj index 6a28e78c..d4288a29 100644 --- a/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart.csproj +++ b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart.csproj @@ -121,12 +121,15 @@ + + Code + Global.asax @@ -137,6 +140,12 @@ Always + + Always + + + Always + @@ -228,6 +237,9 @@ + + + 10.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) diff --git a/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Views/Count/Index.cshtml b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Views/Count/Index.cshtml new file mode 100644 index 00000000..c39a9569 --- /dev/null +++ b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Views/Count/Index.cshtml @@ -0,0 +1,2 @@ +

Singleton Counter object is keeping track of requests for this page.

+

Current Count: @ViewBag.Message

diff --git a/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Web.config b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Web.config index 43da5d0f..9adf53d8 100644 --- a/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Web.config +++ b/examples/Spring/Spring.Mvc4QuickStart/Spring.Mvc4QuickStart/Web.config @@ -14,6 +14,7 @@ + diff --git a/src/Spring/Spring.Web.Mvc4/SpringMvcDependencyResolver.cs b/src/Spring/Spring.Web.Mvc4/SpringMvcDependencyResolver.cs index 7bf504c1..59cb4558 100644 --- a/src/Spring/Spring.Web.Mvc4/SpringMvcDependencyResolver.cs +++ b/src/Spring/Spring.Web.Mvc4/SpringMvcDependencyResolver.cs @@ -60,7 +60,7 @@ namespace Spring.Web.Mvc /// Defaults to using the root (default) Application Context. /// /// The name of the application context. - public static string ApplicationContextName { get; set; } + public string ApplicationContextName { get; set; } /// diff --git a/src/Spring/Spring.Web.Mvc4/SpringWebApiDependencyResolver.cs b/src/Spring/Spring.Web.Mvc4/SpringWebApiDependencyResolver.cs index bb87dcc7..d5528008 100644 --- a/src/Spring/Spring.Web.Mvc4/SpringWebApiDependencyResolver.cs +++ b/src/Spring/Spring.Web.Mvc4/SpringWebApiDependencyResolver.cs @@ -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 /// 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; } + } + + /// + /// Gets or sets the child configuration locations. + /// + /// The child configuration locations. + public virtual IList ChildApplicationContextConfigurationLocations { protected get; set; } + + /// + /// Gets or sets the child configuration resources. + /// + /// The child configuration resources. + public virtual IList ChildApplicationContextConfigurationResources { protected get; set; } + + /// + /// Adds the child configuration resource. + /// + /// The resource. + public virtual void AddChildApplicationContextConfigurationResource(IResource resource) + { + if (null == ChildApplicationContextConfigurationResources) + { + ChildApplicationContextConfigurationResources = new List(); + } + + ChildApplicationContextConfigurationResources.Add(resource); + } + + /// + /// Adds the child configuration location. + /// + /// The location. + public virtual void AddChildApplicationContextConfigurationLocation(string location) + { + if (null == ChildApplicationContextConfigurationLocations) + { + ChildApplicationContextConfigurationLocations = new List(); + } + + ChildApplicationContextConfigurationLocations.Add(location); + } } } \ No newline at end of file diff --git a/test/Spring/Spring.Web.Mvc3.Tests/SpringMvcDependencyResolverTests.cs b/test/Spring/Spring.Web.Mvc3.Tests/SpringMvcDependencyResolverTests.cs index 953b6ee9..b9a75a42 100644 --- a/test/Spring/Spring.Web.Mvc3.Tests/SpringMvcDependencyResolverTests.cs +++ b/test/Spring/Spring.Web.Mvc3.Tests/SpringMvcDependencyResolverTests.cs @@ -29,10 +29,6 @@ using Spring.Web.Mvc.Tests.Controllers; namespace Spring.Web.Mvc.Tests { -// internal class MockContext : HttpContextBase -// { -// } - [TestFixture] public class SpringMvcDependencyResolverTests { diff --git a/test/Spring/Spring.Web.Mvc4.Tests/Spring.Web.Mvc4.Tests.2010.csproj b/test/Spring/Spring.Web.Mvc4.Tests/Spring.Web.Mvc4.Tests.2010.csproj index aa6540a8..fb299ca5 100644 --- a/test/Spring/Spring.Web.Mvc4.Tests/Spring.Web.Mvc4.Tests.2010.csproj +++ b/test/Spring/Spring.Web.Mvc4.Tests/Spring.Web.Mvc4.Tests.2010.csproj @@ -67,9 +67,7 @@ Controllers\SecondContainerRegisteredController.cs - - SpringMvcDependencyResolverTests.cs - + @@ -78,7 +76,7 @@ True - {904C97E0-3667-4D12-A55F-6CC2E6F68A0A} + {CB351EB2-049D-40BE-BB09-1CE4ED68FE67} Spring.Web.Mvc4.2010 diff --git a/test/Spring/Spring.Web.Mvc4.Tests/Spring.Web.Mvc4.Tests.build b/test/Spring/Spring.Web.Mvc4.Tests/Spring.Web.Mvc4.Tests.build index 532e7ff9..4d8b7b44 100644 --- a/test/Spring/Spring.Web.Mvc4.Tests/Spring.Web.Mvc4.Tests.build +++ b/test/Spring/Spring.Web.Mvc4.Tests/Spring.Web.Mvc4.Tests.build @@ -25,6 +25,8 @@ + + diff --git a/test/Spring/Spring.Web.Mvc4.Tests/SpringMvcDependencyResolverTests.cs b/test/Spring/Spring.Web.Mvc4.Tests/SpringMvcDependencyResolverTests.cs new file mode 100644 index 00000000..0c8d6a0e --- /dev/null +++ b/test/Spring/Spring.Web.Mvc4.Tests/SpringMvcDependencyResolverTests.cs @@ -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(); + 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(); + 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(); + Assert.That(service.TestValue, Is.EqualTo("First Definition of Type")); + } + + [Test] + public void RequestForSingleUndefinedTypeReturnsNull() + { + var service = _resolver.GetService(); + Assert.That(service, Is.Null); + } + + [Test] + public void RequestForCollectionOfUndefinedTypesReturnsEmptyCollection() + { + var services = _resolver.GetServices(); + Assert.That(services, Is.Empty); + } + + } +} \ No newline at end of file