Skip to content

Fix OData URL Substitution #384

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Oct 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build/file-version.targets
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<MajorAndMinorVersion>$(AssemblyVersion.Split(`.`)[0]).$(AssemblyVersion.Split(`.`)[1])</MajorAndMinorVersion>
<DaylightSavingTime>$([System.DateTime]::Now.IsDaylightSavingTime())</DaylightSavingTime>
<FileBuildNumber>$([System.DateTime]::Today.Subtract($([System.DateTime]::Parse("1/1/2000"))).ToString("%d"))</FileBuildNumber>
<FileBuildRevision Condition=" '$(DaylightSavingTime)'=='True' " >$([System.Convert]::ToInt32($([MSBuild]::Divide($([System.DateTime]::Now.TimeOfDay.Subtract($([System.TimeSpan]::FromHours(1.0))).TotalSeconds),2))))</FileBuildRevision>
<FileBuildRevision Condition=" '$(DaylightSavingTime)'=='True' " >$([System.Convert]::ToInt32($([MSBuild]::Divide($([System.DateTime]::Now.Subtract($([System.TimeSpan]::FromHours(1.0))).TimeOfDay.TotalSeconds),2))))</FileBuildRevision>
<FileBuildRevision Condition=" '$(DaylightSavingTime)'=='False' " >$([System.Convert]::ToInt32($([MSBuild]::Divide($([System.DateTime]::Now.TimeOfDay.TotalSeconds),2))))</FileBuildRevision>
<FileVersion>$(MajorAndMinorVersion).$(FileBuildNumber).$(FileBuildRevision)</FileVersion>
</PropertyGroup>
Expand Down
12 changes: 7 additions & 5 deletions samples/webapi/AdvancedODataWebApiSample/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

namespace Microsoft.Examples
{
using Configuration;
using global::Owin;
using Microsoft.AspNet.OData;
using Microsoft.AspNet.OData.Batch;
using Microsoft.AspNet.OData.Builder;
using Microsoft.AspNet.OData.Routing;
using Microsoft.Examples.Configuration;
using Microsoft.OData;
using Microsoft.OData.UriParser;
using Microsoft.Web.Http.Versioning;
using System.Web.Http;
using static Microsoft.OData.ODataUrlKeyDelimiter;
Expand All @@ -33,7 +35,6 @@ public void Configuration( IAppBuilder appBuilder )

var modelBuilder = new VersionedODataModelBuilder( configuration )
{
ModelBuilderFactory = () => new ODataConventionModelBuilder().EnableLowerCamelCase(),
ModelConfigurations =
{
new PersonModelConfiguration(),
Expand All @@ -43,14 +44,15 @@ public void Configuration( IAppBuilder appBuilder )
var models = modelBuilder.GetEdmModels();
var batchHandler = new DefaultODataBatchHandler( httpServer );

configuration.MapVersionedODataRoutes( "odata", "api", models, OnConfigureContainer, batchHandler );
configuration.MapVersionedODataRoutes( "odata", "api", models, ConfigureContainer, batchHandler );
configuration.Routes.MapHttpRoute( "orders", "api/{controller}/{id}", new { id = Optional } );
appBuilder.UseWebApi( httpServer );
}

static void OnConfigureContainer( IContainerBuilder builder )
static void ConfigureContainer( IContainerBuilder builder )
{
builder.AddService( Singleton, typeof( IODataPathHandler ), sp => new DefaultODataPathHandler() { UrlKeyDelimiter = Parentheses } );
builder.AddService<IODataPathHandler>( Singleton, sp => new DefaultODataPathHandler() { UrlKeyDelimiter = Parentheses } );
builder.AddService<ODataUriResolver>( Singleton, sp => new UnqualifiedCallAndEnumPrefixFreeResolver() { EnableCaseInsensitive = true } );
}
}
}
19 changes: 15 additions & 4 deletions samples/webapi/BasicODataWebApiSample/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@

