/// <summary> /// Generates an OData link using the default OData route name. /// </summary> /// <param name="urlHelper">The URL helper.</param> /// <param name="pathHandler">The path handler to use for generating the link.</param> /// <param name="segments">The OData path segments.</param> /// <returns>The geerated OData link.</returns> public static string ODataLink(this UrlHelper urlHelper, IODataPathHandler pathHandler, IList<ODataPathSegment> segments) { string odataPath = pathHandler.Link(new ODataPath(segments)); return urlHelper.Link( ODataRouteConstants.RouteName, new HttpRouteValueDictionary() { { ODataRouteConstants.ODataPath, odataPath } }); }
/// <summary> /// Initializes a new instance of the <see cref="ODataPathRouteConstraint" /> class. /// </summary> /// <param name="pathHandler">The OData path handler to use for parsing.</param> /// <param name="model">The EDM model to use for parsing the path.</param> /// <param name="routeName">The name of the route this constraint is associated with.</param> /// <param name="routingConventions">The OData routing conventions to use for selecting the controller name.</param> public ODataPathRouteConstraint(IODataPathHandler pathHandler, IEdmModel model, string routeName, IEnumerable<IODataRoutingConvention> routingConventions) { if (pathHandler == null) { throw Error.ArgumentNull("pathHandler"); } if (model == null) { throw Error.ArgumentNull("model"); } if (routeName == null) { throw Error.ArgumentNull("routeName"); } if (routingConventions == null) { throw Error.ArgumentNull("routingConventions"); } PathHandler = pathHandler; EdmModel = model; RouteName = routeName; RoutingConventions = routingConventions; }
/// <summary> /// Generates an OData link using the given OData route name and path handler. /// </summary> /// <param name="urlHelper">The URL helper.</param> /// <param name="routeName">The name of the OData route.</param> /// <param name="pathHandler">The path handler to use for generating the link.</param> /// <param name="segments">The OData path segments.</param> /// <returns>The generated OData link.</returns> public static string ODataLink(this UrlHelper urlHelper, string routeName, IODataPathHandler pathHandler, IList<ODataPathSegment> segments) { if (urlHelper == null) { throw Error.ArgumentNull("urlHelper"); } if (pathHandler == null) { throw Error.ArgumentNull("pathHandler"); } string odataPath = pathHandler.Link(new ODataPath(segments)); string directLink = urlHelper.GenerateLinkDirectly(routeName, odataPath); if (directLink != null) { return directLink; } // Slow path : use urlHelper.Link because the fast path failed return urlHelper.Link( routeName, new HttpRouteValueDictionary() { { ODataRouteConstants.ODataPath, odataPath } }); }
public static void MapODataRoute(this HttpRouteCollection routes, string routeName, string routePrefix, IEdmModel model, IODataPathHandler pathHandler, IEnumerable<IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler) { if (routes == null) { throw Error.ArgumentNull("routes"); } if (!String.IsNullOrEmpty(routePrefix)) { int routePrefixLastCharIndex = routePrefix.Length - 1; if (routePrefix[routePrefixLastCharIndex] != '/') { // Add the last trailing slash if it doesn't have one. routePrefix += "/"; } } if (batchHandler != null) { batchHandler.ODataRouteName = routeName; routes.MapHttpBatchRoute(routeName + "Batch", routePrefix + ODataRouteConstants.Batch, batchHandler); } string routeTemplate = routePrefix + ODataRouteConstants.ODataPathTemplate; IHttpRouteConstraint routeConstraint = new ODataPathRouteConstraint(pathHandler, model, routeName, routingConventions); HttpRouteValueDictionary constraintDictionary = new HttpRouteValueDictionary() { { ODataRouteConstants.ConstraintName, routeConstraint } }; routes.MapHttpRoute(routeName, routeTemplate, defaults: null, constraints: constraintDictionary); }
/// <summary> /// Map odata route with query string or header constraints /// </summary> public static void MapODataRoute( this HttpRouteCollection routes, string routeName, string routePrefix, IEdmModel model, IODataPathHandler pathHandler, IEnumerable<IODataRoutingConvention> routingConventions, object queryConstraints, object headerConstraints) { if (routes == null) { throw new ArgumentNullException("routes"); } string routeTemplate = string.IsNullOrEmpty(routePrefix) ? ODataRouteConstants.ODataPathTemplate : (routePrefix + "/" + ODataRouteConstants.ODataPathTemplate); ODataVersionRouteConstraint routeConstraint = new ODataVersionRouteConstraint(pathHandler, model, routeName, routingConventions, queryConstraints, headerConstraints); var constraints = new HttpRouteValueDictionary(); constraints.Add(ODataRouteConstants.ConstraintName, routeConstraint); routes.MapHttpRoute( routeName, routeTemplate, defaults: null, constraints: constraints); }
public static void MapODataRoute(this HttpRouteCollection routes, string routeName, string routePrefix, IEdmModel model, IODataPathHandler pathHandler, IEnumerable<IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler) { if (routes == null) { throw Error.ArgumentNull("routes"); } if (!String.IsNullOrEmpty(routePrefix)) { int prefixLastIndex = routePrefix.Length - 1; if (routePrefix[prefixLastIndex] == '/') { // Remove the last trailing slash if it has one. routePrefix = routePrefix.Substring(0, routePrefix.Length - 1); } } if (batchHandler != null) { batchHandler.ODataRouteName = routeName; string batchTemplate = String.IsNullOrEmpty(routePrefix) ? ODataRouteConstants.Batch : routePrefix + '/' + ODataRouteConstants.Batch; routes.MapHttpBatchRoute(routeName + "Batch", batchTemplate, batchHandler); } ODataPathRouteConstraint routeConstraint = new ODataPathRouteConstraint(pathHandler, model, routeName, routingConventions); routes.Add(routeName, new ODataRoute(routePrefix, routeConstraint)); }
/// <summary> /// Maps the specified OData route. /// </summary> /// <param name="routes">A collection of routes for the application.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="model">The EDM model to use for parsing OData paths.</param> /// <param name="pathHandler">The <see cref="IODataPathHandler"/> to use for parsing the OData path.</param> /// <param name="routingConventions"> /// The OData routing conventions to use for controller and action selection. /// </param> /// <returns>The added <see cref="ODataRoute"/>.</returns> public static ODataRoute MapODataServiceRoute(this HttpRouteCollection routes, string routeName, string routePrefix, IEdmModel model, IODataPathHandler pathHandler, IEnumerable<IODataRoutingConvention> routingConventions) { return MapODataServiceRoute(routes, routeName, routePrefix, model, pathHandler, routingConventions, batchHandler: null); }
/// <summary> /// Initializes a new instance of the <see cref="DefaultODataPathRouteConstraint" /> class. /// </summary> /// <param name="pathHandler">The path handler.</param> /// <param name="model">The EDM model.</param> /// <param name="routeName">The name of the route.</param> /// <param name="routingConventions">The routing convention.</param> public DefaultODataPathRouteConstraint( IODataPathHandler pathHandler, IEdmModel model, string routeName, IEnumerable<IODataRoutingConvention> routingConventions) : base(pathHandler, model, routeName, routingConventions) { }
public CustomODataPathRouteConstraint( IODataPathHandler pathHandler, Func<HttpRequestMessage, IEdmModel> modelProvider, string routeName, IEnumerable<IODataRoutingConvention> routingConventions) : base(pathHandler, new EdmModel(), routeName, routingConventions) { EdmModelProvider = modelProvider; }
/// <summary> /// Initializes a new instance of the <see cref="ODataPathRouteConstraint" /> class. /// </summary> /// <param name="pathHandler">The OData path handler to use for parsing.</param> public ODataPathRouteConstraint(IODataPathHandler pathHandler) { if (pathHandler == null) { throw Error.ArgumentNull("pathHandler"); } _pathHandler = pathHandler; }
public ODataVersionRouteConstraint( IODataPathHandler pathHandler, IEdmModel model, string routeName, IEnumerable<IODataRoutingConvention> routingConventions, object queryConstraints, object headerConstraints) : base(pathHandler, model, routeName, routingConventions) { QueryStringConstraints = new HttpRouteValueDictionary(queryConstraints); HeaderConstraints = new HttpRouteValueDictionary(headerConstraints); }
/// <summary> /// Maps the specified OData route. /// </summary> /// <param name="routes">A collection of routes for the application.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="model">The EDM model to use for parsing OData paths.</param> /// <param name="pathHandler">The <see cref="IODataPathHandler"/> to use for parsing the OData path.</param> /// <param name="routingConventions">The OData routing conventions to use for controller and action selection.</param> public static void MapODataRoute(this HttpRouteCollection routes, string routeName, string routePrefix, IEdmModel model, IODataPathHandler pathHandler, IEnumerable<IODataRoutingConvention> routingConventions) { if (routes == null) { throw Error.ArgumentNull("routes"); } string routeTemplate = String.IsNullOrEmpty(routePrefix) ? ODataRouteConstants.ODataPathTemplate : routePrefix + "/" + ODataRouteConstants.ODataPathTemplate; IHttpRouteConstraint routeConstraint = new ODataPathRouteConstraint(pathHandler, model, routeName, routingConventions); HttpRouteValueDictionary constraintDictionary = new HttpRouteValueDictionary() { { ODataRouteConstants.ConstraintName, routeConstraint } }; routes.MapHttpRoute(routeName, routeTemplate, defaults: null, constraints: constraintDictionary); }
/// <summary> /// Generates an OData link using the given OData route name and path handler. /// </summary> /// <param name="urlHelper">The URL helper.</param> /// <param name="routeName">The name of the OData route.</param> /// <param name="pathHandler">The path handler to use for generating the link.</param> /// <param name="segments">The OData path segments.</param> /// <returns>The generated OData link.</returns> public static string ODataLink(this UrlHelper urlHelper, string routeName, IODataPathHandler pathHandler, IList<ODataPathSegment> segments) { if (urlHelper == null) { throw Error.ArgumentNull("urlHelper"); } if (pathHandler == null) { throw Error.ArgumentNull("pathHandler"); } string odataPath = pathHandler.Link(new ODataPath(segments)); return urlHelper.Link( routeName, new HttpRouteValueDictionary() { { ODataRouteConstants.ODataPath, odataPath } }); }
/// <summary> /// Generates an OData link using the given OData route name, path handler, and segments. /// </summary> /// <param name="urlHelper">The URL helper.</param> /// <param name="routeName">The name of the OData route.</param> /// <param name="pathHandler">The path handler to use for generating the link.</param> /// <param name="segments">The OData path segments.</param> /// <returns>The generated OData link.</returns> public static string CreateODataLink(this IUrlHelper urlHelper, string routeName, IODataPathHandler pathHandler, IList<ODataPathSegment> segments) { //if (urlHelper == null) //{ // throw Error.ArgumentNull("urlHelper"); //} //if (pathHandler == null) //{ // throw Error.ArgumentNull("pathHandler"); //} //string odataPath = pathHandler.Link(new ODataPath(segments)); //return urlHelper.Link( // routeName, // new HttpRouteValueDictionary() { { ODataRouteConstants.ODataPath, odataPath } }); return "http://service-root/"; }
private static ODataRoute CustomMapODataServiceRoute( HttpRouteCollection routes, string routeName, string routePrefix, Func<HttpRequestMessage, IEdmModel> modelProvider, IODataPathHandler pathHandler, IEnumerable<IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler) { if (!string.IsNullOrEmpty(routePrefix)) { int prefixLastIndex = routePrefix.Length - 1; if (routePrefix[prefixLastIndex] == '/') { routePrefix = routePrefix.Substring(0, routePrefix.Length - 1); } } if (batchHandler != null) { batchHandler.ODataRouteName = routeName; string batchTemplate = string.IsNullOrEmpty(routePrefix) ? ODataRouteConstants.Batch : routePrefix + '/' + ODataRouteConstants.Batch; routes.MapHttpBatchRoute(routeName + "Batch", batchTemplate, batchHandler); } CustomODataPathRouteConstraint routeConstraint = new CustomODataPathRouteConstraint( pathHandler, modelProvider, routeName, routingConventions); CustomODataRoute odataRoute = new CustomODataRoute(routePrefix, routeConstraint); routes.Add(routeName, odataRoute); return odataRoute; }
/// <summary> /// Maps the specified OData route. /// </summary> /// <param name="routes">A collection of routes for the application.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="model">The EDM model to use for parsing OData paths.</param> /// <param name="pathHandler">The <see cref="IODataPathHandler"/> to use for parsing the OData path.</param> /// <param name="routingConventions">The OData routing conventions to use for controller and action selection.</param> public static void MapODataRoute(this HttpRouteCollection routes, string routeName, string routePrefix, IEdmModel model, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions) { routes.MapODataRoute(routeName, routePrefix, model, pathHandler, routingConventions, batchHandler: null); }
/// <summary> /// Generates an OData link using the given OData route name, path handler, and segments. /// </summary> /// <param name="routeName">The name of the OData route.</param> /// <param name="pathHandler">The path handler to use for generating the link.</param> /// <param name="segments">The OData path segments.</param> /// <returns>The generated OData link.</returns> public static string CreateODataLink(ResourceContext context, string routeName, IODataPathHandler pathHandler, IList <ODataPathSegment> segments) { #if NETCORE return(context.Request.HttpContext.GetUrlHelper().CreateODataLink(routeName, pathHandler, segments)); #else return(context.Url.CreateODataLink(routeName, pathHandler, segments)); #endif }
/// <summary> /// Generates an OData link using the default OData route name. /// </summary> /// <param name="urlHelper">The URL helper.</param> /// <param name="pathHandler">The path handler to use for generating the link.</param> /// <param name="segments">The OData path segments.</param> /// <returns>The generated OData link.</returns> public static string ODataLink(this UrlHelper urlHelper, IODataPathHandler pathHandler, params ODataPathSegment[] segments) { return(urlHelper.ODataLink(pathHandler, segments as IList <ODataPathSegment>)); }
public static ODataRoute MapODataServiceRoute(this HttpConfiguration configuration, string routeName, string routePrefix, IEdmModel model, IODataPathHandler pathHandler, IEnumerable<IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler) { if (configuration == null) { throw Error.ArgumentNull("configuration"); } HttpRouteCollection routes = configuration.Routes; routePrefix = RemoveTrailingSlash(routePrefix); if (batchHandler != null) { batchHandler.ODataRouteName = routeName; string batchTemplate = String.IsNullOrEmpty(routePrefix) ? ODataRouteConstants.Batch : routePrefix + '/' + ODataRouteConstants.Batch; routes.MapHttpBatchRoute(routeName + "Batch", batchTemplate, batchHandler); } DefaultODataPathHandler odataPathHandler = pathHandler as DefaultODataPathHandler; if (odataPathHandler != null) { odataPathHandler.ResolverSetttings = configuration.GetResolverSettings(); } ODataPathRouteConstraint routeConstraint = new ODataPathRouteConstraint(pathHandler, model, routeName, routingConventions); ODataRoute route = new ODataRoute(routePrefix, routeConstraint); routes.Add(routeName, route); return route; }
public static ODataRoute MapODataServiceRoute(this HttpConfiguration configuration, string routeName, string routePrefix, IEdmModel model, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler) { if (configuration == null) { throw Error.ArgumentNull("configuration"); } HttpRouteCollection routes = configuration.Routes; routePrefix = RemoveTrailingSlash(routePrefix); if (batchHandler != null) { batchHandler.ODataRouteName = routeName; string batchTemplate = String.IsNullOrEmpty(routePrefix) ? ODataRouteConstants.Batch : routePrefix + '/' + ODataRouteConstants.Batch; routes.MapHttpBatchRoute(routeName + "Batch", batchTemplate, batchHandler); } DefaultODataPathHandler odataPathHanlder = pathHandler as DefaultODataPathHandler; if (odataPathHanlder != null) { odataPathHanlder.ResolverSetttings = configuration.GetResolverSettings(); } ODataPathRouteConstraint routeConstraint = new ODataPathRouteConstraint(pathHandler, model, routeName, routingConventions); ODataRoute route = new ODataRoute(routePrefix, routeConstraint); routes.Add(routeName, route); return(route); }
public static ODataRoute MapODataServiceRoute(this HttpRouteCollection routes, string routeName, string routePrefix, IEdmModel model, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler) { if (routes == null) { throw Error.ArgumentNull("routes"); } if (!String.IsNullOrEmpty(routePrefix)) { int prefixLastIndex = routePrefix.Length - 1; if (routePrefix[prefixLastIndex] == '/') { // Remove the last trailing slash if it has one. routePrefix = routePrefix.Substring(0, routePrefix.Length - 1); } } if (batchHandler != null) { batchHandler.ODataRouteName = routeName; string batchTemplate = String.IsNullOrEmpty(routePrefix) ? ODataRouteConstants.Batch : routePrefix + '/' + ODataRouteConstants.Batch; routes.MapHttpBatchRoute(routeName + "Batch", batchTemplate, batchHandler); } ODataPathRouteConstraint routeConstraint = new ODataPathRouteConstraint(pathHandler, model, routeName, routingConventions); ODataRoute route = new ODataRoute(routePrefix, routeConstraint); routes.Add(routeName, route); return(route); }
/// <summary> /// Generates an OData link using the given OData route name, path handler, and segments. /// </summary> /// <param name="urlHelper">The URL helper.</param> /// <param name="routeName">The name of the OData route.</param> /// <param name="pathHandler">The path handler to use for generating the link.</param> /// <param name="segments">The OData path segments.</param> /// <returns>The generated OData link.</returns> public static string CreateODataLink(this IUrlHelper urlHelper, string routeName, IODataPathHandler pathHandler, IList <ODataPathSegment> segments) { //if (urlHelper == null) //{ // throw Error.ArgumentNull("urlHelper"); //} //if (pathHandler == null) //{ // throw Error.ArgumentNull("pathHandler"); //} //string odataPath = pathHandler.Link(new ODataPath(segments)); //return urlHelper.Link( // routeName, // new HttpRouteValueDictionary() { { ODataRouteConstants.ODataPath, odataPath } }); return("http://service-root/"); }
public static void SetODataPathHandler(this HttpRequestMessage request, IODataPathHandler pathHandler) { Extensions.HttpRequestMessageExtensions.ODataProperties(request).PathHandler = pathHandler; }
private static void SetResolverSettings( this HttpConfiguration configuration, IODataPathHandler pathHandler ) { Contract.Requires( configuration != null ); // REMARKS: the DefaultODataPathHandler.ResolverSettings property is internal as is the ODataUriResolverSetttings class. // The MapODataServiceRoute normally hooks this up, but we are replacing that process. in order to retain functional // fidelity we'll build and compile a strong-typed delegate that can be used to set the property. // // in additional, the ODataUriResolverSetttings are created lazy-initialized from the property bag. instead of using // Reflection, we'll test for the known key. if the key is not present, we'll use a public extension method // (e.g. EnableCaseInsensitive) with the default, unconfigured value. this will trigger the creation of the // settings and populate the property. var handler = pathHandler as DefaultODataPathHandler; if ( handler == null ) { return; } // REMARKS: this creates and populates the ODataUriResolverSetttings; OData URLs are case-sensitive by default. if ( !configuration.Properties.ContainsKey( ResolverSettingsKey ) ) { configuration.EnableCaseInsensitive( false ); } setResolverSettings.Value( handler, configuration.Properties[ResolverSettingsKey] ); }
/// <summary> /// Sets the <see cref="IODataPathHandler"/> to use for generating links. /// </summary> /// <param name="request">The request.</param> /// <param name="pathHandler">The <see cref="IODataPathHandler"/> to use for generating links.</param> public static void SetODataPathHandler(this HttpRequestMessage request, IODataPathHandler pathHandler) { if (request == null) { throw Error.ArgumentNull("request"); } request.Properties[ODataPathHandlerKey] = pathHandler; }
/// <summary> /// Determines whether this instance equals a specified route. /// </summary> /// <param name="httpContext">The http context.</param> /// <param name="route">The route to compare.</param> /// <param name="routeKey">The name of the route key.</param> /// <param name="values">A list of parameter values.</param> /// <param name="routeDirection">The route direction.</param> /// <returns> /// True if this instance equals a specified route; otherwise, false. /// </returns> public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection) { if (httpContext == null) { throw Error.ArgumentNull("httpContext"); } if (values == null) { throw Error.ArgumentNull("values"); } if (routeDirection == RouteDirection.IncomingRequest) { object odataPathValue; if (!values.TryGetValue(ODataRouteConstants.ODataPath, out odataPathValue)) { return(false); } string odataPathString = odataPathValue as string; ODataPath odataPath; try { // Service root is the current RequestUri, less the query string and the ODataPath (always the // last portion of the absolute path). ODL expects an escaped service root and other service // root calculations are calculated using AbsoluteUri (also escaped). But routing exclusively // uses unescaped strings, determined using // address.GetComponents(UriComponents.Path, UriFormat.Unescaped) // // For example if the AbsoluteUri is // <http://localhost/odata/FunctionCall(p0='Chinese%E8%A5%BF%E9%9B%85%E5%9B%BEChars')>, the // oDataPathString will contain "FunctionCall(p0='Chinese西雅图Chars')". // // Due to this decoding and the possibility of unecessarily-escaped characters, there's no // reliable way to determine the original string from which oDataPathString was derived. // Therefore a straightforward string comparison won't always work. See RemoveODataPath() for // details of chosen approach. HttpRequest request = httpContext.Request; string serviceRoot = GetServiceRoot(request); // string requestLeftPart = request.Path..GetLeftPart(UriPartial.Path); //string serviceRoot = request.Path; /* * if (!String.IsNullOrEmpty(odataPathString)) * { * serviceRoot = RemoveODataPath(serviceRoot, odataPathString); * }*/ // As mentioned above, we also need escaped ODataPath. // The requestLeftPart and request.RequestUri.Query are both escaped. // The ODataPath for service documents is empty. string oDataPathAndQuery = String.Empty; if (!String.IsNullOrEmpty(odataPathString)) { oDataPathAndQuery = odataPathString; } if (request.QueryString.HasValue) { // Ensure path handler receives the query string as well as the path. oDataPathAndQuery += request.QueryString; } // Leave an escaped '/' out of the service route because DefaultODataPathHandler will add a // literal '/' to the end of this string if not already present. That would double the slash // in response links and potentially lead to later 404s. if (serviceRoot.EndsWith(_escapedSlash, StringComparison.OrdinalIgnoreCase)) { serviceRoot = serviceRoot.Substring(0, serviceRoot.Length - _escapedSlash.Length); } IODataPathHandler pathHandler = httpContext.RequestServices.GetRequiredService <IODataPathHandler>(); odataPath = pathHandler.Parse(_model, serviceRoot, oDataPathAndQuery, httpContext.ODataFeature().UriResolverSettings); } catch (ODataException odataException) { odataPath = null; } if (odataPath != null) { IODataFeature odataFeature = httpContext.ODataFeature(); odataFeature.Model = _model; odataFeature.IsValidODataRequest = true; odataFeature.Path = odataPath; odataFeature.RoutePrefix = _routePrefix; return(true); } else { IODataFeature odataFeature = httpContext.ODataFeature(); odataFeature.IsValidODataRequest = false; return(false); } } // This constraint only applies to incomming request. return(false); }
/// <summary> /// Generates an OData link using the given OData route name, path handler, and segments. /// </summary> /// <param name="routeName">The name of the OData route.</param> /// <param name="pathHandler">The path handler to use for generating the link.</param> /// <param name="segments">The OData path segments.</param> /// <returns>The generated OData link.</returns> public string CreateODataLink(string routeName, IODataPathHandler pathHandler, IList <ODataPathSegment> segments) { return(this.innerHelper.CreateODataLink(routeName, pathHandler, segments)); }
public override bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary <string, object> values, HttpRouteDirection routeDirection) { if (request == null) { throw new ArgumentNullException(nameof(request)); } if (values == null) { throw new ArgumentNullException(nameof(values)); } if (routeDirection == HttpRouteDirection.UriResolution) { if (values.TryGetValue(ODataRouteConstants.ODataPath, out object oDataPathValue)) { string oDataPathString = oDataPathValue as string; ODataPath path; try { IServiceProvider requestContainer = request.CreateRequestContainer(this.RouteName); IHttpRequestMessageProvider httpRequestMessageProvider = requestContainer.GetRequiredService <IHttpRequestMessageProvider>(); httpRequestMessageProvider.Request = request; string[] segments = oDataPathString.Split('/'); string dataSource = segments[0]; request.Properties[Constants.ODataDataSource] = dataSource; request.Properties[Constants.CustomODataPath] = string.Join("/", segments, 1, segments.Length - 1); oDataPathString = (string)request.Properties[Constants.CustomODataPath]; // Service root is the current RequestUri, less the query string and the ODataPath (always the // last portion of the absolute path). ODL expects an escaped service root and other service // root calculations are calculated using AbsoluteUri (also escaped). But routing exclusively // uses unescaped strings, determined using // address.GetComponents(UriComponents.Path, UriFormat.Unescaped) // // For example if the AbsoluteUri is // <http://localhost/odata/FunctionCall(p0='Chinese%E8%A5%BF%E9%9B%85%E5%9B%BEChars')>, the // oDataPathString will contain "FunctionCall(p0='Chinese西雅图Chars')". // // Due to this decoding and the possibility of unecessarily-escaped characters, there's no // reliable way to determine the original string from which oDataPathString was derived. // Therefore a straightforward string comparison won't always work. See RemoveODataPath() for // details of chosen approach. string requestLeftPart = request.RequestUri.GetLeftPart(UriPartial.Path); string serviceRoot = requestLeftPart; if (!string.IsNullOrEmpty(oDataPathString)) { serviceRoot = RemoveODataPath(serviceRoot, oDataPathString); } // As mentioned above, we also need escaped ODataPath. // The requestLeftPart and request.RequestUri.Query are both escaped. // The ODataPath for service documents is empty. string oDataPathAndQuery = requestLeftPart.Substring(serviceRoot.Length); if (!string.IsNullOrEmpty(request.RequestUri.Query)) { // Ensure path handler receives the query string as well as the path. oDataPathAndQuery += request.RequestUri.Query; } // Leave an escaped '/' out of the service route because DefaultODataPathHandler will add a // literal '/' to the end of this string if not already present. That would double the slash // in response links and potentially lead to later 404s. if (serviceRoot.EndsWith(escapedSlash, StringComparison.OrdinalIgnoreCase)) { serviceRoot = serviceRoot.Substring(0, serviceRoot.Length - 3); } IODataPathHandler pathHandler = requestContainer.GetRequiredService <IODataPathHandler>(); path = pathHandler.Parse(serviceRoot, oDataPathAndQuery, requestContainer); } catch (ODataException) { path = null; } if (path != null) { // Set all the properties we need for routing, querying, formatting request.ODataProperties().Path = path; request.ODataProperties().RouteName = this.RouteName; if (!values.ContainsKey(ODataRouteConstants.Controller)) { // Select controller name using the routing conventions string controllerName = this.SelectControllerName(path, request); if (controllerName != null) { values[ODataRouteConstants.Controller] = controllerName; } } return(true); } } // The request doesn't match this route so dipose the request container. request.DeleteRequestContainer(true); return(false); } else { // This constraint only applies to URI resolution return(true); } }
/// <summary> /// Maps the specified OData route. /// </summary> /// <param name="configuration">The server configuration.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="model">The EDM model to use for parsing OData paths.</param> /// <param name="pathHandler">The <see cref="IODataPathHandler"/> to use for parsing the OData path.</param> /// <param name="routingConventions"> /// The OData routing conventions to use for controller and action selection. /// </param> /// <returns>The added <see cref="ODataRoute"/>.</returns> public static ODataRoute MapODataServiceRoute(this HttpConfiguration configuration, string routeName, string routePrefix, IEdmModel model, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions) { return(configuration.MapODataServiceRoute(routeName, routePrefix, builder => builder.AddService(ServiceLifetime.Singleton, sp => model) .AddService(ServiceLifetime.Singleton, sp => pathHandler) .AddService(ServiceLifetime.Singleton, sp => routingConventions.ToList().AsEnumerable()))); }
public static void MapODataRoute(this HttpRouteCollection routes, string routeName, string routePrefix, IEdmModel model, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions) { Extensions.HttpRouteCollectionExtensions.MapODataServiceRoute(routes, routeName, routePrefix, model, pathHandler, routingConventions); }
private static IEndpointRouteBuilder MapDynamicODataServiceRoute(this IEndpointRouteBuilder builder, string routeName, string routePrefix, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions, IDataSource dataSource) { ServiceProviderServiceExtensions.GetRequiredService <ApplicationPartManager>(builder.ServiceProvider).ApplicationParts.Add(new AssemblyPart(typeof(DynamicODataController).Assembly)); var odataRoute = builder.MapODataRoute(routeName, routePrefix, containerBuilder => { containerBuilder .AddService <IEdmModel>(Microsoft.OData.ServiceLifetime.Singleton, sp => dataSource.Model) .AddService <IDataSource>(Microsoft.OData.ServiceLifetime.Scoped, sp => dataSource) .AddService(Microsoft.OData.ServiceLifetime.Scoped, sp => routingConventions.ToList().AsEnumerable()); if (pathHandler != null) { containerBuilder.AddService(Microsoft.OData.ServiceLifetime.Singleton, sp => pathHandler); } }); return(odataRoute); }
/// <summary> /// Generates an OData link using the default OData route name. /// </summary> /// <param name="urlHelper">The URL helper.</param> /// <param name="pathHandler">The path handler to use for generating the link.</param> /// <param name="segments">The OData path segments.</param> /// <returns>The generated OData link.</returns> public static string ODataLink(this UrlHelper urlHelper, IODataPathHandler pathHandler, params ODataPathSegment[] segments) { return urlHelper.ODataLink(pathHandler, segments as IList<ODataPathSegment>); }
/// <summary> /// Maps the specified OData route. When the <paramref name="batchHandler"/> is non-<c>null</c>, it will /// create a '$batch' endpoint to handle the batch requests. /// </summary> /// <param name="builder">The <see cref="IRouteBuilder"/> to add the route to.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="model">The EDM model to use for parsing OData paths.</param> /// <param name="pathHandler">The <see cref="IODataPathHandler" /> to use for parsing the OData path.</param> /// <param name="routingConventions"> /// The OData routing conventions to use for controller and action selection. /// </param> /// <param name="batchHandler">The <see cref="ODataBatchHandler"/>.</param> /// <returns>The added <see cref="ODataRoute"/>.</returns> public static ODataRoute MapODataServiceRoute(this IRouteBuilder builder, string routeName, string routePrefix, IEdmModel model, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler) { return(builder.MapODataServiceRoute(routeName, routePrefix, containerBuilder => containerBuilder.AddService(ServiceLifetime.Singleton, sp => model) .AddService(ServiceLifetime.Singleton, sp => pathHandler) .AddService(ServiceLifetime.Singleton, sp => routingConventions.ToList().AsEnumerable()) .AddService(ServiceLifetime.Singleton, sp => batchHandler))); }
/// <summary> /// Maps the specified OData route. When the <paramref name="defaultHandler"/> is non-<c>null</c>, it will map /// it as the handler for the route. /// </summary> /// <param name="configuration">The server configuration.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="model">The EDM model to use for parsing OData paths.</param> /// <param name="pathHandler">The <see cref="IODataPathHandler" /> to use for parsing the OData path.</param> /// <param name="routingConventions"> /// The OData routing conventions to use for controller and action selection. /// </param> /// <param name="defaultHandler">The default <see cref="HttpMessageHandler"/> for this route.</param> /// <returns>The added <see cref="ODataRoute"/>.</returns> public static ODataRoute MapODataServiceRoute(this HttpConfiguration configuration, string routeName, string routePrefix, IEdmModel model, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions, HttpMessageHandler defaultHandler) { if (configuration == null) { throw Error.ArgumentNull("configuration"); } // We have a more specific overload to map batch handlers that creates a different route for the batch // endpoint instead of mapping that handler as the per route handler. Given that HttpMessageHandler is a // base type of ODataBatchHandler, it's possible the compiler will call this overload instead of the one // for the batch handler, so we detect that case and call the appropiate overload for the user. // The case in which the compiler picks the wrong overload is: // HttpRequestMessageHandler batchHandler = new DefaultODataBatchHandler(httpServer); // config.Routes.MapODataServiceRoute("routeName", "routePrefix", model, batchHandler); if (defaultHandler != null) { ODataBatchHandler batchHandler = defaultHandler as ODataBatchHandler; if (batchHandler != null) { return(MapODataServiceRoute(configuration, routeName, routePrefix, model, batchHandler)); } } HttpRouteCollection routes = configuration.Routes; routePrefix = RemoveTrailingSlash(routePrefix); DefaultODataPathHandler odataPathHanlder = pathHandler as DefaultODataPathHandler; if (odataPathHanlder != null) { odataPathHanlder.ResolverSetttings = configuration.GetResolverSettings(); } ODataPathRouteConstraint routeConstraint = new ODataPathRouteConstraint(pathHandler, model, routeName, routingConventions); ODataRoute route = new ODataRoute( routePrefix, routeConstraint, defaults: null, constraints: null, dataTokens: null, handler: defaultHandler); routes.Add(routeName, route); return(route); }
/// <summary> /// Initializes a new instance of the <see cref="T:System.Web.Http.OData.Routing.ODataPathRouteConstraint"/> class. /// </summary> /// <param name="pathHandler">The OData path handler to use for parsing.</param><param name="routeName">The name of the route this constraint is associated with.</param><param name="routingConventions">The OData routing conventions to use for selecting the controller name.</param> public EntityListODataPathRouteConstraint(IODataPathHandler pathHandler, string routeName, IEnumerable <IODataRoutingConvention> routingConventions) : base(pathHandler, CreateEmptyModel(), routeName, routingConventions) { EdmModel = CreateEmptyModel(); }
/// <summary> /// Generates an OData link using the given OData route name, path handler, and segments. /// </summary> /// <param name="urlHelper">The URL helper.</param> /// <param name="routeName">The name of the OData route.</param> /// <param name="pathHandler">The path handler to use for generating the link.</param> /// <param name="segments">The OData path segments.</param> /// <returns>The generated OData link.</returns> public static string CreateODataLink(this IUrlHelper urlHelper, string routeName, IODataPathHandler pathHandler, IList <ODataPathSegment> segments) { if (urlHelper == null) { throw Error.ArgumentNull("urlHelper"); } if (pathHandler == null) { throw Error.ArgumentNull("pathHandler"); } string odataPath = pathHandler.Link(new ODataPath(segments)); return(urlHelper.Link( routeName, new RouteValueDictionary() { { ODataRouteConstants.ODataPath, odataPath } })); }
public ODataPathRouteConstraintTest() { _rootContainer = new MockContainer(_model, _conventions); _pathHandler = _rootContainer.GetRequiredService <IODataPathHandler>(); }
public static void MapODataRoute(this HttpRouteCollection routes, string routeName, string routePrefix, IEdmModel model, IODataPathHandler pathHandler, IEnumerable<IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler) { Extensions.HttpRouteCollectionExtensions.MapODataServiceRoute(routes, routeName, routePrefix, model, pathHandler, routingConventions, batchHandler); }
public static string ODataLink(this UrlHelper urlHelper, string routeName, IODataPathHandler pathHandler, IList <ODataPathSegment> segments) { return(UrlHelperExtensions.CreateODataLink(urlHelper, routeName, pathHandler, segments)); }
/// <summary> /// Maps the specified OData route. When the <paramref name="defaultHandler"/> is non-<c>null</c>, it will map /// it as the handler for the route. /// </summary> /// <param name="configuration">The server configuration.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="model">The EDM model to use for parsing OData paths.</param> /// <param name="pathHandler">The <see cref="IODataPathHandler" /> to use for parsing the OData path.</param> /// <param name="routingConventions"> /// The OData routing conventions to use for controller and action selection. /// </param> /// <param name="defaultHandler">The default <see cref="HttpMessageHandler"/> for this route.</param> /// <returns>The added <see cref="ODataRoute"/>.</returns> public static ODataRoute MapODataServiceRoute(this HttpConfiguration configuration, string routeName, string routePrefix, IEdmModel model, IODataPathHandler pathHandler, IEnumerable<IODataRoutingConvention> routingConventions, HttpMessageHandler defaultHandler) { if (configuration == null) { throw Error.ArgumentNull("configuration"); } // We have a more specific overload to map batch handlers that creates a different route for the batch // endpoint instead of mapping that handler as the per route handler. Given that HttpMessageHandler is a // base type of ODataBatchHandler, it's possible the compiler will call this overload instead of the one // for the batch handler, so we detect that case and call the appropiate overload for the user. // The case in which the compiler picks the wrong overload is: // HttpRequestMessageHandler batchHandler = new DefaultODataBatchHandler(httpServer); // config.Routes.MapODataServiceRoute("routeName", "routePrefix", model, batchHandler); if (defaultHandler != null) { ODataBatchHandler batchHandler = defaultHandler as ODataBatchHandler; if (batchHandler != null) { return MapODataServiceRoute(configuration, routeName, routePrefix, model, batchHandler); } } HttpRouteCollection routes = configuration.Routes; routePrefix = RemoveTrailingSlash(routePrefix); DefaultODataPathHandler odataPathHandler = pathHandler as DefaultODataPathHandler; if (odataPathHandler != null) { odataPathHandler.ResolverSetttings = configuration.GetResolverSettings(); } ODataPathRouteConstraint routeConstraint = new ODataPathRouteConstraint(pathHandler, model, routeName, routingConventions); ODataRoute route = new ODataRoute( routePrefix, routeConstraint, defaults: null, constraints: null, dataTokens: null, handler: defaultHandler); routes.Add(routeName, route); return route; }
public static ODataPath Parse(this IODataPathHandler handler, IEdmModel model, string serviceRoot, string odataPath) { Contract.Assert(handler != null); return(handler.Parse(serviceRoot, odataPath, DefaultContainer)); }
/// <summary> /// Maps the specified versioned OData routes. When the <paramref name="newBatchHandler"/> is provided, it will create a '$batch' endpoint to handle the batch requests. /// </summary> /// <param name="builder">The extended <see cref="IRouteBuilder">route builder</see>.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="models">The <see cref="IEnumerable{T}">sequence</see> of <see cref="IEdmModel">EDM models</see> to use for parsing OData paths.</param> /// <param name="pathHandler">The <see cref="IODataPathHandler">OData path handler</see> to use for parsing the OData path.</param> /// <param name="routingConventions">The <see cref="IEnumerable{T}">sequence</see> of <see cref="IODataRoutingConvention">OData routing conventions</see> /// to use for controller and action selection.</param> /// <param name="newBatchHandler">The <see cref="Func{TResult}">factory method</see> used to create new <see cref="ODataBatchHandler">OData batch handlers</see>.</param> /// <returns>The <see cref="IReadOnlyList{T}">read-only list</see> of added <see cref="ODataRoute">OData routes</see>.</returns> /// <remarks>The specified <paramref name="models"/> must contain the <see cref="ApiVersionAnnotation">API version annotation</see>. This annotation is /// automatically applied when you use the <see cref="VersionedODataModelBuilder"/> and call <see cref="VersionedODataModelBuilder.GetEdmModels"/> to /// create the <paramref name="models"/>.</remarks> public static IReadOnlyList <ODataRoute> MapVersionedODataRoutes( this IRouteBuilder builder, string routeName, string routePrefix, IEnumerable <IEdmModel> models, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions, Func <ODataBatchHandler> newBatchHandler) { Arg.NotNull(builder, nameof(builder)); Arg.NotNullOrEmpty(routeName, nameof(routeName)); Arg.NotNull(models, nameof(models)); Contract.Ensures(Contract.Result <IReadOnlyList <ODataRoute> >() != null); var serviceProvider = builder.ServiceProvider; var options = serviceProvider.GetRequiredService <ODataOptions>(); var routeCollection = serviceProvider.GetRequiredService <IODataRouteCollectionProvider>(); var inlineConstraintResolver = serviceProvider.GetRequiredService <IInlineConstraintResolver>(); var routeConventions = VersionedODataRoutingConventions.AddOrUpdate(routingConventions.ToList()); var routes = builder.Routes; var perRouteContainer = serviceProvider.GetRequiredService <IPerRouteContainer>(); var odataRoutes = new List <ODataRoute>(); var unversionedConstraints = new List <IRouteConstraint>(); if (pathHandler != null && pathHandler.UrlKeyDelimiter == null) { pathHandler.UrlKeyDelimiter = options.UrlKeyDelimiter; } foreach (var model in models) { var versionedRouteName = routeName; var apiVersion = model.GetAnnotationValue <ApiVersionAnnotation>(model)?.ApiVersion; var routeConstraint = MakeVersionedODataRouteConstraint(apiVersion, ref versionedRouteName); IEnumerable <IODataRoutingConvention> NewRouteConventions(IServiceProvider services) { var conventions = new IODataRoutingConvention[routeConventions.Count + 1]; conventions[0] = new VersionedAttributeRoutingConvention(versionedRouteName, serviceProvider, apiVersion); routeConventions.CopyTo(conventions, 1); return(conventions); } var edm = model; var batchHandler = newBatchHandler?.Invoke(); var configureAction = builder.ConfigureDefaultServices(container => container.AddService(Singleton, typeof(IEdmModel), sp => edm) .AddService(Singleton, typeof(IODataPathHandler), sp => pathHandler) .AddService(Singleton, typeof(IEnumerable <IODataRoutingConvention>), NewRouteConventions) .AddService(Singleton, typeof(ODataBatchHandler), sp => batchHandler)); var rootContainer = perRouteContainer.CreateODataRootContainer(versionedRouteName, configureAction); var router = rootContainer.GetService <IRouter>() ?? builder.DefaultHandler; var route = new ODataRoute(router, versionedRouteName, routePrefix.RemoveTrailingSlash(), routeConstraint, inlineConstraintResolver); unversionedConstraints.Add(new ODataPathRouteConstraint(versionedRouteName)); builder.ConfigureBatchHandler(batchHandler, route); routes.Add(route); odataRoutes.Add(route); routeCollection.Add(new ODataRouteMapping(route, apiVersion, rootContainer)); } builder.AddRouteToRespondWithBadRequestWhenAtLeastOneRouteCouldMatch(routeName, routePrefix, unversionedConstraints, inlineConstraintResolver); NotifyRoutesMapped(); return(odataRoutes); }
/// <summary> /// Maps the specified versioned OData routes. When the <paramref name="newBatchHandler"/> is provided, it will create a '$batch' endpoint to handle the batch requests. /// </summary> /// <param name="builder">The extended <see cref="IRouteBuilder">route builder</see>.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="models">The <see cref="IEnumerable{T}">sequence</see> of <see cref="IEdmModel">EDM models</see> to use for parsing OData paths.</param> /// <param name="pathHandler">The <see cref="IODataPathHandler">OData path handler</see> to use for parsing the OData path.</param> /// <param name="routingConventions">The <see cref="IEnumerable{T}">sequence</see> of <see cref="IODataRoutingConvention">OData routing conventions</see> /// to use for controller and action selection.</param> /// <param name="newBatchHandler">The <see cref="Func{TResult}">factory method</see> used to create new <see cref="ODataBatchHandler">OData batch handlers</see>.</param> /// <returns>The <see cref="IReadOnlyList{T}">read-only list</see> of added <see cref="ODataRoute">OData routes</see>.</returns> /// <remarks>The specified <paramref name="models"/> must contain the <see cref="ApiVersionAnnotation">API version annotation</see>. This annotation is /// automatically applied when you use the <see cref="VersionedODataModelBuilder"/> and call <see cref="VersionedODataModelBuilder.GetEdmModels"/> to /// create the <paramref name="models"/>.</remarks> public static IReadOnlyList <ODataRoute> MapVersionedODataRoutes( this IRouteBuilder builder, string routeName, string routePrefix, IEnumerable <IEdmModel> models, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions, Func <ODataBatchHandler>?newBatchHandler) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (IsNullOrEmpty(routeName)) { throw new ArgumentNullException(nameof(routeName)); } if (models == null) { throw new ArgumentNullException(nameof(models)); } var serviceProvider = builder.ServiceProvider; var options = serviceProvider.GetRequiredService <ODataOptions>(); var routeCollection = serviceProvider.GetRequiredService <IODataRouteCollectionProvider>(); var inlineConstraintResolver = serviceProvider.GetRequiredService <IInlineConstraintResolver>(); var routeConventions = VersionedODataRoutingConventions.AddOrUpdate(routingConventions.ToList()); var routes = builder.Routes; var perRouteContainer = serviceProvider.GetRequiredService <IPerRouteContainer>(); var odataRoutes = new List <ODataRoute>(); var unversionedConstraints = new List <IRouteConstraint>(); if (pathHandler != null && pathHandler.UrlKeyDelimiter == null) { pathHandler.UrlKeyDelimiter = options.UrlKeyDelimiter; } foreach (var model in models) { var versionedRouteName = routeName; var annotation = model.GetAnnotationValue <ApiVersionAnnotation>(model) ?? throw new ArgumentException(LocalSR.MissingAnnotation.FormatDefault(typeof(ApiVersionAnnotation).Name)); var apiVersion = annotation.ApiVersion; var routeConstraint = MakeVersionedODataRouteConstraint(apiVersion, ref versionedRouteName); IEnumerable <IODataRoutingConvention> NewRouteConventions(IServiceProvider services) { var conventions = new IODataRoutingConvention[routeConventions !.Count + 1]; conventions[0] = new VersionedAttributeRoutingConvention(versionedRouteName !, serviceProvider !, apiVersion !); routeConventions.CopyTo(conventions, 1); return(conventions); } var edm = model; var batchHandler = newBatchHandler?.Invoke(); var configureAction = builder.ConfigureDefaultServices(container => container.AddService(Singleton, typeof(IEdmModel), sp => edm) .AddService(Singleton, typeof(IODataPathHandler), sp => pathHandler) .AddService(Singleton, typeof(IEnumerable <IODataRoutingConvention>), NewRouteConventions) .AddService(Singleton, typeof(ODataBatchHandler), sp => batchHandler)); var rootContainer = perRouteContainer.CreateODataRootContainer(versionedRouteName, configureAction); var router = rootContainer.GetService <IRouter>() ?? builder.DefaultHandler; var route = new ODataRoute(router, versionedRouteName, routePrefix.RemoveTrailingSlash(), routeConstraint, inlineConstraintResolver); unversionedConstraints.Add(new ODataPathRouteConstraint(versionedRouteName)); builder.ConfigureBatchHandler(batchHandler, route); routes.Add(route); odataRoutes.Add(route); routeCollection.Add(new ODataRouteMapping(route, apiVersion, rootContainer)); }
/// <summary> /// Maps the specified OData route and the OData route attributes. /// </summary> /// <param name="configuration">The server configuration.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="configureAction">The configuring action to add the services to the root container.</param> /// <returns>The added <see cref="ODataRoute"/>.</returns> public static ODataRoute MapODataServiceRoute(this HttpConfiguration configuration, string routeName, string routePrefix, Action <IContainerBuilder> configureAction) { if (configuration == null) { throw Error.ArgumentNull("configuration"); } if (routeName == null) { throw Error.ArgumentNull("routeName"); } // 1) Build and configure the root container. IServiceProvider rootContainer = configuration.CreateODataRootContainer(routeName, configureAction); // 2) Resolve the path handler and set URI resolver to it. IODataPathHandler pathHandler = rootContainer.GetRequiredService <IODataPathHandler>(); // if settings is not on local, use the global configuration settings. if (pathHandler != null && pathHandler.UrlKeyDelimiter == null) { ODataUrlKeyDelimiter urlKeyDelimiter = configuration.GetUrlKeyDelimiter(); pathHandler.UrlKeyDelimiter = urlKeyDelimiter; } // 3) Resolve some required services and create the route constraint. ODataPathRouteConstraint routeConstraint = new ODataPathRouteConstraint(routeName); // Attribute routing must initialized before configuration.EnsureInitialized is called. rootContainer.GetServices <IODataRoutingConvention>(); // 4) Resolve HTTP handler, create the OData route and register it. ODataRoute route; HttpRouteCollection routes = configuration.Routes; routePrefix = RemoveTrailingSlash(routePrefix); HttpMessageHandler messageHandler = rootContainer.GetService <HttpMessageHandler>(); if (messageHandler != null) { route = new ODataRoute( routePrefix, routeConstraint, defaults: null, constraints: null, dataTokens: null, handler: messageHandler); } else { ODataBatchHandler batchHandler = rootContainer.GetService <ODataBatchHandler>(); if (batchHandler != null) { batchHandler.ODataRouteName = routeName; string batchTemplate = String.IsNullOrEmpty(routePrefix) ? ODataRouteConstants.Batch : routePrefix + '/' + ODataRouteConstants.Batch; routes.MapHttpBatchRoute(routeName + "Batch", batchTemplate, batchHandler); } route = new ODataRoute(routePrefix, routeConstraint); } routes.Add(routeName, route); return(route); }
public static IReadOnlyList <ODataRoute> MapVersionedODataRoutes( this HttpConfiguration configuration, string routeName, string routePrefix, IEnumerable <IEdmModel> models, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler) { Arg.NotNull(configuration, nameof(configuration)); Arg.NotNull(models, nameof(models)); Contract.Ensures(Contract.Result <IReadOnlyList <ODataRoute> >() != null); var routeConventions = EnsureConventions(routingConventions.ToList()); var routes = configuration.Routes; var unversionedRouteName = routeName + UnversionedRouteSuffix; if (!IsNullOrEmpty(routePrefix)) { routePrefix = routePrefix.TrimEnd('/'); } if (batchHandler != null) { batchHandler.ODataRouteName = unversionedRouteName; var batchTemplate = IsNullOrEmpty(routePrefix) ? ODataRouteConstants.Batch : routePrefix + '/' + ODataRouteConstants.Batch; routes.MapHttpBatchRoute(routeName + nameof(ODataRouteConstants.Batch), batchTemplate, batchHandler); } if (pathHandler != null && pathHandler.UrlKeyDelimiter == null) { pathHandler.UrlKeyDelimiter = configuration.GetUrlKeyDelimiter(); } routeConventions.Insert(0, null); var odataRoutes = new List <ODataRoute>(); var unversionedConstraints = new List <IHttpRouteConstraint>(); foreach (var model in models) { var versionedRouteName = routeName; var apiVersion = model.GetAnnotationValue <ApiVersionAnnotation>(model)?.ApiVersion; var routeConstraint = MakeVersionedODataRouteConstraint(apiVersion, ref versionedRouteName); routeConventions[0] = new VersionedAttributeRoutingConvention(versionedRouteName, configuration, apiVersion); unversionedConstraints.Add(new ODataPathRouteConstraint(versionedRouteName)); var edm = model; var rootContainer = configuration.CreateODataRootContainer( versionedRouteName, builder => builder.AddService(Singleton, typeof(IEdmModel), sp => edm) .AddService(Singleton, typeof(IODataPathHandler), sp => pathHandler) .AddService(Singleton, typeof(IEnumerable <IODataRoutingConvention>), sp => routeConventions.ToArray()) .AddService(Singleton, typeof(ODataBatchHandler), sp => batchHandler)); rootContainer.InitializeAttributeRouting(); var route = default(ODataRoute); var messageHandler = rootContainer.GetService <HttpMessageHandler>(); if (messageHandler == null) { route = new ODataRoute(routePrefix, routeConstraint); } else { route = new ODataRoute(routePrefix, routeConstraint, defaults: null, constraints: null, dataTokens: null, handler: messageHandler); } routes.Add(versionedRouteName, route); AddApiVersionConstraintIfNecessary(route); odataRoutes.Add(route); } configuration.AddRouteToRespondWithBadRequestWhenAtLeastOneRouteCouldMatch(unversionedRouteName, routePrefix, odataRoutes, unversionedConstraints, _ => { }); return(odataRoutes); }
/// <summary> /// Sets the <see cref="IODataPathHandler"/> on the configuration. /// </summary> /// <param name="configuration">The server's configuration.</param> /// <param name="parser">The <see cref="IODataPathHandler"/> this configuration should use.</param> public static void SetODataPathHandler(this HttpConfiguration configuration, IODataPathHandler parser) { if (configuration == null) { throw Error.ArgumentNull("configuration"); } if (parser == null) { throw Error.ArgumentNull("parser"); } configuration.Properties[ODataPathHandlerKey] = parser; }
static ODataRoute MapVersionedODataRoute( HttpConfiguration configuration, string routeName, string routePrefix, IEdmModel model, ApiVersion apiVersion, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler, HttpMessageHandler defaultHandler) { Arg.NotNull(configuration, nameof(configuration)); Arg.NotNull(model, nameof(model)); Arg.NotNull(apiVersion, nameof(apiVersion)); Contract.Ensures(Contract.Result <ODataRoute>() != null); var routeConventions = EnsureConventions(routingConventions.ToList()); var routes = configuration.Routes; if (!IsNullOrEmpty(routePrefix)) { routePrefix = routePrefix.TrimEnd('/'); } if (pathHandler != null && pathHandler.UrlKeyDelimiter == null) { pathHandler.UrlKeyDelimiter = configuration.GetUrlKeyDelimiter(); } model.SetAnnotationValue(model, new ApiVersionAnnotation(apiVersion)); routeConventions.Insert(0, new VersionedAttributeRoutingConvention(routeName, configuration, apiVersion)); var rootContainer = configuration.CreateODataRootContainer( routeName, builder => builder.AddService(Singleton, typeof(IEdmModel), sp => model) .AddService(Singleton, typeof(IODataPathHandler), sp => pathHandler) .AddService(Singleton, typeof(IEnumerable <IODataRoutingConvention>), sp => routeConventions.ToArray()) .AddService(Singleton, typeof(ODataBatchHandler), sp => batchHandler) .AddService(Singleton, typeof(HttpMessageHandler), sp => defaultHandler)); rootContainer.InitializeAttributeRouting(); var routeConstraint = new VersionedODataPathRouteConstraint(routeName, apiVersion); var route = default(ODataRoute); if (defaultHandler != null) { route = new ODataRoute(routePrefix, routeConstraint, defaults: null, constraints: null, dataTokens: null, handler: defaultHandler); } else { if (batchHandler != null) { batchHandler.ODataRouteName = routeName; var batchTemplate = IsNullOrEmpty(routePrefix) ? ODataRouteConstants.Batch : routePrefix + '/' + ODataRouteConstants.Batch; routes.MapHttpBatchRoute(routeName + nameof(ODataRouteConstants.Batch), batchTemplate, batchHandler); } route = new ODataRoute(routePrefix, routeConstraint); } routes.Add(routeName, route); AddApiVersionConstraintIfNecessary(route); var unversionedRouteConstraint = new ODataPathRouteConstraint(routeName); var unversionedRoute = new ODataRoute(routePrefix, new UnversionedODataPathRouteConstraint(unversionedRouteConstraint, apiVersion)); AddApiVersionConstraintIfNecessary(unversionedRoute); routes.Add(routeName + UnversionedRouteSuffix, unversionedRoute); return(route); }
/// <summary> /// Maps the specified OData route and the OData route attributes. /// </summary> /// <param name="builder">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="configureAction">The configuring action to add the services to the root container.</param> /// <returns>The input <see cref="IEndpointRouteBuilder"/>.</returns> public static IEndpointRouteBuilder MapODataRoute(this IEndpointRouteBuilder builder, string routeName, string routePrefix, Action <IContainerBuilder> configureAction) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (routeName == null) { throw new ArgumentNullException(nameof(routeName)); } // Build and configure the root container. IServiceProvider serviceProvider = builder.ServiceProvider; IPerRouteContainer perRouteContainer = serviceProvider.GetRequiredService <IPerRouteContainer>(); if (perRouteContainer == null) { throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, SRResources.MissingODataServices, nameof(IPerRouteContainer))); } // Make sure the MetadataController is registered with the ApplicationPartManager. ApplicationPartManager applicationPartManager = serviceProvider.GetRequiredService <ApplicationPartManager>(); applicationPartManager.ApplicationParts.Add(new AssemblyPart(typeof(MetadataController).Assembly)); // Create an service provider for this route. Add the default services to the custom configuration actions. Action <IContainerBuilder> builderAction = ConfigureDefaultServices(builder, configureAction); IServiceProvider subServiceProvider = perRouteContainer.CreateODataRootContainer(routeName, builderAction); // Resolve the path handler and set URI resolver to it. IODataPathHandler pathHandler = subServiceProvider.GetRequiredService <IODataPathHandler>(); // If settings is not on local, use the global configuration settings. ODataOptions options = serviceProvider.GetRequiredService <ODataOptions>(); //if (pathHandler != null && pathHandler.UrlKeyDelimiter == null) //{ // pathHandler.UrlKeyDelimiter = options.UrlKeyDelimiter; //} // Resolve HTTP handler, create the OData route and register it. routePrefix = RemoveTrailingSlash(routePrefix); // If a batch handler is present, register the route with the batch path mapper. This will be used // by the batching middleware to handle the batch request. Batching still requires the injection // of the batching middleware via UseODataBatching(). ODataBatchHandler batchHandler = subServiceProvider.GetService <ODataBatchHandler>(); if (batchHandler != null) { // TODO: for the $batch, need refactor/test it for more. batchHandler.ODataRouteName = routeName; string batchPath = String.IsNullOrEmpty(routePrefix) ? '/' + ODataRouteConstants.Batch : '/' + routePrefix + '/' + ODataRouteConstants.Batch; ODataBatchPathMapping batchMapping = builder.ServiceProvider.GetRequiredService <ODataBatchPathMapping>(); batchMapping.IsEndpointRouting = true; batchMapping.AddRoute(routeName, batchPath); } builder.MapDynamicControllerRoute <ODataEndpointRouteValueTransformer>( ODataEndpointPattern.CreateODataEndpointPattern(routeName, routePrefix)); perRouteContainer.AddRoute(routeName, routePrefix); return(builder); }
/// <summary> /// Maps the specified OData route. /// </summary> /// <param name="configuration">The server configuration.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="model">The EDM model to use for parsing OData paths.</param> /// <param name="pathHandler">The <see cref="IODataPathHandler"/> to use for parsing the OData path.</param> /// <param name="routingConventions"> /// The OData routing conventions to use for controller and action selection. /// </param> /// <returns>The added <see cref="ODataRoute"/>.</returns> public static ODataRoute MapODataServiceRoute(this HttpConfiguration configuration, string routeName, string routePrefix, IEdmModel model, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions) { return(MapODataServiceRoute(configuration, routeName, routePrefix, model, pathHandler, routingConventions, batchHandler: null)); }
public static string ODataLink(this UrlHelper urlHelper, string routeName, IODataPathHandler pathHandler, IList<ODataPathSegment> segments) { return UrlHelperExtensions.CreateODataLink(urlHelper, routeName, pathHandler, segments); }
/// <summary> /// Maps the specified OData route and the OData route attributes. /// </summary> /// <param name="builder">The <see cref="IRouteBuilder"/> to add the route to.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="configureAction">The configuring action to add the services to the root container.</param> /// <returns>The added <see cref="ODataRoute"/>.</returns> public static ODataRoute MapODataServiceRoute(this IRouteBuilder builder, string routeName, string routePrefix, Action <IContainerBuilder> configureAction) { if (builder == null) { throw Error.ArgumentNull("builder"); } if (routeName == null) { throw Error.ArgumentNull("routeName"); } // Build and configure the root container. IPerRouteContainer perRouteContainer = builder.ServiceProvider.GetRequiredService <IPerRouteContainer>(); if (perRouteContainer == null) { throw Error.InvalidOperation(SRResources.MissingODataServices, nameof(IPerRouteContainer)); } // Create an service provider for this route. Add the default services to the custom configuration actions. Action <IContainerBuilder> builderAction = ConfigureDefaultServices(builder, configureAction); IServiceProvider serviceProvider = perRouteContainer.CreateODataRootContainer(routeName, builderAction); // Make sure the MetadataController is registered with the ApplicationPartManager. ApplicationPartManager applicationPartManager = builder.ServiceProvider.GetRequiredService <ApplicationPartManager>(); applicationPartManager.ApplicationParts.Add(new AssemblyPart(typeof(MetadataController).Assembly)); // Resolve the path handler and set URI resolver to it. IODataPathHandler pathHandler = serviceProvider.GetRequiredService <IODataPathHandler>(); // If settings is not on local, use the global configuration settings. ODataOptions options = builder.ServiceProvider.GetRequiredService <ODataOptions>(); if (pathHandler != null && pathHandler.UrlKeyDelimiter == null) { pathHandler.UrlKeyDelimiter = options.UrlKeyDelimiter; } // Resolve some required services and create the route constraint. ODataPathRouteConstraint routeConstraint = new ODataPathRouteConstraint(routeName); // Get constraint resolver. IInlineConstraintResolver inlineConstraintResolver = builder .ServiceProvider .GetRequiredService <IInlineConstraintResolver>(); // Resolve HTTP handler, create the OData route and register it. ODataRoute route = null; routePrefix = RemoveTrailingSlash(routePrefix); IRouter customRouter = serviceProvider.GetService <IRouter>(); route = new ODataRoute( customRouter != null ? customRouter : builder.DefaultHandler, routeName, routePrefix, routeConstraint, inlineConstraintResolver); // If a batch handler is present, register the route with the batch path mapper. This will be used // by the batching middleware to handle the batch request. Batching still requires the injection // of the batching middleware via UseODataBatching(). ODataBatchHandler batchHandler = serviceProvider.GetService <ODataBatchHandler>(); if (batchHandler != null) { batchHandler.ODataRoute = route; batchHandler.ODataRouteName = routeName; string batchPath = String.IsNullOrEmpty(routePrefix) ? '/' + ODataRouteConstants.Batch : '/' + routePrefix + '/' + ODataRouteConstants.Batch; ODataBatchPathMapping batchMapping = builder.ServiceProvider.GetRequiredService <ODataBatchPathMapping>(); batchMapping.AddRoute(routeName, batchPath); } builder.Routes.Add(route); return(route); }