Skip to content

Commit

Permalink
Added project template
Browse files Browse the repository at this point in the history
  • Loading branch information
bastianeicher committed Jul 30, 2020
1 parent cd59267 commit d69f7eb
Show file tree
Hide file tree
Showing 22 changed files with 468 additions and 3 deletions.
12 changes: 12 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ jobs:
uses: gittools/actions/gitversion/[email protected]
with:
versionSpec: '5.3.x'
- name: Set up NuGet
uses: nuget/setup-nuget@v1
with:
nuget-version: '5.x'
- name: Check out repository
uses: actions/checkout@v2
with:
Expand Down Expand Up @@ -59,3 +63,11 @@ jobs:
tag_name: ${{github.ref}}
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
- name: Post-release commit
if: github.event_name == 'push' && steps.gitversion.outputs.preReleaseLabel == ''
run: |
set -e
git config user.name github-actions
git config user.email [email protected]
git commit --all -m "Automatic post-release commit"
git push
7 changes: 4 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
*.user
*.bak
*.db

# Caches
/src/.vs/
/src/.idea/
/src/_ReSharper.*/
.vs/
.idea/
_ReSharper.*/
obj/
bin/

Expand Down
1 change: 1 addition & 0 deletions build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pushd $PSScriptRoot

src\build.ps1 $Version
src\test.ps1
template\build.ps1 $Version
doc\build.ps1 $Version

popd
1 change: 1 addition & 0 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ cd `dirname $0`

src/build.sh ${1:-1.0-dev}
src/test.sh
template/build.sh ${1:-1.0-dev}
doc/build.sh ${1:-1.0-dev}
2 changes: 2 additions & 0 deletions doc/main.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ services.AddControllers()
.AddOpenServiceBroker();
```

You can use the **[project template](https://github.com/TypedRest/OpenServiceBroker/tree/master/template)** to quickly set up a pre-configured ASP.NET Core 3.1 project with `OpenServiceBroker.Server`.

### Versioning

The Server Library inspects the `X-Broker-API-Version` header for all requests (as defined in the specification). Currently it accepts all versions from `2.0` to `2.16`.
2 changes: 2 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ services.AddControllers()
.AddOpenServiceBroker();
```

You can use the **[project template](template/)** to quickly set up a pre-configured ASP.NET Core 3.1 project with `OpenServiceBroker.Server`.

### Versioning

The Server Library inspects the `X-Broker-API-Version` header for all requests (as defined in the specification). Currently it accepts all versions from `2.0` to `2.16`.
22 changes: 22 additions & 0 deletions template/OpenServiceBroker.Template.nuspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/10/nuspec.xsd">
<metadata>
<id>OpenServiceBroker.Template</id>
<version>$version$</version>
<title>OpenServiceBroker Template</title>
<authors>Bastian Eicher</authors>
<license type="expression">MIT</license>
<icon>icon.png</icon>
<projectUrl>https://github.com/TypedRest/OpenServiceBroker/tree/master/template</projectUrl>
<description>dotnet-new template for implementing a Service Broker (according to the Open Service Broker API) using ASP.NET Core</description>
<tags>OSB Open Service Broker Template</tags>
<repository type="git" url="https://github.com/TypedRest/OpenServiceBroker" />
<packageTypes>
<packageType name="Template" />
</packageTypes>
</metadata>
<files>
<file src="../icon.png" />
<file src="content/**" exclude="content/**/obj/**;content/**/bin/**;content/.vs/**;content/.idea/**;content/_ReSharper.*/**;content/**/*.user;content/**/*.db;**/.vscode/**" />
</files>
</package>
15 changes: 15 additions & 0 deletions template/build.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Param ([string]$Version = "0.1-dev")
$ErrorActionPreference = "Stop"
pushd $PSScriptRoot

