Compare commits

..

3 Commits

Author SHA1 Message Date
a1999bfe41 Rename WebApi project to Vegasco.Server.Api
All checks were successful
continuous-integration/drone/push Build is passing
And update all references including comments etc.
2025-06-12 18:23:09 +02:00
9d71c86474 Fix broken swagger route 2025-06-12 17:58:50 +02:00
d91b837e44 Update packages, use explicit type, use Microsoft OpenApi package 2025-06-12 17:43:22 +02:00
76 changed files with 315 additions and 455 deletions

View File

@@ -10,18 +10,18 @@ USER app
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["src/WebApi/WebApi.csproj", "src/WebApi/"]
RUN dotnet restore "./src/WebApi/WebApi.csproj"
COPY ["src/Vegasco.Server.Api/Vegasco.Server.Api.csproj", "src/Vegasco.Server.Api/"]
RUN dotnet restore "./src/Vegasco.Server.Api/Vegasco.Server.Api.csproj"
COPY . .
WORKDIR "/src/src/WebApi"
RUN dotnet build "./WebApi.csproj" -c $BUILD_CONFIGURATION -o /app/build
WORKDIR "/src/src/Vegasco.Server.Api"
RUN dotnet build "./Vegasco.Server.Api.csproj" -c $BUILD_CONFIGURATION -o /app/build
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./WebApi.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
RUN dotnet publish "./Vegasco.Server.Api.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
HEALTHCHECK --interval=20s --timeout=1s --start-period=10s --retries=3 CMD curl --fail http://localhost:8080/health || exit 1
ENTRYPOINT ["dotnet", "WebApi.dll"]
ENTRYPOINT ["dotnet", "Vegasco.Server.Api.dll"]

View File

@@ -60,7 +60,7 @@ As appsettings.json (or a environment specific appsettings.*.json):
### Running the application
The solution uses Aspire to orchestrate the application. Specifically, it introduces sensible service defaults, including but not limited to OpenTelemetry,
creates a Postgres database as a docker container, and starts the WebApi with the correct configuration to communicate with the database.
creates a Postgres database as a docker container, and starts the Api with the correct configuration to communicate with the database.
Ensure you have an identity provider set up, for example Keycloak, and configured the relevant options described above.

View File

