mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-12-03 03:58:13 +08:00
Integrating routing work into project
Uncommenting old route collection publisher tests Factoring wrapping handler into async and non-async cases Adding [IContainerProvider] to datatokens at the time the routedata is matched --HG-- branch : dev
This commit is contained in:
@@ -1,109 +1,114 @@
|
||||
//using System;
|
||||
//using System.Linq;
|
||||
//using System.Threading;
|
||||
//using System.Web.Mvc;
|
||||
//using System.Web.Routing;
|
||||
//using NUnit.Framework;
|
||||
//using Orchard.Mvc.Routes;
|
||||
//using Orchard.Tests.Stubs;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using Autofac;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.Mvc.Routes;
|
||||
using Orchard.Tests.Stubs;
|
||||
using Orchard.Tests.Utility;
|
||||
|
||||
//namespace Orchard.Tests.Mvc {
|
||||
// [TestFixture]
|
||||
// public class RouteCollectionPublisherTests {
|
||||
// static RouteDescriptor Desc(string name, string url) {
|
||||
// return new RouteDescriptor {Name = name, Route = new Route(url, new MvcRouteHandler())};
|
||||
// }
|
||||
namespace Orchard.Tests.Mvc {
|
||||
[TestFixture]
|
||||
public class RouteCollectionPublisherTests {
|
||||
private IContainer _container;
|
||||
private RouteCollection _routes;
|
||||
|
||||
// //[Test]
|
||||
// //public void PublisherShouldReplaceRoutes() {
|
||||
static RouteDescriptor Desc(string name, string url) {
|
||||
return new RouteDescriptor { Name = name, Route = new Route(url, new MvcRouteHandler()) };
|
||||
}
|
||||
|
||||
// // var routes = new RouteCollection();
|
||||
// // routes.MapRoute("foo", "{controller}");
|
||||
[SetUp]
|
||||
public void Init() {
|
||||
_routes = new RouteCollection();
|
||||
|
||||
// // IRoutePublisher publisher = new RoutePublisher(routes, new StubContainerProvider(null, null));
|
||||
// // publisher.Publish(new[] {Desc("barname", "bar"), Desc("quuxname", "quux")});
|
||||
|
||||
// // Assert.That(routes.Count(), Is.EqualTo(2));
|
||||
// //}
|
||||
|
||||
// //[Test]
|
||||
// //public void RoutesCanHaveNullOrEmptyNames() {
|
||||
// // var routes = new RouteCollection();
|
||||
// // routes.MapRoute("foo", "{controller}");
|
||||
|
||||
// // IRoutePublisher publisher = new RoutePublisher(routes, new StubContainerProvider(null, null));
|
||||
// // publisher.Publish(new[] { Desc(null, "bar"), Desc(string.Empty, "quux") });
|
||||
|
||||
// // Assert.That(routes.Count(), Is.EqualTo(2));
|
||||
// //}
|
||||
|
||||
// //[Test]
|
||||
// //[ExpectedException(typeof(ArgumentException))]
|
||||
// //public void SameNameTwiceCausesExplosion() {
|
||||
// // var routes = new RouteCollection();
|
||||
// // routes.MapRoute("foo", "{controller}");
|
||||
|
||||
// // IRoutePublisher publisher = new RoutePublisher(routes, new StubContainerProvider(null, null));
|
||||
// // publisher.Publish(new[] {Desc("yarg", "bar"), Desc("yarg", "quux")});
|
||||
|
||||
// // Assert.That(routes.Count(), Is.EqualTo(2));
|
||||
// //}
|
||||
var builder = new ContainerBuilder();
|
||||
builder.RegisterType<RoutePublisher>().As<IRoutePublisher>();
|
||||
builder.RegisterType<ShellRoute>().InstancePerDependency();
|
||||
builder.Register(ctx => _routes);
|
||||
builder.Register(ctx => new ShellSettings { Name = "Default" });
|
||||
builder.RegisterAutoMocking();
|
||||
_container = builder.Build();
|
||||
}
|
||||
|
||||
|
||||
// [Test]
|
||||
// public void ExplosionLeavesOriginalRoutesIntact() {
|
||||
// var routes = new RouteCollection();
|
||||
// routes.MapRoute("foo", "{controller}");
|
||||
[Test]
|
||||
public void PublisherShouldAddRoutesThenReplaceTheOnesWhichWereAdded() {
|
||||
|
||||
// IRoutePublisher publisher = new RoutePublisher(routes, new StubContainerProvider(null, null));
|
||||
// try {
|
||||
// publisher.Publish(new[] { Desc("yarg", "bar"), Desc("yarg", "quux") });
|
||||
// }
|
||||
// catch (ArgumentException) {
|
||||
// Assert.That(routes.Count(), Is.EqualTo(1));
|
||||
// Assert.That(routes.OfType<Route>().Single().Url, Is.EqualTo("{controller}"));
|
||||
// }
|
||||
// }
|
||||
_routes.MapRoute("foo", "{controller}");
|
||||
|
||||
// [Test]
|
||||
// public void RoutesArePaintedWithConainerProviderAsTheyAreApplied() {
|
||||
// var routes = new RouteCollection();
|
||||
// routes.MapRoute("foo", "{controller}");
|
||||
var publisher = _container.Resolve<IRoutePublisher>();
|
||||
publisher.Publish(new[] { Desc("barname", "bar"), Desc("quuxname", "quux") });
|
||||
|
||||
// var containerProvider = new StubContainerProvider(null, null);
|
||||
// IRoutePublisher publisher = new RoutePublisher(routes, containerProvider);
|
||||
// publisher.Publish(new[] { Desc("barname", "bar"), Desc("quuxname", "quux") });
|
||||
Assert.That(_routes.Count(), Is.EqualTo(3));
|
||||
|
||||
// Assert.That(routes.OfType<Route>().Count(), Is.EqualTo(2));
|
||||
// Assert.That(routes.OfType<Route>().SelectMany(r => r.DataTokens.Values).Count(), Is.EqualTo(2));
|
||||
// Assert.That(routes.OfType<Route>().SelectMany(r => r.DataTokens.Values), Has.All.SameAs(containerProvider));
|
||||
// }
|
||||
publisher.Publish(new[] { Desc("baazname", "baaz")});
|
||||
|
||||
// [Test]
|
||||
// public void WriteBlocksWhileReadIsInEffect() {
|
||||
// var routes = new RouteCollection();
|
||||
// routes.MapRoute("foo", "{controller}");
|
||||
Assert.That(_routes.Count(), Is.EqualTo(2));
|
||||
}
|
||||
|
||||
// var containerProvider = new StubContainerProvider(null, null);
|
||||
// IRoutePublisher publisher = new RoutePublisher(routes, containerProvider);
|
||||
[Test]
|
||||
public void RoutesCanHaveNullOrEmptyNames() {
|
||||
_routes.MapRoute("foo", "{controller}");
|
||||
|
||||
// var readLock = routes.GetReadLock();
|
||||
var publisher = _container.Resolve<IRoutePublisher>();
|
||||
publisher.Publish(new[] { Desc(null, "bar"), Desc(string.Empty, "quux") });
|
||||
|
||||
// string where = "init";
|
||||
// var action = new Action(() => {
|
||||
// where = "before";
|
||||
// publisher.Publish(new[] { Desc("barname", "bar"), Desc("quuxname", "quux") });
|
||||
// where = "after";
|
||||
// });
|
||||
Assert.That(_routes.Count(), Is.EqualTo(3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(ArgumentException))]
|
||||
public void SameNameTwiceCausesExplosion() {
|
||||
_routes.MapRoute("foo", "{controller}");
|
||||
|
||||
var publisher = _container.Resolve<IRoutePublisher>();
|
||||
publisher.Publish(new[] { Desc("yarg", "bar"), Desc("yarg", "quux") });
|
||||
|
||||
Assert.That(_routes.Count(), Is.EqualTo(2));
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void ExplosionLeavesOriginalRoutesIntact() {
|
||||
_routes.MapRoute("foo", "{controller}");
|
||||
|
||||
var publisher = _container.Resolve<IRoutePublisher>();
|
||||
try {
|
||||
publisher.Publish(new[] { Desc("yarg", "bar"), Desc("yarg", "quux") });
|
||||
}
|
||||
catch (ArgumentException) {
|
||||
Assert.That(_routes.Count(), Is.EqualTo(1));
|
||||
Assert.That(_routes.OfType<Route>().Single().Url, Is.EqualTo("{controller}"));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WriteBlocksWhileReadIsInEffect() {
|
||||
_routes.MapRoute("foo", "{controller}");
|
||||
|
||||
var publisher = _container.Resolve<IRoutePublisher>();
|
||||
|
||||
var readLock = _routes.GetReadLock();
|
||||
|
||||
string where = "init";
|
||||
var action = new Action(() => {
|
||||
where = "before";
|
||||
publisher.Publish(new[] { Desc("barname", "bar"), Desc("quuxname", "quux") });
|
||||
where = "after";
|
||||
});
|
||||
|
||||
Assert.That(where, Is.EqualTo("init"));
|
||||
var async = action.BeginInvoke(null, null);
|
||||
Thread.Sleep(75);
|
||||
Assert.That(where, Is.EqualTo("before"));
|
||||
readLock.Dispose();
|
||||
Thread.Sleep(75);
|
||||
Assert.That(where, Is.EqualTo("after"));
|
||||
action.EndInvoke(async);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Assert.That(where, Is.EqualTo("init"));
|
||||
// var async = action.BeginInvoke(null, null);
|
||||
// Thread.Sleep(75);
|
||||
// Assert.That(where, Is.EqualTo("before"));
|
||||
// readLock.Dispose();
|
||||
// Thread.Sleep(75);
|
||||
// Assert.That(where, Is.EqualTo("after"));
|
||||
// action.EndInvoke(async);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -24,6 +24,32 @@ namespace Orchard.Tests.Mvc.Routes {
|
||||
private ShellSettings _settingsB;
|
||||
private IContainer _rootContainer;
|
||||
|
||||
[SetUp]
|
||||
public void Init() {
|
||||
_settingsA = new ShellSettings { Name = "Alpha" };
|
||||
_settingsB = new ShellSettings { Name = "Beta", };
|
||||
_routes = new RouteCollection();
|
||||
|
||||
var rootBuilder = new ContainerBuilder();
|
||||
rootBuilder.Register(ctx => _routes);
|
||||
rootBuilder.RegisterType<ShellRoute>().InstancePerDependency();
|
||||
rootBuilder.RegisterType<RunningShellTable>().As<IRunningShellTable>().SingleInstance();
|
||||
|
||||
_rootContainer = rootBuilder.Build();
|
||||
|
||||
_containerA = _rootContainer.BeginLifetimeScope(
|
||||
builder => {
|
||||
builder.Register(ctx => _settingsA);
|
||||
builder.RegisterType<RoutePublisher>().As<IRoutePublisher>().InstancePerLifetimeScope();
|
||||
});
|
||||
|
||||
_containerB = _rootContainer.BeginLifetimeScope(
|
||||
builder => {
|
||||
builder.Register(ctx => _settingsB);
|
||||
builder.RegisterType<RoutePublisher>().As<IRoutePublisher>().InstancePerLifetimeScope();
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FactoryMethodWillCreateShellRoutes() {
|
||||
var settings = new ShellSettings { Name = "Alpha" };
|
||||
@@ -52,33 +78,9 @@ namespace Orchard.Tests.Mvc.Routes {
|
||||
Assert.That(route2.Area, Is.EqualTo("Beta"));
|
||||
}
|
||||
|
||||
private void Init() {
|
||||
_settingsA = new ShellSettings {Name = "Alpha"};
|
||||
_settingsB = new ShellSettings {Name = "Beta", };
|
||||
_routes = new RouteCollection();
|
||||
|
||||
var rootBuilder = new ContainerBuilder();
|
||||
rootBuilder.Register(ctx => _routes);
|
||||
rootBuilder.RegisterType<ShellRoute>().InstancePerDependency();
|
||||
rootBuilder.RegisterType<RunningShellTable>().As<IRunningShellTable>().SingleInstance();
|
||||
|
||||
_rootContainer = rootBuilder.Build();
|
||||
_containerA = _rootContainer.BeginLifetimeScope(
|
||||
builder => {
|
||||
builder.Register(ctx => _settingsA);
|
||||
builder.RegisterType<RoutePublisher>().As<IRoutePublisher>();
|
||||
});
|
||||
|
||||
_containerB = _rootContainer.BeginLifetimeScope(
|
||||
builder => {
|
||||
builder.Register(ctx => _settingsB);
|
||||
builder.RegisterType<RoutePublisher>().As<IRoutePublisher>();
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RoutePublisherReplacesOnlyNamedShellsRoutes() {
|
||||
Init();
|
||||
|
||||
var routeA = new Route("foo", new MvcRouteHandler());
|
||||
var routeB = new Route("bar", new MvcRouteHandler());
|
||||
@@ -108,17 +110,18 @@ namespace Orchard.Tests.Mvc.Routes {
|
||||
|
||||
[Test]
|
||||
public void MatchingRouteToActiveShellTableWillLimitTheAbilityToMatchRoutes() {
|
||||
Init();
|
||||
|
||||
var routeFoo = new Route("foo", new MvcRouteHandler());
|
||||
|
||||
_settingsA.RequestUrlHost = "a.example.com";
|
||||
_containerA.Resolve<IRoutePublisher>().Publish(
|
||||
new[] {new RouteDescriptor {Priority = 0, Route = routeFoo}});
|
||||
_rootContainer.Resolve<IRunningShellTable>().Add(_settingsA);
|
||||
|
||||
_settingsB.RequestUrlHost = "b.example.com";
|
||||
_containerB.Resolve<IRoutePublisher>().Publish(
|
||||
new[] {new RouteDescriptor {Priority = 0, Route = routeFoo}});
|
||||
_rootContainer.Resolve<IRunningShellTable>().Add(_settingsB);
|
||||
|
||||
var httpContext = new StubHttpContext("~/foo");
|
||||
var routeData = _routes.GetRouteData(httpContext);
|
||||
@@ -129,16 +132,16 @@ namespace Orchard.Tests.Mvc.Routes {
|
||||
Assert.That(routeDataA, Is.Not.Null);
|
||||
Assert.That(routeDataA.DataTokens.ContainsKey("IContainerProvider"), Is.True);
|
||||
var routeContainerProviderA = (IContainerProvider)routeDataA.DataTokens["IContainerProvider"];
|
||||
Assert.That(routeContainerProviderA.ApplicationContainer.Resolve<IRouteProvider>(), Is.SameAs(_containerA.Resolve<IRouteProvider>()));
|
||||
Assert.That(routeContainerProviderA.ApplicationContainer.Resolve<IRouteProvider>(), Is.Not.SameAs(_containerB.Resolve<IRouteProvider>()));
|
||||
Assert.That(routeContainerProviderA.ApplicationContainer.Resolve<IRoutePublisher>(), Is.SameAs(_containerA.Resolve<IRoutePublisher>()));
|
||||
Assert.That(routeContainerProviderA.ApplicationContainer.Resolve<IRoutePublisher>(), Is.Not.SameAs(_containerB.Resolve<IRoutePublisher>()));
|
||||
|
||||
var httpContextB = new StubHttpContext("~/foo", "b.example.com");
|
||||
var routeDataB = _routes.GetRouteData(httpContextB);
|
||||
Assert.That(routeDataB, Is.Not.Null);
|
||||
Assert.That(routeDataB.DataTokens.ContainsKey("IContainerProvider"), Is.True);
|
||||
var routeContainerProviderB = (IContainerProvider)routeDataA.DataTokens["IContainerProvider"];
|
||||
Assert.That(routeContainerProviderB.ApplicationContainer.Resolve<IRouteProvider>(), Is.SameAs(_containerB.Resolve<IRouteProvider>()));
|
||||
Assert.That(routeContainerProviderB.ApplicationContainer.Resolve<IRouteProvider>(), Is.Not.SameAs(_containerA.Resolve<IRouteProvider>()));
|
||||
var routeContainerProviderB = (IContainerProvider)routeDataB.DataTokens["IContainerProvider"];
|
||||
Assert.That(routeContainerProviderB.ApplicationContainer.Resolve<IRoutePublisher>(), Is.SameAs(_containerB.Resolve<IRoutePublisher>()));
|
||||
Assert.That(routeContainerProviderB.ApplicationContainer.Resolve<IRoutePublisher>(), Is.Not.SameAs(_containerA.Resolve<IRoutePublisher>()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -51,7 +51,9 @@ namespace Orchard.Mvc.Routes {
|
||||
return null;
|
||||
|
||||
// otherwise paint wrap handler and return it
|
||||
routeData.RouteHandler = new RouteHandler(_container, routeData.RouteHandler);
|
||||
var containerProvider = new ContainerProvider(_container);
|
||||
routeData.RouteHandler = new RouteHandler(containerProvider, routeData.RouteHandler);
|
||||
routeData.DataTokens["IContainerProvider"] = containerProvider;
|
||||
return routeData;
|
||||
}
|
||||
|
||||
@@ -66,33 +68,49 @@ namespace Orchard.Mvc.Routes {
|
||||
return virtualPath;
|
||||
}
|
||||
|
||||
class ContainerProvider : IContainerProvider {
|
||||
public ContainerProvider(IContainer applicationContainer) {
|
||||
ApplicationContainer = applicationContainer;
|
||||
}
|
||||
|
||||
public void BeginRequestLifetime() {
|
||||
RequestLifetime = ApplicationContainer.BeginLifetimeScope("httpRequest");
|
||||
}
|
||||
|
||||
public void EndRequestLifetime() {
|
||||
RequestLifetime.Dispose();
|
||||
RequestLifetime = null;
|
||||
}
|
||||
|
||||
public IContainer ApplicationContainer { get; set; }
|
||||
public ILifetimeScope RequestLifetime { get; set; }
|
||||
}
|
||||
|
||||
class RouteHandler : IRouteHandler {
|
||||
private readonly IContainer _container;
|
||||
private readonly ContainerProvider _containerProvider;
|
||||
private readonly IRouteHandler _routeHandler;
|
||||
|
||||
public RouteHandler(IContainer container, IRouteHandler routeHandler) {
|
||||
_container = container;
|
||||
public RouteHandler(ContainerProvider containerProvider, IRouteHandler routeHandler) {
|
||||
_containerProvider = containerProvider;
|
||||
_routeHandler = routeHandler;
|
||||
}
|
||||
|
||||
public IHttpHandler GetHttpHandler(RequestContext requestContext) {
|
||||
var httpHandler = _routeHandler.GetHttpHandler(requestContext);
|
||||
return new HttpAsyncHandler(
|
||||
_container,
|
||||
requestContext,
|
||||
(IHttpAsyncHandler)httpHandler);
|
||||
if (httpHandler is IHttpAsyncHandler) {
|
||||
return new HttpAsyncHandler(_containerProvider, (IHttpAsyncHandler)httpHandler);
|
||||
}
|
||||
return new HttpHandler(_containerProvider, httpHandler);
|
||||
}
|
||||
}
|
||||
|
||||
class HttpAsyncHandler : IHttpAsyncHandler, IRequiresSessionState, IContainerProvider {
|
||||
private readonly RequestContext _requestContext;
|
||||
private readonly IHttpAsyncHandler _httpAsyncHandler;
|
||||
class HttpHandler : IHttpHandler, IRequiresSessionState {
|
||||
protected readonly ContainerProvider _containerProvider;
|
||||
private readonly IHttpHandler _httpHandler;
|
||||
|
||||
public HttpAsyncHandler(IContainer applicationContainer, RequestContext requestContext, IHttpAsyncHandler httpAsyncHandler) {
|
||||
ApplicationContainer = applicationContainer;
|
||||
_requestContext = requestContext;
|
||||
_httpAsyncHandler = httpAsyncHandler;
|
||||
public HttpHandler(ContainerProvider containerProvider, IHttpHandler httpHandler) {
|
||||
_containerProvider = containerProvider;
|
||||
_httpHandler = httpHandler;
|
||||
}
|
||||
|
||||
public bool IsReusable {
|
||||
@@ -100,22 +118,31 @@ namespace Orchard.Mvc.Routes {
|
||||
}
|
||||
|
||||
public void ProcessRequest(HttpContext context) {
|
||||
BeginRequestLifetime();
|
||||
_containerProvider.BeginRequestLifetime();
|
||||
try {
|
||||
_httpAsyncHandler.ProcessRequest(context);
|
||||
_httpHandler.ProcessRequest(context);
|
||||
}
|
||||
finally {
|
||||
EndRequestLifetime();
|
||||
_containerProvider.EndRequestLifetime();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class HttpAsyncHandler : HttpHandler, IHttpAsyncHandler {
|
||||
private readonly IHttpAsyncHandler _httpAsyncHandler;
|
||||
|
||||
public HttpAsyncHandler(ContainerProvider containerProvider, IHttpAsyncHandler httpAsyncHandler)
|
||||
: base(containerProvider, httpAsyncHandler) {
|
||||
_httpAsyncHandler = httpAsyncHandler;
|
||||
}
|
||||
|
||||
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) {
|
||||
BeginRequestLifetime();
|
||||
_containerProvider.BeginRequestLifetime();
|
||||
try {
|
||||
return _httpAsyncHandler.BeginProcessRequest(context, cb, extraData);
|
||||
}
|
||||
catch {
|
||||
EndRequestLifetime();
|
||||
_containerProvider.EndRequestLifetime();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@@ -125,22 +152,10 @@ namespace Orchard.Mvc.Routes {
|
||||
_httpAsyncHandler.EndProcessRequest(result);
|
||||
}
|
||||
finally {
|
||||
EndRequestLifetime();
|
||||
_containerProvider.EndRequestLifetime();
|
||||
}
|
||||
}
|
||||
|
||||
public void BeginRequestLifetime() {
|
||||
RequestLifetime = ApplicationContainer.BeginLifetimeScope("httpRequest");
|
||||
_requestContext.RouteData.DataTokens["IContainerProvider"] = this;
|
||||
}
|
||||
|
||||
public void EndRequestLifetime() {
|
||||
_requestContext.RouteData.DataTokens.Remove("IContainerProvider");
|
||||
RequestLifetime.Dispose();
|
||||
}
|
||||
|
||||
public IContainer ApplicationContainer { get; set; }
|
||||
public ILifetimeScope RequestLifetime { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user