pushd content
dotnet add . package OpenServiceBroker.Server --version $Version
if ($LASTEXITCODE -ne 0) {throw "Exit Code: $LASTEXITCODE"}
dotnet build
if ($LASTEXITCODE -ne 0) {throw "Exit Code: $LASTEXITCODE"}
popd

nuget pack -Version $Version -OutputDirectory ..\artifacts\Release -NoPackageAnalysis
if ($LASTEXITCODE -ne 0) {throw "Exit Code: $LASTEXITCODE"}

popd
10 changes: 10 additions & 0 deletions template/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
set -e
cd `dirname $0`

pushd content
dotnet add . package OpenServiceBroker.Server --version ${1:-1.0-dev}
dotnet build
popd

nuget pack -Version ${1:-1.0-dev} -OutputDirectory ../artifacts/Release -NoPackageAnalysis
13 changes: 13 additions & 0 deletions template/content/.template.config/template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"author": "Bastian Eicher",
"classifications": [ "Web", "OpenServiceBroker" ],
"name": "Open Service Broker",
"shortName": "osb",
"identity": "OpenServiceBroker",
"groupIdentity": "OpenServiceBroker",
"tags": {
"language": "C#"
},
"sourceName": "MyServiceBroker",
"preferNameDirectory": true
}
20 changes: 20 additions & 0 deletions template/content/CatalogService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Threading.Tasks;
using OpenServiceBroker.Catalogs;

namespace MyServiceBroker
{
public class CatalogService : ICatalogService
{
private readonly Catalog _catalog;

public CatalogService(Catalog catalog)
{
_catalog = catalog;
}

public Task<Catalog> GetCatalogAsync()
{
return Task.FromResult(_catalog);
}
}
}
17 changes: 17 additions & 0 deletions template/content/DbContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Microsoft.EntityFrameworkCore;

namespace MyServiceBroker
{
/// <summary>
/// Describes the service's database model.
/// Used as a combination of the Unit Of Work and Repository patterns.
/// </summary>
public class DbContext : Microsoft.EntityFrameworkCore.DbContext
{
public DbSet<ServiceInstanceEntity> ServiceInstances { get; set; } = default!;

public DbContext(DbContextOptions options)
: base(options)
{}
}
}
17 changes: 17 additions & 0 deletions template/content/MyServiceBroker.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
<NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="OpenServiceBroker.Server" Version="0.3.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.6" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.5.1" />
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="5.5.1" />
</ItemGroup>

