diff --git a/ODataNetCore/01-Basic/01-Basic.csproj b/ODataNetCore/01-Basic/01-Basic.csproj
new file mode 100644
index 00000000..d02e2ad8
--- /dev/null
+++ b/ODataNetCore/01-Basic/01-Basic.csproj
@@ -0,0 +1,13 @@
+
+
+
+ netcoreapp2.1
+ ODataNetCore-Simple
+
+
+
+
+
+
+
+
diff --git a/ODataNetCore/01-Basic/DemoRequests.http b/ODataNetCore/01-Basic/DemoRequests.http
new file mode 100644
index 00000000..5bfb0954
--- /dev/null
+++ b/ODataNetCore/01-Basic/DemoRequests.http
@@ -0,0 +1,8 @@
+GET http://localhost:5000/odata/Customers
+
+###
+GET http://localhost:5000/odata/Customers?$top=1
+
+###
+GET http://localhost:5000/odata/$metadata
+Accept: application/json
diff --git a/ODataNetCore/01-Basic/Program.cs b/ODataNetCore/01-Basic/Program.cs
new file mode 100644
index 00000000..e9990759
--- /dev/null
+++ b/ODataNetCore/01-Basic/Program.cs
@@ -0,0 +1,72 @@
+using System.Linq;
+using Microsoft.AspNet.OData;
+using Microsoft.AspNet.OData.Builder;
+using Microsoft.AspNet.OData.Extensions;
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.OData.Edm;
+
+namespace ODataNetCoreSimple
+{
+ public class Program
+ {
+ public static void Main(string[] args) =>
+ WebHost.CreateDefaultBuilder(args).UseStartup().Build().Run();
+ }
+
+ public class Customer
+ {
+ public int CustomerId { get; set; }
+
+ public string FirstName { get; set; }
+
+ public string LastName { get; set; }
+ }
+
+ public class Startup
+ {
+ public void ConfigureServices(IServiceCollection services)
+ {
+ // Add OData to ASP.NET Core's dependency injection system
+ services.AddOData();
+
+ services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
+ }
+
+ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
+ {
+ app.UseMvc(routeBuilder =>
+ {
+ // Specify allowed OData operations
+ routeBuilder.Select().Filter().MaxTop(50);
+
+ // Set route name, prefix, and OData data model
+ routeBuilder.MapODataServiceRoute("odata", "odata", GetEdmModel());
+ });
+ }
+
+ private static IEdmModel GetEdmModel()
+ {
+ // Use a convention builder to derive model from C# classes
+ // See http://odata.github.io/WebApi/#02-04-convention-model-builder for details
+ var builder = new ODataConventionModelBuilder();
+ builder.EntitySet("Customers");
+ return builder.GetEdmModel();
+ }
+ }
+
+ public class CustomersController : ODataController
+ {
+ private static Customer[] Customers { get; } = new []
+ {
+ new Customer { CustomerId = 1, FirstName = "John", LastName = "Doe" },
+ new Customer { CustomerId = 2, FirstName = "Foo", LastName = "Bar" }
+ };
+
+ [EnableQuery]
+ public IActionResult Get() => Ok(Customers.AsQueryable());
+ }
+}
diff --git a/ODataNetCore/02-CustomProvider/02-CustomProvider.csproj b/ODataNetCore/02-CustomProvider/02-CustomProvider.csproj
new file mode 100644
index 00000000..fd398060
--- /dev/null
+++ b/ODataNetCore/02-CustomProvider/02-CustomProvider.csproj
@@ -0,0 +1,13 @@
+
+
+
+ netcoreapp2.1
+ ODataNetCore-CustomProvider
+
+
+
+
+
+
+
+
diff --git a/ODataNetCore/02-CustomProvider/DemoRequests.http b/ODataNetCore/02-CustomProvider/DemoRequests.http
new file mode 100644
index 00000000..b2e38072
--- /dev/null
+++ b/ODataNetCore/02-CustomProvider/DemoRequests.http
@@ -0,0 +1,10 @@
+GET http://localhost:5000/odata/Customers
+
+###
+GET http://localhost:5000/odata/Customers?$filter=LastName eq 'Smith'
+
+###
+GET http://localhost:5000/odata/Customers?$top=3
+
+###
+GET http://localhost:5000/odata/$metadata
diff --git a/ODataNetCore/02-CustomProvider/Program.cs b/ODataNetCore/02-CustomProvider/Program.cs
new file mode 100644
index 00000000..8379bf56
--- /dev/null
+++ b/ODataNetCore/02-CustomProvider/Program.cs
@@ -0,0 +1,136 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.AspNet.OData;
+using Microsoft.AspNet.OData.Builder;
+using Microsoft.AspNet.OData.Extensions;
+using Microsoft.AspNet.OData.Query;
+using Microsoft.AspNet.OData.Routing;
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.OData.Edm;
+using Microsoft.OData.UriParser;
+
+namespace ODataNetCoreCustomProvider
+{
+ public class Program
+ {
+ public static void Main(string[] args) =>
+ WebHost.CreateDefaultBuilder(args).UseStartup().Build().Run();
+ }
+
+ public class Customer
+ {
+ public int CustomerId { get; set; }
+
+ public string FirstName { get; set; }
+
+ public string LastName { get; set; }
+ }
+
+ public class Startup
+ {
+ public void ConfigureServices(IServiceCollection services)
+ {
+ // Add OData to ASP.NET Core's dependency injection system
+ services.AddOData();
+
+ services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
+ }
+
+ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
+ {
+ app.UseMvc(routeBuilder =>
+ {
+ // Specify allowed OData operations
+ routeBuilder.Select().Filter().MaxTop(50);
+
+ // Set route name, prefix, and OData data model
+ routeBuilder.MapODataServiceRoute("odata", "odata", GetEdmModel());
+ });
+ }
+
+ private static IEdmModel GetEdmModel()
+ {
+ // Use a convention builder to derive model from C# classes
+ // See http://odata.github.io/WebApi/#02-04-convention-model-builder for details
+ var builder = new ODataConventionModelBuilder();
+ builder.EntitySet("Customers");
+ return builder.GetEdmModel();
+ }
+ }
+
+ public class CustomersController : ODataController
+ {
+ // Helpers for generating customer names
+ private readonly char[] letters1 = "aeiou".ToArray();
+ private readonly char[] letters2 = "bcdfgklmnpqrstvw".ToArray();
+ private Random random = new Random();
+
+ private const int pageSize = 100;
+
+ [EnableQuery]
+ [ODataRoute]
+ public IActionResult Get(ODataQueryOptions options)
+ {
+ // Calculate number of results based on $top
+ var numberOfResults = pageSize;
+ if (options.Top != null)
+ {
+ numberOfResults = options.Top.Value;
+ }
+
+ // Analyze $filter
+ string equalFilter = null;
+ if (options.Filter != null)
+ {
+ // We only support a single "eq" filter
+ var binaryOperator = options.Filter.FilterClause.Expression as BinaryOperatorNode;
+ if (binaryOperator == null || binaryOperator.OperatorKind != BinaryOperatorKind.Equal)
+ {
+ return BadRequest();
+ }
+
+ // One side has to be a reference to CustomerName property, the other side has to be a constant
+ var propertyAccess = binaryOperator.Left as SingleValuePropertyAccessNode ?? binaryOperator.Right as SingleValuePropertyAccessNode;
+ var constant = binaryOperator.Left as ConstantNode ?? binaryOperator.Right as ConstantNode;
+ if (propertyAccess == null || propertyAccess.Property.Name != "LastName" || constant == null)
+ {
+ return BadRequest();
+ }
+
+ // Save equal filter value
+ equalFilter = constant.Value.ToString();
+
+ // Return between 1 and 2 rows (CustomerName is not a primary key)
+ numberOfResults = Math.Min(random.Next(1, 3), numberOfResults);
+ }
+
+ // Generate result
+ var result = new List();
+ for (var i = 0; i < numberOfResults; i++)
+ {
+ result.Add(new Customer() { CustomerId = i + 1, FirstName = "Foo", LastName = equalFilter ?? GenerateCustomerName() });
+ }
+
+ return Ok(result.AsQueryable());
+ }
+
+ private string GenerateCustomerName()
+ {
+ var length = random.Next(5, 8);
+ var result = new StringBuilder(length);
+ for (var i = 0; i < length; i++)
+ {
+ var letter = (i % 2 == 0 ? letters1[random.Next(letters1.Length)] : letters2[random.Next(letters2.Length)]).ToString();
+ result.Append(i == 0 ? letter.ToUpper() : letter);
+ }
+
+ return result.ToString();
+ }
+ }
+}