using System; using System.Threading.Tasks; using Swan; namespace EmbedIO.Routing { /// /// Base class for modules that handle requests by resolving route / method pairs associated with handlers. /// /// public abstract class RoutingModuleBase : WebModuleBase { private readonly RouteVerbResolverCollection _resolvers = new RouteVerbResolverCollection(nameof(RoutingModuleBase)); /// /// /// Initializes a new instance of the class. /// protected RoutingModuleBase(string baseRoute) : base(baseRoute) { } /// public override bool IsFinalHandler => true; /// protected override async Task OnRequestAsync(IHttpContext context) { var result = await _resolvers.ResolveAsync(context).ConfigureAwait(false); switch (result) { case RouteResolutionResult.RouteNotMatched: case RouteResolutionResult.NoHandlerSuccessful: await OnPathNotFoundAsync(context).ConfigureAwait(false); break; case RouteResolutionResult.NoHandlerSelected: await OnMethodNotAllowedAsync(context).ConfigureAwait(false); break; case RouteResolutionResult.Success: return; default: throw SelfCheck.Failure($"Internal error: unknown route resolution result {result}."); } } /// /// Associates a HTTP method and a route to a handler. /// /// A constant representing the HTTP method /// to associate with , or /// if can handle all HTTP methods. /// The used to match URL paths. /// A callback used to handle matching contexts. /// /// is . /// - or - /// is . /// protected void AddHandler(HttpVerbs verb, RouteMatcher matcher, RouteHandlerCallback handler) => _resolvers.Add(verb, matcher, handler); /// /// Associates a HTTP method and a route to a synchronous handler. /// /// A constant representing the HTTP method /// to associate with , or /// if can handle all HTTP methods. /// The used to match URL paths. /// A callback used to handle matching contexts. /// /// is . /// - or - /// is . /// protected void AddHandler(HttpVerbs verb, RouteMatcher matcher, SyncRouteHandlerCallback handler) => _resolvers.Add(verb, matcher, handler); /// /// Adds handlers, associating them with HTTP method / route pairs by means /// of Route attributes. /// See for further information. /// /// Where to look for compatible handlers. /// The number of handlers that were added. /// is . protected int AddHandlersFrom(object target) => _resolvers.AddFrom(target); /// /// Associates all requests matching a route to a handler. /// /// The used to match URL paths. /// A callback used to handle matching contexts. /// /// is . /// - or - /// is . /// protected void OnAny(RouteMatcher matcher, RouteHandlerCallback handler) => _resolvers.Add(HttpVerbs.Any, matcher, handler); /// /// Associates all requests matching a route to a synchronous handler. /// /// The used to match URL paths. /// A callback used to handle matching contexts. /// /// is . /// - or - /// is . /// protected void OnAny(RouteMatcher matcher, SyncRouteHandlerCallback handler) => _resolvers.Add(HttpVerbs.Any, matcher, handler); /// /// Associates DELETE requests matching a route to a handler. /// /// The used to match URL paths. /// A callback used to handle matching contexts. /// /// is . /// - or - /// is . /// protected void OnDelete(RouteMatcher matcher, RouteHandlerCallback handler) => _resolvers.Add(HttpVerbs.Delete, matcher, handler); /// /// Associates DELETE requests matching a route to a synchronous handler. /// /// The used to match URL paths. /// A callback used to handle matching contexts. /// /// is . /// - or - /// is . /// protected void OnDelete(RouteMatcher matcher, SyncRouteHandlerCallback handler) => _resolvers.Add(HttpVerbs.Delete, matcher, handler); /// /// Associates GET requests matching a route to a handler. /// /// The used to match URL paths. /// A callback used to handle matching contexts. /// /// is . /// - or - /// is . /// protected void OnGet(RouteMatcher matcher, RouteHandlerCallback handler) => _resolvers.Add(HttpVerbs.Get, matcher, handler); /// /// Associates GET requests matching a route to a synchronous handler. /// /// The used to match URL paths. /// A callback used to handle matching contexts. /// /// is . /// - or - /// is . /// protected void OnGet(RouteMatcher matcher, SyncRouteHandlerCallback handler) => _resolvers.Add(HttpVerbs.Get, matcher, handler); /// /// Associates HEAD requests matching a route to a handler. /// /// The used to match URL paths. /// A callback used to handle matching contexts. /// /// is . /// - or - /// is . /// protected void OnHead(RouteMatcher matcher, RouteHandlerCallback handler) => _resolvers.Add(HttpVerbs.Head, matcher, handler); /// /// Associates HEAD requests matching a route to a synchronous handler. /// /// The used to match URL paths. /// A callback used to handle matching contexts. /// /// is . /// - or - /// is . /// protected void OnHead(RouteMatcher matcher, SyncRouteHandlerCallback handler) => _resolvers.Add(HttpVerbs.Head, matcher, handler); /// /// Associates OPTIONS requests matching a route to a handler. /// /// The used to match URL paths. /// A callback used to handle matching contexts. /// /// is . /// - or - /// is . /// protected void OnOptions(RouteMatcher matcher, RouteHandlerCallback handler) => _resolvers.Add(HttpVerbs.Options, matcher, handler); /// /// Associates OPTIONS requests matching a route to a synchronous handler. /// /// The used to match URL paths. /// A callback used to handle matching contexts. /// /// is . /// - or - /// is . /// protected void OnOptions(RouteMatcher matcher, SyncRouteHandlerCallback handler) => _resolvers.Add(HttpVerbs.Options, matcher, handler); /// /// Associates PATCH requests matching a route to a handler. /// /// The used to match URL paths. /// A callback used to handle matching contexts. /// /// is . /// - or - /// is . /// protected void OnPatch(RouteMatcher matcher, RouteHandlerCallback handler) => _resolvers.Add(HttpVerbs.Patch, matcher, handler); /// /// Associates PATCH requests matching a route to a synchronous handler. /// /// The used to match URL paths. /// A callback used to handle matching contexts. /// /// is . /// - or - /// is . /// protected void OnPatch(RouteMatcher matcher, SyncRouteHandlerCallback handler) => _resolvers.Add(HttpVerbs.Patch, matcher, handler); /// /// Associates POST requests matching a route to a handler. /// /// The used to match URL paths. /// A callback used to handle matching contexts. /// /// is . /// - or - /// is . /// protected void OnPost(RouteMatcher matcher, RouteHandlerCallback handler) => _resolvers.Add(HttpVerbs.Post, matcher, handler); /// /// Associates POST requests matching a route to a synchronous handler. /// /// The used to match URL paths. /// A callback used to handle matching contexts. /// /// is . /// - or - /// is . /// protected void OnPost(RouteMatcher matcher, SyncRouteHandlerCallback handler) => _resolvers.Add(HttpVerbs.Post, matcher, handler); /// /// Associates PUT requests matching a route to a handler. /// /// The used to match URL paths. /// A callback used to handle matching contexts. /// /// is . /// - or - /// is . /// protected void OnPut(RouteMatcher matcher, RouteHandlerCallback handler) => _resolvers.Add(HttpVerbs.Put, matcher, handler); /// /// Associates PUT requests matching a route to a synchronous handler. /// /// The used to match URL paths. /// A callback used to handle matching contexts. /// /// is . /// - or - /// is . /// protected void OnPut(RouteMatcher matcher, SyncRouteHandlerCallback handler) => _resolvers.Add(HttpVerbs.Put, matcher, handler); /// /// Called when no route is matched for the requested URL path. /// The default behavior is to send an empty 404 Not Found response. /// /// The context of the request being handled. /// A representing the ongoing operation. protected virtual Task OnPathNotFoundAsync(IHttpContext context) => throw HttpException.NotFound(); /// /// Called when at least one route is matched for the requested URL path, /// but none of them is associated with the HTTP method of the request. /// The default behavior is to send an empty 405 Method Not Allowed response. /// /// The context of the request being handled. /// A representing the ongoing operation. protected virtual Task OnMethodNotAllowedAsync(IHttpContext context) => throw HttpException.MethodNotAllowed(); } }