parent
a9b47f6722
commit
b01072eb47
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.Dispatcher;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Dispatcher;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Routing.Template;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace DispatcherSample
|
||||
|
|
@ -13,6 +16,60 @@ namespace DispatcherSample
|
|||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.Configure<DispatcherOptions>(options =>
|
||||
{
|
||||
options.DispatcherEntryList = new List<DispatcherEntry>()
|
||||
{
|
||||
new DispatcherEntry
|
||||
{
|
||||
RouteTemplate = TemplateParser.Parse("{Endpoint=example}"),
|
||||
Endpoints = new []
|
||||
{
|
||||
new RouteValuesEndpoint("example")
|
||||
{
|
||||
RequiredValues = new RouteValueDictionary(new { Endpoint = "First" }),
|
||||
RequestDelegate = async (context) =>
|
||||
{
|
||||
await context.Response.WriteAsync("Hello from the example!");
|
||||
}
|
||||
},
|
||||
new RouteValuesEndpoint("example2")
|
||||
{
|
||||
RequiredValues = new RouteValueDictionary(new { Endpoint = "Second" }),
|
||||
RequestDelegate = async (context) =>
|
||||
{
|
||||
await context.Response.WriteAsync("Hello from the second example!");
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
new DispatcherEntry
|
||||
{
|
||||
RouteTemplate = TemplateParser.Parse("{Endpoint=example}/{Parameter=foo}"),
|
||||
Endpoints = new []
|
||||
{
|
||||
new RouteValuesEndpoint("example")
|
||||
{
|
||||
RequiredValues = new RouteValueDictionary(new { Endpoint = "First", Parameter = "param1"}),
|
||||
RequestDelegate = async (context) =>
|
||||
{
|
||||
await context.Response.WriteAsync("Hello from the example for foo!");
|
||||
}
|
||||
},
|
||||
new RouteValuesEndpoint("example2")
|
||||
{
|
||||
RequiredValues = new RouteValueDictionary(new { Endpoint = "Second", Parameter = "param2"}),
|
||||
RequestDelegate = async (context) =>
|
||||
{
|
||||
await context.Response.WriteAsync("Hello from the second example for foo!");
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
services.AddSingleton<UrlGenerator>();
|
||||
services.AddSingleton<RouteValueAddressTable>();
|
||||
services.AddDispatcher();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Routing.Template;
|
||||
|
||||
namespace Microsoft.AspNetCore.Dispatcher
|
||||
{
|
||||
public class DispatcherEntry
|
||||
{
|
||||
public IList<RouteValuesEndpoint> Endpoints { get; set; }
|
||||
|
||||
public RouteTemplate RouteTemplate { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,60 +1,98 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Routing.Template;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Dispatcher
|
||||
{
|
||||
public class DispatcherMiddleware
|
||||
{
|
||||
private readonly DispatcherOptions _options;
|
||||
private readonly RequestDelegate _next;
|
||||
|
||||
public DispatcherMiddleware(RequestDelegate next)
|
||||
public DispatcherMiddleware(IOptions<DispatcherOptions> options, RequestDelegate next)
|
||||
{
|
||||
_options = options.Value;
|
||||
_next = next;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext httpContext)
|
||||
{
|
||||
var dictionary = new Dictionary<string, DispatcherFeature>
|
||||
foreach (var entry in _options.DispatcherEntryList)
|
||||
{
|
||||
{
|
||||
"/example",
|
||||
new DispatcherFeature
|
||||
{
|
||||
Endpoint = new DispatcherEndpoint("example"),
|
||||
RequestDelegate = async (context) =>
|
||||
{
|
||||
await context.Response.WriteAsync("Hello from the example!");
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"/example2",
|
||||
new DispatcherFeature
|
||||
{
|
||||
Endpoint = new DispatcherEndpoint("example2"),
|
||||
RequestDelegate = async (context) =>
|
||||
{
|
||||
await context.Response.WriteAsync("Hello from the second example!");
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
var parsedTemplate = entry.RouteTemplate;
|
||||
var defaults = GetDefaults(parsedTemplate);
|
||||
var templateMatcher = new TemplateMatcher(parsedTemplate, defaults);
|
||||
var values = new RouteValueDictionary();
|
||||
|
||||
if (dictionary.TryGetValue(httpContext.Request.Path, out var value))
|
||||
{
|
||||
var dispatcherFeature = new DispatcherFeature
|
||||
foreach (var endpoint in entry.Endpoints)
|
||||
{
|
||||
Endpoint = value.Endpoint,
|
||||
RequestDelegate = value.RequestDelegate
|
||||
};
|
||||
if (templateMatcher.TryMatch(httpContext.Request.Path, values))
|
||||
{
|
||||
if (!CompareRouteValues(values, endpoint.RequiredValues))
|
||||
{
|
||||
values.Clear();
|
||||
}
|
||||
|
||||
httpContext.Features.Set<IDispatcherFeature>(dispatcherFeature);
|
||||
await _next(httpContext);
|
||||
else
|
||||
{
|
||||
var dispatcherFeature = new DispatcherFeature
|
||||
{
|
||||
Endpoint = endpoint,
|
||||
RequestDelegate = endpoint.RequestDelegate
|
||||
};
|
||||
|
||||
httpContext.Features.Set<IDispatcherFeature>(dispatcherFeature);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await _next(httpContext);
|
||||
}
|
||||
|
||||
private RouteValueDictionary GetDefaults(RouteTemplate parsedTemplate)
|
||||
{
|
||||
var result = new RouteValueDictionary();
|
||||
|
||||
foreach (var parameter in parsedTemplate.Parameters)
|
||||
{
|
||||
if (parameter.DefaultValue != null)
|
||||
{
|
||||
result.Add(parameter.Name, parameter.DefaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool CompareRouteValues(RouteValueDictionary values, RouteValueDictionary requiredValues)
|
||||
{
|
||||
foreach (var kvp in requiredValues)
|
||||
{
|
||||
if (string.IsNullOrEmpty(kvp.Value.ToString()))
|
||||
{
|
||||
if (values.TryGetValue(kvp.Key, out var routeValue) && !string.IsNullOrEmpty(routeValue.ToString()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!values.TryGetValue(kvp.Key, out var routeValue) || !string.Equals(kvp.Value.ToString(), routeValue.ToString(), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNetCore.Dispatcher
|
||||
{
|
||||
public class DispatcherOptions
|
||||
{
|
||||
public IList<DispatcherEntry> DispatcherEntryList { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,8 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Dispatcher.Abstractions\Microsoft.AspNetCore.Dispatcher.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\Microsoft.AspNetCore.Dispatcher.Abstractions\Microsoft.AspNetCore.Dispatcher.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\Microsoft.AspNetCore.Routing\Microsoft.AspNetCore.Routing.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
|
||||
namespace Microsoft.AspNetCore.Dispatcher
|
||||
{
|
||||
public class RouteValuesEndpoint : Endpoint
|
||||
{
|
||||
public RouteValuesEndpoint(string displayName)
|
||||
{
|
||||
DisplayName = displayName;
|
||||
}
|
||||
|
||||
public override string DisplayName { get; }
|
||||
|
||||
public RequestDelegate RequestDelegate { get; set; }
|
||||
|
||||
public RouteValueDictionary RequiredValues { get; set; }
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue