Skip to content

Commit 4993819

Browse files
Chris Martinezcommonsensesoftware
authored andcommitted
Baseline changes to support exploring all OData routes
1 parent 127b721 commit 4993819

File tree

39 files changed

+2370
-50
lines changed

39 files changed

+2370
-50
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
namespace Microsoft.Examples.Configuration
2+
{
3+
using Microsoft.AspNet.OData.Builder;
4+
using Microsoft.AspNetCore.Mvc;
5+
using Microsoft.Examples.Models;
6+
using System;
7+
8+
/// <summary>
9+
/// Represents the model configuration for products.
10+
/// </summary>
11+
public class ProductConfiguration : IModelConfiguration
12+
{
13+
/// <summary>
14+
/// Applies model configurations using the provided builder for the specified API version.
15+
/// </summary>
16+
/// <param name="builder">The <see cref="ODataModelBuilder">builder</see> used to apply configurations.</param>
17+
/// <param name="apiVersion">The <see cref="ApiVersion">API version</see> associated with the <paramref name="builder"/>.</param>
18+
public void Apply( ODataModelBuilder builder, ApiVersion apiVersion )
19+
{
20+
if ( apiVersion < ApiVersions.V3 )
21+
{
22+
return;
23+
}
24+
25+
var product = builder.EntitySet<Product>( "Products" ).EntityType.HasKey( p => p.Id );
26+
}
27+
}
28+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
namespace Microsoft.Examples.Configuration
2+
{
3+
using Microsoft.AspNet.OData.Builder;
4+
using Microsoft.AspNetCore.Mvc;
5+
using Microsoft.Examples.Models;
6+
7+
/// <summary>
8+
/// Represents the model configuration for suppliers.
9+
/// </summary>
10+
public class SupplierConfiguration : IModelConfiguration
11+
{
12+
/// <summary>
13+
/// Applies model configurations using the provided builder for the specified API version.
14+
/// </summary>
15+
/// <param name="builder">The <see cref="ODataModelBuilder">builder</see> used to apply configurations.</param>
16+
/// <param name="apiVersion">The <see cref="ApiVersion">API version</see> associated with the <paramref name="builder"/>.</param>
17+
public void Apply( ODataModelBuilder builder, ApiVersion apiVersion )
18+
{
19+
if ( apiVersion < ApiVersions.V3 )
20+
{
21+
return;
22+
}
23+
24+
var supplier = builder.EntitySet<Supplier>( "Suppliers" ).EntityType.HasKey( p => p.Id );
25+
}
26+
}
27+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
namespace Microsoft.Examples.Models
2+
{
3+
using System;
4+
using System.ComponentModel.DataAnnotations.Schema;
5+
6+
/// <summary>
7+
/// Represents a product.
8+
/// </summary>
9+
public class Product
10+
{
11+
/// <summary>
12+
/// Gets or sets the unique identifier for the product.
13+
/// </summary>
14+
/// <value>The product's unique identifier.</value>
15+
public int Id { get; set; }
16+
17+
/// <summary>
18+
/// Gets or sets the product name.
19+
/// </summary>
20+
/// <value>The product's name.</value>
21+
public string Name { get; set; }
22+
23+
/// <summary>
24+
/// Gets or sets the product price.
25+
/// </summary>
26+
/// <value>The price's name.</value>
27+
public decimal Price { get; set; }
28+
29+
/// <summary>
30+
/// Gets or sets the product category.
31+
/// </summary>
32+
/// <value>The category's name.</value>
33+
public string Category { get; set; }
34+
35+
/// <summary>
36+
/// Gets or sets the associated supplier identifier.
37+
/// </summary>
38+
/// <value>The associated supplier identifier.</value>
39+
[ForeignKey( nameof( Supplier ) )]
40+
public int? SupplierId { get; set; }
41+
42+
/// <summary>
43+
/// Gets or sets the associated supplier.
44+
/// </summary>
45+
/// <value>The associated supplier.</value>
46+
public virtual Supplier Supplier { get; set; }
47+
}
48+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
namespace Microsoft.Examples.Models
2+
{
3+
using System;
4+
using System.Collections.Generic;
5+
6+
/// <summary>
7+
/// Represents a supplier.
8+
/// </summary>
9+
public class Supplier
10+
{
11+
/// <summary>
12+
/// Gets or sets the unique identifier for the supplier.
13+
/// </summary>
14+
/// <value>The supplier's unique identifier.</value>
15+
public int Id { get; set; }
16+
17+
/// <summary>
18+
/// Gets or sets the supplier name.
19+
/// </summary>
20+
/// <value>The supplier's name.</value>
21+
public string Name { get; set; }
22+
23+
/// <summary>
24+
/// Gets or sets products associated with the supplier.
25+
/// </summary>
26+
/// <value>The collection of associated products.</value>
27+
public ICollection<Product> Products { get; set; }
28+
}
29+
}
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
namespace Microsoft.Examples.V3
2+
{
3+
using Microsoft.AspNet.OData;
4+
using Microsoft.AspNet.OData.Extensions;
5+
using Microsoft.AspNetCore.Mvc;
6+
using Microsoft.Examples.Models;
7+
using Microsoft.OData.UriParser;
8+
using System;
9+
using System.Collections.Generic;
10+
using System.Linq;
11+
using System.Text;
12+
using static Microsoft.AspNetCore.Http.StatusCodes;
13+
14+
/// <summary>
15+
/// Represents a RESTful service of products.
16+
/// </summary>
17+
[ApiVersion( "3.0" )]
18+
public class ProductsController : ODataController
19+
{
20+
private readonly IQueryable<Product> products = new[] { NewProduct( 1 ), NewProduct( 2 ), NewProduct( 3 ), }.AsQueryable();
21+
22+
/// <summary>
23+
/// Retrieves all products.
24+
/// </summary>
25+
/// <returns>All available products.</returns>
26+
/// <response code="200">Products successfully retrieved.</response>
27+
[EnableQuery]
28+
[Produces( "application/json" )]
29+
[ProducesResponseType( typeof( ODataValue<IEnumerable<Product>> ), Status200OK )]
30+
public IQueryable<Product> Get() => products;
31+
32+
/// <summary>
33+
/// Gets a single product.
34+
/// </summary>
35+
/// <param name="key">The requested product identifier.</param>
36+
/// <returns>The requested product.</returns>
37+
/// <response code="200">The product was successfully retrieved.</response>
38+
/// <response code="404">The product does not exist.</response>
39+
[EnableQuery]
40+
[Produces( "application/json" )]
41+
[ProducesResponseType( typeof( Product ), Status200OK )]
42+
[ProducesResponseType( Status404NotFound )]
43+
public SingleResult<Product> Get( [FromODataUri] int key ) => SingleResult.Create( products.Where( p => p.Id == key ) );
44+
45+
/// <summary>
46+
/// Creates a new product.
47+
/// </summary>
48+
/// <param name="product">The product to create.</param>
49+
/// <returns>The created product.</returns>
50+
/// <response code="201">The product was successfully created.</response>
51+
/// <response code="204">The product was successfully created.</response>
52+
/// <response code="400">The product is invalid.</response>
53+
[Produces( "application/json" )]
54+
[ProducesResponseType( typeof( Product ), Status201Created )]
55+
[ProducesResponseType( Status204NoContent )]
56+
[ProducesResponseType( Status400BadRequest )]
57+
public IActionResult Post( [FromBody] Product product )
58+
{
59+
if ( !ModelState.IsValid )
60+
{
61+
return BadRequest( ModelState );
62+
}
63+
64+
product.Id = 42;
65+
66+
return Created( product );
67+
}
68+
69+
/// <summary>
70+
/// Updates an existing product.
71+
/// </summary>
72+
/// <param name="key">The requested product identifier.</param>
73+
/// <param name="delta">The partial product to update.</param>
74+
/// <returns>The updated product.</returns>
75+
/// <response code="200">The product was successfully updated.</response>
76+
/// <response code="204">The product was successfully updated.</response>
77+
/// <response code="400">The product is invalid.</response>
78+
/// <response code="404">The product does not exist.</response>
79+
[Produces( "application/json" )]
80+
[ProducesResponseType( typeof( Product ), Status200OK )]
81+
[ProducesResponseType( Status204NoContent )]
82+
[ProducesResponseType( Status400BadRequest )]
83+
[ProducesResponseType( Status404NotFound )]
84+
public IActionResult Patch( [FromODataUri] int key, Delta<Product> delta )
85+
{
86+
if ( !ModelState.IsValid )
87+
{
88+
return BadRequest( ModelState );
89+
}
90+
91+
var product = new Product() { Id = key, Name = "Updated Product " + key.ToString() };
92+
93+
delta.Patch( product );
94+
95+
return Updated( delta );
96+
}
97+
98+
/// <summary>
99+
/// Updates an existing product.
100+
/// </summary>
101+
/// <param name="key">The requested product identifier.</param>
102+
/// <param name="update">The product to update.</param>
103+
/// <returns>The updated product.</returns>
104+
/// <response code="200">The product was successfully updated.</response>
105+
/// <response code="204">The product was successfully updated.</response>
106+
/// <response code="400">The product is invalid.</response>
107+
/// <response code="404">The product does not exist.</response>
108+
[Produces( "application/json" )]
109+
[ProducesResponseType( typeof( Product ), Status200OK )]
110+
[ProducesResponseType( Status204NoContent )]
111+
[ProducesResponseType( Status400BadRequest )]
112+
[ProducesResponseType( Status404NotFound )]
113+
public IActionResult Put( [FromODataUri] int key, [FromBody] Product update )
114+
{
115+
if ( !ModelState.IsValid )
116+
{
117+
return BadRequest( ModelState );
118+
}
119+
120+
return Updated( update );
121+
}
122+
123+
/// <summary>
124+
/// Deletes a product.
125+
/// </summary>
126+
/// <param name="key">The product to delete.</param>
127+
/// <returns>None</returns>
128+
/// <response code="204">The product was successfully deleted.</response>
129+
[ProducesResponseType( Status204NoContent )]
130+
[ProducesResponseType( Status404NotFound )]
131+
public IActionResult Delete( [FromODataUri] int key ) => NoContent();
132+
133+
/// <summary>
134+
/// Gets the supplier associated with the product.
135+
/// </summary>
136+
/// <param name="key">The product identifier.</param>
137+
/// <returns>The supplier</returns>
138+
/// <returns>The requested supplier.</returns>
139+
[EnableQuery]
140+
[Produces( "application/json" )]
141+
[ProducesResponseType( typeof( Supplier ), Status200OK )]
142+
[ProducesResponseType( Status404NotFound )]
143+
public SingleResult<Supplier> GetSupplier( [FromODataUri] int key ) => SingleResult.Create( products.Where( p => p.Id == key ).Select( p => p.Supplier ) );
144+
145+
/// <summary>
146+
/// Gets the link to the associated supplier, if any.
147+
/// </summary>
148+
/// <param name="key">The product identifier.</param>
149+
/// <param name="navigationProperty">The supplier to link.</param>
150+
/// <returns>The supplier link.</returns>
151+
[Produces( "application/json" )]
152+
[ProducesResponseType( typeof( ODataId ), Status200OK )]
153+
[ProducesResponseType( Status404NotFound )]
154+
public IActionResult GetRefToSupplier( [FromODataUri] int key, [FromODataUri] string navigationProperty )
155+
{
156+
var segments = Request.ODataFeature().Path.Segments.ToArray();
157+
var entitySet = ( (EntitySetSegment) segments[0] ).EntitySet;
158+
var property = entitySet.NavigationPropertyBindings.Single( p => p.Path.Path == navigationProperty ).NavigationProperty;
159+
160+
segments[segments.Length - 1] = new NavigationPropertySegment( property, entitySet );
161+
162+
var relatedKey = new Uri( Url.CreateODataLink( segments ) );
163+
164+
return Ok( relatedKey );
165+
}
166+
167+
/// <summary>
168+
/// Links a supplier to a product.
169+
/// </summary>
170+
/// <param name="key">The product identifier.</param>
171+
/// <param name="navigationProperty">The supplier to link.</param>
172+
/// <param name="link">The supplier identifier.</param>
173+
/// <returns>None</returns>
174+
[HttpPut]
175+
[ProducesResponseType( Status204NoContent )]
176+
[ProducesResponseType( Status404NotFound )]
177+
public IActionResult CreateRefToSupplier( [FromODataUri] int key, [FromODataUri] string navigationProperty, [FromBody] Uri link ) => NoContent();
178+
179+
/// <summary>
180+
/// Unlinks a supplier from a product.
181+
/// </summary>
182+
/// <param name="key">The product identifier.</param>
183+
/// <param name="navigationProperty">The supplier to unlink.</param>
184+
/// <returns>None</returns>
185+
[ProducesResponseType( Status204NoContent )]
186+
[ProducesResponseType( Status404NotFound )]
187+
public IActionResult DeleteRefToSupplier( [FromODataUri] int key, [FromODataUri] string navigationProperty ) => NoContent();
188+
189+
static Product NewProduct( int id ) =>
190+
new Product()
191+
{
192+
Id = id,
193+
Category = "Test",
194+
Name = "Product " + id.ToString(),
195+
Price = id,
196+
Supplier = new Supplier() { Id = id, Name = "Supplier " + id.ToString() },
197+
SupplierId = id,
198+
};
199+
}
200+
}

0 commit comments

Comments
 (0)