(
22 | name: "IsDeleted",
23 | table: "Users",
24 | nullable: false,
25 | defaultValue: false);
26 | }
27 |
28 | protected override void Down(MigrationBuilder migrationBuilder)
29 | {
30 | migrationBuilder.DropColumn(
31 | name: "DateCreated",
32 | table: "Users");
33 |
34 | migrationBuilder.DropColumn(
35 | name: "DateUpdated",
36 | table: "Users");
37 |
38 | migrationBuilder.DropColumn(
39 | name: "IsDeleted",
40 | table: "Users");
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Template.Swagger/SwaggerSetup.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.Extensions.DependencyInjection;
3 | using Microsoft.OpenApi.Models;
4 | using System.IO;
5 |
6 | namespace Template.Swagger
7 | {
8 | public static class SwaggerSetup
9 | {
10 | public static IServiceCollection AddSwaggerConfiguration(this IServiceCollection services)
11 | {
12 | return services.AddSwaggerGen(opt =>
13 | {
14 | opt.SwaggerDoc("v1", new OpenApiInfo
15 | {
16 | Title = "Template .Net Core",
17 | Version = "v1",
18 | Description = "Tutorial de desenvolvimento com .Net Core e Angular.",
19 | Contact = new OpenApiContact
20 | {
21 | Name = "Nicolas Fontes",
22 | Email = "nicolas.rfontes@gmail.com"
23 | }
24 | });
25 |
26 | string xmlPath = Path.Combine("wwwroot", "api-doc.xml");
27 | opt.IncludeXmlComments(xmlPath);
28 | });
29 | }
30 |
31 | public static IApplicationBuilder UseSwaggerConfiguration(this IApplicationBuilder app)
32 | {
33 | return app.UseSwagger().UseSwaggerUI(c =>
34 | {
35 | c.RoutePrefix = "documentation";
36 | c.SwaggerEndpoint("../swagger/v1/swagger.json", "API v1");
37 | });
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Template/ClientApp/src/app/home/home.component.html:
--------------------------------------------------------------------------------
1 | Hello, world!!!
2 | Welcome to your new single-page application, built with:
3 |
8 | To help you get started, we've also set up:
9 |
10 | Client-side navigation . For example, click Counter then Back to return here.
11 | Angular CLI integration . In development mode, there's no need to run ng serve. It runs in the background automatically, so your client-side resources are dynamically built on demand and the page refreshes when you modify any file.
12 | Efficient production builds . In production mode, development-time features are disabled, and your dotnet publish configuration automatically invokes ng build to produce minified, ahead-of-time compiled JavaScript files.
13 |
14 | The ClientApp subdirectory is a standard Angular CLI application. If you open a command prompt in that directory, you can run any ng command (e.g., ng test), or use npm to install extra packages into it.
15 |
--------------------------------------------------------------------------------
/Template.Auth/Services/TokenService.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.IdentityModel.Tokens;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IdentityModel.Tokens.Jwt;
5 | using System.Security.Claims;
6 | using System.Security.Principal;
7 | using System.Text;
8 | using Template.Auth.Models;
9 | using Template.Domain.Entities;
10 |
11 | namespace Template.Auth.Services
12 | {
13 | public static class TokenService
14 | {
15 | public static string GenerateToken(User user)
16 | {
17 | var tokenHandler = new JwtSecurityTokenHandler();
18 | var key = Encoding.ASCII.GetBytes(Settings.Secret);
19 | var tokenDescriptor = new SecurityTokenDescriptor
20 | {
21 | Subject = new ClaimsIdentity(new Claim[]
22 | {
23 | new Claim(ClaimTypes.Name, user.Name),
24 | new Claim(ClaimTypes.Email, user.Email),
25 | new Claim(ClaimTypes.NameIdentifier, user.Id.ToString())
26 | }),
27 | Expires = DateTime.UtcNow.AddHours(3),
28 | SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
29 | };
30 | var token = tokenHandler.CreateToken(tokenDescriptor);
31 | return tokenHandler.WriteToken(token);
32 | }
33 |
34 | public static string GetValueFromClaim(IIdentity identity, string field)
35 | {
36 | var claims = identity as ClaimsIdentity;
37 |
38 | return claims.FindFirst(field).Value;
39 | }
40 |
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Template.Data/Migrations/20200627153606_User Table.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Metadata;
6 | using Microsoft.EntityFrameworkCore.Migrations;
7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
8 | using Template.Data.Context;
9 |
10 | namespace Template.Data.Migrations
11 | {
12 | [DbContext(typeof(TemplateContext))]
13 | [Migration("20200627153606_User Table")]
14 | partial class UserTable
15 | {
16 | protected override void BuildTargetModel(ModelBuilder modelBuilder)
17 | {
18 | #pragma warning disable 612, 618
19 | modelBuilder
20 | .HasAnnotation("ProductVersion", "3.1.5")
21 | .HasAnnotation("Relational:MaxIdentifierLength", 128)
22 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
23 |
24 | modelBuilder.Entity("Template.Domain.Entities.User", b =>
25 | {
26 | b.Property("Id")
27 | .ValueGeneratedOnAdd()
28 | .HasColumnType("uniqueidentifier");
29 |
30 | b.Property("Name")
31 | .IsRequired()
32 | .HasColumnType("nvarchar(100)")
33 | .HasMaxLength(100);
34 |
35 | b.HasKey("Id");
36 |
37 | b.ToTable("Users");
38 | });
39 | #pragma warning restore 612, 618
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Template.Domain/Interfaces/IRepository.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Linq.Expressions;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Template.Domain.Interfaces
9 | {
10 | public interface IRepository : IDisposable where TEntity : class
11 | {
12 | TEntity Create(TEntity model);
13 |
14 | List Create(List model);
15 |
16 | bool Update(TEntity model);
17 |
18 | bool Update(List model);
19 |
20 | bool Delete(TEntity model);
21 |
22 | bool Delete(params object[] Keys);
23 |
24 | bool Delete(Expression> where);
25 |
26 | int Save();
27 |
28 | TEntity Find(params object[] Keys);
29 |
30 | TEntity Find(Expression> where);
31 |
32 | TEntity Find(Expression> predicate, Func, object> includes);
33 |
34 | IQueryable Query(Expression> where);
35 |
36 | IQueryable Query(Expression> predicate, Func, object> includes);
37 |
38 | Task CreateAsync(TEntity model);
39 |
40 | Task UpdateAsync(TEntity model);
41 |
42 | Task DeleteAsync(Expression> where);
43 |
44 | Task DeleteAsync(TEntity model);
45 |
46 | Task DeleteAsync(params object[] Keys);
47 |
48 | Task SaveAsync();
49 |
50 | Task GetAsync(params object[] Keys);
51 |
52 | Task GetAsync(Expression> where);
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/Template.Data/Migrations/20200627153843_Field Email in User Table.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Metadata;
6 | using Microsoft.EntityFrameworkCore.Migrations;
7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
8 | using Template.Data.Context;
9 |
10 | namespace Template.Data.Migrations
11 | {
12 | [DbContext(typeof(TemplateContext))]
13 | [Migration("20200627153843_Field Email in User Table")]
14 | partial class FieldEmailinUserTable
15 | {
16 | protected override void BuildTargetModel(ModelBuilder modelBuilder)
17 | {
18 | #pragma warning disable 612, 618
19 | modelBuilder
20 | .HasAnnotation("ProductVersion", "3.1.5")
21 | .HasAnnotation("Relational:MaxIdentifierLength", 128)
22 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
23 |
24 | modelBuilder.Entity("Template.Domain.Entities.User", b =>
25 | {
26 | b.Property("Id")
27 | .ValueGeneratedOnAdd()
28 | .HasColumnType("uniqueidentifier");
29 |
30 | b.Property("Email")
31 | .HasColumnType("nvarchar(max)");
32 |
33 | b.Property("Name")
34 | .IsRequired()
35 | .HasColumnType("nvarchar(100)")
36 | .HasMaxLength(100);
37 |
38 | b.HasKey("Id");
39 |
40 | b.ToTable("Users");
41 | });
42 | #pragma warning restore 612, 618
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Template/ClientApp/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "template",
3 | "version": "0.0.0",
4 | "scripts": {
5 | "ng": "ng",
6 | "start": "ng serve",
7 | "build": "ng build",
8 | "build:ssr": "ng run Template:server:dev",
9 | "test": "ng test",
10 | "lint": "ng lint",
11 | "e2e": "ng e2e"
12 | },
13 | "private": true,
14 | "dependencies": {
15 | "@angular/animations": "8.2.12",
16 | "@angular/common": "8.2.12",
17 | "@angular/compiler": "8.2.12",
18 | "@angular/core": "8.2.12",
19 | "@angular/forms": "8.2.12",
20 | "@angular/platform-browser": "8.2.12",
21 | "@angular/platform-browser-dynamic": "8.2.12",
22 | "@angular/platform-server": "8.2.12",
23 | "@angular/router": "8.2.12",
24 | "@nguniversal/module-map-ngfactory-loader": "8.1.1",
25 | "aspnet-prerendering": "^3.0.1",
26 | "bootstrap": "^4.3.1",
27 | "core-js": "^3.3.3",
28 | "jquery": "3.4.1",
29 | "oidc-client": "^1.9.1",
30 | "popper.js": "^1.16.0",
31 | "rxjs": "^6.5.3",
32 | "zone.js": "0.9.1"
33 | },
34 | "devDependencies": {
35 | "@angular-devkit/build-angular": "^0.803.14",
36 | "@angular/cli": "8.3.14",
37 | "@angular/compiler-cli": "8.2.12",
38 | "@angular/language-service": "8.2.12",
39 | "@types/jasmine": "~3.4.4",
40 | "@types/jasminewd2": "~2.0.8",
41 | "@types/node": "~12.11.6",
42 | "codelyzer": "^5.2.0",
43 | "jasmine-core": "~3.5.0",
44 | "jasmine-spec-reporter": "~4.2.1",
45 | "karma": "^4.4.1",
46 | "karma-chrome-launcher": "~3.1.0",
47 | "karma-coverage-istanbul-reporter": "~2.1.0",
48 | "karma-jasmine": "~2.0.1",
49 | "karma-jasmine-html-reporter": "^1.4.2",
50 | "typescript": "3.5.3"
51 | },
52 | "optionalDependencies": {
53 | "node-sass": "^4.12.0",
54 | "protractor": "~5.4.2",
55 | "ts-node": "~8.4.1",
56 | "tslint": "~5.20.0"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Template.Data/Migrations/20200627154559_Inserting Default User.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Metadata;
6 | using Microsoft.EntityFrameworkCore.Migrations;
7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
8 | using Template.Data.Context;
9 |
10 | namespace Template.Data.Migrations
11 | {
12 | [DbContext(typeof(TemplateContext))]
13 | [Migration("20200627154559_Inserting Default User")]
14 | partial class InsertingDefaultUser
15 | {
16 | protected override void BuildTargetModel(ModelBuilder modelBuilder)
17 | {
18 | #pragma warning disable 612, 618
19 | modelBuilder
20 | .HasAnnotation("ProductVersion", "3.1.5")
21 | .HasAnnotation("Relational:MaxIdentifierLength", 128)
22 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
23 |
24 | modelBuilder.Entity("Template.Domain.Entities.User", b =>
25 | {
26 | b.Property("Id")
27 | .ValueGeneratedOnAdd()
28 | .HasColumnType("uniqueidentifier");
29 |
30 | b.Property("Email")
31 | .HasColumnType("nvarchar(max)");
32 |
33 | b.Property("Name")
34 | .IsRequired()
35 | .HasColumnType("nvarchar(100)")
36 | .HasMaxLength(100);
37 |
38 | b.HasKey("Id");
39 |
40 | b.ToTable("Users");
41 |
42 | b.HasData(
43 | new
44 | {
45 | Id = new Guid("c7dce21b-d207-4869-bf5f-08eb138bb919"),
46 | Email = "userdefault@template.com",
47 | Name = "User Default"
48 | });
49 | });
50 | #pragma warning restore 612, 618
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Template.Data/Migrations/20200627175238_GlobalConfigurations.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.EntityFrameworkCore.Migrations;
3 |
4 | namespace Template.Data.Migrations
5 | {
6 | public partial class GlobalConfigurations : Migration
7 | {
8 | protected override void Up(MigrationBuilder migrationBuilder)
9 | {
10 | migrationBuilder.AlterColumn(
11 | name: "IsDeleted",
12 | table: "Users",
13 | nullable: false,
14 | defaultValue: false,
15 | oldClrType: typeof(bool),
16 | oldType: "bit");
17 |
18 | migrationBuilder.AlterColumn(
19 | name: "DateCreated",
20 | table: "Users",
21 | nullable: false,
22 | defaultValue: new DateTime(2020, 6, 27, 18, 52, 38, 325, DateTimeKind.Local).AddTicks(9630),
23 | oldClrType: typeof(DateTime),
24 | oldType: "datetime2");
25 |
26 | migrationBuilder.UpdateData(
27 | table: "Users",
28 | keyColumn: "Id",
29 | keyValue: new Guid("c7dce21b-d207-4869-bf5f-08eb138bb919"),
30 | column: "DateCreated",
31 | value: new DateTime(2020, 2, 2, 0, 0, 0, 0, DateTimeKind.Unspecified));
32 | }
33 |
34 | protected override void Down(MigrationBuilder migrationBuilder)
35 | {
36 | migrationBuilder.AlterColumn(
37 | name: "IsDeleted",
38 | table: "Users",
39 | type: "bit",
40 | nullable: false,
41 | oldClrType: typeof(bool),
42 | oldDefaultValue: false);
43 |
44 | migrationBuilder.AlterColumn(
45 | name: "DateCreated",
46 | table: "Users",
47 | type: "datetime2",
48 | nullable: false,
49 | oldClrType: typeof(DateTime),
50 | oldDefaultValue: new DateTime(2020, 6, 27, 18, 52, 38, 325, DateTimeKind.Local).AddTicks(9630));
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Template/Controllers/UsersController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Security.Claims;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Authorization;
7 | using Microsoft.AspNetCore.Http;
8 | using Microsoft.AspNetCore.Mvc;
9 | using Template.Application.Interfaces;
10 | using Template.Application.ViewModels;
11 | using Template.Auth.Services;
12 |
13 | namespace Template.Controllers
14 | {
15 | [Route("api/[controller]")]
16 | [ApiController, Authorize]
17 | public class UsersController : ControllerBase
18 | {
19 |
20 | private readonly IUserService userService;
21 |
22 | public UsersController(IUserService userService)
23 | {
24 | this.userService = userService;
25 | }
26 |
27 | [HttpGet]
28 | public IActionResult Get()
29 | {
30 | return Ok(this.userService.Get());
31 | }
32 |
33 | [HttpPost, AllowAnonymous]
34 | public IActionResult Post(UserViewModel userViewModel)
35 | {
36 | if (!ModelState.IsValid)
37 | return BadRequest(ModelState);
38 |
39 | return Ok(this.userService.Post(userViewModel));
40 | }
41 |
42 | [HttpGet("{id}")]
43 | public IActionResult GetById(string id)
44 | {
45 | return Ok(this.userService.GetById(id));
46 | }
47 |
48 | [HttpPut]
49 | public IActionResult Put(UserViewModel userViewModel)
50 | {
51 | return Ok(this.userService.Put(userViewModel));
52 | }
53 |
54 | [HttpDelete]
55 | public IActionResult Delete()
56 | {
57 | string _userId = TokenService.GetValueFromClaim(HttpContext.User.Identity, ClaimTypes.NameIdentifier);
58 |
59 | return Ok(this.userService.Delete(_userId));
60 | }
61 |
62 | [HttpPost("authenticate"), AllowAnonymous]
63 | public IActionResult Authenticate(UserAuthenticateRequestViewModel userViewModel)
64 | {
65 | return Ok(this.userService.Authenticate(userViewModel));
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Template.Data/Extensions/ModelBuilderExtension.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 | using Template.Domain.Entities;
6 | using Microsoft.EntityFrameworkCore.Metadata;
7 | using Template.Domain.Models;
8 |
9 | namespace Template.Data.Extensions
10 | {
11 | public static class ModelBuilderExtension
12 | {
13 |
14 | public static ModelBuilder ApplyGlobalConfigurations(this ModelBuilder builder)
15 | {
16 | foreach (IMutableEntityType entityType in builder.Model.GetEntityTypes())
17 | {
18 | foreach (IMutableProperty property in entityType.GetProperties())
19 | {
20 | switch (property.Name)
21 | {
22 | case nameof(Entity.Id):
23 | property.IsKey();
24 | break;
25 | case nameof(Entity.DateUpdated):
26 | property.IsNullable = true;
27 | break;
28 | case nameof(Entity.DateCreated):
29 | property.IsNullable = false;
30 | property.SetDefaultValue(DateTime.Now);
31 | break;
32 | case nameof(Entity.IsDeleted):
33 | property.IsNullable = false;
34 | property.SetDefaultValue(false);
35 | break;
36 | default:
37 | break;
38 | }
39 | }
40 | }
41 |
42 | return builder;
43 | }
44 |
45 | public static ModelBuilder SeedData(this ModelBuilder builder)
46 | {
47 | builder.Entity()
48 | .HasData(
49 | new User { Id = Guid.Parse("c7dce21b-d207-4869-bf5f-08eb138bb919"), Name = "User Default", Email = "userdefault@template.com", DateCreated = new DateTime(2020,2,2), IsDeleted = false, DateUpdated = null }
50 | );
51 |
52 |
53 | return builder;
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Template.Data/Migrations/20200926072248_Password Field.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.EntityFrameworkCore.Migrations;
3 |
4 | namespace Template.Data.Migrations
5 | {
6 | public partial class PasswordField : Migration
7 | {
8 | protected override void Up(MigrationBuilder migrationBuilder)
9 | {
10 | migrationBuilder.AlterColumn(
11 | name: "DateCreated",
12 | table: "Users",
13 | nullable: false,
14 | defaultValue: new DateTime(2020, 9, 26, 8, 22, 47, 961, DateTimeKind.Local).AddTicks(3033),
15 | oldClrType: typeof(DateTime),
16 | oldType: "datetime2",
17 | oldDefaultValue: new DateTime(2020, 6, 27, 18, 52, 38, 325, DateTimeKind.Local).AddTicks(9630));
18 |
19 | migrationBuilder.AddColumn(
20 | name: "Password",
21 | table: "Users",
22 | nullable: false,
23 | defaultValue: "TesteTemplate");
24 |
25 | migrationBuilder.UpdateData(
26 | table: "Users",
27 | keyColumn: "Id",
28 | keyValue: new Guid("c7dce21b-d207-4869-bf5f-08eb138bb919"),
29 | column: "DateCreated",
30 | value: new DateTime(2020, 2, 2, 0, 0, 0, 0, DateTimeKind.Unspecified));
31 | }
32 |
33 | protected override void Down(MigrationBuilder migrationBuilder)
34 | {
35 | migrationBuilder.DropColumn(
36 | name: "Password",
37 | table: "Users");
38 |
39 | migrationBuilder.AlterColumn(
40 | name: "DateCreated",
41 | table: "Users",
42 | type: "datetime2",
43 | nullable: false,
44 | defaultValue: new DateTime(2020, 6, 27, 18, 52, 38, 325, DateTimeKind.Local).AddTicks(9630),
45 | oldClrType: typeof(DateTime),
46 | oldDefaultValue: new DateTime(2020, 9, 26, 8, 22, 47, 961, DateTimeKind.Local).AddTicks(3033));
47 |
48 | migrationBuilder.UpdateData(
49 | table: "Users",
50 | keyColumn: "Id",
51 | keyValue: new Guid("c7dce21b-d207-4869-bf5f-08eb138bb919"),
52 | column: "DateCreated",
53 | value: new DateTime(2020, 2, 2, 0, 0, 0, 0, DateTimeKind.Unspecified));
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Template.Data/Migrations/20200627164211_Common Fields.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Metadata;
6 | using Microsoft.EntityFrameworkCore.Migrations;
7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
8 | using Template.Data.Context;
9 |
10 | namespace Template.Data.Migrations
11 | {
12 | [DbContext(typeof(TemplateContext))]
13 | [Migration("20200627164211_Common Fields")]
14 | partial class CommonFields
15 | {
16 | protected override void BuildTargetModel(ModelBuilder modelBuilder)
17 | {
18 | #pragma warning disable 612, 618
19 | modelBuilder
20 | .HasAnnotation("ProductVersion", "3.1.5")
21 | .HasAnnotation("Relational:MaxIdentifierLength", 128)
22 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
23 |
24 | modelBuilder.Entity("Template.Domain.Entities.User", b =>
25 | {
26 | b.Property("Id")
27 | .ValueGeneratedOnAdd()
28 | .HasColumnType("uniqueidentifier");
29 |
30 | b.Property("DateCreated")
31 | .HasColumnType("datetime2");
32 |
33 | b.Property("DateUpdated")
34 | .HasColumnType("datetime2");
35 |
36 | b.Property("Email")
37 | .HasColumnType("nvarchar(max)");
38 |
39 | b.Property("IsDeleted")
40 | .HasColumnType("bit");
41 |
42 | b.Property("Name")
43 | .IsRequired()
44 | .HasColumnType("nvarchar(100)")
45 | .HasMaxLength(100);
46 |
47 | b.HasKey("Id");
48 |
49 | b.ToTable("Users");
50 |
51 | b.HasData(
52 | new
53 | {
54 | Id = new Guid("c7dce21b-d207-4869-bf5f-08eb138bb919"),
55 | DateCreated = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
56 | Email = "userdefault@template.com",
57 | IsDeleted = false,
58 | Name = "User Default"
59 | });
60 | });
61 | #pragma warning restore 612, 618
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Template.Data/Migrations/20200627164403_Updating Default User.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Metadata;
6 | using Microsoft.EntityFrameworkCore.Migrations;
7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
8 | using Template.Data.Context;
9 |
10 | namespace Template.Data.Migrations
11 | {
12 | [DbContext(typeof(TemplateContext))]
13 | [Migration("20200627164403_Updating Default User")]
14 | partial class UpdatingDefaultUser
15 | {
16 | protected override void BuildTargetModel(ModelBuilder modelBuilder)
17 | {
18 | #pragma warning disable 612, 618
19 | modelBuilder
20 | .HasAnnotation("ProductVersion", "3.1.5")
21 | .HasAnnotation("Relational:MaxIdentifierLength", 128)
22 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
23 |
24 | modelBuilder.Entity("Template.Domain.Entities.User", b =>
25 | {
26 | b.Property("Id")
27 | .ValueGeneratedOnAdd()
28 | .HasColumnType("uniqueidentifier");
29 |
30 | b.Property("DateCreated")
31 | .HasColumnType("datetime2");
32 |
33 | b.Property("DateUpdated")
34 | .HasColumnType("datetime2");
35 |
36 | b.Property("Email")
37 | .HasColumnType("nvarchar(max)");
38 |
39 | b.Property("IsDeleted")
40 | .HasColumnType("bit");
41 |
42 | b.Property("Name")
43 | .IsRequired()
44 | .HasColumnType("nvarchar(100)")
45 | .HasMaxLength(100);
46 |
47 | b.HasKey("Id");
48 |
49 | b.ToTable("Users");
50 |
51 | b.HasData(
52 | new
53 | {
54 | Id = new Guid("c7dce21b-d207-4869-bf5f-08eb138bb919"),
55 | DateCreated = new DateTime(2020, 2, 2, 0, 0, 0, 0, DateTimeKind.Unspecified),
56 | Email = "userdefault@template.com",
57 | IsDeleted = false,
58 | Name = "User Default"
59 | });
60 | });
61 | #pragma warning restore 612, 618
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Template/ClientApp/src/app/users/users.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Welcome ({{userLogged?.user?.name}})
4 | {{showList ? 'Novo usuário' : 'Lista de Usuários'}}
5 | Users ({{users?.length}})
6 |
7 |
8 |
9 |
10 |
11 | Actions
12 | ID
13 | Name
14 | Email
15 |
16 |
17 |
18 |
19 |
20 |
21 | Editar
22 | Excluir
23 |
24 | {{user.id}}
25 | {{user.name}}
26 | {{user.email}}
27 |
28 |
29 |
30 |
31 |
32 |
49 |
50 |
63 |
--------------------------------------------------------------------------------
/Template.Data/Migrations/20200627175238_GlobalConfigurations.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Metadata;
6 | using Microsoft.EntityFrameworkCore.Migrations;
7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
8 | using Template.Data.Context;
9 |
10 | namespace Template.Data.Migrations
11 | {
12 | [DbContext(typeof(TemplateContext))]
13 | [Migration("20200627175238_GlobalConfigurations")]
14 | partial class GlobalConfigurations
15 | {
16 | protected override void BuildTargetModel(ModelBuilder modelBuilder)
17 | {
18 | #pragma warning disable 612, 618
19 | modelBuilder
20 | .HasAnnotation("ProductVersion", "3.1.5")
21 | .HasAnnotation("Relational:MaxIdentifierLength", 128)
22 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
23 |
24 | modelBuilder.Entity("Template.Domain.Entities.User", b =>
25 | {
26 | b.Property("Id")
27 | .ValueGeneratedOnAdd()
28 | .HasColumnType("uniqueidentifier");
29 |
30 | b.Property("DateCreated")
31 | .ValueGeneratedOnAdd()
32 | .HasColumnType("datetime2")
33 | .HasDefaultValue(new DateTime(2020, 6, 27, 18, 52, 38, 325, DateTimeKind.Local).AddTicks(9630));
34 |
35 | b.Property("DateUpdated")
36 | .HasColumnType("datetime2");
37 |
38 | b.Property("Email")
39 | .HasColumnType("nvarchar(max)");
40 |
41 | b.Property("IsDeleted")
42 | .ValueGeneratedOnAdd()
43 | .HasColumnType("bit")
44 | .HasDefaultValue(false);
45 |
46 | b.Property("Name")
47 | .IsRequired()
48 | .HasColumnType("nvarchar(100)")
49 | .HasMaxLength(100);
50 |
51 | b.HasKey("Id");
52 |
53 | b.ToTable("Users");
54 |
55 | b.HasData(
56 | new
57 | {
58 | Id = new Guid("c7dce21b-d207-4869-bf5f-08eb138bb919"),
59 | DateCreated = new DateTime(2020, 2, 2, 0, 0, 0, 0, DateTimeKind.Unspecified),
60 | Email = "userdefault@template.com",
61 | IsDeleted = false,
62 | Name = "User Default"
63 | });
64 | });
65 | #pragma warning restore 612, 618
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Template-DotNetCore
2 |
3 | ## Aplicação em .Net Core com Angular
4 |
5 | ### Vídeos:
6 | - Criando um projeto .Net Core com Angular no Visual Studio:
7 | * https://www.youtube.com/watch?v=zkbk1pnwz5Q&t=15s
8 | * https://medium.com/@nicolas.rfontes/criando-um-projeto-net-core-com-angular-no-visual-studio-a1ac1bc30f94
9 |
10 | - Publicando um projeto .Net Core no Github pelo Visual Studio:
11 | * https://www.youtube.com/watch?v=Bzz63URwTrw&t=19s
12 | * https://medium.com/@nicolas.rfontes/publicando-um-projeto-net-core-no-github-pelo-visual-studio-f6e91ac9d1e9
13 |
14 | - Criando uma arquitetura de projeto backend em .Net Core (Projetos e Pastas):
15 | * https://www.youtube.com/watch?v=SHyF8Tc-s8Q
16 | * https://medium.com/@nicolas.rfontes/criando-uma-arquitetura-de-projeto-backend-em-net-core-3f9a8a1df6f
17 |
18 | - Instalando e Configurando Entity Framework Core (Code First) em um projeto .Net Core:
19 | * https://www.youtube.com/watch?v=2FGTJX1sWZk
20 | * https://medium.com/@nicolas.rfontes/instalando-e-configurando-entity-framework-core-9980582ce148
21 |
22 | - Configurando Injeção de Dependência em um projeto .Net Core:
23 | * https://www.youtube.com/watch?v=kSAdyvMFL9I
24 | * https://medium.com/@nicolas.rfontes/configurando-inje%C3%A7%C3%A3o-de-depend%C3%AAncia-em-um-projeto-net-core-8b7a1a112c09
25 |
26 | - Criando api Get em .Net Core para retornar valores do banco SQL Server:
27 | * https://www.youtube.com/watch?v=hm4KbhEhdv4
28 | * https://medium.com/@nicolas.rfontes/criando-uma-api-get-em-net-core-comunicando-com-o-banco-de-dados-sql-server-14e37a415ad
29 |
30 | - Criando api Post em .Net Core para retornar valores do banco SQL Server:
31 | * https://www.youtube.com/watch?v=oDIXGnQlbfE
32 | * https://medium.com/@nicolas.rfontes/criando-uma-api-post-em-net-core-para-salvar-e-retornar-valores-do-banco-sql-server-27a1c4743a77
33 |
34 | - Configurando AutoMapper em um projeto .Net Core:
35 | * https://www.youtube.com/watch?v=gJ5xyhMPNWc
36 | * https://medium.com/@nicolas.rfontes/configurando-o-automapper-em-um-aplica%C3%A7%C3%A3o-net-core-2e5f5920640
37 |
38 | - Configurando o Swagger em um projeto .Net Core:
39 | * https://www.youtube.com/watch?v=wYLEMHhICXo
40 | * https://medium.com/@nicolas.rfontes/configurando-o-swagger-em-uma-aplica%C3%A7%C3%A3o-net-core-120776c320ce
41 |
42 | - Criando api GetOne e Put em uma aplicação .Net Core:
43 | * https://www.youtube.com/watch?v=9tO2UaE5YYI
44 | * https://medium.com/@nicolas.rfontes/criando-api-getone-e-put-em-uma-aplica%C3%A7%C3%A3o-net-core-e542c1ae13b0
45 |
46 | - Criando API Delete em uma aplicação .Net Core
47 | * https://www.youtube.com/watch?v=BUTZt669SpQ
48 | * https://medium.com/@nicolas.rfontes/criando-api-delete-em-uma-aplica%C3%A7%C3%A3o-net-core-5f1448d07bd5
49 |
50 | - Autenticando um usuário com JWT em uma aplicação .Net Core
51 |
52 | - Definindo APIs publicas e privadas em uma aplicação .Net Core
53 |
--------------------------------------------------------------------------------
/Template.Data/Migrations/TemplateContextModelSnapshot.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Metadata;
6 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
7 | using Template.Data.Context;
8 |
9 | namespace Template.Data.Migrations
10 | {
11 | [DbContext(typeof(TemplateContext))]
12 | partial class TemplateContextModelSnapshot : ModelSnapshot
13 | {
14 | protected override void BuildModel(ModelBuilder modelBuilder)
15 | {
16 | #pragma warning disable 612, 618
17 | modelBuilder
18 | .HasAnnotation("ProductVersion", "3.1.5")
19 | .HasAnnotation("Relational:MaxIdentifierLength", 128)
20 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
21 |
22 | modelBuilder.Entity("Template.Domain.Entities.User", b =>
23 | {
24 | b.Property("Id")
25 | .ValueGeneratedOnAdd()
26 | .HasColumnType("uniqueidentifier");
27 |
28 | b.Property("DateCreated")
29 | .ValueGeneratedOnAdd()
30 | .HasColumnType("datetime2")
31 | .HasDefaultValue(new DateTime(2020, 9, 26, 8, 22, 47, 961, DateTimeKind.Local).AddTicks(3033));
32 |
33 | b.Property("DateUpdated")
34 | .HasColumnType("datetime2");
35 |
36 | b.Property("Email")
37 | .HasColumnType("nvarchar(max)");
38 |
39 | b.Property("IsDeleted")
40 | .ValueGeneratedOnAdd()
41 | .HasColumnType("bit")
42 | .HasDefaultValue(false);
43 |
44 | b.Property("Name")
45 | .IsRequired()
46 | .HasColumnType("nvarchar(100)")
47 | .HasMaxLength(100);
48 |
49 | b.Property("Password")
50 | .IsRequired()
51 | .ValueGeneratedOnAdd()
52 | .HasColumnType("nvarchar(max)")
53 | .HasDefaultValue("TesteTemplate");
54 |
55 | b.HasKey("Id");
56 |
57 | b.ToTable("Users");
58 |
59 | b.HasData(
60 | new
61 | {
62 | Id = new Guid("c7dce21b-d207-4869-bf5f-08eb138bb919"),
63 | DateCreated = new DateTime(2020, 2, 2, 0, 0, 0, 0, DateTimeKind.Unspecified),
64 | Email = "userdefault@template.com",
65 | IsDeleted = false,
66 | Name = "User Default"
67 | });
68 | });
69 | #pragma warning restore 612, 618
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Template/ClientApp/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/guide/browser-support
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */
22 | // import 'classlist.js'; // Run `npm install --save classlist.js`.
23 |
24 | /**
25 | * Web Animations `@angular/platform-browser/animations`
26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
28 | */
29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
30 |
31 | /**
32 | * By default, zone.js will patch all possible macroTask and DomEvents
33 | * user can disable parts of macroTask/DomEvents patch by setting following flags
34 | * because those flags need to be set before `zone.js` being loaded, and webpack
35 | * will put import in the top of bundle, so user need to create a separate file
36 | * in this directory (for example: zone-flags.ts), and put the following flags
37 | * into that file, and then add the following code before importing zone.js.
38 | * import './zone-flags.ts';
39 | *
40 | * The flags allowed in zone-flags.ts are listed here.
41 | *
42 | * The following flags will work for all browsers.
43 | *
44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
47 | *
48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge
50 | *
51 | * (window as any).__Zone_enable_cross_context_check = true;
52 | *
53 | */
54 |
55 | /***************************************************************************************************
56 | * Zone JS is required by default for Angular itself.
57 | */
58 | import 'zone.js/dist/zone'; // Included with Angular CLI.
59 |
60 |
61 | /***************************************************************************************************
62 | * APPLICATION IMPORTS
63 | */
64 |
--------------------------------------------------------------------------------
/Template/ClientApp/src/app/users/users.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { UserDataService } from '../_data-services/user.data-service';
3 |
4 | @Component({
5 | selector: 'app-users',
6 | templateUrl: './users.component.html',
7 | styleUrls: ['./users.component.css']
8 | })
9 | export class UsersComponent implements OnInit {
10 |
11 | users: any[] = [];
12 | user: any = {};
13 | userLogin: any = {};
14 | userLogged: any = {};
15 | showList: boolean = true;
16 | isAuthenticated: boolean = false;
17 |
18 | constructor(private userDataService: UserDataService) { }
19 |
20 | ngOnInit() {
21 |
22 | }
23 |
24 | get() {
25 | this.userDataService.get().subscribe((data:any[]) => {
26 | this.users = data;
27 | this.showList = true;
28 | }, error => {
29 | console.log(error);
30 | alert('erro interno do sistema');
31 | })
32 | }
33 |
34 | save() {
35 | if (this.user.id) {
36 | this.put();
37 | } else {
38 | this.post();
39 | }
40 | }
41 |
42 | openDetails(user) {
43 | this.showList = false;
44 | this.user = user;
45 | }
46 |
47 | post() {
48 | this.userDataService.post(this.user).subscribe(data => {
49 | if (data) {
50 | alert('Usuário cadastrado com sucesso');
51 | this.get();
52 | this.user = {};
53 | } else {
54 | alert('Erro ao cadastrar usuário');
55 | }
56 | }, error => {
57 | console.log(error);
58 | alert('erro interno do sistema');
59 | })
60 | }
61 |
62 | put() {
63 | this.userDataService.put(this.user).subscribe(data => {
64 | if (data) {
65 | alert('Usuário atualizado com sucesso');
66 | this.get();
67 | this.user = {};
68 | } else {
69 | alert('Erro ao atualizar usuário');
70 | }
71 | }, error => {
72 | console.log(error);
73 | alert('erro interno do sistema');
74 | })
75 | }
76 |
77 | delete() {
78 | this.userDataService.delete().subscribe(data => {
79 | if (data) {
80 | alert('Usuário excluído com sucesso');
81 | this.get();
82 | this.user = {};
83 | } else {
84 | alert('Erro ao excluir usuário');
85 | }
86 | }, error => {
87 | console.log(error);
88 | alert('erro interno do sistema');
89 | })
90 | }
91 |
92 | authenticate() {
93 | this.userDataService.authenticate(this.userLogin).subscribe((data:any) => {
94 | if (data.user) {
95 | localStorage.setItem('user_logged', JSON.stringify(data));
96 | this.get();
97 | this.getUserData();
98 | } else {
99 | alert('User invalid.');
100 | }
101 | }, error => {
102 | console.log(error);
103 | alert('User invalid');
104 | })
105 | }
106 |
107 | getUserData() {
108 | this.userLogged = JSON.parse(localStorage.getItem('user_logged'));
109 | this.isAuthenticated = this.userLogged != null;
110 | }
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/Template.Data/Migrations/20200926072248_Password Field.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Metadata;
6 | using Microsoft.EntityFrameworkCore.Migrations;
7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
8 | using Template.Data.Context;
9 |
10 | namespace Template.Data.Migrations
11 | {
12 | [DbContext(typeof(TemplateContext))]
13 | [Migration("20200926072248_Password Field")]
14 | partial class PasswordField
15 | {
16 | protected override void BuildTargetModel(ModelBuilder modelBuilder)
17 | {
18 | #pragma warning disable 612, 618
19 | modelBuilder
20 | .HasAnnotation("ProductVersion", "3.1.5")
21 | .HasAnnotation("Relational:MaxIdentifierLength", 128)
22 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
23 |
24 | modelBuilder.Entity("Template.Domain.Entities.User", b =>
25 | {
26 | b.Property("Id")
27 | .ValueGeneratedOnAdd()
28 | .HasColumnType("uniqueidentifier");
29 |
30 | b.Property("DateCreated")
31 | .ValueGeneratedOnAdd()
32 | .HasColumnType("datetime2")
33 | .HasDefaultValue(new DateTime(2020, 9, 26, 8, 22, 47, 961, DateTimeKind.Local).AddTicks(3033));
34 |
35 | b.Property("DateUpdated")
36 | .HasColumnType("datetime2");
37 |
38 | b.Property("Email")
39 | .HasColumnType("nvarchar(max)");
40 |
41 | b.Property("IsDeleted")
42 | .ValueGeneratedOnAdd()
43 | .HasColumnType("bit")
44 | .HasDefaultValue(false);
45 |
46 | b.Property("Name")
47 | .IsRequired()
48 | .HasColumnType("nvarchar(100)")
49 | .HasMaxLength(100);
50 |
51 | b.Property("Password")
52 | .IsRequired()
53 | .ValueGeneratedOnAdd()
54 | .HasColumnType("nvarchar(max)")
55 | .HasDefaultValue("TesteTemplate");
56 |
57 | b.HasKey("Id");
58 |
59 | b.ToTable("Users");
60 |
61 | b.HasData(
62 | new
63 | {
64 | Id = new Guid("c7dce21b-d207-4869-bf5f-08eb138bb919"),
65 | DateCreated = new DateTime(2020, 2, 2, 0, 0, 0, 0, DateTimeKind.Unspecified),
66 | Email = "userdefault@template.com",
67 | IsDeleted = false,
68 | Name = "User Default"
69 | });
70 | });
71 | #pragma warning restore 612, 618
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/Template/ClientApp/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rulesDirectory": [
3 | "node_modules/codelyzer"
4 | ],
5 | "rules": {
6 | "arrow-return-shorthand": true,
7 | "callable-types": true,
8 | "class-name": true,
9 | "comment-format": [
10 | true,
11 | "check-space"
12 | ],
13 | "curly": true,
14 | "deprecation": {
15 | "severity": "warn"
16 | },
17 | "eofline": true,
18 | "forin": true,
19 | "import-blacklist": [
20 | true,
21 | "rxjs/Rx"
22 | ],
23 | "import-spacing": true,
24 | "indent": [
25 | true,
26 | "spaces"
27 | ],
28 | "interface-over-type-literal": true,
29 | "label-position": true,
30 | "max-line-length": [
31 | true,
32 | 140
33 | ],
34 | "member-access": false,
35 | "member-ordering": [
36 | true,
37 | {
38 | "order": [
39 | "static-field",
40 | "instance-field",
41 | "static-method",
42 | "instance-method"
43 | ]
44 | }
45 | ],
46 | "no-arg": true,
47 | "no-bitwise": true,
48 | "no-console": [
49 | true,
50 | "debug",
51 | "info",
52 | "time",
53 | "timeEnd",
54 | "trace"
55 | ],
56 | "no-construct": true,
57 | "no-debugger": true,
58 | "no-duplicate-super": true,
59 | "no-empty": false,
60 | "no-empty-interface": true,
61 | "no-eval": true,
62 | "no-inferrable-types": [
63 | true,
64 | "ignore-params"
65 | ],
66 | "no-misused-new": true,
67 | "no-non-null-assertion": true,
68 | "no-shadowed-variable": true,
69 | "no-string-literal": false,
70 | "no-string-throw": true,
71 | "no-switch-case-fall-through": true,
72 | "no-trailing-whitespace": true,
73 | "no-unnecessary-initializer": true,
74 | "no-unused-expression": true,
75 | "no-use-before-declare": true,
76 | "no-var-keyword": true,
77 | "object-literal-sort-keys": false,
78 | "one-line": [
79 | true,
80 | "check-open-brace",
81 | "check-catch",
82 | "check-else",
83 | "check-whitespace"
84 | ],
85 | "prefer-const": true,
86 | "quotemark": [
87 | true,
88 | "single"
89 | ],
90 | "radix": true,
91 | "semicolon": [
92 | true,
93 | "always"
94 | ],
95 | "triple-equals": [
96 | true,
97 | "allow-null-check"
98 | ],
99 | "typedef-whitespace": [
100 | true,
101 | {
102 | "call-signature": "nospace",
103 | "index-signature": "nospace",
104 | "parameter": "nospace",
105 | "property-declaration": "nospace",
106 | "variable-declaration": "nospace"
107 | }
108 | ],
109 | "unified-signatures": true,
110 | "variable-name": false,
111 | "whitespace": [
112 | true,
113 | "check-branch",
114 | "check-decl",
115 | "check-operator",
116 | "check-separator",
117 | "check-type"
118 | ],
119 | "no-output-on-prefix": true,
120 | "no-inputs-metadata-property": true,
121 | "no-outputs-metadata-property": true,
122 | "no-host-metadata-property": true,
123 | "no-input-rename": true,
124 | "no-output-rename": true,
125 | "use-lifecycle-interface": true,
126 | "use-pipe-transform-interface": true,
127 | "component-class-suffix": true,
128 | "directive-class-suffix": true
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/Template/Startup.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.AspNetCore.Hosting;
3 | using Microsoft.AspNetCore.HttpsPolicy;
4 | using Microsoft.AspNetCore.SpaServices.AngularCli;
5 | using Microsoft.Extensions.Configuration;
6 | using Microsoft.Extensions.DependencyInjection;
7 | using Microsoft.Extensions.Hosting;
8 | using Template.Data.Context;
9 | using Microsoft.EntityFrameworkCore;
10 | using Template.IoC;
11 | using Template.Application.AutoMapper;
12 | using AutoMapper;
13 | using Template.Swagger;
14 | using System.Text;
15 | using Template.Auth.Models;
16 | using Microsoft.AspNetCore.Authentication.JwtBearer;
17 | using Microsoft.IdentityModel.Tokens;
18 |
19 | namespace Template
20 | {
21 | public class Startup
22 | {
23 | public Startup(IConfiguration configuration)
24 | {
25 | Configuration = configuration;
26 | }
27 |
28 | public IConfiguration Configuration { get; }
29 |
30 | // This method gets called by the runtime. Use this method to add services to the container.
31 | public void ConfigureServices(IServiceCollection services)
32 | {
33 | services.AddControllersWithViews();
34 |
35 | services.AddDbContext(opt => opt.UseSqlServer(Configuration.GetConnectionString("TemplateDB")).EnableSensitiveDataLogging());
36 | NativeInjector.RegisterServices(services);
37 |
38 | services.AddAutoMapper(typeof(AutoMapperSetup));
39 | services.AddSwaggerConfiguration();
40 |
41 | var key = Encoding.ASCII.GetBytes(Settings.Secret);
42 | services.AddAuthentication(x =>
43 | {
44 | x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
45 | x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
46 | }).AddJwtBearer(x =>
47 | {
48 | x.RequireHttpsMetadata = false;
49 | x.SaveToken = true;
50 | x.TokenValidationParameters = new TokenValidationParameters
51 | {
52 | ValidateIssuerSigningKey = true,
53 | IssuerSigningKey = new SymmetricSecurityKey(key),
54 | ValidateIssuer = false,
55 | ValidateAudience = false
56 | };
57 | });
58 |
59 |
60 | // In production, the Angular files will be served from this directory
61 | services.AddSpaStaticFiles(configuration =>
62 | {
63 | configuration.RootPath = "ClientApp/dist";
64 | });
65 | }
66 |
67 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
68 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
69 | {
70 | if (env.IsDevelopment())
71 | {
72 | app.UseDeveloperExceptionPage();
73 | }
74 | else
75 | {
76 | app.UseExceptionHandler("/Error");
77 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
78 | app.UseHsts();
79 | }
80 |
81 | app.UseSwaggerConfiguration();
82 |
83 | app.UseHttpsRedirection();
84 | app.UseStaticFiles();
85 | if (!env.IsDevelopment())
86 | {
87 | app.UseSpaStaticFiles();
88 | }
89 |
90 | app.UseRouting();
91 |
92 | app.UseAuthentication();
93 | app.UseAuthorization();
94 |
95 | app.UseEndpoints(endpoints =>
96 | {
97 | endpoints.MapControllerRoute(
98 | name: "default",
99 | pattern: "{controller}/{action=Index}/{id?}");
100 | });
101 |
102 | app.UseSpa(spa =>
103 | {
104 | // To learn more about options for serving an Angular SPA from ASP.NET Core,
105 | // see https://go.microsoft.com/fwlink/?linkid=864501
106 |
107 | spa.Options.SourcePath = "ClientApp";
108 |
109 | if (env.IsDevelopment())
110 | {
111 | spa.UseAngularCliServer(npmScript: "start");
112 | }
113 | });
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/Template.Application.Tests/Services/UserServiceTests.cs:
--------------------------------------------------------------------------------
1 | using AutoMapper;
2 | using Moq;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.ComponentModel.DataAnnotations;
6 | using Template.Application.AutoMapper;
7 | using Template.Application.Services;
8 | using Template.Application.ViewModels;
9 | using Template.Domain.Entities;
10 | using Template.Domain.Interfaces;
11 | using Xunit;
12 |
13 | namespace Template.Application.Tests.Services
14 | {
15 | public class UserServiceTests
16 | {
17 | private UserService userService;
18 |
19 | public UserServiceTests()
20 | {
21 | userService = new UserService(new Mock().Object, new Mock().Object);
22 | }
23 |
24 | #region ValidatingSendingID
25 |
26 | [Fact]
27 | public void Post_SendingValidId()
28 | {
29 | var exception = Assert.Throws(() => userService.Post(new UserViewModel { Id = Guid.NewGuid() }));
30 | Assert.Equal("UserID must be empty", exception.Message);
31 | }
32 |
33 | [Fact]
34 | public void GetById_SendingEmptyGuid()
35 | {
36 | var exception = Assert.Throws(() => userService.GetById(""));
37 | Assert.Equal("UserID is not valid", exception.Message);
38 | }
39 |
40 | [Fact]
41 | public void Put_SendingEmptyGuid()
42 | {
43 | var exception = Assert.Throws(() => userService.Put(new UserViewModel()));
44 | Assert.Equal("ID is invalid", exception.Message);
45 | }
46 |
47 | [Fact]
48 | public void Delete_SendingEmptyGuid()
49 | {
50 | var exception = Assert.Throws(() => userService.Delete(""));
51 | Assert.Equal("UserID is not valid", exception.Message);
52 | }
53 |
54 | [Fact]
55 | public void Authenticate_SendingEmptyValues()
56 | {
57 | var exception = Assert.Throws(() => userService.Authenticate(new UserAuthenticateRequestViewModel()));
58 | Assert.Equal("Email/Password are required.", exception.Message);
59 | }
60 |
61 | #endregion
62 |
63 | #region ValidatingCorrectObject
64 |
65 | [Fact]
66 | public void Post_SendingValidObject()
67 | {
68 | var result = userService.Post(new UserViewModel { Name = "Nicolas Fontes", Email = "nicolas.rfontes@gmail.com" });
69 | Assert.True(result);
70 | }
71 |
72 | [Fact]
73 | public void Get_ValidatingObject()
74 | {
75 | //Criando a lista com um objeto para que seja retornado pelo repository
76 | List _users = new List();
77 | _users.Add(new User { Id = Guid.NewGuid(), Name = "Nicolas Fontes", Email = "nicolas.rfontes@gmail.com", DateCreated = DateTime.Now });
78 | //Criando um objeto mock do UserRepository e configurando para retornar a lista criada anteriormente se chamar o método GetAll()
79 | var _userRepository = new Mock();
80 | _userRepository.Setup(x => x.GetAll()).Returns(_users);
81 | //Criando um objeto mock do AutoMapper para que possamos converter o retorno para o tipo List()
82 | var _autoMapperProfile = new AutoMapperSetup();
83 | var _configuration = new MapperConfiguration(x => x.AddProfile(_autoMapperProfile));
84 | IMapper _mapper = new Mapper(_configuration);
85 | //Istanciando nossa classe de serviço novamente com os novos objetos mocks que criamos
86 | userService = new UserService(_userRepository.Object, _mapper);
87 | //Obtendo os valores do método Get para validar se vai retornar o objeto criado acima.
88 | var result = userService.Get();
89 | //Validando se o retorno contém uma lista com objetos.
90 | Assert.True(result.Count > 0);
91 | }
92 |
93 | #endregion
94 |
95 | #region ValidatingRequiredFields
96 |
97 | [Fact]
98 | public void Post_SendingInvalidObject()
99 | {
100 | var exception = Assert.Throws(() => userService.Post(new UserViewModel { Name = "Nicolas Fontes" }));
101 | Assert.Equal("The Email field is required.", exception.Message);
102 | }
103 |
104 | #endregion
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/Template/Template.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 | true
6 | Latest
7 | false
8 | ClientApp\
9 | $(DefaultItemExcludes);$(SpaRoot)node_modules\**
10 |
11 |
12 | false
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | all
22 | runtime; build; native; contentfiles; analyzers; buildtransitive
23 |
24 |
25 |
26 | all
27 | runtime; build; native; contentfiles; analyzers; buildtransitive
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | %(DistFiles.Identity)
79 | PreserveNewest
80 | true
81 |
82 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | build/
21 | bld/
22 | bin/
23 | Bin/
24 | obj/
25 | Obj/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | *.lock
30 |
31 | # MSTest test Results
32 | [Tt]est[Rr]esult*/
33 | [Bb]uild[Ll]og.*
34 |
35 | # NUNIT
36 | *.VisualState.xml
37 | TestResult.xml
38 |
39 | # Build Results of an ATL Project
40 | [Dd]ebugPS/
41 | [Rr]eleasePS/
42 | dlldata.c
43 |
44 | *_i.c
45 | *_p.c
46 | *_i.h
47 | *.ilk
48 | *.meta
49 | *.obj
50 | *.pch
51 | *.pdb
52 | *.pgc
53 | *.pgd
54 | *.rsp
55 | *.sbr
56 | *.tlb
57 | *.tli
58 | *.tlh
59 | *.tmp
60 | *.tmp_proj
61 | *.log
62 | *.vspscc
63 | *.vssscc
64 | .builds
65 | *.pidb
66 | *.svclog
67 | *.scc
68 |
69 | # Chutzpah Test files
70 | _Chutzpah*
71 |
72 | # Visual C++ cache files
73 | ipch/
74 | *.aps
75 | *.ncb
76 | *.opendb
77 | *.opensdf
78 | *.sdf
79 | *.cachefile
80 |
81 | # Visual Studio profiler
82 | *.psess
83 | *.vsp
84 | *.vspx
85 | *.sap
86 |
87 | # TFS 2012 Local Workspace
88 | $tf/
89 |
90 | # Guidance Automation Toolkit
91 | *.gpState
92 |
93 | # ReSharper is a .NET coding add-in
94 | _ReSharper*/
95 | *.[Rr]e[Ss]harper
96 | *.DotSettings.user
97 |
98 | # JustCode is a .NET coding add-in
99 | .JustCode
100 |
101 | # TeamCity is a build add-in
102 | _TeamCity*
103 |
104 | # DotCover is a Code Coverage Tool
105 | *.dotCover
106 |
107 | # NCrunch
108 | _NCrunch_*
109 | .*crunch*.local.xml
110 | nCrunchTemp_*
111 |
112 | # MightyMoose
113 | *.mm.*
114 | AutoTest.Net/
115 |
116 | # Web workbench (sass)
117 | .sass-cache/
118 |
119 | # Installshield output folder
120 | [Ee]xpress/
121 |
122 | # DocProject is a documentation generator add-in
123 | DocProject/buildhelp/
124 | DocProject/Help/*.HxT
125 | DocProject/Help/*.HxC
126 | DocProject/Help/*.hhc
127 | DocProject/Help/*.hhk
128 | DocProject/Help/*.hhp
129 | DocProject/Help/Html2
130 | DocProject/Help/html
131 |
132 | # Click-Once directory
133 | publish/
134 |
135 | # Publish Web Output
136 | *.[Pp]ublish.xml
137 | *.azurePubxml
138 | # TODO: Comment the next line if you want to checkin your web deploy settings
139 | # but database connection strings (with potential passwords) will be unencrypted
140 | *.pubxml
141 | *.publishproj
142 |
143 | # NuGet Packages
144 | *.nupkg
145 | # The packages folder can be ignored because of Package Restore
146 | **/packages/*
147 | # except build/, which is used as an MSBuild target.
148 | !**/packages/build/
149 | # Uncomment if necessary however generally it will be regenerated when needed
150 | #!**/packages/repositories.config
151 |
152 | # Microsoft Azure Build Output
153 | csx/
154 | *.build.csdef
155 |
156 | # Microsoft Azure Emulator
157 | ecf/
158 | rcf/
159 |
160 | # Microsoft Azure ApplicationInsights config file
161 | ApplicationInsights.config
162 |
163 | # Windows Store app package directory
164 | AppPackages/
165 | BundleArtifacts/
166 |
167 | # Visual Studio cache files
168 | # files ending in .cache can be ignored
169 | *.[Cc]ache
170 | # but keep track of directories ending in .cache
171 | !*.[Cc]ache/
172 |
173 | # Others
174 | ClientBin/
175 | ~$*
176 | *~
177 | *.dbmdl
178 | *.dbproj.schemaview
179 | *.pfx
180 | *.publishsettings
181 | orleans.codegen.cs
182 |
183 | /node_modules
184 |
185 | # RIA/Silverlight projects
186 | Generated_Code/
187 |
188 | # Backup & report files from converting an old project file
189 | # to a newer Visual Studio version. Backup files are not needed,
190 | # because we have git ;-)
191 | _UpgradeReport_Files/
192 | Backup*/
193 | UpgradeLog*.XML
194 | UpgradeLog*.htm
195 |
196 | # SQL Server files
197 | *.mdf
198 | *.ldf
199 |
200 | # Business Intelligence projects
201 | *.rdl.data
202 | *.bim.layout
203 | *.bim_*.settings
204 |
205 | # Microsoft Fakes
206 | FakesAssemblies/
207 |
208 | # GhostDoc plugin setting file
209 | *.GhostDoc.xml
210 |
211 | # Node.js Tools for Visual Studio
212 | .ntvs_analysis.dat
213 |
214 | # Visual Studio 6 build log
215 | *.plg
216 |
217 | # Visual Studio 6 workspace options file
218 | *.opt
219 |
220 | # Visual Studio LightSwitch build output
221 | **/*.HTMLClient/GeneratedArtifacts
222 | **/*.DesktopClient/GeneratedArtifacts
223 | **/*.DesktopClient/ModelManifest.xml
224 | **/*.Server/GeneratedArtifacts
225 | **/*.Server/ModelManifest.xml
226 | _Pvt_Extensions
227 |
228 | # Paket dependency manager
229 | .paket/paket.exe
230 |
231 | # FAKE - F# Make
232 | .fake/
233 |
--------------------------------------------------------------------------------
/Template.Application/Services/UserService.cs:
--------------------------------------------------------------------------------
1 | using AutoMapper;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.ComponentModel.DataAnnotations;
5 | using System.Security.Cryptography;
6 | using System.Text;
7 | using Template.Application.Interfaces;
8 | using Template.Application.ViewModels;
9 | using Template.Auth.Services;
10 | using Template.Domain.Entities;
11 | using Template.Domain.Interfaces;
12 | using ValidationContext = System.ComponentModel.DataAnnotations.ValidationContext;
13 |
14 | namespace Template.Application.Services
15 | {
16 | public class UserService : IUserService
17 | {
18 |
19 | private readonly IUserRepository userRepository;
20 | private readonly IMapper mapper;
21 |
22 | public UserService(IUserRepository userRepository, IMapper mapper)
23 | {
24 | this.userRepository = userRepository;
25 | this.mapper = mapper;
26 | }
27 |
28 | public List Get()
29 | {
30 | IEnumerable _users = this.userRepository.GetAll();
31 |
32 | List _userViewModels = mapper.Map>(_users);
33 |
34 | return _userViewModels;
35 | }
36 |
37 | public bool Post(UserViewModel userViewModel)
38 | {
39 | if (userViewModel.Id != Guid.Empty)
40 | throw new Exception("UserID must be empty");
41 |
42 | Validator.ValidateObject(userViewModel, new ValidationContext(userViewModel), true);
43 |
44 | User _user = mapper.Map(userViewModel);
45 | _user.Password = EncryptPassword(_user.Password);
46 |
47 | this.userRepository.Create(_user);
48 |
49 | return true;
50 | }
51 |
52 | public UserViewModel GetById(string id)
53 | {
54 | if (!Guid.TryParse(id, out Guid userId))
55 | throw new Exception("UserID is not valid");
56 |
57 | User _user = this.userRepository.Find(x => x.Id == userId && !x.IsDeleted);
58 | if (_user == null)
59 | throw new Exception("User not found");
60 |
61 | return mapper.Map(_user);
62 | }
63 |
64 | public bool Put(UserViewModel userViewModel)
65 | {
66 | if (userViewModel.Id == Guid.Empty)
67 | throw new Exception("ID is invalid");
68 |
69 | User _user = this.userRepository.Find(x => x.Id == userViewModel.Id && !x.IsDeleted);
70 | if (_user == null)
71 | throw new Exception("User not found");
72 |
73 | _user = mapper.Map(userViewModel);
74 | _user.Password = EncryptPassword(_user.Password);
75 |
76 | this.userRepository.Update(_user);
77 |
78 | return true;
79 | }
80 |
81 | public bool Delete(string id)
82 | {
83 | if (!Guid.TryParse(id, out Guid userId))
84 | throw new Exception("UserID is not valid");
85 |
86 | User _user = this.userRepository.Find(x => x.Id == userId && !x.IsDeleted);
87 | if (_user == null)
88 | throw new Exception("User not found");
89 |
90 | return this.userRepository.Delete(_user);
91 | }
92 |
93 | public UserAuthenticateResponseViewModel Authenticate(UserAuthenticateRequestViewModel user)
94 | {
95 | if (string.IsNullOrEmpty(user.Email) || string.IsNullOrEmpty(user.Password))
96 | throw new Exception("Email/Password are required.");
97 |
98 | user.Password = EncryptPassword(user.Password);
99 |
100 | User _user = this.userRepository.Find(x => !x.IsDeleted && x.Email.ToLower() == user.Email.ToLower()
101 | && x.Password.ToLower() == user.Password.ToLower());
102 | if (_user == null)
103 | throw new Exception("User not found");
104 |
105 | return new UserAuthenticateResponseViewModel(mapper.Map(_user), TokenService.GenerateToken(_user));
106 | }
107 |
108 | private string EncryptPassword(string password)
109 | {
110 | HashAlgorithm sha = new SHA1CryptoServiceProvider();
111 |
112 | byte[] encryptedPassword = sha.ComputeHash(Encoding.UTF8.GetBytes(password));
113 |
114 | StringBuilder stringBuilder = new StringBuilder();
115 | foreach (var caracter in encryptedPassword)
116 | {
117 | stringBuilder.Append(caracter.ToString("X2"));
118 | }
119 |
120 | return stringBuilder.ToString();
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/Template/ClientApp/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "Template": {
7 | "root": "",
8 | "sourceRoot": "src",
9 | "projectType": "application",
10 | "prefix": "app",
11 | "schematics": {},
12 | "architect": {
13 | "build": {
14 | "builder": "@angular-devkit/build-angular:browser",
15 | "options": {
16 | "progress": false,
17 | "extractCss": true,
18 | "outputPath": "dist",
19 | "index": "src/index.html",
20 | "main": "src/main.ts",
21 | "polyfills": "src/polyfills.ts",
22 | "tsConfig": "src/tsconfig.app.json",
23 | "assets": ["src/assets"],
24 | "styles": [
25 | "node_modules/bootstrap/dist/css/bootstrap.min.css",
26 | "src/styles.css"
27 | ],
28 | "scripts": []
29 | },
30 | "configurations": {
31 | "production": {
32 | "fileReplacements": [
33 | {
34 | "replace": "src/environments/environment.ts",
35 | "with": "src/environments/environment.prod.ts"
36 | }
37 | ],
38 | "optimization": true,
39 | "outputHashing": "all",
40 | "sourceMap": false,
41 | "extractCss": true,
42 | "namedChunks": false,
43 | "aot": true,
44 | "extractLicenses": true,
45 | "vendorChunk": false,
46 | "buildOptimizer": true
47 | }
48 | }
49 | },
50 | "serve": {
51 | "builder": "@angular-devkit/build-angular:dev-server",
52 | "options": {
53 | "browserTarget": "Template:build"
54 | },
55 | "configurations": {
56 | "production": {
57 | "browserTarget": "Template:build:production"
58 | }
59 | }
60 | },
61 | "extract-i18n": {
62 | "builder": "@angular-devkit/build-angular:extract-i18n",
63 | "options": {
64 | "browserTarget": "Template:build"
65 | }
66 | },
67 | "test": {
68 | "builder": "@angular-devkit/build-angular:karma",
69 | "options": {
70 | "main": "src/test.ts",
71 | "polyfills": "src/polyfills.ts",
72 | "tsConfig": "src/tsconfig.spec.json",
73 | "karmaConfig": "src/karma.conf.js",
74 | "styles": ["src/styles.css"],
75 | "scripts": [],
76 | "assets": ["src/assets"]
77 | }
78 | },
79 | "lint": {
80 | "builder": "@angular-devkit/build-angular:tslint",
81 | "options": {
82 | "tsConfig": ["src/tsconfig.app.json", "src/tsconfig.spec.json"],
83 | "exclude": ["**/node_modules/**"]
84 | }
85 | },
86 | "server": {
87 | "builder": "@angular-devkit/build-angular:server",
88 | "options": {
89 | "outputPath": "dist-server",
90 | "main": "src/main.ts",
91 | "tsConfig": "src/tsconfig.server.json"
92 | },
93 | "configurations": {
94 | "dev": {
95 | "optimization": true,
96 | "outputHashing": "all",
97 | "sourceMap": false,
98 | "namedChunks": false,
99 | "extractLicenses": true,
100 | "vendorChunk": true
101 | },
102 | "production": {
103 | "optimization": true,
104 | "outputHashing": "all",
105 | "sourceMap": false,
106 | "namedChunks": false,
107 | "extractLicenses": true,
108 | "vendorChunk": false
109 | }
110 | }
111 | }
112 | }
113 | },
114 | "Template-e2e": {
115 | "root": "e2e/",
116 | "projectType": "application",
117 | "architect": {
118 | "e2e": {
119 | "builder": "@angular-devkit/build-angular:protractor",
120 | "options": {
121 | "protractorConfig": "e2e/protractor.conf.js",
122 | "devServerTarget": "Template:serve"
123 | }
124 | },
125 | "lint": {
126 | "builder": "@angular-devkit/build-angular:tslint",
127 | "options": {
128 | "tsConfig": "e2e/tsconfig.e2e.json",
129 | "exclude": ["**/node_modules/**"]
130 | }
131 | }
132 | }
133 | }
134 | },
135 | "defaultProject": "Template"
136 | }
137 |
--------------------------------------------------------------------------------
/Template.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29806.167
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Template", "Template\Template.csproj", "{6320DFD8-E27B-4E4B-912F-BFD2951ECD83}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1-Web", "1-Web", "{5FDDA9FF-71E5-4C2C-9DAB-8EB130EE9410}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2-Application", "2-Application", "{5ADA0AA9-2348-4872-9BE6-05B5935E77ED}"
11 | EndProject
12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3-Domain", "3-Domain", "{CA5C55F7-FBA6-42FC-B21D-9175306A4897}"
13 | EndProject
14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4-Infra", "4-Infra", "{32B5710B-7A1E-4490-BF06-E9940194DAD1}"
15 | EndProject
16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Template.Application", "Template.Application\Template.Application.csproj", "{EC79EA08-438C-4ED8-BD16-9C1975A9756F}"
17 | EndProject
18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Template.Domain", "Template.Domain\Template.Domain.csproj", "{B5A019DD-7D6D-4EBC-BE6F-D8317F0059CE}"
19 | EndProject
20 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4.1-Data", "4.1-Data", "{CA6EFB8A-8096-44F6-92C4-C1D3D358B126}"
21 | EndProject
22 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4.2-CrossCutting", "4.2-CrossCutting", "{D1622043-B330-4635-A337-284F24CD86C6}"
23 | EndProject
24 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Template.Data", "Template.Data\Template.Data.csproj", "{6E215AC8-4ADD-4327-8E09-496D86A7866E}"
25 | EndProject
26 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Template.IoC", "Template.IoC\Template.IoC.csproj", "{EBB690B0-6FC8-49FE-BCF9-E649B086718B}"
27 | EndProject
28 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Template.Swagger", "Template.Swagger\Template.Swagger.csproj", "{43BD5FC5-686A-47C3-8B0D-C479ABD05F16}"
29 | EndProject
30 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Template.Auth", "Template.Auth\Template.Auth.csproj", "{1A3A29A3-99CC-4EAF-B947-55DCAC33767B}"
31 | EndProject
32 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "0-Tests", "0-Tests", "{971A04D8-EB17-42ED-971C-F52C8ED4AB8A}"
33 | EndProject
34 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Template.Application.Tests", "Template.Application.Tests\Template.Application.Tests.csproj", "{352A6888-B09B-4248-83E0-2C00A32675D8}"
35 | EndProject
36 | Global
37 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
38 | Debug|Any CPU = Debug|Any CPU
39 | Release|Any CPU = Release|Any CPU
40 | EndGlobalSection
41 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
42 | {6320DFD8-E27B-4E4B-912F-BFD2951ECD83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
43 | {6320DFD8-E27B-4E4B-912F-BFD2951ECD83}.Debug|Any CPU.Build.0 = Debug|Any CPU
44 | {6320DFD8-E27B-4E4B-912F-BFD2951ECD83}.Release|Any CPU.ActiveCfg = Release|Any CPU
45 | {6320DFD8-E27B-4E4B-912F-BFD2951ECD83}.Release|Any CPU.Build.0 = Release|Any CPU
46 | {EC79EA08-438C-4ED8-BD16-9C1975A9756F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
47 | {EC79EA08-438C-4ED8-BD16-9C1975A9756F}.Debug|Any CPU.Build.0 = Debug|Any CPU
48 | {EC79EA08-438C-4ED8-BD16-9C1975A9756F}.Release|Any CPU.ActiveCfg = Release|Any CPU
49 | {EC79EA08-438C-4ED8-BD16-9C1975A9756F}.Release|Any CPU.Build.0 = Release|Any CPU
50 | {B5A019DD-7D6D-4EBC-BE6F-D8317F0059CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
51 | {B5A019DD-7D6D-4EBC-BE6F-D8317F0059CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
52 | {B5A019DD-7D6D-4EBC-BE6F-D8317F0059CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
53 | {B5A019DD-7D6D-4EBC-BE6F-D8317F0059CE}.Release|Any CPU.Build.0 = Release|Any CPU
54 | {6E215AC8-4ADD-4327-8E09-496D86A7866E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
55 | {6E215AC8-4ADD-4327-8E09-496D86A7866E}.Debug|Any CPU.Build.0 = Debug|Any CPU
56 | {6E215AC8-4ADD-4327-8E09-496D86A7866E}.Release|Any CPU.ActiveCfg = Release|Any CPU
57 | {6E215AC8-4ADD-4327-8E09-496D86A7866E}.Release|Any CPU.Build.0 = Release|Any CPU
58 | {EBB690B0-6FC8-49FE-BCF9-E649B086718B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
59 | {EBB690B0-6FC8-49FE-BCF9-E649B086718B}.Debug|Any CPU.Build.0 = Debug|Any CPU
60 | {EBB690B0-6FC8-49FE-BCF9-E649B086718B}.Release|Any CPU.ActiveCfg = Release|Any CPU
61 | {EBB690B0-6FC8-49FE-BCF9-E649B086718B}.Release|Any CPU.Build.0 = Release|Any CPU
62 | {43BD5FC5-686A-47C3-8B0D-C479ABD05F16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
63 | {43BD5FC5-686A-47C3-8B0D-C479ABD05F16}.Debug|Any CPU.Build.0 = Debug|Any CPU
64 | {43BD5FC5-686A-47C3-8B0D-C479ABD05F16}.Release|Any CPU.ActiveCfg = Release|Any CPU
65 | {43BD5FC5-686A-47C3-8B0D-C479ABD05F16}.Release|Any CPU.Build.0 = Release|Any CPU
66 | {1A3A29A3-99CC-4EAF-B947-55DCAC33767B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
67 | {1A3A29A3-99CC-4EAF-B947-55DCAC33767B}.Debug|Any CPU.Build.0 = Debug|Any CPU
68 | {1A3A29A3-99CC-4EAF-B947-55DCAC33767B}.Release|Any CPU.ActiveCfg = Release|Any CPU
69 | {1A3A29A3-99CC-4EAF-B947-55DCAC33767B}.Release|Any CPU.Build.0 = Release|Any CPU
70 | {352A6888-B09B-4248-83E0-2C00A32675D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
71 | {352A6888-B09B-4248-83E0-2C00A32675D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
72 | {352A6888-B09B-4248-83E0-2C00A32675D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
73 | {352A6888-B09B-4248-83E0-2C00A32675D8}.Release|Any CPU.Build.0 = Release|Any CPU
74 | EndGlobalSection
75 | GlobalSection(SolutionProperties) = preSolution
76 | HideSolutionNode = FALSE
77 | EndGlobalSection
78 | GlobalSection(NestedProjects) = preSolution
79 | {6320DFD8-E27B-4E4B-912F-BFD2951ECD83} = {5FDDA9FF-71E5-4C2C-9DAB-8EB130EE9410}
80 | {EC79EA08-438C-4ED8-BD16-9C1975A9756F} = {5ADA0AA9-2348-4872-9BE6-05B5935E77ED}
81 | {B5A019DD-7D6D-4EBC-BE6F-D8317F0059CE} = {CA5C55F7-FBA6-42FC-B21D-9175306A4897}
82 | {CA6EFB8A-8096-44F6-92C4-C1D3D358B126} = {32B5710B-7A1E-4490-BF06-E9940194DAD1}
83 | {D1622043-B330-4635-A337-284F24CD86C6} = {32B5710B-7A1E-4490-BF06-E9940194DAD1}
84 | {6E215AC8-4ADD-4327-8E09-496D86A7866E} = {CA6EFB8A-8096-44F6-92C4-C1D3D358B126}
85 | {EBB690B0-6FC8-49FE-BCF9-E649B086718B} = {D1622043-B330-4635-A337-284F24CD86C6}
86 | {43BD5FC5-686A-47C3-8B0D-C479ABD05F16} = {D1622043-B330-4635-A337-284F24CD86C6}
87 | {1A3A29A3-99CC-4EAF-B947-55DCAC33767B} = {D1622043-B330-4635-A337-284F24CD86C6}
88 | {352A6888-B09B-4248-83E0-2C00A32675D8} = {971A04D8-EB17-42ED-971C-F52C8ED4AB8A}
89 | EndGlobalSection
90 | GlobalSection(ExtensibilityGlobals) = postSolution
91 | SolutionGuid = {F53D0144-A66D-447B-87B9-5ACE17D16941}
92 | EndGlobalSection
93 | EndGlobal
94 |
--------------------------------------------------------------------------------
/Template.Data/Repositories/Repository.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.EntityFrameworkCore.ChangeTracking;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Linq.Expressions;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using Template.Data.Context;
10 | using Template.Domain.Interfaces;
11 | using Template.Domain.Models;
12 |
13 | namespace Template.Data.Repositories
14 | {
15 | public class Repository : IRepository where TEntity : class
16 | {
17 | #region 'Properties'
18 |
19 | protected readonly TemplateContext _context;
20 |
21 | protected DbSet DbSet
22 | {
23 | get
24 | {
25 | return _context.Set();
26 | }
27 | }
28 |
29 | #endregion
30 |
31 | public Repository(TemplateContext context)
32 | {
33 | _context = context;
34 | }
35 |
36 | #region 'Methods: Create/Update/Remove/Save'
37 |
38 | public TEntity Create(TEntity model)
39 | {
40 | try
41 | {
42 | DbSet.Add(model);
43 | Save();
44 | return model;
45 | }
46 | catch (Exception)
47 | {
48 |
49 | throw;
50 | }
51 | }
52 |
53 | public List Create(List models)
54 | {
55 | try
56 | {
57 | DbSet.AddRange(models);
58 | Save();
59 | return models;
60 | }
61 | catch (Exception)
62 | {
63 | throw;
64 | }
65 | }
66 |
67 | public bool Update(TEntity model)
68 | {
69 | try
70 | {
71 | EntityEntry entry = NewMethod(model);
72 |
73 | DbSet.Attach(model);
74 |
75 | entry.State = EntityState.Modified;
76 |
77 | return Save() > 0;
78 | }
79 | catch (Exception)
80 | {
81 |
82 | throw;
83 | }
84 | }
85 |
86 | private EntityEntry NewMethod(TEntity model)
87 | {
88 | return _context.Entry(model);
89 | }
90 |
91 | public bool Update(List models)
92 | {
93 | try
94 | {
95 | foreach (TEntity register in models)
96 | {
97 | EntityEntry entry = _context.Entry(register);
98 | DbSet.Attach(register);
99 | entry.State = EntityState.Modified;
100 | }
101 |
102 | return Save() > 0;
103 | }
104 | catch (Exception)
105 | {
106 |
107 | throw;
108 | }
109 | }
110 |
111 | public bool Delete(TEntity model)
112 | {
113 | try
114 | {
115 | if (model is Entity)
116 | {
117 | (model as Entity).IsDeleted = true;
118 | EntityEntry _entry = _context.Entry(model);
119 |
120 | DbSet.Attach(model);
121 |
122 | _entry.State = EntityState.Modified;
123 | }
124 | else
125 | {
126 | EntityEntry _entry = _context.Entry(model);
127 | DbSet.Attach(model);
128 | _entry.State = EntityState.Deleted;
129 | }
130 |
131 | return Save() > 0;
132 | }
133 | catch (Exception)
134 | {
135 | throw;
136 | }
137 | }
138 |
139 | public bool Delete(params object[] Keys)
140 | {
141 | try
142 | {
143 | TEntity model = DbSet.Find(Keys);
144 | return (model != null) && Delete(model);
145 | }
146 | catch (Exception)
147 | {
148 |
149 | throw;
150 | }
151 | }
152 |
153 | public bool Delete(Expression> where)
154 | {
155 | try
156 | {
157 | TEntity model = DbSet.Where(where).FirstOrDefault();
158 |
159 | return (model != null) && Delete(model);
160 | }
161 | catch (Exception)
162 | {
163 |
164 | throw;
165 | }
166 | }
167 |
168 | public int Save()
169 | {
170 | try
171 | {
172 | return _context.SaveChanges();
173 | }
174 | catch (Exception)
175 | {
176 |
177 | throw;
178 | }
179 | }
180 |
181 | #endregion
182 |
183 | #region 'Methods: Search'
184 |
185 | public TEntity Find(params object[] Keys)
186 | {
187 | try
188 | {
189 | return DbSet.Find(Keys);
190 | }
191 | catch (Exception)
192 | {
193 |
194 | throw;
195 | }
196 | }
197 |
198 | public TEntity Find(Expression> where)
199 | {
200 | try
201 | {
202 | return DbSet.AsNoTracking().FirstOrDefault(where);
203 | }
204 | catch (Exception)
205 | {
206 |
207 | throw;
208 | }
209 | }
210 |
211 | public TEntity Find(Expression> predicate, Func, object> includes)
212 | {
213 | try
214 | {
215 | IQueryable _query = DbSet;
216 |
217 | if (includes != null)
218 | _query = includes(_query) as IQueryable;
219 |
220 | return _query.SingleOrDefault(predicate);
221 | }
222 | catch (Exception)
223 | {
224 |
225 | throw;
226 | }
227 | }
228 |
229 | public IQueryable Query(Expression> where)
230 | {
231 | try
232 | {
233 | return DbSet.Where(where);
234 | }
235 | catch (Exception)
236 | {
237 |
238 | throw;
239 | }
240 | }
241 | //Func, IIncludableQueryable> include
242 | public IQueryable Query(Expression> predicate, Func, object> includes)
243 | {
244 | try
245 | {
246 | IQueryable _query = DbSet;
247 |
248 | if (includes != null)
249 | _query = includes(_query) as IQueryable;
250 |
251 | return _query.Where(predicate).AsQueryable();
252 | }
253 | catch (Exception)
254 | {
255 |
256 | throw;
257 | }
258 | }
259 |
260 | #endregion
261 |
262 | #region 'Assyncronous Methods'
263 |
264 | public async Task CreateAsync(TEntity model)
265 | {
266 | try
267 | {
268 | DbSet.Add(model);
269 | await SaveAsync();
270 | return model;
271 | }
272 | catch (Exception)
273 | {
274 |
275 | throw;
276 | }
277 | }
278 |
279 | public async Task UpdateAsync(TEntity model)
280 | {
281 | try
282 | {
283 | EntityEntry entry = _context.Entry(model);
284 |
285 | DbSet.Attach(model);
286 |
287 | entry.State = EntityState.Modified;
288 |
289 | return await SaveAsync() > 0;
290 | }
291 | catch (Exception)
292 | {
293 |
294 | throw;
295 | }
296 | }
297 |
298 | public async Task DeleteAsync(TEntity model)
299 | {
300 | try
301 | {
302 | EntityEntry entry = _context.Entry(model);
303 |
304 | DbSet.Attach(model);
305 |
306 | entry.State = EntityState.Deleted;
307 |
308 | return await SaveAsync() > 0;
309 | }
310 | catch (Exception)
311 | {
312 |
313 | throw;
314 | }
315 | }
316 |
317 | public async Task DeleteAsync(params object[] Keys)
318 | {
319 | try
320 | {
321 | TEntity model = DbSet.Find(Keys);
322 | return (model != null) && await DeleteAsync(model);
323 | }
324 | catch (Exception)
325 | {
326 |
327 | throw;
328 | }
329 | }
330 |
331 | public async Task DeleteAsync(Expression> where)
332 | {
333 | try
334 | {
335 | TEntity model = DbSet.FirstOrDefault(where);
336 |
337 | return (model != null) && await DeleteAsync(model);
338 | }
339 | catch (Exception)
340 | {
341 |
342 | throw;
343 | }
344 | }
345 |
346 | public async Task SaveAsync()
347 | {
348 | try
349 | {
350 | return await _context.SaveChangesAsync();
351 | }
352 | catch (Exception)
353 | {
354 |
355 | throw;
356 | }
357 | }
358 |
359 | #endregion
360 |
361 | #region 'Search Methods Async'
362 |
363 | public async Task GetAsync(params object[] Keys)
364 | {
365 | try
366 | {
367 | return await DbSet.FindAsync(Keys);
368 | }
369 | catch (Exception)
370 | {
371 |
372 | throw;
373 | }
374 | }
375 |
376 | public async Task GetAsync(Expression> where)
377 | {
378 | try
379 | {
380 | return await DbSet.AsNoTracking().FirstOrDefaultAsync(where);
381 | }
382 | catch (Exception)
383 | {
384 |
385 | throw;
386 | }
387 | }
388 |
389 | #endregion
390 |
391 |
392 | public void Dispose()
393 | {
394 | try
395 | {
396 | if (_context != null)
397 | _context.Dispose();
398 | GC.SuppressFinalize(this);
399 | }
400 | catch (Exception)
401 | {
402 |
403 | throw;
404 | }
405 | }
406 | }
407 |
408 | }
409 |
--------------------------------------------------------------------------------