@@ -1,6 +1,6 @@
using FluentValidation;
namespace Vegasco.WebApi.Authentication;
namespace Vegasco.Server.Api.Authentication;
public class JwtOptions
{

View File

@@ -2,7 +2,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Security.Claims;
namespace Vegasco.WebApi.Authentication;
namespace Vegasco.Server.Api.Authentication;
public sealed class UserAccessor
{
@@ -47,14 +47,14 @@ public sealed class UserAccessor
private string GetClaimValue(string claimType)
{
var httpContext = _httpContextAccessor.HttpContext;
HttpContext? httpContext = _httpContextAccessor.HttpContext;
if (httpContext is null)
{
ThrowForMissingHttpContext();
}
var claimValue = httpContext.User.FindFirstValue(claimType);
string? claimValue = httpContext.User.FindFirstValue(claimType);
if (string.IsNullOrWhiteSpace(claimValue))
{

View File

@@ -1,9 +1,9 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Vegasco.WebApi.Consumptions;
using Vegasco.WebApi.Users;
using Vegasco.Server.Api.Consumptions;
using Vegasco.Server.Api.Users;
namespace Vegasco.WebApi.Cars;
namespace Vegasco.Server.Api.Cars;
public class Car
{

View File

@@ -1,6 +1,6 @@
using StronglyTypedIds;
namespace Vegasco.WebApi.Cars;
namespace Vegasco.Server.Api.Cars;
[StronglyTypedId]
public partial struct CarId;

View File

@@ -1,11 +1,11 @@
using FluentValidation;
using FluentValidation.Results;
using Vegasco.WebApi.Authentication;
using Vegasco.WebApi.Common;
using Vegasco.WebApi.Persistence;
using Vegasco.WebApi.Users;
using Vegasco.Server.Api.Authentication;
using Vegasco.Server.Api.Common;
using Vegasco.Server.Api.Persistence;
using Vegasco.Server.Api.Users;
namespace Vegasco.WebApi.Cars;
namespace Vegasco.Server.Api.Cars;
public static class CreateCar
{
@@ -42,9 +42,9 @@ public static class CreateCar
return TypedResults.BadRequest(new HttpValidationProblemDetails(failedValidations.ToCombinedDictionary()));
}
var userId = userAccessor.GetUserId();
string userId = userAccessor.GetUserId();
var user = await dbContext.Users.FindAsync([userId], cancellationToken: cancellationToken);
User? user = await dbContext.Users.FindAsync([userId], cancellationToken: cancellationToken);
if (user is null)
{
user = new User

View File

@@ -1,6 +1,6 @@
using Vegasco.WebApi.Persistence;
using Vegasco.Server.Api.Persistence;
namespace Vegasco.WebApi.Cars;
namespace Vegasco.Server.Api.Cars;
public static class DeleteCar
{
@@ -16,7 +16,7 @@ public static class DeleteCar
ApplicationDbContext dbContext,
CancellationToken cancellationToken)
{
var car = await dbContext.Cars.FindAsync([new CarId(id)], cancellationToken: cancellationToken);
Car? car = await dbContext.Cars.FindAsync([new CarId(id)], cancellationToken: cancellationToken);
if (car is null)
{

View File

@@ -1,6 +1,6 @@
using Vegasco.WebApi.Persistence;
using Vegasco.Server.Api.Persistence;
namespace Vegasco.WebApi.Cars;
namespace Vegasco.Server.Api.Cars;
public static class GetCar
{

View File

@@ -1,9 +1,9 @@
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Vegasco.WebApi.Persistence;
using Vegasco.Server.Api.Persistence;
namespace Vegasco.WebApi.Cars;
namespace Vegasco.Server.Api.Cars;
public static class GetCars
{

View File

@@ -1,10 +1,10 @@
using FluentValidation;
using FluentValidation.Results;
using Vegasco.WebApi.Authentication;
using Vegasco.WebApi.Common;
using Vegasco.WebApi.Persistence;
using Vegasco.Server.Api.Authentication;
using Vegasco.Server.Api.Common;
using Vegasco.Server.Api.Persistence;
namespace Vegasco.WebApi.Cars;
namespace Vegasco.Server.Api.Cars;
public static class UpdateCar
{

View File

@@ -1,4 +1,4 @@
namespace Vegasco.WebApi.Common;
namespace Vegasco.Server.Api.Common;
public static class Constants
{

View File

@@ -2,26 +2,23 @@
using FluentValidation;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Options;
using Vegasco.WebApi.Authentication;
using Vegasco.WebApi.Endpoints;
using Vegasco.WebApi.Endpoints.OpenApi;
using Vegasco.WebApi.Persistence;
using Vegasco.Server.Api.Authentication;
using Vegasco.Server.Api.Common;
using Vegasco.Server.Api.Persistence;
namespace Vegasco.WebApi.Common;
namespace Vegasco.Server.Api.Common;
public static class DependencyInjectionExtensions
{
/// <summary>
/// Adds all the WebApi related services to the Dependency Injection container.
/// Adds all the Api related services to the Dependency Injection container.
/// </summary>
/// <param name="services"></param>
/// <param name="configuration"></param>
/// <param name="environment"></param>
public static void AddWebApiServices(this IHostApplicationBuilder builder)
/// <param name="builder"></param>
public static void AddApiServices(this IHostApplicationBuilder builder)
{
builder.Services
.AddMiscellaneousServices()
.AddOpenApi()
.AddCustomOpenApi()
.AddApiVersioning()
.AddAuthenticationAndAuthorization(builder.Environment);
@@ -34,11 +31,10 @@ public static class DependencyInjectionExtensions
services.AddValidatorsFromAssemblies(
[
typeof(IWebApiMarker).Assembly
typeof(IApiMarker).Assembly
], ServiceLifetime.Singleton);
services.AddHealthChecks();
services.AddEndpointsFromAssemblyContaining<IWebApiMarker>();
services.AddHttpContextAccessor();
@@ -47,32 +43,30 @@ public static class DependencyInjectionExtensions
return services;
}
private static IServiceCollection AddOpenApi(this IServiceCollection services)
private static IServiceCollection AddCustomOpenApi(this IServiceCollection services)
{
services.ConfigureOptions<ConfigureSwaggerGenOptions>();
services.AddEndpointsApiExplorer();
services.AddSwaggerGen(o =>
services.AddOpenApi(o =>
{
o.CustomSchemaIds(type =>
o.CreateSchemaReferenceId = jsonTypeInfo =>
{
if (string.IsNullOrEmpty(type.FullName))
if (string.IsNullOrEmpty(jsonTypeInfo.Type.FullName))
{
return type.Name;
return jsonTypeInfo.Type.Name;
}
var fullClassName = type.FullName;
string? fullClassName = jsonTypeInfo.Type.FullName;
if (!string.IsNullOrEmpty(type.Namespace))
if (!string.IsNullOrEmpty(jsonTypeInfo.Type.Namespace))
{
fullClassName = fullClassName
.Replace(type.Namespace, "")
.Replace(jsonTypeInfo.Type.Namespace, "")
.TrimStart('.');
}
fullClassName = fullClassName.Replace('+', '_');
return fullClassName;
});
};
});
return services;
@@ -132,7 +126,7 @@ public static class DependencyInjectionExtensions
private static IHostApplicationBuilder AddDbContext(this IHostApplicationBuilder builder)
{
builder.AddNpgsqlDbContext<ApplicationDbContext>(Server.AppHost.Shared.Constants.Database.Name);
builder.AddNpgsqlDbContext<ApplicationDbContext>(AppHost.Shared.Constants.Database.Name);
return builder;
}
}

View File

@@ -1,7 +1,8 @@
using FluentValidation;
using FluentValidation.Results;
using Microsoft.Extensions.Options;
namespace Vegasco.WebApi.Common;
namespace Vegasco.Server.Api.Common;
public class FluentValidationOptions<TOptions> : IValidateOptions<TOptions>
where TOptions : class
@@ -25,7 +26,7 @@ public class FluentValidationOptions<TOptions> : IValidateOptions<TOptions>
ArgumentNullException.ThrowIfNull(options);
var failedValidations = _validators.ValidateAllAsync(options).Result;
List<ValidationResult> failedValidations = _validators.ValidateAllAsync(options).Result;
if (failedValidations.Count == 0)
{
return ValidateOptionsResult.Success;

View File

@@ -0,0 +1,3 @@
namespace Vegasco.Server.Api.Common;
public interface IApiMarker;

View File

@@ -1,9 +1,9 @@
using Asp.Versioning.ApiExplorer;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Localization;
using System.Globalization;
using Vegasco.WebApi.Endpoints;
using Vegasco.Server.Api.Endpoints;
using Vegasco.Server.ServiceDefaults;
namespace Vegasco.WebApi.Common;
namespace Vegasco.Server.Api.Common;
internal static class StartupExtensions
{
@@ -13,7 +13,7 @@ internal static class StartupExtensions
builder.Configuration.AddEnvironmentVariables("Vegasco_");
builder.AddWebApiServices();
builder.AddApiServices();
WebApplication app = builder.Build();
return app;
@@ -45,18 +45,7 @@ internal static class StartupExtensions
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(o =>
{
// Create a Swagger endpoint for each API version
IReadOnlyList<ApiVersionDescription> apiVersions = app.DescribeApiVersions();
foreach (ApiVersionDescription apiVersionDescription in apiVersions)
{
string url = $"/swagger/{apiVersionDescription.GroupName}/swagger.json";
string name = apiVersionDescription.GroupName.ToUpperInvariant();
o.SwaggerEndpoint(url, name);
}
});
app.MapOpenApi("/swagger/{documentName}/swagger.json");
}
return app;

View File

@@ -2,7 +2,7 @@
using FluentValidation.Results;
using Microsoft.Extensions.Options;
namespace Vegasco.WebApi.Common;
namespace Vegasco.Server.Api.Common;
public static class ValidatorExtensions
{
@@ -15,7 +15,7 @@ public static class ValidatorExtensions
/// <returns>The failed validation results.</returns>
public static async Task<List<ValidationResult>> ValidateAllAsync<T>(this IEnumerable<IValidator<T>> validators, T instance, CancellationToken cancellationToken = default)
{
var validationTasks = validators
List<Task<ValidationResult>> validationTasks = validators
.Select(validator => validator.ValidateAsync(instance, cancellationToken))
.ToList();
@@ -34,11 +34,11 @@ public static class ValidatorExtensions
// Use a hash set to avoid duplicate error messages.
Dictionary<string, HashSet<string>> combinedErrors = [];
foreach (var error in validationResults.SelectMany(x => x.Errors))
foreach (ValidationFailure? error in validationResults.SelectMany(x => x.Errors))
{
if (!combinedErrors.TryGetValue(error.PropertyName, out HashSet<string>? value))
{
value = ([error.ErrorMessage]);
value = [error.ErrorMessage];
combinedErrors[error.PropertyName] = value;
continue;
}
@@ -54,7 +54,7 @@ public static class ValidatorExtensions
{
builder.Services.AddTransient<IValidateOptions<T>>(serviceProvider =>
{
var validators = serviceProvider.GetServices<IValidator<T>>() ?? [];
IEnumerable<IValidator<T>> validators = serviceProvider.GetServices<IValidator<T>>() ?? [];
return new FluentValidationOptions<T>(builder.Name, validators);
});
return builder;

View File

@@ -1,8 +1,8 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Vegasco.WebApi.Cars;
using Vegasco.Server.Api.Cars;
namespace Vegasco.WebApi.Consumptions;
namespace Vegasco.Server.Api.Consumptions;
public class Consumption
{

View File

@@ -1,6 +1,6 @@
using StronglyTypedIds;
namespace Vegasco.WebApi.Consumptions;
namespace Vegasco.Server.Api.Consumptions;
[StronglyTypedId]

View File

@@ -1,10 +1,10 @@
using FluentValidation;
using FluentValidation.Results;
using Vegasco.WebApi.Cars;
using Vegasco.WebApi.Common;
using Vegasco.WebApi.Persistence;
using Vegasco.Server.Api.Cars;
using Vegasco.Server.Api.Common;
using Vegasco.Server.Api.Persistence;
namespace Vegasco.WebApi.Consumptions;
namespace Vegasco.Server.Api.Consumptions;
public static class CreateConsumption
{

View File

@@ -1,6 +1,6 @@
using Vegasco.WebApi.Persistence;
using Vegasco.Server.Api.Persistence;
namespace Vegasco.WebApi.Consumptions;
namespace Vegasco.Server.Api.Consumptions;
public static class DeleteConsumption
{

View File

@@ -1,6 +1,6 @@
using Vegasco.WebApi.Persistence;
using Vegasco.Server.Api.Persistence;
namespace Vegasco.WebApi.Consumptions;
namespace Vegasco.Server.Api.Consumptions;
public static class GetConsumption
{

View File

@@ -1,9 +1,9 @@
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Vegasco.WebApi.Persistence;
using Vegasco.Server.Api.Persistence;
namespace Vegasco.WebApi.Consumptions;
namespace Vegasco.Server.Api.Consumptions;
public static class GetConsumptions
{

View File

@@ -1,9 +1,9 @@
using FluentValidation;
using FluentValidation.Results;
using Vegasco.WebApi.Common;
using Vegasco.WebApi.Persistence;
using Vegasco.Server.Api.Common;
using Vegasco.Server.Api.Persistence;
namespace Vegasco.WebApi.Consumptions;
namespace Vegasco.Server.Api.Consumptions;
public static class UpdateConsumption
{

View File

@@ -1,31 +1,14 @@
using Asp.Versioning.Builder;
using Asp.Versioning.Conventions;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Vegasco.WebApi.Cars;
using Vegasco.WebApi.Common;
using Vegasco.WebApi.Consumptions;
using Vegasco.WebApi.Info;
using Vegasco.Server.Api.Cars;
using Vegasco.Server.Api.Common;
using Vegasco.Server.Api.Consumptions;
using Vegasco.Server.Api.Info;
namespace Vegasco.WebApi.Endpoints;
namespace Vegasco.Server.Api.Endpoints;
public static class EndpointExtensions
{
public static IServiceCollection AddEndpointsFromAssemblyContaining<T>(this IServiceCollection services)
{
var assembly = typeof(T).Assembly;
ServiceDescriptor[] serviceDescriptors = assembly
.DefinedTypes
.Where(type => type is { IsAbstract: false, IsInterface: false } &&
type.IsAssignableTo(typeof(IEndpoint)))
.Select(type => ServiceDescriptor.Transient(typeof(IEndpoint), type))
.ToArray();
services.TryAddEnumerable(serviceDescriptors);
return services;
}
public static void MapEndpoints(this IEndpointRouteBuilder builder)
{
ApiVersionSet apiVersionSet = builder.NewApiVersionSet()

View File

@@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Http.HttpResults;
namespace Vegasco.WebApi.Info;
namespace Vegasco.Server.Api.Info;
public class GetServerInfo
{

View File

@@ -1,10 +1,10 @@
using Microsoft.EntityFrameworkCore;
using Vegasco.WebApi.Cars;
using Vegasco.WebApi.Common;
using Vegasco.WebApi.Consumptions;
using Vegasco.WebApi.Users;
using Vegasco.Server.Api.Cars;
using Vegasco.Server.Api.Common;
using Vegasco.Server.Api.Consumptions;
using Vegasco.Server.Api.Users;
namespace Vegasco.WebApi.Persistence;
namespace Vegasco.Server.Api.Persistence;
public class ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : DbContext(options)
{
@@ -17,6 +17,6 @@ public class ApplicationDbContext(DbContextOptions<ApplicationDbContext> options
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(typeof(IWebApiMarker).Assembly);
modelBuilder.ApplyConfigurationsFromAssembly(typeof(IApiMarker).Assembly);
}
}

View File

@@ -1,19 +1,15 @@
using Microsoft.EntityFrameworkCore;
namespace Vegasco.WebApi.Persistence;
namespace Vegasco.Server.Api.Persistence;
public class ApplyMigrationsService : IHostedService
public class ApplyMigrationsService(ILogger<ApplyMigrationsService> logger, IServiceScopeFactory scopeFactory)
: IHostedService
{
private readonly IServiceScopeFactory _scopeFactory;
public ApplyMigrationsService(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
using IServiceScope scope = _scopeFactory.CreateScope();
logger.LogInformation("Starting migrations");
using IServiceScope scope = scopeFactory.CreateScope();
await using var dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
await dbContext.Database.MigrateAsync(cancellationToken);
}

View File

@@ -5,11 +5,12 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Vegasco.WebApi.Persistence;
using Vegasco.Server.Api.Persistence;
#nullable disable
namespace Vegasco.WebApi.Persistence.Migrations
namespace Vegasco.Server.Api.Persistence.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20240818105918_Initial")]
@@ -25,7 +26,7 @@ namespace Vegasco.WebApi.Persistence.Migrations
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Vegasco.WebApi.Cars.Car", b =>
modelBuilder.Entity("Vegasco.Server.Api.Cars.Car", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
@@ -46,7 +47,7 @@ namespace Vegasco.WebApi.Persistence.Migrations
b.ToTable("Cars");
});
modelBuilder.Entity("Vegasco.WebApi.Consumptions.Consumption", b =>
modelBuilder.Entity("Vegasco.Server.Api.Consumptions.Consumption", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
@@ -73,7 +74,7 @@ namespace Vegasco.WebApi.Persistence.Migrations
b.ToTable("Consumptions");
});
modelBuilder.Entity("Vegasco.WebApi.Users.User", b =>
modelBuilder.Entity("Vegasco.Server.Api.Users.User", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
@@ -83,9 +84,9 @@ namespace Vegasco.WebApi.Persistence.Migrations
b.ToTable("Users");
});
modelBuilder.Entity("Vegasco.WebApi.Cars.Car", b =>
modelBuilder.Entity("Vegasco.Server.Api.Cars.Car", b =>
{
b.HasOne("Vegasco.WebApi.Users.User", "User")
b.HasOne("Vegasco.Server.Api.Users.User", "User")
.WithMany("Cars")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@@ -94,9 +95,9 @@ namespace Vegasco.WebApi.Persistence.Migrations
b.Navigation("User");
});
modelBuilder.Entity("Vegasco.WebApi.Consumptions.Consumption", b =>
modelBuilder.Entity("Vegasco.Server.Api.Consumptions.Consumption", b =>
{
b.HasOne("Vegasco.WebApi.Cars.Car", "Car")
b.HasOne("Vegasco.Server.Api.Cars.Car", "Car")
.WithMany("Consumptions")
.HasForeignKey("CarId")
.OnDelete(DeleteBehavior.Cascade)
@@ -105,12 +106,12 @@ namespace Vegasco.WebApi.Persistence.Migrations
b.Navigation("Car");
});
modelBuilder.Entity("Vegasco.WebApi.Cars.Car", b =>
modelBuilder.Entity("Vegasco.Server.Api.Cars.Car", b =>
{
b.Navigation("Consumptions");
});
modelBuilder.Entity("Vegasco.WebApi.Users.User", b =>
modelBuilder.Entity("Vegasco.Server.Api.Users.User", b =>
{
b.Navigation("Cars");
});

View File

@@ -1,9 +1,8 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Vegasco.WebApi.Persistence.Migrations
namespace Vegasco.Server.Api.Persistence.Migrations
{
/// <inheritdoc />
public partial class Initial : Migration

View File

@@ -4,11 +4,12 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Vegasco.WebApi.Persistence;
using Vegasco.Server.Api.Persistence;
#nullable disable
namespace Vegasco.WebApi.Persistence.Migrations
namespace Vegasco.Server.Api.Persistence.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
@@ -22,7 +23,7 @@ namespace Vegasco.WebApi.Persistence.Migrations
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Vegasco.WebApi.Cars.Car", b =>
modelBuilder.Entity("Vegasco.Server.Api.Cars.Car", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
@@ -43,7 +44,7 @@ namespace Vegasco.WebApi.Persistence.Migrations
b.ToTable("Cars");
});
modelBuilder.Entity("Vegasco.WebApi.Consumptions.Consumption", b =>
modelBuilder.Entity("Vegasco.Server.Api.Consumptions.Consumption", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
@@ -70,7 +71,7 @@ namespace Vegasco.WebApi.Persistence.Migrations
b.ToTable("Consumptions");
});
modelBuilder.Entity("Vegasco.WebApi.Users.User", b =>
modelBuilder.Entity("Vegasco.Server.Api.Users.User", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
@@ -80,9 +81,9 @@ namespace Vegasco.WebApi.Persistence.Migrations
b.ToTable("Users");
});
modelBuilder.Entity("Vegasco.WebApi.Cars.Car", b =>
modelBuilder.Entity("Vegasco.Server.Api.Cars.Car", b =>
{
b.HasOne("Vegasco.WebApi.Users.User", "User")
b.HasOne("Vegasco.Server.Api.Users.User", "User")
.WithMany("Cars")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@@ -91,9 +92,9 @@ namespace Vegasco.WebApi.Persistence.Migrations
b.Navigation("User");
});
modelBuilder.Entity("Vegasco.WebApi.Consumptions.Consumption", b =>
modelBuilder.Entity("Vegasco.Server.Api.Consumptions.Consumption", b =>
{
b.HasOne("Vegasco.WebApi.Cars.Car", "Car")
b.HasOne("Vegasco.Server.Api.Cars.Car", "Car")
.WithMany("Consumptions")
.HasForeignKey("CarId")
.OnDelete(DeleteBehavior.Cascade)
@@ -102,12 +103,12 @@ namespace Vegasco.WebApi.Persistence.Migrations
b.Navigation("Car");
});
modelBuilder.Entity("Vegasco.WebApi.Cars.Car", b =>
modelBuilder.Entity("Vegasco.Server.Api.Cars.Car", b =>
{
b.Navigation("Consumptions");
});
modelBuilder.Entity("Vegasco.WebApi.Users.User", b =>
modelBuilder.Entity("Vegasco.Server.Api.Users.User", b =>
{
b.Navigation("Cars");
});

View File

@@ -1,4 +1,4 @@
using Vegasco.WebApi.Common;
using Vegasco.Server.Api.Common;
WebApplication.CreateBuilder(args)
.ConfigureServices()

View File

@@ -1,6 +1,6 @@
using Vegasco.WebApi.Cars;
using Vegasco.Server.Api.Cars;
namespace Vegasco.WebApi.Users;
namespace Vegasco.Server.Api.Users;
public class User
{

View File

@@ -1,7 +1,7 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Vegasco.WebApi.Users;
namespace Vegasco.Server.Api.Users;
public class UserTableConfiguration : IEntityTypeConfiguration<User>
{

View File

@@ -7,31 +7,30 @@
<UserSecretsId>4bf893d3-0c16-41ec-8b46-2768d841215d</UserSecretsId>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>..\..</DockerfileContext>
<RootNamespace>Vegasco.WebApi</RootNamespace>
<RootNamespace>Vegasco.Server.Api</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Asp.Versioning.Http" Version="8.1.0" />
<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.1.0" />
<PackageReference Include="Aspire.Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.0" />
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.11.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0">
<PackageReference Include="Aspire.Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.3.0" />
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="12.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.5" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.0" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.2" />
<PackageReference Include="OpenTelemetry" Version="1.10.0" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.10.0" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.10.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.10.1" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.10.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.2" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
<PackageReference Include="OpenTelemetry" Version="1.12.0" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.12.0" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.12.0" />
<PackageReference Include="StronglyTypedId" Version="1.0.0-beta08" PrivateAssets="all" ExcludeAssets="runtime" />
<PackageReference Include="StronglyTypedId.Templates" Version="1.0.0-beta08" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.2.0" />
</ItemGroup>
<ItemGroup>
@@ -40,7 +39,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Update="Nerdbank.GitVersioning" Version="3.7.112" />
<PackageReference Update="Nerdbank.GitVersioning" Version="3.7.115" />
</ItemGroup>
</Project>

View File

@@ -4,13 +4,13 @@ public static class Constants
{
public static class Projects
{
public const string WebApiName = "webapi";
public const string Api = "Vegasco_Server_Api";
}
public static class Database
{
public const string ServiceName = "postgres";
public const string Name = "vegasco";
public const string Name = "vegasco-database";
}
}

View File

@@ -6,4 +6,10 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Update="Nerdbank.GitVersioning">
<Version>3.7.115</Version>
</PackageReference>
</ItemGroup>
</Project>

View File

@@ -1,13 +1,13 @@
using Vegasco.Server.AppHost.Shared;
var builder = DistributedApplication.CreateBuilder(args);
IDistributedApplicationBuilder builder = DistributedApplication.CreateBuilder(args);
var postgres = builder.AddPostgres(Constants.Database.ServiceName)
IResourceBuilder<PostgresDatabaseResource> postgres = builder.AddPostgres(Constants.Database.ServiceName)
.WithDataVolume()
.AddDatabase(Constants.Database.Name);
builder
.AddProject<Projects.WebApi>(Constants.Projects.WebApiName)
.AddProject<Projects.Vegasco_Server_Api>(Constants.Projects.Api)
.WithReference(postgres)
.WaitFor(postgres);

View File

@@ -12,13 +12,16 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.0.0" />
<PackageReference Include="Aspire.Hosting.PostgreSQL" Version="9.0.0" />
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.3.0" />
<PackageReference Include="Aspire.Hosting.PostgreSQL" Version="9.3.0" />
<PackageReference Update="Nerdbank.GitVersioning">
<Version>3.7.115</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Vegasco.Server.AppHost.Shared\Vegasco.Server.AppHost.Shared.csproj" IsAspireProjectResource="false" />
<ProjectReference Include="..\WebApi\WebApi.csproj" />
<ProjectReference Include="..\Vegasco.Server.Api\Vegasco.Server.Api.csproj" />
</ItemGroup>
</Project>

View File

@@ -2,13 +2,13 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.ServiceDiscovery;
using OpenTelemetry;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
namespace Microsoft.Extensions.Hosting;
namespace Vegasco.Server.ServiceDefaults;
// Adds common .NET Aspire services: service discovery, resilience, health checks, and OpenTelemetry.
// This project should be referenced by each service project in your solution.
@@ -72,7 +72,7 @@ public static class Extensions
private static TBuilder AddOpenTelemetryExporters<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
{
var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);
bool useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);
if (useOtlpExporter)
{

View File

@@ -10,13 +10,16 @@
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" Version="9.0.0" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.9.0" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="9.5.0" />
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" Version="9.3.0" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.12.0" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.12.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.12.0" />
<PackageReference Update="Nerdbank.GitVersioning">
<Version>3.7.115</Version>
</PackageReference>
</ItemGroup>
</Project>

View File

@@ -1,3 +0,0 @@
namespace Vegasco.WebApi.Common;
public interface IWebApiMarker;

View File

@@ -1,6 +0,0 @@
namespace Vegasco.WebApi.Endpoints;
public interface IEndpoint
{
void MapEndpoint(IEndpointRouteBuilder builder);
}

View File

@@ -1,56 +0,0 @@
using Asp.Versioning.ApiExplorer;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace Vegasco.WebApi.Endpoints.OpenApi;
/// <summary>
/// Registers each api version as its own swagger document.
/// </summary>
/// <param name="versionDescriptionProvider"></param>
public class ConfigureSwaggerGenOptions(
IApiVersionDescriptionProvider versionDescriptionProvider)
: IConfigureNamedOptions<SwaggerGenOptions>
{
private readonly IApiVersionDescriptionProvider _versionDescriptionProvider = versionDescriptionProvider;
public void Configure(SwaggerGenOptions options)
{
foreach (ApiVersionDescription description in _versionDescriptionProvider.ApiVersionDescriptions)
{
OpenApiSecurityScheme securityScheme = new()
{
Name = "Bearer",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Scheme = "bearer",
Reference = new OpenApiReference
{
Id = IdentityConstants.BearerScheme,
Type = ReferenceType.SecurityScheme
}
};
options.AddSecurityDefinition(securityScheme.Reference.Id, securityScheme);
options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{ securityScheme, Array.Empty<string>() }
});
OpenApiInfo openApiInfo = new()
{
Title = "Vegasco API",
Version = description.ApiVersion.ToString()
};
options.SwaggerDoc(description.GroupName, openApiInfo);
}
}
public void Configure(string? name, SwaggerGenOptions options)
{
Configure(options);
}
}

View File

@@ -1,6 +0,0 @@
namespace Vegasco.WebApi.Endpoints.OpenApi;
public static class SwaggerDocConstants
{
}

View File

@@ -1,7 +1,7 @@
using Bogus;
using Vegasco.WebApi.Cars;
using Vegasco.Server.Api.Cars;
namespace WebApi.Tests.Integration;
namespace Vegasco.Server.Api.Tests.Integration;
internal class CarFaker
{

View File

@@ -3,10 +3,10 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using System.Net;
using System.Net.Http.Json;
using Vegasco.WebApi.Cars;
using Vegasco.WebApi.Persistence;
using Vegasco.Server.Api.Cars;
using Vegasco.Server.Api.Persistence;
namespace WebApi.Tests.Integration.Cars;
namespace Vegasco.Server.Api.Tests.Integration.Cars;
[Collection(SharedTestCollection.Name)]
public class CreateCarTests : IAsyncLifetime
@@ -28,10 +28,10 @@ public class CreateCarTests : IAsyncLifetime
public async Task CreateCar_ShouldCreateCar_WhenRequestIsValid()
{
// Arrange
var createCarRequest = _carFaker.CreateCarRequest();
CreateCar.Request createCarRequest = _carFaker.CreateCarRequest();
// Act
var response = await _factory.HttpClient.PostAsJsonAsync("v1/cars", createCarRequest);
HttpResponseMessage response = await _factory.HttpClient.PostAsJsonAsync("v1/cars", createCarRequest);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.Created);
@@ -49,7 +49,7 @@ public class CreateCarTests : IAsyncLifetime
var createCarRequest = new CreateCar.Request("");
// Act
var response = await _factory.HttpClient.PostAsJsonAsync("v1/cars", createCarRequest);
HttpResponseMessage response = await _factory.HttpClient.PostAsJsonAsync("v1/cars", createCarRequest);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);

View File

@@ -2,10 +2,10 @@
using Microsoft.Extensions.DependencyInjection;
using System.Net;
using System.Net.Http.Json;
using Vegasco.WebApi.Cars;
using Vegasco.WebApi.Persistence;
using Vegasco.Server.Api.Cars;
using Vegasco.Server.Api.Persistence;
namespace WebApi.Tests.Integration.Cars;
namespace Vegasco.Server.Api.Tests.Integration.Cars;
[Collection(SharedTestCollection.Name)]
public class DeleteCarTests : IAsyncLifetime
@@ -30,7 +30,7 @@ public class DeleteCarTests : IAsyncLifetime
var randomCarId = Guid.NewGuid();
// Act
var response = await _factory.HttpClient.DeleteAsync($"v1/cars/{randomCarId}");
HttpResponseMessage response = await _factory.HttpClient.DeleteAsync($"v1/cars/{randomCarId}");
// Assert
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
@@ -40,13 +40,13 @@ public class DeleteCarTests : IAsyncLifetime
public async Task DeleteCar_ShouldDeleteCar_WhenCarExists()
{
// Arrange
var createCarRequest = _carFaker.CreateCarRequest();
var createCarResponse = await _factory.HttpClient.PostAsJsonAsync("v1/cars", createCarRequest);
CreateCar.Request createCarRequest = _carFaker.CreateCarRequest();
HttpResponseMessage createCarResponse = await _factory.HttpClient.PostAsJsonAsync("v1/cars", createCarRequest);
createCarResponse.EnsureSuccessStatusCode();
var createdCar = await createCarResponse.Content.ReadFromJsonAsync<CreateCar.Response>();
// Act
var response = await _factory.HttpClient.DeleteAsync($"v1/cars/{createdCar!.Id}");
HttpResponseMessage response = await _factory.HttpClient.DeleteAsync($"v1/cars/{createdCar!.Id}");
// Assert
response.StatusCode.Should().Be(HttpStatusCode.NoContent);

View File

@@ -1,9 +1,9 @@
using FluentAssertions;
using System.Net;
using System.Net.Http.Json;
using Vegasco.WebApi.Cars;
using Vegasco.Server.Api.Cars;
namespace WebApi.Tests.Integration.Cars;
namespace Vegasco.Server.Api.Tests.Integration.Cars;
[Collection(SharedTestCollection.Name)]
public class GetCarTests : IAsyncLifetime
@@ -24,7 +24,7 @@ public class GetCarTests : IAsyncLifetime
var randomCarId = Guid.NewGuid();
// Act
var response = await _factory.HttpClient.GetAsync($"v1/cars/{randomCarId}");
HttpResponseMessage response = await _factory.HttpClient.GetAsync($"v1/cars/{randomCarId}");
// Assert
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
@@ -34,13 +34,13 @@ public class GetCarTests : IAsyncLifetime
public async Task GetCar_ShouldReturnCar_WhenCarExists()
{
// Arrange
var createCarRequest = _carFaker.CreateCarRequest();
var createCarResponse = await _factory.HttpClient.PostAsJsonAsync("v1/cars", createCarRequest);
CreateCar.Request createCarRequest = _carFaker.CreateCarRequest();
HttpResponseMessage createCarResponse = await _factory.HttpClient.PostAsJsonAsync("v1/cars", createCarRequest);
createCarResponse.EnsureSuccessStatusCode();
var createdCar = await createCarResponse.Content.ReadFromJsonAsync<CreateCar.Response>();
// Act
var response = await _factory.HttpClient.GetAsync($"v1/cars/{createdCar!.Id}");
HttpResponseMessage response = await _factory.HttpClient.GetAsync($"v1/cars/{createdCar!.Id}");
// Assert
response.StatusCode.Should().Be(HttpStatusCode.OK);

View File

@@ -1,9 +1,9 @@
using FluentAssertions;
using System.Net;
using System.Net.Http.Json;
using Vegasco.WebApi.Cars;
using Vegasco.Server.Api.Cars;
namespace WebApi.Tests.Integration.Cars;
namespace Vegasco.Server.Api.Tests.Integration.Cars;
[Collection(SharedTestCollection.Name)]
public class GetCarsTests : IAsyncLifetime

View File

@@ -3,10 +3,10 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using System.Net;
using System.Net.Http.Json;
using Vegasco.WebApi.Cars;
using Vegasco.WebApi.Persistence;
using Vegasco.Server.Api.Cars;
using Vegasco.Server.Api.Persistence;
namespace WebApi.Tests.Integration.Cars;
namespace Vegasco.Server.Api.Tests.Integration.Cars;
[Collection(SharedTestCollection.Name)]
public class UpdateCarTests : IAsyncLifetime
@@ -28,15 +28,15 @@ public class UpdateCarTests : IAsyncLifetime
public async Task UpdateCar_ShouldUpdateCar_WhenCarExistsAndRequestIsValid()
{
// Arrange
var createCarRequest = _carFaker.CreateCarRequest();
var createCarResponse = await _factory.HttpClient.PostAsJsonAsync("v1/cars", createCarRequest);
CreateCar.Request createCarRequest = _carFaker.CreateCarRequest();
HttpResponseMessage createCarResponse = await _factory.HttpClient.PostAsJsonAsync("v1/cars", createCarRequest);
createCarResponse.EnsureSuccessStatusCode();
var createdCar = await createCarResponse.Content.ReadFromJsonAsync<CreateCar.Response>();
var updateCarRequest = _carFaker.UpdateCarRequest();
UpdateCar.Request updateCarRequest = _carFaker.UpdateCarRequest();
// Act
var response = await _factory.HttpClient.PutAsJsonAsync($"v1/cars/{createdCar!.Id}", updateCarRequest);
HttpResponseMessage response = await _factory.HttpClient.PutAsJsonAsync($"v1/cars/{createdCar!.Id}", updateCarRequest);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.OK);
@@ -54,15 +54,15 @@ public class UpdateCarTests : IAsyncLifetime
public async Task UpdateCar_ShouldReturnValidationProblems_WhenRequestIsNotValid()
{
// Arrange
var createCarRequest = _carFaker.CreateCarRequest();
var createCarResponse = await _factory.HttpClient.PostAsJsonAsync("v1/cars", createCarRequest);
CreateCar.Request createCarRequest = _carFaker.CreateCarRequest();
HttpResponseMessage createCarResponse = await _factory.HttpClient.PostAsJsonAsync("v1/cars", createCarRequest);
createCarResponse.EnsureSuccessStatusCode();
var createdCar = await createCarResponse.Content.ReadFromJsonAsync<CreateCar.Response>();
var updateCarRequest = new UpdateCar.Request("");
// Act
var response = await _factory.HttpClient.PutAsJsonAsync($"v1/cars/{createdCar!.Id}", updateCarRequest);
HttpResponseMessage response = await _factory.HttpClient.PutAsJsonAsync($"v1/cars/{createdCar!.Id}", updateCarRequest);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
@@ -79,11 +79,11 @@ public class UpdateCarTests : IAsyncLifetime
public async Task UpdateCar_ShouldReturnNotFound_WhenNoCarWithIdExists()
{
// Arrange
var updateCarRequest = _carFaker.UpdateCarRequest();
UpdateCar.Request updateCarRequest = _carFaker.UpdateCarRequest();
var randomCarId = Guid.NewGuid();
// Act
var response = await _factory.HttpClient.PutAsJsonAsync($"v1/cars/{randomCarId}", updateCarRequest);
HttpResponseMessage response = await _factory.HttpClient.PutAsJsonAsync($"v1/cars/{randomCarId}", updateCarRequest);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.NotFound);

View File

@@ -1,7 +1,7 @@
using Bogus;
using Vegasco.WebApi.Consumptions;
using Vegasco.Server.Api.Consumptions;
namespace WebApi.Tests.Integration;
namespace Vegasco.Server.Api.Tests.Integration;
internal class ConsumptionFaker
{

View File

@@ -3,11 +3,11 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using System.Net;
using System.Net.Http.Json;
using Vegasco.WebApi.Cars;
using Vegasco.WebApi.Consumptions;
using Vegasco.WebApi.Persistence;
using Vegasco.Server.Api.Cars;
using Vegasco.Server.Api.Consumptions;
using Vegasco.Server.Api.Persistence;
namespace WebApi.Tests.Integration.Consumptions;
namespace Vegasco.Server.Api.Tests.Integration.Consumptions;
[Collection(SharedTestCollection.Name)]
public class CreateConsumptionTests : IAsyncLifetime

View File

@@ -2,11 +2,11 @@
using Microsoft.Extensions.DependencyInjection;
using System.Net;
using System.Net.Http.Json;
using Vegasco.WebApi.Cars;
using Vegasco.WebApi.Consumptions;
using Vegasco.WebApi.Persistence;
using Vegasco.Server.Api.Cars;
using Vegasco.Server.Api.Consumptions;
using Vegasco.Server.Api.Persistence;
namespace WebApi.Tests.Integration.Consumptions;
namespace Vegasco.Server.Api.Tests.Integration.Consumptions;
[Collection(SharedTestCollection.Name)]
public class DeleteConsumptionTests : IAsyncLifetime

View File

@@ -2,11 +2,11 @@
using Microsoft.Extensions.DependencyInjection;
using System.Net;
using System.Net.Http.Json;
using Vegasco.WebApi.Cars;
using Vegasco.WebApi.Consumptions;
using Vegasco.WebApi.Persistence;
using Vegasco.Server.Api.Cars;
using Vegasco.Server.Api.Consumptions;
using Vegasco.Server.Api.Persistence;
namespace WebApi.Tests.Integration.Consumptions;
namespace Vegasco.Server.Api.Tests.Integration.Consumptions;
[Collection(SharedTestCollection.Name)]
public class GetConsumptionTests : IAsyncLifetime
@@ -35,7 +35,7 @@ public class GetConsumptionTests : IAsyncLifetime
using HttpResponseMessage response = await _factory.HttpClient.GetAsync($"v1/consumptions/{createdConsumption.Id}");
// Assert
var content = await response.Content.ReadAsStringAsync();
string content = await response.Content.ReadAsStringAsync();
response.StatusCode.Should().Be(HttpStatusCode.OK);
var consumption = await response.Content.ReadFromJsonAsync<GetConsumption.Response>();
consumption.Should().BeEquivalentTo(createdConsumption);

View File

@@ -2,11 +2,11 @@
using Microsoft.Extensions.DependencyInjection;
using System.Net;
using System.Net.Http.Json;
using Vegasco.WebApi.Cars;
using Vegasco.WebApi.Consumptions;
using Vegasco.WebApi.Persistence;
using Vegasco.Server.Api.Cars;
using Vegasco.Server.Api.Consumptions;
using Vegasco.Server.Api.Persistence;
namespace WebApi.Tests.Integration.Consumptions;
namespace Vegasco.Server.Api.Tests.Integration.Consumptions;
[Collection(SharedTestCollection.Name)]
public class GetConsumptionsTests : IAsyncLifetime

View File

@@ -3,11 +3,11 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using System.Net;
using System.Net.Http.Json;
using Vegasco.WebApi.Cars;
using Vegasco.WebApi.Consumptions;
using Vegasco.WebApi.Persistence;
using Vegasco.Server.Api.Cars;
using Vegasco.Server.Api.Consumptions;
using Vegasco.Server.Api.Persistence;
namespace WebApi.Tests.Integration.Consumptions;
namespace Vegasco.Server.Api.Tests.Integration.Consumptions;
[Collection(SharedTestCollection.Name)]
public class UpdateConsumptionTests : IAsyncLifetime
@@ -37,7 +37,7 @@ public class UpdateConsumptionTests : IAsyncLifetime
using HttpResponseMessage response = await _factory.HttpClient.PutAsJsonAsync($"v1/consumptions/{createdConsumption.Id}", updateConsumptionRequest);
// Assert
var content = await response.Content.ReadAsStringAsync();
string content = await response.Content.ReadAsStringAsync();
response.StatusCode.Should().Be(HttpStatusCode.OK);
var updatedConsumption = await response.Content.ReadFromJsonAsync<UpdateConsumption.Response>();
updatedConsumption.Should().BeEquivalentTo(updateConsumptionRequest, o => o.ExcludingMissingMembers());
@@ -65,7 +65,7 @@ public class UpdateConsumptionTests : IAsyncLifetime
using HttpResponseMessage response = await _factory.HttpClient.PutAsJsonAsync($"v1/consumptions/{randomGuid}", updateConsumptionRequest);
// Assert
var content = await response.Content.ReadAsStringAsync();
string content = await response.Content.ReadAsStringAsync();
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
var validationProblemDetails = await response.Content.ReadFromJsonAsync<ValidationProblemDetails>();
validationProblemDetails!.Errors.Keys.Should().Contain(x =>
@@ -86,7 +86,7 @@ public class UpdateConsumptionTests : IAsyncLifetime
using HttpResponseMessage response = await _factory.HttpClient.PutAsJsonAsync($"v1/consumptions/{randomGuid}", updateConsumptionRequest);
// Assert
var content = await response.Content.ReadAsStringAsync();
string content = await response.Content.ReadAsStringAsync();
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
_dbContext.Consumptions.Should().NotContainEquivalentOf(updateConsumptionRequest);

View File

@@ -1,6 +1,7 @@
using FluentAssertions;
namespace WebApi.Tests.Integration;
namespace Vegasco.Server.Api.Tests.Integration;
internal static class FluentAssertionConfiguration
{
private const int DateTimeComparisonPrecision = 100;

View File

@@ -1,9 +1,9 @@
using System.Net.Http.Json;
using FluentAssertions;
using FluentAssertions.Extensions;
using Vegasco.WebApi.Info;
using Vegasco.Server.Api.Info;
namespace WebApi.Tests.Integration.Info;
namespace Vegasco.Server.Api.Tests.Integration.Info;
[Collection(SharedTestCollection.Name)]
public class GetServerInfoTests

View File

@@ -2,7 +2,7 @@
using Respawn;
using System.Data.Common;
namespace WebApi.Tests.Integration;
namespace Vegasco.Server.Api.Tests.Integration;
internal sealed class PostgresRespawner : IDisposable
{
private readonly DbConnection _connection;

View File

@@ -1,4 +1,4 @@
namespace WebApi.Tests.Integration;
namespace Vegasco.Server.Api.Tests.Integration;
[CollectionDefinition(Name)]
public class SharedTestCollection : ICollectionFixture<WebAppFactory>

View File

@@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Authorization.Policy;
using Microsoft.AspNetCore.Http;
using System.Security.Claims;
namespace WebApi.Tests.Integration;
namespace Vegasco.Server.Api.Tests.Integration;
public sealed class TestUserAlwaysAuthorizedPolicyEvaluator : IPolicyEvaluator
{
@@ -26,7 +26,7 @@ public sealed class TestUserAlwaysAuthorizedPolicyEvaluator : IPolicyEvaluator
ClaimsIdentity identity = new(claims, JwtBearerDefaults.AuthenticationScheme);
ClaimsPrincipal principal = new(identity);
AuthenticationTicket ticket = new(principal, JwtBearerDefaults.AuthenticationScheme);
var result = AuthenticateResult.Success(ticket);
AuthenticateResult result = AuthenticateResult.Success(ticket);
return Task.FromResult(result); ;
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
@@ -10,21 +10,21 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" Version="1.13.1" />
<PackageReference Include="Bogus" Version="35.6.1" />
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PackageReference Include="Azure.Identity" Version="1.14.0" />
<PackageReference Include="Bogus" Version="35.6.3" />
<PackageReference Include="coverlet.collector" Version="6.0.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="FluentAssertions" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="FluentAssertions" Version="[7.2.0,8.0.0)" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.5" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="Respawn" Version="6.2.1" />
<PackageReference Include="System.Formats.Asn1" Version="9.0.0" />
<PackageReference Include="Testcontainers.PostgreSql" Version="4.1.0" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.0">
<PackageReference Include="System.Formats.Asn1" Version="9.0.5" />
<PackageReference Include="Testcontainers.PostgreSql" Version="4.5.0" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
@@ -32,7 +32,7 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Vegasco.Server.AppHost.Shared\Vegasco.Server.AppHost.Shared.csproj" />
<ProjectReference Include="..\..\src\WebApi\WebApi.csproj" />
<ProjectReference Include="..\..\src\Vegasco.Server.Api\Vegasco.Server.Api.csproj" />
</ItemGroup>
<ItemGroup>
@@ -40,7 +40,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Update="Nerdbank.GitVersioning" Version="3.7.112" />
<PackageReference Update="Nerdbank.GitVersioning" Version="3.7.115" />
</ItemGroup>
</Project>

View File

@@ -7,11 +7,11 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Testcontainers.PostgreSql;
using Vegasco.WebApi.Common;
using Vegasco.Server.Api.Common;
namespace WebApi.Tests.Integration;
namespace Vegasco.Server.Api.Tests.Integration;
public sealed class WebAppFactory : WebApplicationFactory<IWebApiMarker>, IAsyncLifetime
public sealed class WebAppFactory : WebApplicationFactory<IApiMarker>, IAsyncLifetime
{
private readonly PostgreSqlContainer _database = new PostgreSqlBuilder()
.WithImage(DockerImage)
@@ -38,7 +38,7 @@ public sealed class WebAppFactory : WebApplicationFactory<IWebApiMarker>, IAsync
{
IEnumerable<KeyValuePair<string, string?>> customConfig =
[
new KeyValuePair<string, string?>($"ConnectionStrings:{Vegasco.Server.AppHost.Shared.Constants.Database.Name}", _database.GetConnectionString()),
new KeyValuePair<string, string?>($"ConnectionStrings:{AppHost.Shared.Constants.Database.Name}", _database.GetConnectionString()),
new KeyValuePair<string, string?>("JWT:ValidAudience", "https://localhost"),
new KeyValuePair<string, string?>("JWT:MetadataUrl", "https://localhost"),
new KeyValuePair<string, string?>("JWT:NameClaimType", null),

View File

@@ -3,9 +3,9 @@ using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using NSubstitute;
using System.Security.Claims;
using Vegasco.WebApi.Authentication;
using Vegasco.Server.Api.Authentication;
namespace WebApi.Tests.Unit.Authentication;
namespace Vegasco.Server.Api.Tests.Unit.Authentication;
public sealed class UserAccessorTests
{
private readonly UserAccessor _sut;
@@ -50,7 +50,7 @@ public sealed class UserAccessorTests
// Arrange
// Act
var result = _sut.GetUsername();
string result = _sut.GetUsername();
// Assert
result.Should().Be(_defaultUsername);
@@ -67,7 +67,7 @@ public sealed class UserAccessorTests
]));
// Act
var result = _sut.GetUsername();
string result = _sut.GetUsername();
// Assert
result.Should().Be(_defaultUsername);
@@ -81,7 +81,7 @@ public sealed class UserAccessorTests
_options.ClearReceivedCalls();
// Act
var result = _sut.GetUsername();
string result = _sut.GetUsername();
// Assert
result.Should().Be(_defaultUsername);
@@ -95,7 +95,7 @@ public sealed class UserAccessorTests
_httpContextAccessor.HttpContext = null;
// Act
var action = () => _sut.GetUsername();
Func<string> action = () => _sut.GetUsername();
// Assert
action.Should().ThrowExactly<InvalidOperationException>()
@@ -109,7 +109,7 @@ public sealed class UserAccessorTests
_httpContextAccessor.HttpContext!.User = new ClaimsPrincipal();
// Act
var action = () => _sut.GetUsername();
Func<string> action = () => _sut.GetUsername();
// Assert
action.Should().ThrowExactly<InvalidOperationException>()
@@ -126,7 +126,7 @@ public sealed class UserAccessorTests
// Arrange
// Act
var result = _sut.GetUserId();
string result = _sut.GetUserId();
// Assert
result.Should().Be(_defaultId);
@@ -140,7 +140,7 @@ public sealed class UserAccessorTests
_options.ClearReceivedCalls();
// Act
var result = _sut.GetUserId();
string result = _sut.GetUserId();
// Assert
result.Should().Be(_defaultId);
@@ -154,7 +154,7 @@ public sealed class UserAccessorTests
_httpContextAccessor.HttpContext = null;
// Act
var action = () => _sut.GetUserId();
Func<string> action = () => _sut.GetUserId();
// Assert
action.Should().ThrowExactly<InvalidOperationException>()
@@ -168,7 +168,7 @@ public sealed class UserAccessorTests
_httpContextAccessor.HttpContext!.User = new ClaimsPrincipal();
// Act
var action = () => _sut.GetUserId();
Func<string> action = () => _sut.GetUserId();
// Assert
action.Should().ThrowExactly<InvalidOperationException>()

View File

@@ -1,7 +1,8 @@
using FluentAssertions;
using Vegasco.WebApi.Cars;
using FluentValidation.Results;
using Vegasco.Server.Api.Cars;
namespace WebApi.Tests.Unit.Cars;
namespace Vegasco.Server.Api.Tests.Unit.Cars;
public sealed class CreateCarRequestValidatorTests
{
@@ -15,7 +16,7 @@ public sealed class CreateCarRequestValidatorTests
// Arrange
// Act
var result = await _sut.ValidateAsync(_validRequest);
ValidationResult? result = await _sut.ValidateAsync(_validRequest);
// Assert
result.IsValid.Should().BeTrue();
@@ -27,10 +28,10 @@ public sealed class CreateCarRequestValidatorTests
public async Task ValidateAsync_ShouldBeValid_WhenNameIsJustWithinTheLimits(int nameLength)
{
// Arrange
var request = _validRequest with { Name = new string('s', nameLength) };
CreateCar.Request request = _validRequest with { Name = new string('s', nameLength) };
// Act
var result = await _sut.ValidateAsync(request);
ValidationResult? result = await _sut.ValidateAsync(request);
// Assert
result.IsValid.Should().BeTrue();
@@ -40,10 +41,10 @@ public sealed class CreateCarRequestValidatorTests
public async Task ValidateAsync_ShouldNotBeValid_WhenNameIsEmpty()
{
// Arrange
var request = _validRequest with { Name = "" };
CreateCar.Request request = _validRequest with { Name = "" };
// Act
var result = await _sut.ValidateAsync(request);
ValidationResult? result = await _sut.ValidateAsync(request);
// Assert
result.IsValid.Should().BeFalse();
@@ -57,10 +58,10 @@ public sealed class CreateCarRequestValidatorTests
{
// Arrange
const int nameMaxLength = 50;
var request = _validRequest with { Name = new string('s', nameMaxLength + 1) };
CreateCar.Request request = _validRequest with { Name = new string('s', nameMaxLength + 1) };
// Act
var result = await _sut.ValidateAsync(request);
ValidationResult? result = await _sut.ValidateAsync(request);
// Assert
result.IsValid.Should().BeFalse();

View File

@@ -1,7 +1,8 @@
using FluentAssertions;
using Vegasco.WebApi.Cars;
using FluentValidation.Results;
using Vegasco.Server.Api.Cars;
namespace WebApi.Tests.Unit.Cars;
namespace Vegasco.Server.Api.Tests.Unit.Cars;
public sealed class UpdateCarRequestValidatorTests
{
@@ -15,7 +16,7 @@ public sealed class UpdateCarRequestValidatorTests
// Arrange
// Act
var result = await _sut.ValidateAsync(_validRequest);
ValidationResult? result = await _sut.ValidateAsync(_validRequest);
// Assert
result.IsValid.Should().BeTrue();
@@ -27,10 +28,10 @@ public sealed class UpdateCarRequestValidatorTests
public async Task ValidateAsync_ShouldBeValid_WhenNameIsJustWithinTheLimits(int nameLength)
{
// Arrange
var request = _validRequest with { Name = new string('s', nameLength) };
UpdateCar.Request request = _validRequest with { Name = new string('s', nameLength) };
// Act
var result = await _sut.ValidateAsync(request);
ValidationResult? result = await _sut.ValidateAsync(request);
// Assert
result.IsValid.Should().BeTrue();
@@ -40,10 +41,10 @@ public sealed class UpdateCarRequestValidatorTests
public async Task ValidateAsync_ShouldNotBeValid_WhenNameIsEmpty()
{
// Arrange
var request = _validRequest with { Name = "" };
UpdateCar.Request request = _validRequest with { Name = "" };
// Act
var result = await _sut.ValidateAsync(request);
ValidationResult? result = await _sut.ValidateAsync(request);
// Assert
result.IsValid.Should().BeFalse();
@@ -57,10 +58,10 @@ public sealed class UpdateCarRequestValidatorTests
{
// Arrange
const int nameMaxLength = 50;
var request = _validRequest with { Name = new string('s', nameMaxLength + 1) };
UpdateCar.Request request = _validRequest with { Name = new string('s', nameMaxLength + 1) };
// Act
var result = await _sut.ValidateAsync(request);
ValidationResult? result = await _sut.ValidateAsync(request);
// Assert
result.IsValid.Should().BeFalse();

View File

@@ -1,9 +1,9 @@
using FluentAssertions;
using FluentValidation.Results;
using NSubstitute;
using Vegasco.WebApi.Consumptions;
using Vegasco.Server.Api.Consumptions;
namespace WebApi.Tests.Unit.Consumptions;
namespace Vegasco.Server.Api.Tests.Unit.Consumptions;
public class CreateConsumptionRequestValidatorTests
{
private readonly CreateConsumption.Validator _sut;

View File

@@ -1,9 +1,9 @@
using FluentAssertions;
using FluentValidation.Results;
using NSubstitute;
using Vegasco.WebApi.Consumptions;
using Vegasco.Server.Api.Consumptions;
namespace WebApi.Tests.Unit.Consumptions;
namespace Vegasco.Server.Api.Tests.Unit.Consumptions;
public class UpdateConsumptionRequestValidatorTests
{

View File

@@ -10,23 +10,23 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PackageReference Include="coverlet.collector" Version="6.0.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="FluentAssertions" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="FluentAssertions" Version="8.3.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.5" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="NSubstitute" Version="5.3.0" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.0">
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WebApi\WebApi.csproj" />
<ProjectReference Include="..\..\src\Vegasco.Server.Api\Vegasco.Server.Api.csproj" />
</ItemGroup>
<ItemGroup>
@@ -34,7 +34,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Update="Nerdbank.GitVersioning" Version="3.7.112" />
<PackageReference Update="Nerdbank.GitVersioning" Version="3.7.115" />
</ItemGroup>
</Project>

View File

@@ -1,50 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.13.35617.110
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{089100B1-113F-4E66-888A-E83F3999EAFD}"
ProjectSection(SolutionItems) = preProject
.drone.yml = .drone.yml
Dockerfile = Dockerfile
README.md = README.md
version.json = version.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApi", "src\WebApi\WebApi.csproj", "{1B0A04C3-E6BC-0FB7-7994-7C99BDAB1788}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0AB3BF05-4346-4AA6-1389-037BE0695223}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApi.Tests.Integration", "tests\WebApi.Tests.Integration\WebApi.Tests.Integration.csproj", "{72BF8CBC-E916-1472-A1E2-8F5DCF1A95C6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApi.Tests.Unit", "tests\WebApi.Tests.Unit\WebApi.Tests.Unit.csproj", "{2DD4D427-6FA5-EC56-76FC-9D71C4631E00}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1B0A04C3-E6BC-0FB7-7994-7C99BDAB1788}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1B0A04C3-E6BC-0FB7-7994-7C99BDAB1788}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1B0A04C3-E6BC-0FB7-7994-7C99BDAB1788}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1B0A04C3-E6BC-0FB7-7994-7C99BDAB1788}.Release|Any CPU.Build.0 = Release|Any CPU
{72BF8CBC-E916-1472-A1E2-8F5DCF1A95C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{72BF8CBC-E916-1472-A1E2-8F5DCF1A95C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{72BF8CBC-E916-1472-A1E2-8F5DCF1A95C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{72BF8CBC-E916-1472-A1E2-8F5DCF1A95C6}.Release|Any CPU.Build.0 = Release|Any CPU
{2DD4D427-6FA5-EC56-76FC-9D71C4631E00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2DD4D427-6FA5-EC56-76FC-9D71C4631E00}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2DD4D427-6FA5-EC56-76FC-9D71C4631E00}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2DD4D427-6FA5-EC56-76FC-9D71C4631E00}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{1B0A04C3-E6BC-0FB7-7994-7C99BDAB1788} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{72BF8CBC-E916-1472-A1E2-8F5DCF1A95C6} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
{2DD4D427-6FA5-EC56-76FC-9D71C4631E00} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
EndGlobalSection
EndGlobal

View File

@@ -6,13 +6,13 @@
<File Path="version.json" />
</Folder>
<Folder Name="/src/">
<Project Path="src/Vegasco.Server.AppHost.Shared/Vegasco.Server.AppHost.Shared.csproj" Id="218fcbfa-9ff7-45a2-a9b9-2351a304223f" />
<Project Path="src/Vegasco.Server.AppHost/Vegasco.Server.AppHost.csproj" Id="ae9c4f8c-43c9-4fad-bcc6-23b952458935" />
<Project Path="src/Vegasco.Server.AppHost.Shared/Vegasco.Server.AppHost.Shared.csproj" />
<Project Path="src/Vegasco.Server.AppHost/Vegasco.Server.AppHost.csproj" />
<Project Path="src/Vegasco.Server.ServiceDefaults/Vegasco.Server.ServiceDefaults.csproj" />
<Project Path="src/WebApi/WebApi.csproj" />
<Project Path="src/Vegasco.Server.Api/Vegasco.Server.Api.csproj" />
</Folder>
<Folder Name="/tests/">
<Project Path="tests/WebApi.Tests.Integration/WebApi.Tests.Integration.csproj" />
<Project Path="tests/WebApi.Tests.Unit/WebApi.Tests.Unit.csproj" />
<Project Path="tests/Vegasco.Server.Api.Tests.Integration/Vegasco.Server.Api.Tests.Integration.csproj" />
<Project Path="tests/Vegasco.Server.Api.Tests.Unit/Vegasco.Server.Api.Tests.Unit.csproj" />
</Folder>
</Solution>
</Solution>