Respond to feedback about handler factory
- Handler factories are now associated with the dispatcher entry - Handler factory is now an interface
This commit is contained in:
parent
63d2cc4637
commit
56ae2e0177
|
|
@ -1,17 +0,0 @@
|
||||||
// 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;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Dispatcher
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A delegate which attempts to create a <see cref="Func{RequestDelegate, RequestDelegate}"/> for the selected <see cref="Endpoint"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="endpoint">The <see cref="Endpoint"/> selected by the dispatcher.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// A <see cref="Func{RequestDelegate, RequestDelegate}"/> that invokes the operation represented by the <see cref="Endpoint"/>, or <c>null</c>.
|
|
||||||
/// </returns>
|
|
||||||
public delegate Func<RequestDelegate, RequestDelegate> EndpointHandlerFactory(Endpoint endpoint);
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
// 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;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Dispatcher
|
||||||
|
{
|
||||||
|
public class CompositeHandlerFactory : IHandlerFactory
|
||||||
|
{
|
||||||
|
private readonly IHandlerFactory[] _factories;
|
||||||
|
|
||||||
|
public CompositeHandlerFactory(IEnumerable<IHandlerFactory> factories)
|
||||||
|
{
|
||||||
|
if (factories == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(factories));
|
||||||
|
}
|
||||||
|
|
||||||
|
_factories = factories.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Func<RequestDelegate, RequestDelegate> CreateHandler(Endpoint endpoint)
|
||||||
|
{
|
||||||
|
if (endpoint == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(endpoint));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < _factories.Length; i++)
|
||||||
|
{
|
||||||
|
var handler = _factories[i].CreateHandler(endpoint);
|
||||||
|
if (handler != null)
|
||||||
|
{
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,13 +12,13 @@ namespace Microsoft.AspNetCore.Dispatcher
|
||||||
private readonly IEnumerable<DispatcherDataSource> _dataSources;
|
private readonly IEnumerable<DispatcherDataSource> _dataSources;
|
||||||
private readonly IDefaultMatcherFactory _dispatcherFactory;
|
private readonly IDefaultMatcherFactory _dispatcherFactory;
|
||||||
private readonly IEnumerable<EndpointSelector> _endpointSelectors;
|
private readonly IEnumerable<EndpointSelector> _endpointSelectors;
|
||||||
private readonly IEnumerable<EndpointHandlerFactoryBase> _handlerFactories;
|
private readonly IEnumerable<IHandlerFactory> _handlerFactories;
|
||||||
|
|
||||||
public DefaultDispatcherConfigureOptions(
|
public DefaultDispatcherConfigureOptions(
|
||||||
IDefaultMatcherFactory dispatcherFactory,
|
IDefaultMatcherFactory dispatcherFactory,
|
||||||
IEnumerable<DispatcherDataSource> dataSources,
|
IEnumerable<DispatcherDataSource> dataSources,
|
||||||
IEnumerable<EndpointSelector> endpointSelectors,
|
IEnumerable<EndpointSelector> endpointSelectors,
|
||||||
IEnumerable<EndpointHandlerFactoryBase> handlerFactories)
|
IEnumerable<IHandlerFactory> handlerFactories)
|
||||||
{
|
{
|
||||||
_dispatcherFactory = dispatcherFactory;
|
_dispatcherFactory = dispatcherFactory;
|
||||||
_dataSources = dataSources;
|
_dataSources = dataSources;
|
||||||
|
|
@ -33,12 +33,15 @@ namespace Microsoft.AspNetCore.Dispatcher
|
||||||
throw new ArgumentNullException(nameof(options));
|
throw new ArgumentNullException(nameof(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
options.Matchers.Add(_dispatcherFactory.CreateDispatcher(new CompositeDispatcherDataSource(_dataSources), _endpointSelectors));
|
var matcher = _dispatcherFactory.CreateMatcher(new CompositeDispatcherDataSource(_dataSources), _endpointSelectors);
|
||||||
|
|
||||||
foreach (var handlerFactory in _handlerFactories)
|
options.Matchers.Add(new MatcherEntry()
|
||||||
{
|
{
|
||||||
options.HandlerFactories.Add(handlerFactory.CreateHandler);
|
Matcher = matcher,
|
||||||
}
|
AddressProvider = matcher as IAddressCollectionProvider,
|
||||||
|
EndpointProvider = matcher as IEndpointCollectionProvider,
|
||||||
|
HandlerFactory = new CompositeHandlerFactory(_handlerFactories),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,15 +63,10 @@ namespace Microsoft.AspNetCore.Dispatcher
|
||||||
feature.Endpoint = context.Endpoint;
|
feature.Endpoint = context.Endpoint;
|
||||||
feature.Values = context.Values;
|
feature.Values = context.Values;
|
||||||
|
|
||||||
// Associate this with the DispatcherEntry, not global
|
feature.Handler = entry.HandlerFactory.CreateHandler(feature.Endpoint);
|
||||||
for (var i = 0; i < _options.HandlerFactories.Count; i++)
|
if (feature.Handler == null)
|
||||||
{
|
{
|
||||||
var middleware = _options.HandlerFactories[i](feature.Endpoint);
|
throw new InvalidOperationException("Couldn't create a handler, that's bad.");
|
||||||
if (middleware != null)
|
|
||||||
{
|
|
||||||
feature.Handler = middleware;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,5 @@ namespace Microsoft.AspNetCore.Dispatcher
|
||||||
public class DispatcherOptions
|
public class DispatcherOptions
|
||||||
{
|
{
|
||||||
public MatcherCollection Matchers { get; } = new MatcherCollection();
|
public MatcherCollection Matchers { get; } = new MatcherCollection();
|
||||||
|
|
||||||
public IList<EndpointHandlerFactory> HandlerFactories { get; } = new List<EndpointHandlerFactory>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
services.AddSingleton<AddressTable, DefaultAddressTable>();
|
services.AddSingleton<AddressTable, DefaultAddressTable>();
|
||||||
services.AddSingleton<TemplateAddressSelector>();
|
services.AddSingleton<TemplateAddressSelector>();
|
||||||
|
|
||||||
services.TryAddEnumerable(ServiceDescriptor.Singleton<EndpointHandlerFactoryBase, TemplateEndpointHandlerFactory>());
|
services.TryAddEnumerable(ServiceDescriptor.Singleton<IHandlerFactory, TemplateEndpointHandlerFactory>());
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
// 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;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Dispatcher
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A simple implementation of <see cref="IHandlerFactory"/> that adapts a particular endpoint
|
||||||
|
/// type to a handler.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class HandlerFactory<TEndpoint> : IHandlerFactory
|
||||||
|
{
|
||||||
|
private readonly Func<TEndpoint, Func<RequestDelegate, RequestDelegate>> _adapter;
|
||||||
|
|
||||||
|
public HandlerFactory(Func<TEndpoint, Func<RequestDelegate, RequestDelegate>> adapter)
|
||||||
|
{
|
||||||
|
if (adapter == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(adapter));
|
||||||
|
}
|
||||||
|
|
||||||
|
_adapter = adapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Func<RequestDelegate, RequestDelegate> CreateHandler(Endpoint endpoint)
|
||||||
|
{
|
||||||
|
if (endpoint == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(endpoint));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endpoint is TEndpoint myTypeOfEndpoint)
|
||||||
|
{
|
||||||
|
return _adapter(myTypeOfEndpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,6 @@ namespace Microsoft.AspNetCore.Dispatcher
|
||||||
{
|
{
|
||||||
public interface IDefaultMatcherFactory
|
public interface IDefaultMatcherFactory
|
||||||
{
|
{
|
||||||
MatcherEntry CreateDispatcher(DispatcherDataSource dataSource, IEnumerable<EndpointSelector> endpointSelectors);
|
IMatcher CreateMatcher(DispatcherDataSource dataSource, IEnumerable<EndpointSelector> endpointSelectors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,20 +8,20 @@ namespace Microsoft.AspNetCore.Dispatcher
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>
|
/// <para>
|
||||||
/// Base class for implementations that can create a middleware-like delegate from an <see cref="Endpoint"/>.
|
/// An interface for components that can create a middleware-like delegate from an <see cref="Endpoint"/>.
|
||||||
/// </para>
|
/// </para>
|
||||||
/// <para>
|
/// <para>
|
||||||
/// Implementations registered in the application services using the service type <see cref="EndpointHandlerFactoryBase"/>
|
/// Implementations registered in the application services using the service type <see cref="IHandlerFactory"/>
|
||||||
/// will be automatically added to <see cref="DispatcherOptions.HandlerFactories"/>.
|
/// will be automatically added to set of handler factories used by the default dispatcher.
|
||||||
/// </para>
|
/// </para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class EndpointHandlerFactoryBase
|
public interface IHandlerFactory
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a middleware-like delegate for the provided <see cref="Endpoint"/>.
|
/// Creates a middleware-like delegate for the provided <see cref="Endpoint"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="endpoint">The <see cref="Endpoint"/> that will execute for the current request.</param>
|
/// <param name="endpoint">The <see cref="Endpoint"/> that will execute for the current request.</param>
|
||||||
/// <returns>An <see cref="Func{RequestDelegate, RequestDelegate}"/> or <c>null</c>.</returns>
|
/// <returns>An <see cref="Func{RequestDelegate, RequestDelegate}"/> or <c>null</c>.</returns>
|
||||||
public abstract Func<RequestDelegate, RequestDelegate> CreateHandler(Endpoint endpoint);
|
Func<RequestDelegate, RequestDelegate> CreateHandler(Endpoint endpoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Dispatcher
|
||||||
{
|
{
|
||||||
public class MatcherCollection : Collection<MatcherEntry>
|
public class MatcherCollection : Collection<MatcherEntry>
|
||||||
{
|
{
|
||||||
public void Add(MatcherBase matcher)
|
public void Add(IMatcher matcher, IHandlerFactory handerFactory)
|
||||||
{
|
{
|
||||||
if (matcher == null)
|
if (matcher == null)
|
||||||
{
|
{
|
||||||
|
|
@ -18,21 +18,10 @@ namespace Microsoft.AspNetCore.Dispatcher
|
||||||
Add(new MatcherEntry()
|
Add(new MatcherEntry()
|
||||||
{
|
{
|
||||||
Matcher = matcher,
|
Matcher = matcher,
|
||||||
AddressProvider = matcher,
|
AddressProvider = matcher as IAddressCollectionProvider,
|
||||||
EndpointProvider = matcher,
|
EndpointProvider = matcher as IEndpointCollectionProvider,
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(IMatcher matcher)
|
HandlerFactory = handerFactory,
|
||||||
{
|
|
||||||
if (matcher == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(matcher));
|
|
||||||
}
|
|
||||||
|
|
||||||
Add(new MatcherEntry()
|
|
||||||
{
|
|
||||||
Matcher = matcher,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ namespace Microsoft.AspNetCore.Dispatcher
|
||||||
{
|
{
|
||||||
public class MatcherEntry
|
public class MatcherEntry
|
||||||
{
|
{
|
||||||
|
public IHandlerFactory HandlerFactory { get; set; }
|
||||||
|
|
||||||
public IMatcher Matcher { get; set; }
|
public IMatcher Matcher { get; set; }
|
||||||
|
|
||||||
public IAddressCollectionProvider AddressProvider { get; set; }
|
public IAddressCollectionProvider AddressProvider { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@ using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Dispatcher
|
namespace Microsoft.AspNetCore.Dispatcher
|
||||||
{
|
{
|
||||||
public class TemplateEndpointHandlerFactory : EndpointHandlerFactoryBase
|
public sealed class TemplateEndpointHandlerFactory : IHandlerFactory
|
||||||
{
|
{
|
||||||
public override Func<RequestDelegate, RequestDelegate> CreateHandler(Endpoint endpoint)
|
public Func<RequestDelegate, RequestDelegate> CreateHandler(Endpoint endpoint)
|
||||||
{
|
{
|
||||||
if (endpoint == null)
|
if (endpoint == null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Routing.Dispatcher
|
||||||
{
|
{
|
||||||
public class TreeMatcherFactory : IDefaultMatcherFactory
|
public class TreeMatcherFactory : IDefaultMatcherFactory
|
||||||
{
|
{
|
||||||
public MatcherEntry CreateDispatcher(DispatcherDataSource dataSource, IEnumerable<EndpointSelector> endpointSelectors)
|
public IMatcher CreateMatcher(DispatcherDataSource dataSource, IEnumerable<EndpointSelector> endpointSelectors)
|
||||||
{
|
{
|
||||||
if (dataSource == null)
|
if (dataSource == null)
|
||||||
{
|
{
|
||||||
|
|
@ -26,12 +26,7 @@ namespace Microsoft.AspNetCore.Routing.Dispatcher
|
||||||
matcher.Selectors.Add(endpointSelector);
|
matcher.Selectors.Add(endpointSelector);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MatcherEntry()
|
return matcher;
|
||||||
{
|
|
||||||
AddressProvider = matcher,
|
|
||||||
Matcher = matcher,
|
|
||||||
EndpointProvider = matcher,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,9 +72,8 @@ namespace Microsoft.AspNetCore.Dispatcher.FunctionalTest
|
||||||
Selectors =
|
Selectors =
|
||||||
{
|
{
|
||||||
new HttpMethodEndpointSelector(),
|
new HttpMethodEndpointSelector(),
|
||||||
}
|
},
|
||||||
});
|
}, new TemplateEndpointHandlerFactory());
|
||||||
options.HandlerFactories.Add(endpoint => (endpoint as TemplateEndpoint)?.HandlerFactory);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task Products_Fallback(HttpContext httpContext) => httpContext.Response.WriteAsync("Hello, Products_Fallback");
|
private Task Products_Fallback(HttpContext httpContext) => httpContext.Response.WriteAsync("Hello, Products_Fallback");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue