diff --git a/samples/MvcSample.Web/LinkController.cs b/samples/MvcSample.Web/LinkController.cs index a423af189d..f08451b9c6 100644 --- a/samples/MvcSample.Web/LinkController.cs +++ b/samples/MvcSample.Web/LinkController.cs @@ -19,7 +19,7 @@ namespace MvcSample.Web public string Get() { // Creates a url like: http://localhost:58195/Home/Details#CoolBeans! - return Url.RouteUrl(new { controller = "Home", action = "Details" }, protocol: "http", host: null, fragment: "CoolBeans!"); + return Url.RouteUrl("CoolBeansRoute", new { controller = "Home", action = "Details" }, protocol: "http", host: null, fragment: "CoolBeans!"); } public string Link1() diff --git a/samples/MvcSample.Web/Startup.cs b/samples/MvcSample.Web/Startup.cs index ed79a5f291..bcb46d6140 100644 --- a/samples/MvcSample.Web/Startup.cs +++ b/samples/MvcSample.Web/Startup.cs @@ -27,7 +27,7 @@ namespace MvcSample.Web new { controller = "Home", action = "Index" }); routes.MapRoute( - "ControllerOnlyRoute", + "controllerRoute", "{controller}", new { controller = "Home" }); }); diff --git a/src/Microsoft.AspNet.Mvc.Core/ActionResults/RedirectToRouteResult.cs b/src/Microsoft.AspNet.Mvc.Core/ActionResults/RedirectToRouteResult.cs index bb4aa9627b..544320b867 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ActionResults/RedirectToRouteResult.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ActionResults/RedirectToRouteResult.cs @@ -7,21 +7,34 @@ namespace Microsoft.AspNet.Mvc { public class RedirectToRouteResult : ActionResult { - public RedirectToRouteResult([NotNull] IUrlHelper urlHelper, IDictionary routeValues) - : this(urlHelper, routeValues, permanent: false) + public RedirectToRouteResult([NotNull] IUrlHelper urlHelper, + object routeValues) + : this(urlHelper, routeName: null, routeValues: routeValues) { } - public RedirectToRouteResult([NotNull] IUrlHelper urlHelper, - IDictionary routeValues, bool permanent) + public RedirectToRouteResult([NotNull] IUrlHelper urlHelper, + string routeName, + object routeValues) + : this(urlHelper, routeName, routeValues, permanent: false) + { + } + + public RedirectToRouteResult([NotNull] IUrlHelper urlHelper, + string routeName, + object routeValues, + bool permanent) { UrlHelper = urlHelper; - RouteValues = routeValues; + RouteName = routeName; + RouteValues = TypeHelper.ObjectToDictionary(routeValues); Permanent = permanent; } public IUrlHelper UrlHelper { get; private set; } + public string RouteName { get; private set; } + public IDictionary RouteValues { get; private set; } public bool Permanent { get; private set; } diff --git a/src/Microsoft.AspNet.Mvc.Core/Controller.cs b/src/Microsoft.AspNet.Mvc.Core/Controller.cs index 36a3a06a9a..0f53922466 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Controller.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Controller.cs @@ -164,14 +164,34 @@ namespace Microsoft.AspNet.Mvc TypeHelper.ObjectToDictionary(routeValues), permanent: true); } + public RedirectToRouteResult RedirectToRoute(string routeName) + { + return RedirectToRoute(routeName, routeValues: null); + } + public RedirectToRouteResult RedirectToRoute(object routeValues) { - return new RedirectToRouteResult(Url, TypeHelper.ObjectToDictionary(routeValues)); + return RedirectToRoute(routeName: null, routeValues: routeValues); + } + + public RedirectToRouteResult RedirectToRoute(string routeName, object routeValues) + { + return new RedirectToRouteResult(Url, routeName, routeValues); + } + + public RedirectToRouteResult RedirectToRoutePermanent(string routeName) + { + return RedirectToRoutePermanent(routeName, routeValues: null); } public RedirectToRouteResult RedirectToRoutePermanent(object routeValues) { - return new RedirectToRouteResult(Url, TypeHelper.ObjectToDictionary(routeValues), permanent: true); + return RedirectToRoutePermanent(routeName: null, routeValues: routeValues); + } + + public RedirectToRouteResult RedirectToRoutePermanent(string routeName, object routeValues) + { + return new RedirectToRouteResult(Url, routeName, routeValues, permanent: true); } } } diff --git a/src/Microsoft.AspNet.Mvc.Core/IUrlHelper.cs b/src/Microsoft.AspNet.Mvc.Core/IUrlHelper.cs index 010b6f40e5..87f80b805f 100644 --- a/src/Microsoft.AspNet.Mvc.Core/IUrlHelper.cs +++ b/src/Microsoft.AspNet.Mvc.Core/IUrlHelper.cs @@ -8,6 +8,6 @@ bool IsLocalUrl(string url); - string RouteUrl(object values, string protocol, string host, string fragment); + string RouteUrl(string routeName, object values, string protocol, string host, string fragment); } } diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs index ac65526509..5c5afa50b4 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs @@ -416,6 +416,20 @@ namespace Microsoft.AspNet.Mvc.Rendering return new HtmlString(value == null ? null : value.ToString()); } + /// + public HtmlString RouteLink( + [NotNull] string linkText, + string routeName, + string protocol, + string hostName, + string fragment, + object routeValues, + object htmlAttributes) + { + var url = _urlHelper.RouteUrl(routeName, routeValues, protocol, hostName, fragment); + return GenerateLink(linkText, url, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); + } + /// public HtmlString ValidationMessage(string expression, string message, object htmlAttributes) { diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/HtmlHelperLinkExtensions.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/HtmlHelperLinkExtensions.cs index fc38d04928..137872acd2 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Rendering/HtmlHelperLinkExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/HtmlHelperLinkExtensions.cs @@ -107,5 +107,104 @@ namespace Microsoft.AspNet.Mvc.Rendering routeValues: routeValues, htmlAttributes: htmlAttributes); } + + public static HtmlString RouteLink( + [NotNull] this IHtmlHelper htmlHelper, + [NotNull] string linkText, + object routeValues) + { + return htmlHelper.RouteLink( + linkText, + routeName: null, + protocol: null, + hostName: null, + fragment: null, + routeValues: routeValues, + htmlAttributes: null); + } + + public static HtmlString RouteLink( + [NotNull] this IHtmlHelper htmlHelper, + [NotNull] string linkText, + string routeName) + { + return htmlHelper.RouteLink( + linkText, + routeName, + protocol: null, + hostName: null, + fragment: null, + routeValues: null, + htmlAttributes: null); + } + + public static HtmlString RouteLink( + [NotNull] this IHtmlHelper htmlHelper, + [NotNull] string linkText, + string routeName, + object routeValues) + { + return htmlHelper.RouteLink( + linkText, + routeName, + protocol: null, + hostName: null, + fragment: null, + routeValues: routeValues, + htmlAttributes: null); + } + + public static HtmlString RouteLink( + [NotNull] this IHtmlHelper htmlHelper, + [NotNull] string linkText, + object routeValues, + object htmlAttributes) + { + return htmlHelper.RouteLink( + linkText, + routeName: null, + protocol: null, + hostName: null, + fragment: null, + routeValues: routeValues, + htmlAttributes: htmlAttributes); + } + + public static HtmlString RouteLink( + [NotNull] this IHtmlHelper htmlHelper, + [NotNull] string linkText, + string routeName, + object routeValues, + object htmlAttributes) + { + return htmlHelper.RouteLink( + linkText, + routeName, + protocol: null, + hostName: null, + fragment: null, + routeValues: routeValues, + htmlAttributes: htmlAttributes); + } + + public static HtmlString RouteLink( + [NotNull] this IHtmlHelper htmlHelper, + [NotNull] string linkText, + string routeName, + string protocol, + string hostName, + string fragment, + object routeValues, + object htmlAttributes) + { + return htmlHelper.RouteLink( + linkText, + routeName, + protocol, + hostName, + fragment, + routeValues, + htmlAttributes); + } } } diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/IHtmlHelper.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/IHtmlHelper.cs index 0891342236..4d0fac5183 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Rendering/IHtmlHelper.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/IHtmlHelper.cs @@ -358,6 +358,35 @@ namespace Microsoft.AspNet.Mvc.Rendering /// A task that represents when rendering has completed. Task RenderPartialAsync([NotNull] string partialViewName, object model, ViewDataDictionary viewData); + /// + /// Returns an anchor element (a element) that contains a URL path to the specified route. + /// + /// The inner text of the anchor element. + /// The name of the route. + /// The protocol for the URL, such as "http" or "https". + /// The host name for the URL. + /// The URL fragment name (the anchor name). + /// + /// An object that contains the parameters for a route. The parameters are retrieved through reflection by + /// examining the properties of the object. This object is typically created using object initializer syntax. + /// Alternatively, an instance containing the route parameters. + /// + /// + /// An object that contains the HTML attributes to set for the element. Alternatively, an + /// instance containing the HTML attributes. + /// + /// + /// An anchor element (a element). + /// + HtmlString RouteLink( + [NotNull] string linkText, + string routeName, + string protocol, + string hostName, + string fragment, + object routeValues, + object htmlAttributes); + /// /// Render a textarea. /// @@ -375,7 +404,7 @@ namespace Microsoft.AspNet.Mvc.Rendering /// /// New containing the rendered HTML. HtmlString TextArea(string name, string value, int rows, int columns, object htmlAttributes); - + /// /// Render an input element of type "text". /// diff --git a/src/Microsoft.AspNet.Mvc.Core/UrlHelper.cs b/src/Microsoft.AspNet.Mvc.Core/UrlHelper.cs index fef108200a..c48029a6f1 100644 --- a/src/Microsoft.AspNet.Mvc.Core/UrlHelper.cs +++ b/src/Microsoft.AspNet.Mvc.Core/UrlHelper.cs @@ -1,12 +1,10 @@ -using System; + +using System; using System.Collections.Generic; using System.Diagnostics.Contracts; -using System.Globalization; using System.Linq; -using System.Linq.Expressions; using Microsoft.AspNet.Abstractions; using Microsoft.AspNet.DependencyInjection; -using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Routing; namespace Microsoft.AspNet.Mvc @@ -69,21 +67,20 @@ namespace Microsoft.AspNet.Mvc public bool IsLocalUrl(string url) { - return + return !string.IsNullOrEmpty(url) && // Allows "/" or "/foo" but not "//" or "/\". ((url[0] == '/' && (url.Length == 1 || (url[1] != '/' && url[1] != '\\'))) || // Allows "~/" or "~/foo". - (url.Length > 1 && url[0] == '~' && url[1] == '/')); + (url.Length > 1 && url[0] == '~' && url[1] == '/')); } - public string RouteUrl(object values, string protocol, string host, string fragment) + public string RouteUrl(string routeName, object values, string protocol, string host, string fragment) { var valuesDictionary = TypeHelper.ObjectToDictionary(values); - - var path = GeneratePathFromRoute(valuesDictionary); + var path = GeneratePathFromRoute(routeName, valuesDictionary); if (path == null) { return null; @@ -94,7 +91,12 @@ namespace Microsoft.AspNet.Mvc private string GeneratePathFromRoute(IDictionary values) { - var context = new VirtualPathContext(_httpContext, _ambientValues, values); + return GeneratePathFromRoute(routeName: null, values: values); + } + + private string GeneratePathFromRoute(string routeName, IDictionary values) + { + var context = new VirtualPathContext(_httpContext, _ambientValues, values, routeName); var path = _router.GetVirtualPath(context); if (path == null) { @@ -123,7 +125,7 @@ namespace Microsoft.AspNet.Mvc return GenerateClientUrl(_httpContext.Request.PathBase, contentPath); } - private static string GenerateClientUrl([NotNull] PathString applicationPath, + private static string GenerateClientUrl([NotNull] PathString applicationPath, [NotNull] string path) { if (path.StartsWith("~/", StringComparison.Ordinal)) @@ -132,12 +134,11 @@ namespace Microsoft.AspNet.Mvc return applicationPath.Add(segment).Value; } return path; - } + } private string GenerateUrl(string protocol, string host, string path, string fragment) { // We should have a robust and centrallized version of this code. See HttpAbstractions#28 - Contract.Assert(path != null); var url = path; @@ -167,4 +168,4 @@ namespace Microsoft.AspNet.Mvc } } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/UrlHelperExtensions.cs b/src/Microsoft.AspNet.Mvc.Core/UrlHelperExtensions.cs index fbbda27443..4b397125ae 100644 --- a/src/Microsoft.AspNet.Mvc.Core/UrlHelperExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.Core/UrlHelperExtensions.cs @@ -56,17 +56,31 @@ public static string RouteUrl([NotNull] this IUrlHelper helper, object values) { - return helper.RouteUrl(values, protocol: null, host: null, fragment: null); + return helper.RouteUrl(routeName: null, values: values, protocol: null, host: null, fragment: null); } - public static string RouteUrl([NotNull] this IUrlHelper helper, object values, string protocol) + public static string RouteUrl([NotNull] this IUrlHelper helper, string routeName) { - return helper.RouteUrl(values, protocol, host: null, fragment: null); + return helper.RouteUrl(routeName, values: null, protocol: null, host: null, fragment: null); } - public static string RouteUrl([NotNull] this IUrlHelper helper, object values, string protocol, string host) + public static string RouteUrl([NotNull] this IUrlHelper helper, string routeName, object values) { - return helper.RouteUrl(values, protocol, host, fragment: null); + return helper.RouteUrl(routeName, values, protocol: null, host: null, fragment: null); + } + + public static string RouteUrl([NotNull] this IUrlHelper helper, string routeName, object values, string protocol) + { + return helper.RouteUrl(routeName, values, protocol, host: null, fragment: null); + } + + public static string RouteUrl([NotNull] this IUrlHelper helper, + string routeName, + object values, + string protocol, + string host) + { + return helper.RouteUrl(routeName, values, protocol, host, fragment: null); } } } diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ActionResults/RedirectToRouteResultTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ActionResults/RedirectToRouteResultTest.cs index 62388bda89..a02056b1db 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ActionResults/RedirectToRouteResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ActionResults/RedirectToRouteResultTest.cs @@ -26,7 +26,9 @@ namespace Microsoft.AspNet.Mvc.Core new Dictionary(), new ActionDescriptor()); IUrlHelper urlHelper = GetMockUrlHelper(expectedUrl); - RedirectToRouteResult result = new RedirectToRouteResult(urlHelper, TypeHelper.ObjectToDictionary(values)); + RedirectToRouteResult result = new RedirectToRouteResult(urlHelper, + null, + TypeHelper.ObjectToDictionary(values)); // Act await result.ExecuteResultAsync(actionContext); @@ -50,7 +52,9 @@ namespace Microsoft.AspNet.Mvc.Core new ActionDescriptor()); IUrlHelper urlHelper = GetMockUrlHelper(returnValue: null); - RedirectToRouteResult result = new RedirectToRouteResult(urlHelper, new Dictionary()); + RedirectToRouteResult result = new RedirectToRouteResult(urlHelper, + null, + new Dictionary()); // Act & Assert ExceptionAssert.ThrowsAsync( @@ -81,7 +85,7 @@ namespace Microsoft.AspNet.Mvc.Core private static IUrlHelper GetMockUrlHelper(string returnValue) { var urlHelper = new Mock(); - urlHelper.Setup(o => o.RouteUrl(It.IsAny(), It.IsAny(), + urlHelper.Setup(o => o.RouteUrl(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(returnValue); return urlHelper.Object; } diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/UrlHelperTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/UrlHelperTest.cs index 6812d5a640..6ea42a795e 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/UrlHelperTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/UrlHelperTest.cs @@ -12,8 +12,8 @@ namespace Microsoft.AspNet.Mvc.Core.Test [Theory] [InlineData("", "/Home/About", "/Home/About")] [InlineData("/myapproot", "/test", "/test")] - public void Content_ReturnsContentPath_WhenItDoesNotStartWithToken(string appRoot, - string contentPath, + public void Content_ReturnsContentPath_WhenItDoesNotStartWithToken(string appRoot, + string contentPath, string expectedPath) { // Arrange @@ -36,8 +36,8 @@ namespace Microsoft.AspNet.Mvc.Core.Test [InlineData("/myapproot", "~/", "/myapproot/")] [InlineData("", "~/Home/About", "/Home/About")] [InlineData("/myapproot", "~/", "/myapproot/")] - public void Content_ReturnsAppRelativePath_WhenItStartsWithToken(string appRoot, - string contentPath, + public void Content_ReturnsAppRelativePath_WhenItStartsWithToken(string appRoot, + string contentPath, string expectedPath) { // Arrange @@ -247,22 +247,223 @@ namespace Microsoft.AspNet.Mvc.Core.Test Assert.False(result); } + [Fact] + public void RouteUrlWithDictionary() + { + // Arrange + var urlHelper = CreateUrlHelperWithRouteCollection("/app"); + + // Act + var url = urlHelper.RouteUrl(values: new RouteValueDictionary( + new + { + Action = "newaction", + Controller = "home2", + id = "someid" + })); + + // Assert + Assert.Equal("/app/home2/newaction/someid", url); + } + + [Fact] + public void RouteUrlWithEmptyHostName() + { + // Arrange + var urlHelper = CreateUrlHelperWithRouteCollection("/app"); + + // Act + var url = urlHelper.RouteUrl(routeName: "namedroute", + values: new RouteValueDictionary( + new + { + Action = "newaction", + Controller = "home2", + id = "someid" + }), + protocol: "http", + host: string.Empty); + + // Assert + Assert.Equal("http://localhost/app/named/home2/newaction/someid", url); + } + + [Fact] + public void RouteUrlWithEmptyProtocol() + { + // Arrange + var urlHelper = CreateUrlHelperWithRouteCollection("/app"); + + // Act + var url = urlHelper.RouteUrl(routeName: "namedroute", + values: new RouteValueDictionary( + new + { + Action = "newaction", + Controller = "home2", + id = "someid" + }), + protocol: string.Empty, + host: "foo.bar.com"); + + // Assert + Assert.Equal("http://foo.bar.com/app/named/home2/newaction/someid", url); + } + + [Fact] + public void RouteUrlWithNullProtocol() + { + // Arrange + var urlHelper = CreateUrlHelperWithRouteCollection("/app"); + + // Act + var url = urlHelper.RouteUrl(routeName: "namedroute", + values: new RouteValueDictionary( + new + { + Action = "newaction", + Controller = "home2", + id = "someid" + }), + protocol: null, + host: "foo.bar.com"); + + // Assert + Assert.Equal("http://foo.bar.com/app/named/home2/newaction/someid", url); + } + + [Fact] + public void RouteUrlWithNullProtocolAndNullHostName() + { + // Arrange + var urlHelper = CreateUrlHelperWithRouteCollection("/app"); + + // Act + var url = urlHelper.RouteUrl(routeName: "namedroute", + values: new RouteValueDictionary( + new + { + Action = "newaction", + Controller = "home2", + id = "someid" + }), + protocol: null, + host: null); + + // Assert + Assert.Equal("/app/named/home2/newaction/someid", url); + } + + [Fact] + public void RouteUrlWithObjectProperties() + { + // Arrange + var urlHelper = CreateUrlHelperWithRouteCollection("/app"); + + // Act + var url = urlHelper.RouteUrl(new { Action = "newaction", Controller = "home2", id = "someid" }); + + // Assert + Assert.Equal("/app/home2/newaction/someid", url); + } + + [Fact] + public void RouteUrlWithProtocol() + { + // Arrange + var urlHelper = CreateUrlHelperWithRouteCollection("/app"); + + // Act + var url = urlHelper.RouteUrl(routeName: "namedroute", + values: new + { + Action = "newaction", + Controller = "home2", + id = "someid" + }, + protocol: "https"); + + // Assert + Assert.Equal("https://localhost/app/named/home2/newaction/someid", url); + } + + [Fact] + public void RouteUrlWithRouteNameAndDefaults() + { + // Arrange + var routeCollection = GetRouteCollection("MyRouteName", "any/url"); + var urlHelper = CreateUrlHelper("/app", routeCollection); + + // Act + var url = urlHelper.RouteUrl("MyRouteName"); + + // Assert + Assert.Equal("/app/any/url", url); + } + + [Fact] + public void RouteUrlWithRouteNameAndDictionary() + { + // Arrange + var urlHelper = CreateUrlHelperWithRouteCollection("/app"); + + // Act + var url = urlHelper.RouteUrl(routeName: "namedroute", + values: new RouteValueDictionary( + new + { + Action = "newaction", + Controller = "home2", + id = "someid" + })); + + // Assert + Assert.Equal("/app/named/home2/newaction/someid", url); + } + + [Fact] + public void RouteUrlWithRouteNameAndObjectProperties() + { + // Arrange + var urlHelper = CreateUrlHelperWithRouteCollection("/app"); + + // Act + var url = urlHelper.RouteUrl(routeName: "namedroute", + values: new + { + Action = "newaction", + Controller = "home2", + id = "someid" + }); + + // Assert + Assert.Equal("/app/named/home2/newaction/someid", url); + } + private static HttpContext CreateHttpContext(string appRoot) { var appRootPath = new PathString(appRoot); var request = new Mock(); request.SetupGet(r => r.PathBase) .Returns(appRootPath); + request.SetupGet(r => r.Host) + .Returns(new HostString("localhost")); var context = new Mock(); context.SetupGet(c => c.Request) .Returns(request.Object); + return context.Object; } private static IContextAccessor CreateActionContext(HttpContext context) + { + return CreateActionContext(context, (new Mock()).Object); + } + + private static IContextAccessor CreateActionContext(HttpContext context, IRouter router) { var actionContext = new ActionContext(context, - Mock.Of(), + router, new Dictionary(), new ActionDescriptor()); var contextAccessor = new Mock>(); @@ -296,5 +497,52 @@ namespace Microsoft.AspNet.Mvc.Core.Test var actionSelector = new Mock(MockBehavior.Strict); return new UrlHelper(contextAccessor, actionSelector.Object); } + + private static UrlHelper CreateUrlHelper(string appBase, IRouter router) + { + var context = CreateHttpContext(appBase); + var actionContext = CreateActionContext(context, router); + + var actionSelector = new Mock(MockBehavior.Strict); + return new UrlHelper(actionContext, actionSelector.Object); + } + + private static UrlHelper CreateUrlHelperWithRouteCollection(string appPrefix) + { + var routeCollection = GetRouteCollection(); + return CreateUrlHelper("/app", routeCollection); + } + + private static RouteCollection GetRouteCollection() + { + return GetRouteCollection("mockRoute", "/mockTemplate"); + } + + private static RouteCollection GetRouteCollection(string mockRouteName, string mockTemplateValue) + { + var rt = new RouteCollection(); + var target = new Mock(MockBehavior.Strict); + target + .Setup(e => e.GetVirtualPath(It.IsAny())) + .Callback(c => c.IsBound = true) + .Returns(rc => null); + rt.DefaultHandler = target.Object; + + rt.MapRoute(string.Empty, + "{controller}/{action}/{id}", + new RouteValueDictionary(new { id = "defaultid" })); + rt.MapRoute("namedroute", + "named/{controller}/{action}/{id}", + new RouteValueDictionary(new { id = "defaultid" })); + + var mockHttpRoute = new Mock(); + mockHttpRoute.Setup(mock => + mock.GetVirtualPath(It.Is(c => string.Equals(c.RouteName, + mockRouteName) + ))) + .Returns(mockTemplateValue); + rt.Add(mockHttpRoute.Object); + return rt; + } } -} +} \ No newline at end of file