diff --git a/Microsoft.AspNet.AngularServices/project.json b/Microsoft.AspNet.AngularServices/project.json index 41c8f1a..01fbeb6 100644 --- a/Microsoft.AspNet.AngularServices/project.json +++ b/Microsoft.AspNet.AngularServices/project.json @@ -26,7 +26,8 @@ }, "dependencies": { "Microsoft.AspNet.NodeServices": "1.0.0-alpha7", - "Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-rc1-*" + "Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-rc1-*", + "Microsoft.AspNet.SpaServices": "1.0.0-alpha7" }, "resource": [ "Content/**/*" diff --git a/Microsoft.AspNet.SpaServices/.gitignore b/Microsoft.AspNet.SpaServices/.gitignore new file mode 100644 index 0000000..ae3c172 --- /dev/null +++ b/Microsoft.AspNet.SpaServices/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/Microsoft.AspNet.SpaServices/SpaRouteConstraint.cs b/Microsoft.AspNet.SpaServices/SpaRouteConstraint.cs new file mode 100644 index 0000000..d4df4c7 --- /dev/null +++ b/Microsoft.AspNet.SpaServices/SpaRouteConstraint.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.Routing; + +namespace Microsoft.AspNet.SpaServices +{ + internal class SpaRouteConstraint : IRouteConstraint + { + private readonly string clientRouteTokenName; + + public SpaRouteConstraint(string clientRouteTokenName) { + if (string.IsNullOrEmpty(clientRouteTokenName)) { + throw new ArgumentException("Value cannot be null or empty", "clientRouteTokenName"); + } + + this.clientRouteTokenName = clientRouteTokenName; + } + + public bool Match(HttpContext httpContext, IRouter route, string routeKey, IDictionary values, RouteDirection routeDirection) + { + var clientRouteValue = (values[this.clientRouteTokenName] as string) ?? string.Empty; + return !HasDotInLastSegment(clientRouteValue); + } + + private bool HasDotInLastSegment(string uri) + { + var lastSegmentStartPos = uri.LastIndexOf('/'); + return uri.IndexOf('.', lastSegmentStartPos + 1) >= 0; + } + } +} diff --git a/Microsoft.AspNet.SpaServices/SpaRouteExtensions.cs b/Microsoft.AspNet.SpaServices/SpaRouteExtensions.cs new file mode 100644 index 0000000..a471204 --- /dev/null +++ b/Microsoft.AspNet.SpaServices/SpaRouteExtensions.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using Microsoft.AspNet.Routing; +using Microsoft.AspNet.SpaServices; + +// Putting in this namespace so it's always available whenever MapRoute is +namespace Microsoft.AspNet.Builder +{ + public static class SpaRouteExtensions + { + private const string ClientRouteTokenName = "clientRoute"; + + public static void MapSpaFallbackRoute(this IRouteBuilder routeBuilder, string name, object defaults, object constraints = null, object dataTokens = null) + { + MapSpaFallbackRoute(routeBuilder, name, /* templatePrefix */ (string)null, defaults, constraints, dataTokens); + } + + public static void MapSpaFallbackRoute(this IRouteBuilder routeBuilder, string name, string templatePrefix, object defaults, object constraints = null, object dataTokens = null) + { + var template = CreateRouteTemplate(templatePrefix); + + var constraintsDict = ObjectToDictionary(constraints); + constraintsDict.Add(ClientRouteTokenName, new SpaRouteConstraint(ClientRouteTokenName)); + + routeBuilder.MapRoute(name, template, defaults, constraintsDict, dataTokens); + } + + private static string CreateRouteTemplate(string templatePrefix) + { + templatePrefix = templatePrefix ?? string.Empty; + + if (templatePrefix.Contains("?")) { + // TODO: Consider supporting this. The {*clientRoute} part should be added immediately before the '?' + throw new ArgumentException("SPA fallback route templates don't support querystrings"); + } + + if (templatePrefix.Contains("#")) { + throw new ArgumentException("SPA fallback route templates should not include # characters. The hash part of a URI does not get sent to the server."); + } + + if (templatePrefix != string.Empty && !templatePrefix.EndsWith("/")) { + templatePrefix += "/"; + } + + return templatePrefix + $"{{*{ ClientRouteTokenName }}}"; + } + + private static IDictionary ObjectToDictionary(object value) + { + return value as IDictionary ?? new RouteValueDictionary(value); + } + } +} diff --git a/Microsoft.AspNet.SpaServices/project.json b/Microsoft.AspNet.SpaServices/project.json new file mode 100644 index 0000000..19c848c --- /dev/null +++ b/Microsoft.AspNet.SpaServices/project.json @@ -0,0 +1,22 @@ +{ + "version": "1.0.0-alpha7", + "description": "Microsoft.AspNet.SpaServices", + "authors": [ + "Microsoft" + ], + "tags": [ + "" + ], + "projectUrl": "", + "licenseUrl": "", + "dependencies": { + "Microsoft.AspNet.Routing": "1.0.0-rc1-*" + }, + "frameworks": { + "dnx451": {}, + "dnxcore50": { + "dependencies": { + } + } + } +} \ No newline at end of file diff --git a/samples/angular/MusicStore/Startup.cs b/samples/angular/MusicStore/Startup.cs index e49748e..eda8958 100755 --- a/samples/angular/MusicStore/Startup.cs +++ b/samples/angular/MusicStore/Startup.cs @@ -3,9 +3,7 @@ using System.Collections.Generic; using Microsoft.AspNet.Authorization; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Hosting; -using Microsoft.AspNet.Http; using Microsoft.AspNet.Identity.EntityFramework; -using Microsoft.AspNet.Routing; using Microsoft.Data.Entity; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -125,61 +123,4 @@ namespace MusicStore }); } } - internal static class SpaRouteExtensions { - private const string ClientRouteTokenName = "clientRoute"; - - public static void MapSpaFallbackRoute(this IRouteBuilder routeBuilder, string name, object defaults, object constraints = null, object dataTokens = null) { - MapSpaFallbackRoute(routeBuilder, name, /* templatePrefix */ (string)null, defaults, constraints, dataTokens); - } - - public static void MapSpaFallbackRoute(this IRouteBuilder routeBuilder, string name, string templatePrefix, object defaults, object constraints = null, object dataTokens = null) - { - var template = CreateRouteTemplate(templatePrefix); - - var constraintsDict = ObjectToDictionary(constraints); - constraintsDict.Add(ClientRouteTokenName, new SpaRouteConstraint()); - - routeBuilder.MapRoute(name, template, defaults, constraintsDict, dataTokens); - } - - private static string CreateRouteTemplate(string templatePrefix) - { - templatePrefix = templatePrefix ?? string.Empty; - - if (templatePrefix.Contains("?")) { - // TODO: Consider supporting this. The {*clientRoute} part should be added immediately before the '?' - throw new ArgumentException("SPA fallback route templates don't support querystrings"); - } - - if (templatePrefix.Contains("#")) { - throw new ArgumentException("SPA fallback route templates should not include # characters. The hash part of a URI does not get sent to the server."); - } - - if (templatePrefix != string.Empty && !templatePrefix.EndsWith("/")) { - templatePrefix += "/"; - } - - return templatePrefix + $"{{*{ ClientRouteTokenName }}}"; - } - - private static IDictionary ObjectToDictionary(object value) - { - return value as IDictionary ?? new RouteValueDictionary(value); - } - - private class SpaRouteConstraint : IRouteConstraint - { - public bool Match(HttpContext httpContext, IRouter route, string routeKey, IDictionary values, RouteDirection routeDirection) - { - var clientRouteValue = (values[ClientRouteTokenName] as string) ?? string.Empty; - return !HasDotInLastSegment(clientRouteValue); - } - - private bool HasDotInLastSegment(string uri) - { - var lastSegmentStartPos = uri.LastIndexOf('/'); - return uri.IndexOf('.', lastSegmentStartPos + 1) >= 0; - } - } - } }