Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add config to create .NET template #25

Merged
merged 4 commits into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions .template-config/template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
{
"$schema": "http://json.schemastore.org/template",
"author": "Vanderlan Gomes",
"name": "Orion API Project Template",
"description": "A simple project template for creating a .NET API (v7.0)",
"classifications": [ "WebApi" ],
"identity": "Orion.Api.Project.Template",
"shortName": "orion-api",
"tags": {
"language": "C#",
"type": "project"
},
"sourceName": "Orion",
"symbols": {

"firstEntity": {
"type": "parameter",
"datatype": "text",
"replaces": "Customer",
"isRequired": true
},

"pascalCasedFirstEntity": {
"type": "derived",
"valueSource": "firstEntity",
"replaces": "Customer",
"valueTransform": "pascalCase"
},

"camelCasedFirstEntity": {
"type": "derived",
"valueSource": "pascalCasedFirstEntity",
"replaces": "customer",
"valueTransform": "firtstLowerCase"
},

"joinedRename": {
"type": "generated",
"generator": "join",
"fileRename": "Customer",
"parameters": {
"symbols": [
{
"type": "ref",
"value": "firstEntity"
}
],
"separator": "/",
"removeEmptyValues": true
}
}
},

"forms": {
"titleCase": {
"identifier": "titleCase"
},
"invalidChars": {
"identifier": "replace",
"pattern": "([\\-_\\.\\ ])",
"replacement": ""
},
"pascalCase": {
"identifier": "chain",
"steps": [
"titleCase",
"invalidChars"
]
},
"kebabCase": {
"identifier": "kebabCase"
},
"firtstLowerCase": {
"identifier": "firstLowerCaseInvariant"
}
}
}
6 changes: 6 additions & 0 deletions Orion.sln
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Orion.Ioc", "src\Orion.Ioc\
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Orion.Domain", "src\Orion.Domain\Orion.Domain.csproj", "{9F14F904-BBC6-4616-BB80-76E485EAEC14}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "template-config", "template-config", "{309303F2-F07E-4578-8079-C7D2CE2AE329}"
ProjectSection(SolutionItems) = preProject
.template-config\template.json = .template-config\template.json
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -78,6 +83,7 @@ Global
{8C70C31A-892F-4C8F-B7B0-A710C97A55FA} = {2D8CC498-597C-4415-95BF-48E623039F90}
{BF0248B6-C870-4419-862D-1DCAD4561946} = {434E301F-C36C-4203-B334-D3948130B660}
{9F14F904-BBC6-4616-BB80-76E485EAEC14} = {67A0BEBC-35B1-436C-9F05-AC8F60AF1688}
{309303F2-F07E-4578-8079-C7D2CE2AE329} = {2D8CC498-597C-4415-95BF-48E623039F90}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E5867FB8-481E-460E-8D41-10F9F592DB25}
Expand Down
19 changes: 13 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ The main objective is to start projects with a clean and simple architecture, wi
**Configurations and Patterns**

1. Business Exceptions;
2. Exception handler;
2. Exception Middleware;
3. Repository Pattern;
4. Faker Objects;
5. Unit Of Work;
Expand All @@ -53,13 +53,20 @@ The main objective is to start projects with a clean and simple architecture, wi
3. Continuous Delivery;
4. DockerHub Integration.

**Todo**

1. API Test.
# **Create your Project based on the Orion Api Template**

**Run database migrations**

dotnet ef database update -p Orion.Data -s Orion.Api --verbose
**Install template and create your project**

dotnet new install .

dotnet new orion-api -o MyNewProject --firstEntity "EntityName"

**Migrations**

# in the src/ folder

dotnet ef migrations add MigrationName -p Orion.Data -s Orion.Api
dotnet ef database update -p Orion.Data -s Orion.Api --verbose

Author: https://github.com/vanderlan
2 changes: 2 additions & 0 deletions src/Orion.Api/Bootstrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,7 @@ public static void ConfigureServices(this IServiceCollection services, IConfigur
services.AddDomainServices();

services.ConfigureAutoMapper();

services.AddHttpContextAccessor();
}
}
29 changes: 21 additions & 8 deletions src/Orion.Api/Configuration/AuthenticationConfiguration.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Orion.Api.AutoMapper.Output;
using Orion.Api.Jwt;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
Expand All @@ -27,7 +26,9 @@ public static void ConfigureAuthentication(this IServiceCollection services, ICo
{
ValidateAudience = true,
ValidAudience = jwtOptions.Audience,
ValidateIssuer = true,
ValidIssuer = jwtOptions.Issuer,
ValidAlgorithms = new[] { SecurityAlgorithms.HmacSha512 },
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SymmetricSecurityKey)),
ClockSkew = TimeSpan.Zero
};
Expand All @@ -38,12 +39,13 @@ public static JwtSecurityToken CreateToken(UserOutput userOutput, IConfiguration
{
var jwtOptions = configuration.GetSection("JwtOptions").Get<JwtOptions>();

var claim = new[] {
new Claim(JwtRegisteredClaimNames.Email, userOutput.Email),
new Claim(JwtRegisteredClaimNames.GivenName, userOutput.Name),
new Claim(JwtRegisteredClaimNames.UniqueName, userOutput.PublicId),
new Claim(ClaimTypes.Role, userOutput.ProfileDescription),
};
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Email, userOutput.Email),
new Claim(JwtRegisteredClaimNames.GivenName, userOutput.Name),
new Claim(JwtRegisteredClaimNames.UniqueName, userOutput.PublicId),
new Claim(ClaimTypes.Role, userOutput.ProfileDescription),
};

var signinKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SymmetricSecurityKey));

Expand All @@ -52,9 +54,20 @@ public static JwtSecurityToken CreateToken(UserOutput userOutput, IConfiguration
audience: jwtOptions.Audience,
expires: DateTime.UtcNow.AddMinutes(jwtOptions.TokenExpirationMinutes),
signingCredentials: new SigningCredentials(signinKey, SecurityAlgorithms.HmacSha512),
claims: claim
claims: claims
);

return token;
}
}

/// <summary>
/// Section of appsettings that contains the JWT app configuration
/// </summary>
public class JwtOptions
{
public string SymmetricSecurityKey { get; set; }
public string Issuer { get; set; }
public string Audience { get; set; }
public int TokenExpirationMinutes { get; set; }
}
4 changes: 3 additions & 1 deletion src/Orion.Api/Configuration/LoggingConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ public static void ConfigureLogging(this IConfiguration configuration)
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.Enrich.WithEnvironmentName()
.Enrich.WithCorrelationId()
.Enrich.WithCorrelationIdHeader()
.WriteTo.Console(outputTemplate: "[{CorrelationId} - {Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")
.WriteTo.Debug()
.WriteTo.Console()
.WriteTo.Elasticsearch(ConfigureElasticSink(configuration))
.Enrich.WithProperty("AppName", configuration["Serilog:AppName"])
.ReadFrom.Configuration(configuration)
Expand Down
3 changes: 0 additions & 3 deletions src/Orion.Api/Configuration/SwaggerConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ public static class SwaggerConfiguration
{
public static void ConfigureSwagger(this IServiceCollection services)
{
//To Disable Swagger in production environment
//if (!_env.IsProduction())

services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
Expand Down
9 changes: 0 additions & 9 deletions src/Orion.Api/Jwt/JwtOptions.cs

This file was deleted.

1 change: 1 addition & 0 deletions src/Orion.Api/Orion.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.10" />
<PackageReference Include="Serilog.AspNetCore" Version="7.0.0" />
<PackageReference Include="Serilog.Enrichers.CorrelationId" Version="3.0.1" />
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.3.0" />
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" />
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="9.0.3" />
Expand Down
4 changes: 2 additions & 2 deletions src/Orion.Data/Context/DataContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ private void AddTimestamps()
{
if (entity.State == EntityState.Added)
{
((BaseEntity)entity.Entity).CreatedAt = DateTime.Now;
((BaseEntity)entity.Entity).CreatedAt = DateTime.UtcNow;
((BaseEntity)entity.Entity).PublicId = Guid.NewGuid().ToString();
}

((BaseEntity)entity.Entity).LastUpdated = DateTime.Now;
((BaseEntity)entity.Entity).LastUpdated = DateTime.UtcNow;
}
}
}
1 change: 1 addition & 0 deletions src/Orion.Data/Mapping/CustomerMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ public void Configure(EntityTypeBuilder<Customer> builder)
builder.Property(x => x.Name).HasMaxLength(100).IsRequired();
builder.Property(x => x.PublicId).HasMaxLength(50).IsRequired();
builder.HasIndex(x => x.Name).IsUnique();
builder.HasIndex(x => x.PublicId).IsUnique();
}
}
1 change: 1 addition & 0 deletions src/Orion.Data/Mapping/RefreshTokenMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public void Configure(EntityTypeBuilder<RefreshToken> builder)
builder.Property(x => x.Refreshtoken).HasMaxLength(300).IsRequired();
builder.Property(x => x.Email).HasMaxLength(200).IsRequired();
builder.HasIndex(x => x.Email).IsUnique();
builder.HasIndex(x => x.PublicId).IsUnique();
builder.HasKey(x => x.Refreshtoken);
}
}
12 changes: 7 additions & 5 deletions src/Orion.Data/Mapping/UserMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using Orion.Domain.Entities.Enuns;
using Orion.Domain.Entities;
using Orion.Domain.Extensions;

namespace Orion.Data.Mapping;

Expand All @@ -14,6 +15,7 @@ public void Configure(EntityTypeBuilder<User> builder)
builder.Property(x => x.Name).HasMaxLength(100).IsRequired();
builder.Property(x => x.Email).HasMaxLength(200).IsRequired();
builder.HasIndex(x => x.Email).IsUnique();
builder.HasIndex(x => x.PublicId).IsUnique();
builder.Property(x => x.Password).HasMaxLength(300).IsRequired();

//Default System User
Expand All @@ -22,12 +24,12 @@ public void Configure(EntityTypeBuilder<User> builder)
{
UserId = 1,
PublicId = Guid.NewGuid().ToString(),
CreatedAt = DateTime.Now,
Email = "vanderlan.gs@gmail.com",
Name = "Vanderlan Gomes da Silva",
LastUpdated = DateTime.Now,
CreatedAt = DateTime.UtcNow,
Email = "adm@orion-api.com",
Name = "Orion Admin User",
LastUpdated = DateTime.UtcNow,
Profile = UserProfile.Admin,
Password = "3c9909afec25354d551dae21590bb26e38d53f2173b8d3dc3eee4c047e7ab1c1eb8b85103e3be7ba613b31bb5c9c36214dc9f14a42fd7a2fdb84856bca5c44c2"
Password = "123".ToSha512()
}
);
}
Expand Down
Loading
Loading