namespace Microsoft.Examples
{
using Configuration;
using global::Owin;
using Microsoft.AspNet.OData;
using Microsoft.AspNet.OData.Batch;
using Microsoft.AspNet.OData.Builder;
using Microsoft.AspNet.OData.Routing;
using Microsoft.Examples.Configuration;
using Microsoft.OData;
using Microsoft.OData.UriParser;
using System.Web.Http;
using static Microsoft.OData.ODataUrlKeyDelimiter;
using static Microsoft.OData.ServiceLifetime;

public class Startup
{
Expand All @@ -20,7 +26,6 @@ public void Configuration( IAppBuilder appBuilder )

var modelBuilder = new VersionedODataModelBuilder( configuration )
{
ModelBuilderFactory = () => new ODataConventionModelBuilder().EnableLowerCamelCase(),
ModelConfigurations =
{
new PersonModelConfiguration(),
Expand All @@ -30,9 +35,15 @@ public void Configuration( IAppBuilder appBuilder )
var models = modelBuilder.GetEdmModels();
var batchHandler = new DefaultODataBatchHandler( httpServer );

configuration.MapVersionedODataRoutes( "odata", "api", models, batchHandler );
configuration.MapVersionedODataRoutes( "odata-bypath", "v{apiVersion}", models );
configuration.MapVersionedODataRoutes( "odata", "api", models, ConfigureContainer, batchHandler );
configuration.MapVersionedODataRoutes( "odata-bypath", "v{apiVersion}", models, ConfigureContainer );
appBuilder.UseWebApi( httpServer );
}

static void ConfigureContainer( IContainerBuilder builder )
{
builder.AddService<IODataPathHandler>( Singleton, sp => new DefaultODataPathHandler() { UrlKeyDelimiter = Parentheses } );
builder.AddService<ODataUriResolver>( Singleton, sp => new UnqualifiedCallAndEnumPrefixFreeResolver() { EnableCaseInsensitive = true } );
}
}
}
21 changes: 16 additions & 5 deletions samples/webapi/ConventionsODataWebApiSample/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@

namespace Microsoft.Examples
{
using Configuration;
using Controllers;
using global::Owin;
using Microsoft.AspNet.OData;
using Microsoft.AspNet.OData.Batch;
using Microsoft.AspNet.OData.Builder;
using Microsoft.AspNet.OData.Routing;
using Microsoft.Examples.Configuration;
using Microsoft.Examples.Controllers;
using Microsoft.OData;
using Microsoft.OData.UriParser;
using Microsoft.Web.Http.Versioning.Conventions;
using System.Web.Http;
using static Microsoft.OData.ODataUrlKeyDelimiter;
using static Microsoft.OData.ServiceLifetime;

public class Startup
{
Expand Down Expand Up @@ -38,7 +44,6 @@ public void Configuration( IAppBuilder appBuilder )

var modelBuilder = new VersionedODataModelBuilder( configuration )
{
ModelBuilderFactory = () => new ODataConventionModelBuilder().EnableLowerCamelCase(),
ModelConfigurations =
{
new PersonModelConfiguration(),
Expand All @@ -48,9 +53,15 @@ public void Configuration( IAppBuilder appBuilder )
var models = modelBuilder.GetEdmModels();
var batchHandler = new DefaultODataBatchHandler( httpServer );

configuration.MapVersionedODataRoutes( "odata", "api", models, batchHandler );
configuration.MapVersionedODataRoutes( "odata-bypath", "v{apiVersion}", models );
configuration.MapVersionedODataRoutes( "odata", "api", models, ConfigureContainer, batchHandler );
configuration.MapVersionedODataRoutes( "odata-bypath", "v{apiVersion}", models, ConfigureContainer );
appBuilder.UseWebApi( httpServer );
}

static void ConfigureContainer( IContainerBuilder builder )
{
builder.AddService<IODataPathHandler>( Singleton, sp => new DefaultODataPathHandler() { UrlKeyDelimiter = Parentheses } );
builder.AddService<ODataUriResolver>( Singleton, sp => new UnqualifiedCallAndEnumPrefixFreeResolver() { EnableCaseInsensitive = true } );
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ public void Apply( ODataModelBuilder builder, ApiVersion apiVersion )

if ( apiVersion >= ApiVersions.V1 )
{
// order.Collection.Function( "MostExpensive" ).ReturnsFromEntitySet<Order>( "Orders" );
order.Collection.Function( "MostExpensive" ).ReturnsFromEntitySet<Order>( "Orders" );
}

if ( apiVersion >= ApiVersions.V2 )
{
//order.Action( "Rate" ).Parameter<int>( "rating" );
order.Action( "Rate" ).Parameter<int>( "rating" );
}
}
}
Expand Down
19 changes: 14 additions & 5 deletions samples/webapi/SwaggerODataWebApiSample/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,21 @@
namespace Microsoft.Examples
{
using global::Owin;
using Microsoft.AspNet.OData;
using Microsoft.AspNet.OData.Builder;
using Microsoft.AspNet.OData.Extensions;
using Microsoft.AspNet.OData.Routing;
using Microsoft.Examples.Configuration;
using Microsoft.OData;
using Microsoft.OData.UriParser;
using Newtonsoft.Json.Serialization;
using Swashbuckle.Application;
using System.IO;
using System.Reflection;
using System.Web.Http;
using System.Web.Http.Description;
using static Microsoft.OData.ODataUrlKeyDelimiter;
using static Microsoft.OData.ServiceLifetime;

/// <summary>
/// Represents the startup process for the application.
Expand All @@ -28,8 +34,6 @@ public void Configuration( IAppBuilder builder )
var configuration = new HttpConfiguration();
var httpServer = new HttpServer( configuration );

configuration.SetUrlKeyDelimiter( OData.ODataUrlKeyDelimiter.Parentheses );

// reporting api versions will return the headers "api-supported-versions" and "api-deprecated-versions"
configuration.AddApiVersioning( o => o.ReportApiVersions = true );

Expand All @@ -38,7 +42,6 @@ public void Configuration( IAppBuilder builder )

var modelBuilder = new VersionedODataModelBuilder( configuration )
{
ModelBuilderFactory = () => new ODataConventionModelBuilder().EnableLowerCamelCase(),
ModelConfigurations =
{
new AllConfigurations(),
Expand All @@ -51,10 +54,10 @@ public void Configuration( IAppBuilder builder )
// TODO: while you can use both, you should choose only ONE of the following; comment, uncomment, or remove as necessary

// WHEN VERSIONING BY: query string, header, or media type
configuration.MapVersionedODataRoutes( "odata", routePrefix, models );
configuration.MapVersionedODataRoutes( "odata", routePrefix, models, ConfigureContainer );

// WHEN VERSIONING BY: url segment
//configuration.MapVersionedODataRoutes( "odata-bypath", "api/v{apiVersion}", models, ConfigureODataServices );
//configuration.MapVersionedODataRoutes( "odata-bypath", "api/v{apiVersion}", models, ConfigureContainer );

// add the versioned IApiExplorer and capture the strongly-typed implementation (e.g. ODataApiExplorer vs IApiExplorer)
// note: the specified format code will format the version as "'v'major[.minor][-status]"
Expand Down Expand Up @@ -114,5 +117,11 @@ static string XmlCommentsFilePath
return Path.Combine( basePath, fileName );
}
}

static void ConfigureContainer( IContainerBuilder builder )
{
builder.AddService<IODataPathHandler>( Singleton, sp => new DefaultODataPathHandler() { UrlKeyDelimiter = Parentheses } );
builder.AddService<ODataUriResolver>( Singleton, sp => new UnqualifiedCallAndEnumPrefixFreeResolver() { EnableCaseInsensitive = true } );
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,6 @@
<Reference Include="Swashbuckle.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cd1bb07a5ac7c7bc, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\Swashbuckle.Core.5.5.3\lib\net40\Swashbuckle.Core.dll</HintPath>
</Reference>
<!--<Reference Include="Swashbuckle.OData, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a2e252c86e553959, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\Swashbuckle.OData.3.2.0\lib\net452\Swashbuckle.OData.dll</HintPath>
</Reference>-->
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.Formatting, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll</HintPath>
Expand Down Expand Up @@ -178,7 +175,7 @@
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>1874</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:1874/</IISUrl>
<IISUrl>http://localhost:1874/swagger</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
Expand Down
17 changes: 17 additions & 0 deletions src/Common.ApiExplorer/ApiExplorerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,22 @@ public partial class ApiExplorerOptions
/// <value>The default description for API version parameters. The default value
/// is "The requested API version".</value>
public string DefaultApiVersionParameterDescription { get; set; } = LocalSR.DefaultApiVersionParamDesc;

/// <summary>
/// Gets or sets a value indicating whether API version parameters are added when an API is version-neutral.
/// </summary>
/// <value>True if API version parameters should be included when exploring a version-neutral API; otherwise, false.
/// The default value is <c>false</c>.</value>
/// <remarks>
/// <para>
/// A version-neutral API can accept any API version, including none at all. Setting this property to true
/// will enable exploring parameter descriptors for an API version that can be used to generate user input, which
/// may be useful for a version-neutral API that its own per-API version logic.
/// </para>
/// <para>
/// An API version defined using the URLsegment method is unaffected by this setting because path-based route
/// parameters are always required.
/// </para></remarks>
public bool AddApiVersionParametersWhenVersionNeutral { get; set; }
}
}
32 changes: 27 additions & 5 deletions src/Common.OData.ApiExplorer/AspNet.OData/ClassProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@

struct ClassProperty
{
readonly Type type;
internal readonly string Name;
internal readonly Type Type;

internal ClassProperty( PropertyInfo clrProperty, Type propertyType )
{
Contract.Requires( clrProperty != null );
Contract.Requires( propertyType != null );

Name = clrProperty.Name;
Type = propertyType;
type = propertyType;
Attributes = AttributesFromProperty( clrProperty );
}

Expand All @@ -30,12 +30,36 @@ internal ClassProperty( IEnumerable<Assembly> assemblies, IEdmOperationParameter
Contract.Requires( parameter != null );

Name = parameter.Name;
Type = parameter.Type.Definition.GetClrType( assemblies );
type = parameter.Type.Definition.GetClrType( assemblies );
Attributes = AttributesFromOperationParameter( parameter );
}

internal IEnumerable<CustomAttributeBuilder> Attributes { get; }

public override int GetHashCode() => ( Name.GetHashCode() * 397 ) ^ type.GetHashCode();

public Type GetType( Type declaringType )
{
Contract.Requires( declaringType != null );
Contract.Ensures( Contract.Result<Type>() != null );

if ( type == DeclaringType.Value )
{
return declaringType;
}
else if ( type.IsGenericType )
{
var typeArgs = type.GetGenericArguments();

if ( typeArgs.Length == 1 && typeArgs[0] == DeclaringType.Value )
{
return type.GetGenericTypeDefinition().MakeGenericType( declaringType );
}
}

return type;
}

static IEnumerable<CustomAttributeBuilder> AttributesFromProperty( PropertyInfo clrProperty )
{
Contract.Requires( clrProperty != null );
Expand Down Expand Up @@ -93,7 +117,5 @@ static IEnumerable<CustomAttributeBuilder> AttributesFromOperationParameter( IEd

yield return new CustomAttributeBuilder( ctor, args );
}

public override int GetHashCode() => ( Name.GetHashCode() * 397 ) ^ Type.GetHashCode();
}
}
9 changes: 9 additions & 0 deletions src/Common.OData.ApiExplorer/AspNet.OData/DeclaringType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Microsoft.AspNet.OData
{
using System;

struct DeclaringType
{
internal static Type Value = typeof( DeclaringType );
}
}
Loading