diff --git a/Cosmonaut.sln b/Cosmonaut.sln index fc889e5..759ac74 100644 --- a/Cosmonaut.sln +++ b/Cosmonaut.sln @@ -21,6 +21,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cosmonaut.System", "tests\C EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cosmonaut.Extensions.Microsoft.DependencyInjection", "src\Cosmonaut.Extensions.Microsoft.DependencyInjection\Cosmonaut.Extensions.Microsoft.DependencyInjection.csproj", "{D8538294-44A5-4A32-A110-39A4A4BB83A5}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cosmonaut.NetCore2WebApi", "samples\Cosmonaut.NetCore2WebApi\Cosmonaut.NetCore2WebApi.csproj", "{AEE4D100-8AE8-4C59-BCAE-BD4F0CCA56D4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -51,6 +53,10 @@ Global {D8538294-44A5-4A32-A110-39A4A4BB83A5}.Debug|Any CPU.Build.0 = Debug|Any CPU {D8538294-44A5-4A32-A110-39A4A4BB83A5}.Release|Any CPU.ActiveCfg = Release|Any CPU {D8538294-44A5-4A32-A110-39A4A4BB83A5}.Release|Any CPU.Build.0 = Release|Any CPU + {AEE4D100-8AE8-4C59-BCAE-BD4F0CCA56D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AEE4D100-8AE8-4C59-BCAE-BD4F0CCA56D4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AEE4D100-8AE8-4C59-BCAE-BD4F0CCA56D4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AEE4D100-8AE8-4C59-BCAE-BD4F0CCA56D4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -62,6 +68,7 @@ Global {C53E8DF6-9172-499E-9919-10A049A234C6} = {42392F64-A623-4C18-BF93-A5181AEE30C1} {87BB5EC9-0781-476E-8336-C3288ABCB591} = {1900E4D6-A0A0-4675-A049-AA2843143E01} {D8538294-44A5-4A32-A110-39A4A4BB83A5} = {42392F64-A623-4C18-BF93-A5181AEE30C1} + {AEE4D100-8AE8-4C59-BCAE-BD4F0CCA56D4} = {E50F9511-8F2F-4753-8D4B-B0CAD4E5D573} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {CBCF8635-B781-4296-9756-2D461FD0AE27} diff --git a/samples/Cosmonaut.Console/Program.cs b/samples/Cosmonaut.Console/Program.cs index 0f47e59..b93b7f5 100644 --- a/samples/Cosmonaut.Console/Program.cs +++ b/samples/Cosmonaut.Console/Program.cs @@ -39,7 +39,7 @@ static async Task Main(string[] args) settings.ConnectionPolicy = connectionPolicy; settings.DefaultCollectionThroughput = 5000; }); - + serviceCollection.AddCosmosStore(cosmosSettings); var provider = serviceCollection.BuildServiceProvider(); diff --git a/samples/Cosmonaut.NetCore2WebApi/Contract/CreatePersonRequest.cs b/samples/Cosmonaut.NetCore2WebApi/Contract/CreatePersonRequest.cs new file mode 100644 index 0000000..f182350 --- /dev/null +++ b/samples/Cosmonaut.NetCore2WebApi/Contract/CreatePersonRequest.cs @@ -0,0 +1,7 @@ +namespace Cosmonaut.NetCore2WebApi.Contract +{ + public class CreatePersonRequest + { + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/samples/Cosmonaut.NetCore2WebApi/Contract/EditPersonRequest.cs b/samples/Cosmonaut.NetCore2WebApi/Contract/EditPersonRequest.cs new file mode 100644 index 0000000..d283012 --- /dev/null +++ b/samples/Cosmonaut.NetCore2WebApi/Contract/EditPersonRequest.cs @@ -0,0 +1,9 @@ +using System; + +namespace Cosmonaut.NetCore2WebApi.Contract +{ + public class EditPersonRequest + { + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/samples/Cosmonaut.NetCore2WebApi/Contract/GetPersonResponse.cs b/samples/Cosmonaut.NetCore2WebApi/Contract/GetPersonResponse.cs new file mode 100644 index 0000000..aa97a21 --- /dev/null +++ b/samples/Cosmonaut.NetCore2WebApi/Contract/GetPersonResponse.cs @@ -0,0 +1,10 @@ +using System; + +namespace Cosmonaut.NetCore2WebApi.Contract +{ + public class GetPersonResponse + { + public string Identifier { get; set; } + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/samples/Cosmonaut.NetCore2WebApi/Contract/UpsertPersonRequest.cs b/samples/Cosmonaut.NetCore2WebApi/Contract/UpsertPersonRequest.cs new file mode 100644 index 0000000..a90296f --- /dev/null +++ b/samples/Cosmonaut.NetCore2WebApi/Contract/UpsertPersonRequest.cs @@ -0,0 +1,8 @@ +namespace Cosmonaut.NetCore2WebApi.Contract +{ + public class UpsertPersonRequest + { + public string Id { get; set; } + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/samples/Cosmonaut.NetCore2WebApi/Controllers/SampleController.cs b/samples/Cosmonaut.NetCore2WebApi/Controllers/SampleController.cs new file mode 100644 index 0000000..9c90124 --- /dev/null +++ b/samples/Cosmonaut.NetCore2WebApi/Controllers/SampleController.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Cosmonaut.Extensions; +using Cosmonaut.NetCore2WebApi.Contract; +using Cosmonaut.NetCore2WebApi.Model; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.Documents.SystemFunctions; +using Microsoft.EntityFrameworkCore; + +namespace Cosmonaut.NetCore2WebApi.Controllers +{ + public class SampleController : Controller + { + private readonly ICosmosStore _peopleCosmosStore; + + public SampleController(ICosmosStore peopleCosmosStore) + { + _peopleCosmosStore = peopleCosmosStore; + } + + [HttpGet("/api/people")] + public async Task GetAllPaged([FromQuery] string continuationToken, + CancellationToken cancellationToken, [FromQuery] int pageSize = 10) + { + if (pageSize > 50 || pageSize <= 0) + { + return BadRequest("Page Size Invalid! Must be 0 < pageSize < 50"); + } + + if (continuationToken == null || continuationToken.Trim().Length == 0) + { + var initialPage = await _peopleCosmosStore.Query().OrderBy(person => person.Name) + .WithPagination(1, pageSize).ToPagedListAsync(cancellationToken: cancellationToken); + + return Ok(initialPage); + } + + var page = await _peopleCosmosStore.Query().OrderBy(person => person.Name) + .WithPagination(continuationToken, pageSize).ToPagedListAsync(cancellationToken: cancellationToken); + + return Ok(page); + } + + [HttpGet("/api/people/{id:Guid}")] + public async Task GetById(Guid id, CancellationToken cancellationToken) + { + if (id == Guid.Empty) + { + return BadRequest("Invalid Person Id"); + } + + var person = + await _peopleCosmosStore.FindAsync(id.ToString(), cancellationToken: cancellationToken); + + if (person == null) + { + return NotFound(); + } + + var response = new GetPersonResponse + { + Identifier = person.Id, + Name = person.Name, + }; + + return Ok(response); + } + + [HttpPost("/api/people")] + public async Task Create([FromBody] CreatePersonRequest request, + CancellationToken cancellationToken) + { + var personToCreate = new Person + { + Name = request.Name + }; + + var result = await _peopleCosmosStore.UpsertAsync(personToCreate, cancellationToken: cancellationToken); + + var personId = result.Entity.Id; + + if (personId == null) + { + return BadRequest(); + } + + return Ok(personId); + } + + [HttpPut("/api/people/{id:Guid}")] + public async Task Update(Guid id, [FromBody] EditPersonRequest request, + CancellationToken cancellationToken) + { + if (id == Guid.Empty) + { + return BadRequest("Invalid Person Id"); + } + + if (request.Name.Trim().Length == 0) + { + return BadRequest("Person Name can not be empty"); + } + + var existingPerson = + await _peopleCosmosStore.FindAsync(id.ToString(), cancellationToken: cancellationToken); + + if (existingPerson == null) + { + return NotFound(); + } + + var personToSave = new Person + { + Id = id.ToString(), + Name = request.Name + }; + + var result = await _peopleCosmosStore.UpdateAsync(personToSave, cancellationToken: cancellationToken); + + var personId = result.Entity.Id; + + if (personId == null) + { + return BadRequest(); + } + + return Ok(personId); + } + + [HttpDelete("/api/people/{id:Guid}")] + public async Task Delete(Guid id, CancellationToken cancellationToken) + { + if (id == Guid.Empty) + { + return BadRequest(); + } + + await _peopleCosmosStore.RemoveByIdAsync(id.ToString(), cancellationToken: cancellationToken); + + return Ok(); + } + + //Alternative to having 1 endpoint for Creation and 1 for Update -> Upsert + [HttpPut("/api/people")] + public async Task Upsert([FromBody] UpsertPersonRequest request, + CancellationToken cancellationToken) + { + var personToUpsert = new Person + { + Id = request.Id, + Name = request.Name + }; + + var result = await _peopleCosmosStore.UpsertAsync(personToUpsert, cancellationToken: cancellationToken); + + var personId = result.Entity.Id; + + if (personId == null) + { + return BadRequest(); + } + + return Ok(personId); + } + } +} \ No newline at end of file diff --git a/samples/Cosmonaut.NetCore2WebApi/Cosmonaut.NetCore2WebApi.csproj b/samples/Cosmonaut.NetCore2WebApi/Cosmonaut.NetCore2WebApi.csproj new file mode 100644 index 0000000..129206e --- /dev/null +++ b/samples/Cosmonaut.NetCore2WebApi/Cosmonaut.NetCore2WebApi.csproj @@ -0,0 +1,21 @@ + + + + netcoreapp2.0 + + + + + + + + + + + + + + + + + diff --git a/samples/Cosmonaut.NetCore2WebApi/CosmonautConfiguration.cs b/samples/Cosmonaut.NetCore2WebApi/CosmonautConfiguration.cs new file mode 100644 index 0000000..adcbdee --- /dev/null +++ b/samples/Cosmonaut.NetCore2WebApi/CosmonautConfiguration.cs @@ -0,0 +1,50 @@ +using Cosmonaut.Extensions.Microsoft.DependencyInjection; +using Cosmonaut.NetCore2WebApi.Model; +using Microsoft.Azure.Documents.Client; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace Cosmonaut.NetCore2WebApi +{ + public class CosmonautConfiguration + { + public static void Configure(IServiceCollection services, IConfiguration configuration) + { + //Look at appsettings.Development.json | https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-2.1 + var cosmosConfig = new AppSettingsSection(); + configuration.GetSection("CosmosDb").Bind(cosmosConfig); + + var connectionPolicy = new ConnectionPolicy + { + ConnectionProtocol = Protocol.Tcp, + ConnectionMode = ConnectionMode.Direct + }; + + var cosmosSettings = new CosmosStoreSettings(cosmosConfig.CosmosDatabaseName, + cosmosConfig.CosmosDatabaseUrl, + cosmosConfig.CosmosAuthKey + , connectionPolicy + , defaultCollectionThroughput: cosmosConfig.DefaultConnectionThroughput); + + AddCosmosStores(services, cosmosSettings); + } + + private static void AddCosmosStores(IServiceCollection services, CosmosStoreSettings cosmosSettings) + { + services.AddCosmosStore(cosmosSettings); + } + } + + public class AppSettingsSection + { + public AppSettingsSection() + { + DefaultConnectionThroughput = 5000; + } + + public string CosmosDatabaseName { get; set; } + public string CosmosDatabaseUrl { get; set; } + public string CosmosAuthKey { get; set; } + public int DefaultConnectionThroughput { get; set; } + } +} \ No newline at end of file diff --git a/samples/Cosmonaut.NetCore2WebApi/Model/Person.cs b/samples/Cosmonaut.NetCore2WebApi/Model/Person.cs new file mode 100644 index 0000000..e4b8ea0 --- /dev/null +++ b/samples/Cosmonaut.NetCore2WebApi/Model/Person.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Cosmonaut.NetCore2WebApi.Model +{ + public class Person + { + [JsonProperty("id")] + public string Id { get; set; } + + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/samples/Cosmonaut.NetCore2WebApi/Program.cs b/samples/Cosmonaut.NetCore2WebApi/Program.cs new file mode 100644 index 0000000..2332423 --- /dev/null +++ b/samples/Cosmonaut.NetCore2WebApi/Program.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace Cosmonaut.NetCore2WebApi +{ + public class Program + { + public static void Main(string[] args) + { + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseStartup() + .Build(); + } +} \ No newline at end of file diff --git a/samples/Cosmonaut.NetCore2WebApi/Startup.cs b/samples/Cosmonaut.NetCore2WebApi/Startup.cs new file mode 100644 index 0000000..60c6e46 --- /dev/null +++ b/samples/Cosmonaut.NetCore2WebApi/Startup.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace Cosmonaut.NetCore2WebApi +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + public void ConfigureServices(IServiceCollection services) + { + CosmonautConfiguration.Configure(services, Configuration); + services.AddMvc(); + } + + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseMvc(); + } + } +} \ No newline at end of file diff --git a/samples/Cosmonaut.NetCore2WebApi/appsettings.Development.json b/samples/Cosmonaut.NetCore2WebApi/appsettings.Development.json new file mode 100644 index 0000000..8f8ffd3 --- /dev/null +++ b/samples/Cosmonaut.NetCore2WebApi/appsettings.Development.json @@ -0,0 +1,15 @@ +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + }, + "CosmosDb": { + "CosmosDatabaseName": "localtest", + "CosmosDatabaseUrl": "https://localhost:8081", + "CosmosAuthKey": "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==" + } +} diff --git a/samples/Cosmonaut.NetCore2WebApi/appsettings.json b/samples/Cosmonaut.NetCore2WebApi/appsettings.json new file mode 100644 index 0000000..a8eec0d --- /dev/null +++ b/samples/Cosmonaut.NetCore2WebApi/appsettings.json @@ -0,0 +1,20 @@ +{ + "Logging": { + "IncludeScopes": false, + "Debug": { + "LogLevel": { + "Default": "Warning" + } + }, + "Console": { + "LogLevel": { + "Default": "Warning" + } + } + }, + "CosmosDb": { + "CosmosDatabaseName": "", + "CosmosDatabaseUrl": "", + "CosmosAuthKey": "" + } +}