</Project>
23 changes: 23 additions & 0 deletions template/content/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace MyServiceBroker
{
// Manage process lifecycle, configuration and logging
public static class Program
{
public static async Task Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
await scope.ServiceProvider.GetRequiredService<DbContext>().Database.EnsureCreatedAsync();
await host.RunAsync();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>());
}
}
13 changes: 13 additions & 0 deletions template/content/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"profiles": {
"ServiceBroker": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "http://localhost:12345",
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
16 changes: 16 additions & 0 deletions template/content/ServiceInstanceEntity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.ComponentModel.DataAnnotations;

namespace MyServiceBroker
{
public class ServiceInstanceEntity
{
[Key]
public string Id { get; set; } = default!;

public string ServiceId { get; set; } = default!;

public string PlanId { get; set; } = default!;

public string? Parameters { get; set; }
}
}
125 changes: 125 additions & 0 deletions template/content/ServiceInstanceService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OpenServiceBroker.Catalogs;
using OpenServiceBroker.Errors;
using OpenServiceBroker.Instances;

namespace MyServiceBroker
{
public class ServiceInstanceService : IServiceInstanceBlocking
{
private readonly DbContext _context;
private readonly ILogger<ServiceInstanceService> _logger;
private readonly Catalog _catalog;

public ServiceInstanceService(DbContext context, Catalog catalog, ILogger<ServiceInstanceService> logger)
{
_context = context;
_logger = logger;
_catalog = catalog;
}

public async Task<ServiceInstanceResource> FetchAsync(string instanceId)
{
_logger.LogTrace("Read instance {0}", instanceId);

var entity = await _context.ServiceInstances.FindAsync(instanceId);
if (entity == null) throw new NotFoundException($"Instance '{instanceId}' not found.");

return new ServiceInstanceResource
{
ServiceId = entity.ServiceId,
PlanId = entity.PlanId,
Parameters = JsonConvert.DeserializeObject<JObject>(entity.Parameters)
};
}

public async Task<ServiceInstanceProvision> ProvisionAsync(ServiceInstanceContext context, ServiceInstanceProvisionRequest request)
{
_logger.LogInformation("Provisioning instance {0} as service {1}.", context.InstanceId, request.ServiceId);

if (GetService(request.ServiceId).Plans.All(x => x.Id != request.PlanId))
throw new BadRequestException($"Unknown plan ID '{request.PlanId}'.");

var entity = await _context.ServiceInstances.FindAsync(context.InstanceId);
if (entity != null)
{
if (entity.ServiceId == request.ServiceId
&& entity.PlanId == request.PlanId
&& JsonConvert.SerializeObject(request.Parameters) == (entity.Parameters ?? "null"))
return new ServiceInstanceProvision {Unchanged = true};
else
throw new ConflictException($"There is already an instance {context.InstanceId} with different settings.");
}

await _context.ServiceInstances.AddAsync(new ServiceInstanceEntity
{
Id = context.InstanceId,
ServiceId = request.ServiceId,
PlanId = request.PlanId,
Parameters = JsonConvert.SerializeObject(request.Parameters)
});
try
{
await _context.SaveChangesAsync();
}
catch (Exception ex)
{
throw new ConflictException(ex.InnerException?.Message ?? ex.Message);
}

return new ServiceInstanceProvision();
}

private Service GetService(string id)
{
var service = _catalog.Services.FirstOrDefault(x => x.Id == id);
if (service == null)
throw new BadRequestException($"Unknown service ID '{id}'.");
return service;
}

public async Task UpdateAsync(ServiceInstanceContext context, ServiceInstanceUpdateRequest request)
{
_logger.LogInformation("Updating instance {0} as service {1}.", context.InstanceId, request.ServiceId);

var entity = await _context.ServiceInstances.FindAsync(context.InstanceId);
if (entity == null) throw new NotFoundException($"Instance '{context.InstanceId}' not found.");

if (request.ServiceId != entity.ServiceId)
throw new BadRequestException($"Cannot change service ID of instance '{context.InstanceId}' from '{entity.ServiceId}' to '{request.ServiceId}'.");
if (request.PlanId != null && request.PlanId != entity.PlanId)
{
var service = GetService(request.ServiceId);
if (!service.PlanUpdateable)
throw new BadRequestException($"Service ID '{request.ServiceId}' does not allow changing the Plan ID.");
if (service.Plans.All(x => x.Id != request.PlanId))
throw new BadRequestException($"Unknown plan ID '{request.PlanId}'.");
entity.PlanId = request.PlanId;
}
if (request.Parameters != null)
entity.Parameters = JsonConvert.SerializeObject(request.Parameters);

_context.Update(entity);
await _context.SaveChangesAsync();
}

public async Task DeprovisionAsync(ServiceInstanceContext context, string serviceId, string planId)
{
_logger.LogInformation("Deprovisioning instance {0}.", context.InstanceId);

var entity = await _context.ServiceInstances.FindAsync(context.InstanceId);
if (entity == null)
throw new GoneException($"Instance '{context.InstanceId}' not found.");
if (entity.ServiceId != serviceId || entity.PlanId != planId)
throw new BadRequestException($"Service and/or plan ID for instance '{context.InstanceId}' do not match.");

_context.ServiceInstances.Remove(entity);
await _context.SaveChangesAsync();
}
}
}
Loading

0 comments on commit d69f7eb

Please sign in to comment.