Forked from maartenba/DomainTemplateRoute - GetVirtualPath
Last active
August 29, 2015 14:15
-
-
Save mahizsas/6911adbc95fce7a2b711 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public string GetVirtualPath(VirtualPathContext context) | |
{ | |
foreach (var matcherParameter in _matcher.Template.Parameters) | |
{ | |
context.Values.Remove(matcherParameter.Name); // make sure none of the domain-placeholders are appended as query string parameters | |
} | |
return _innerRoute.GetVirtualPath(context); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public async Task RouteAsync(RouteContext context) | |
{ | |
EnsureLoggers(context.HttpContext); | |
using (_logger.BeginScope("DomainTemplateRoute.RouteAsync")) | |
{ | |
var requestHost = context.HttpContext.Request.Host.Value; | |
if (IgnorePort && requestHost.Contains(":")) // check if we want to match a port as well | |
{ | |
requestHost = requestHost.Substring(0, requestHost.IndexOf(":")); | |
} | |
var values = _matcher.Match(requestHost); | |
if (values == null) | |
{ | |
// if we got back a null value set, that means the URI did not match | |
return; | |
} | |
var oldRouteData = context.RouteData; | |
var newRouteData = new RouteData(oldRouteData); | |
MergeValues(newRouteData.DataTokens, DataTokens); | |
newRouteData.Routers.Add(_target); | |
MergeValues(newRouteData.Values, values.ToImmutableDictionary()); | |
try | |
{ | |
context.RouteData = newRouteData; | |
// delegate further processing to inner route | |
await _innerRoute.RouteAsync(context); | |
} | |
finally | |
{ | |
// Restore the original values to prevent polluting the route data. | |
if (!context.IsHandled) | |
{ | |
context.RouteData = oldRouteData; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Collections.Immutable; | |
using System.Threading.Tasks; | |
using Microsoft.AspNet.Http; | |
using Microsoft.AspNet.Routing; | |
using Microsoft.AspNet.Routing.Template; | |
using Microsoft.Framework.DependencyInjection; | |
using Microsoft.Framework.Logging; | |
namespace Multitenancy.Routing | |
{ | |
public class DomainTemplateRoute | |
: INamedRouter, IRouter | |
{ | |
private readonly TemplateRoute _innerRoute; | |
private readonly IRouter _target; | |
private readonly string _domainTemplate; | |
private readonly TemplateMatcher _matcher; | |
private ILogger _logger; | |
public DomainTemplateRoute(IRouter target, string domainTemplate, string routeTemplate, bool ignorePort, IInlineConstraintResolver inlineConstraintResolver) | |
: this(target, domainTemplate, routeTemplate, null, null, null, ignorePort, inlineConstraintResolver) | |
{ | |
} | |
public DomainTemplateRoute(IRouter target, string domainTemplate, string routeTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, bool ignorePort, IInlineConstraintResolver inlineConstraintResolver) | |
: this(target, null, domainTemplate, routeTemplate, defaults, constraints, dataTokens, ignorePort, inlineConstraintResolver) | |
{ | |
} | |
public DomainTemplateRoute(IRouter target, string routeName, string domainTemplate, string routeTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, bool ignorePort, IInlineConstraintResolver inlineConstraintResolver) | |
{ | |
_innerRoute = new TemplateRoute(target, routeName, routeTemplate, defaults, constraints, dataTokens, inlineConstraintResolver); | |
_target = target; | |
_domainTemplate = domainTemplate; | |
_matcher = new TemplateMatcher( | |
TemplateParser.Parse(DomainTemplate), Defaults); | |
Name = routeName; | |
IgnorePort = ignorePort; | |
} | |
public string Name { get; private set; } | |
public IReadOnlyDictionary<string, object> Defaults | |
{ | |
get | |
{ | |
return _innerRoute.Defaults; | |
} | |
} | |
public IReadOnlyDictionary<string, object> DataTokens | |
{ | |
get | |
{ | |
return _innerRoute.DataTokens; | |
} | |
} | |
public string RouteTemplate | |
{ | |
get | |
{ | |
return _innerRoute.RouteTemplate; | |
} | |
} | |
public IReadOnlyDictionary<string, IRouteConstraint> Constraints | |
{ | |
get | |
{ | |
return _innerRoute.Constraints; | |
} | |
} | |
public string DomainTemplate | |
{ | |
get | |
{ | |
return _domainTemplate; | |
} | |
} | |
public bool IgnorePort { get; set; } | |
public async Task RouteAsync(RouteContext context) | |
{ | |
EnsureLoggers(context.HttpContext); | |
using (_logger.BeginScope("DomainTemplateRoute.RouteAsync")) | |
{ | |
var requestHost = context.HttpContext.Request.Host.Value; | |
if (IgnorePort && requestHost.Contains(":")) | |
{ | |
requestHost = requestHost.Substring(0, requestHost.IndexOf(":")); | |
} | |
var values = _matcher.Match(requestHost); | |
if (values == null) | |
{ | |
if (_logger.IsEnabled(LogLevel.Verbose)) | |
{ | |
_logger.WriteVerbose("DomainTemplateRoute " + Name + " - Host \"" + context.HttpContext.Request.Host + "\" did not match."); | |
} | |
// If we got back a null value set, that means the URI did not match | |
return; | |
} | |
var oldRouteData = context.RouteData; | |
var newRouteData = new RouteData(oldRouteData); | |
MergeValues(newRouteData.DataTokens, DataTokens); | |
newRouteData.Routers.Add(_target); | |
MergeValues(newRouteData.Values, values.ToImmutableDictionary()); | |
try | |
{ | |
context.RouteData = newRouteData; | |
// delegate further processing to inner route | |
await _innerRoute.RouteAsync(context); | |
} | |
finally | |
{ | |
// Restore the original values to prevent polluting the route data. | |
if (!context.IsHandled) | |
{ | |
context.RouteData = oldRouteData; | |
} | |
} | |
} | |
} | |
public string GetVirtualPath(VirtualPathContext context) | |
{ | |
foreach (var matcherParameter in _matcher.Template.Parameters) | |
{ | |
context.Values.Remove(matcherParameter.Name); // make sure none of the domain-placeholders are appended as query string parameters | |
} | |
return _innerRoute.GetVirtualPath(context); | |
} | |
private static void MergeValues(IDictionary<string, object> destination, IReadOnlyDictionary<string, object> values) | |
{ | |
foreach (var kvp in values) | |
{ | |
// This will replace the original value for the specified key. | |
// Values from the matched route will take preference over previous | |
// data in the route context. | |
destination[kvp.Key] = kvp.Value; | |
} | |
} | |
private void EnsureLoggers(HttpContext context) | |
{ | |
if (_logger == null) | |
{ | |
var factory = context.RequestServices.GetRequiredService<ILoggerFactory>(); | |
_logger = factory.Create<TemplateRoute>(); | |
} | |
} | |
public override string ToString() | |
{ | |
return _domainTemplate + "/" + RouteTemplate; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using Microsoft.AspNet.Routing; | |
using Microsoft.Framework.DependencyInjection; | |
namespace Multitenancy.Routing | |
{ | |
public static class DomainTemplateRouteBuilderExtensions | |
{ | |
public static IRouteBuilder MapDomainRoute(this IRouteBuilder routeCollectionBuilder, string name, string domainTemplate, string routeTemplate) | |
{ | |
MapDomainRoute(routeCollectionBuilder, name, domainTemplate, routeTemplate, (object)null); | |
return routeCollectionBuilder; | |
} | |
public static IRouteBuilder MapDomainRoute(this IRouteBuilder routeCollectionBuilder, string name, string domainTemplate, string routeTemplate, object defaults, bool ignorePort = true) | |
{ | |
return MapDomainRoute(routeCollectionBuilder, name, domainTemplate, routeTemplate, defaults, null, ignorePort); | |
} | |
public static IRouteBuilder MapDomainRoute(this IRouteBuilder routeCollectionBuilder, string name, string domainTemplate, string routeTemplate, object defaults, object constraints, bool ignorePort = true) | |
{ | |
return MapDomainRoute(routeCollectionBuilder, name, domainTemplate, routeTemplate, defaults, constraints, null, ignorePort); | |
} | |
public static IRouteBuilder MapDomainRoute(this IRouteBuilder routeCollectionBuilder, string name, string domainTemplate, string routeTemplate, object defaults, object constraints, object dataTokens, bool ignorePort = true) | |
{ | |
if (routeCollectionBuilder.DefaultHandler == null) | |
throw new InvalidOperationException("Default handler must be set."); | |
var inlineConstraintResolver = routeCollectionBuilder.ServiceProvider.GetRequiredService<IInlineConstraintResolver>(); | |
routeCollectionBuilder.Routes.Add(new DomainTemplateRoute(routeCollectionBuilder.DefaultHandler, name, domainTemplate, routeTemplate, ObjectToDictionary(defaults), ObjectToDictionary(constraints), ObjectToDictionary(dataTokens), ignorePort, inlineConstraintResolver)); | |
return routeCollectionBuilder; | |
} | |
private static IDictionary<string, object> ObjectToDictionary(object value) | |
{ | |
return value as IDictionary<string, object> ?? new RouteValueDictionary(value); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Multitenancy.Features | |
{ | |
public interface ITenantFeature | |
{ | |
Tenant Tenant { get; } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"authors": [ "Maarten Balliauw <[email protected]>" ], | |
"description": "Domain routing and tenant middleware.", | |
"version": "1.0.0-*", | |
"dependencies": { | |
"Microsoft.AspNet.Mvc": "6.0.0-beta4-12742", | |
"Microsoft.AspNet.Diagnostics": "1.0.0-beta4-12200", | |
"Microsoft.Framework.Logging": "1.0.0-beta4-10854" | |
}, | |
"frameworks": { | |
"aspnet50": { | |
"dependencies": { | |
} | |
}, | |
"aspnetcore50": { | |
"dependencies": { | |
"System.Runtime": "4.0.20-beta-22231" | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Multitenancy.Features | |
{ | |
public class Tenant | |
{ | |
public string Id { get; set; } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Multitenancy.Features | |
{ | |
public class TenantFeature | |
: ITenantFeature | |
{ | |
public TenantFeature(Tenant tenant) | |
{ | |
Tenant = tenant; | |
} | |
public Tenant Tenant { get; private set; } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Threading.Tasks; | |
using Microsoft.AspNet.Builder; | |
using Microsoft.AspNet.Http; | |
using Microsoft.Framework.Logging; | |
namespace Multitenancy.Features | |
{ | |
public class TenantResolverMiddleware | |
{ | |
private readonly RequestDelegate _next; | |
private readonly ILogger _logger; | |
public TenantResolverMiddleware(RequestDelegate next, ILoggerFactory loggerFactory) | |
{ | |
_next = next; | |
_logger = loggerFactory.Create<TenantResolverMiddleware>(); | |
} | |
public async Task Invoke(HttpContext context) | |
{ | |
using (_logger.BeginScope("TenantResolverMiddleware")) | |
{ | |
var tenant = new Tenant | |
{ | |
Id = "Sample" // todo: determine this based on HttpContext etc. | |
}; | |
_logger.WriteInformation(string.Format("Resolved tenant. Current tenant: {0}", tenant.Id)); | |
var tenantFeature = new TenantFeature(tenant); | |
context.SetFeature<ITenantFeature>(tenantFeature); | |
await _next(context); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.AspNet.Builder; | |
namespace Multitenancy.Features | |
{ | |
public static class TenantResolverMiddlewareAppBuilderExtensions | |
{ | |
public static void UseTenantResolver(this IApplicationBuilder builder) | |
{ | |
builder.UseMiddleware<TenantResolverMiddleware>(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ... | |
app.UseMvc(routes => | |
{ | |
routes.MapDomainRoute( | |
name: "SampleDomainRoute", | |
domainTemplate: "{tenant}.localtest.me", | |
routeTemplate: "{controller}/{action}/{id?}", | |
defaults: new { controller = "Home", action = "Index" }); | |
// ... more routes here ... | |
}); | |
// ... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
app.UseTenantResolver(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment