Skip to content
/ REST Public
forked from fabiojansenbr/REST

REST com ASP.NET Core WebAPI integrado ao SPA Angular 7

Notifications You must be signed in to change notification settings

Wennlys/REST

 
 

Repository files navigation

inicialização back end (abrindo swagger)

ctrl + shift + b
inicializar na DevIO.Api

inicialização front end ( abrindo aplicação)

npm install
npm update 
npm start  
npm s 

soluções para possiveis erro na depedencia do front

npm cache clean --force
npm pkill node
npm install  

app em : https://github.com/alfredo1995/SPA7


Essa API recebe Request automaticamente da aplicação pelo verbo GET, acessando a base de dados 
através da class abstrata Repository que está sendo injetada através de uma interface injetada 
no construtor da Controller p/ n precisar passar pela camada de negocio, evitando autoacoplamento 

Retorna uma entidade de negocio convertido pelo Repository do Entity Framework e com AutoMap 
fazendo essa entidade virar uma DTO (Viewmodel) rertonando em json para o client

criar solution blank como projeto

project type> other > blank solution

blank solution

MinhaApiCompleta
C:\Users\Alfredo\source\repos
place solution and project in the same diretory

criar as pastas no setup da aplicação (raiz do projeto contenndo a sln e sln.DotSeting.user)

.vs
sql
src
teste

criar camadas dentro da pasta src> reaproveitando as camadas de projetos que realizei e estão nesse repositorio para focar na API

DevIo.Bunsiness  (camada de negocio)
DevIo.Data	 (camada de acesso ao dados)
DevIo.API	 (camada de aplicação)

Criar as camadas na Solution 'MinhaApiCompleta'

criar a camada DevIo.Bunsiness
criar a camada DevIo.Data
criar a camada DevIo.API

DevIo.Bunsiness

criada a pasta Models responsavel por :
casdastrar forncedor.cs que possui relacionamento com as entidades produto.cs, endereco.cs

criada a pasta Notifation responsavel por:
notificacao.cs entidade mandar notificaçao atravessando todas as camadas para chegar ate a api

criada a pasta Interface contendo as entidades responsavel por:
IEnderecoRepository.cs interage e apresenta dados ao usuário atraves de injeçao de depedencia

criada a pasta Service responsavel pelas regras de negocio:
produtoService.cs entidade contendo regra de negocio para cadastra novos produtos
fornecedor.cs entidade contendo regra de negocio para cadastra novos fornecedores

DevIo.Data

criada a pasta Context contendo as entidades responsavel por :
consultar um banco de dados e agrupar as alterações que serão gravadas
MeuDbContext : dbContext contexto do efcore contendo as tabelas referente as entidade da models

criada a pasta Mappings contendo as entidades responsavel por :
Mapear as tabelas para configurar o mapeamento do banco de dados 

criada a pasta Repository contendo as entidades responsavel por :
Implementação dos repositorios genericos e especializados

DevIo.Bunsiness

Criada a pasta models contento as entidades 	

criada a class Fornecedor.cs

using System;
using System.Collections.Generic;

namespace DevIO.Business.Models
{
	public class Fornecedor : Entity
	{
		public string Nome { get; set; }
		public string Documento { get; set; }
		public TipoFornecedor TipoFornecedor { get; set; }
		public Endereco Endereco { get; set; }
		public bool Ativo { get; set; }

		/* EF Relations */
		public IEnumerable<Produto> Produtos { get; set; }
	}
}

criada a class Endereco.cs

using System;

namespace DevIO.Business.Models
{
	public class Endereco : Entity
	{
		public Guid FornecedorId { get; set; }
		public string Logradouro { get; set; }
		public string Numero { get; set; }
		public string Complemento { get; set; }
		public string Cep { get; set; }
		public string Bairro { get; set; }
		public string Cidade { get; set; }
		public string Estado { get; set; }

		/* EF Relation */
		public Fornecedor Fornecedor { get; set; }
	}
}

Criada a class Produto.cs

using System;

namespace DevIO.Business.Models
{
	public class Produto : Entity
	{
		public Guid FornecedorId { get; set; }

		public string Nome { get; set; }
		public string Descricao { get; set; }
		public string Imagem { get; set; }
		public decimal Valor { get; set; }
		public DateTime DataCadastro { get; set; }
		public bool Ativo { get; set; }

		/* EF Relations */
		public Fornecedor Fornecedor { get; set; }
	}
}

criada a class TipoFornecedor.cs

namespace DevIO.Business.Models
{
	public enum TipoFornecedor
	{
		PessoaFisica = 1,
		PessoaJuridica
	}
}

criada class complementando Entity.cs

using System;

namespace DevIO.Business.Models
{
	public abstract class Entity
	{
		protected Entity()
		{
			Id = Guid.NewGuid();
		}

		public Guid Id { get; set; }
	}
}

DevIo.Bunsiness

Criada a pasta Notificacoes contento as entidades 

criada a class Notificacoes.cs

namespace DevIO.Business.Notificacoes
{
	public class Notificacao
	{
		public Notificacao(string mensagem)
		{
			Mensagem = mensagem;
		}

		public string Mensagem { get; }
	}
}

criada a class Notificador.cs

using System.Collections.Generic;
using System.Linq;
using DevIO.Business.Intefaces;

namespace DevIO.Business.Notificacoes
{
	public class Notificador : INotificador
	{
		private List<Notificacao> _notificacoes;

		public Notificador()
		{
			_notificacoes = new List<Notificacao>();
		}

		public void Handle(Notificacao notificacao)
		{
			_notificacoes.Add(notificacao);
		}

		public List<Notificacao> ObterNotificacoes()
		{
			return _notificacoes;
		}

		public bool TemNotificacao()
		{
			return _notificacoes.Any();
		}
	}
}

DevIo.Bunsiness

cCriada a pasta Services contento as entidades 

criada a class FornecedorService.cs

	using System;
	using System.Linq;
	using System.Threading.Tasks;
	using DevIO.Business.Intefaces;
	using DevIO.Business.Models;
	using DevIO.Business.Models.Validations;

	namespace DevIO.Business.Services
	{
		public class FornecedorService : BaseService, IFornecedorService
		{
			private readonly IFornecedorRepository _fornecedorRepository;
			private readonly IEnderecoRepository _enderecoRepository;

			public FornecedorService(IFornecedorRepository fornecedorRepository, 
									 IEnderecoRepository enderecoRepository,
									 INotificador notificador) : base(notificador)
			{
				_fornecedorRepository = fornecedorRepository;
				_enderecoRepository = enderecoRepository;
			}

			public async Task<bool> Adicionar(Fornecedor fornecedor)
			{
				if (!ExecutarValidacao(new FornecedorValidation(), fornecedor) 
					|| !ExecutarValidacao(new EnderecoValidation(), fornecedor.Endereco)) return false;

				if (_fornecedorRepository.Buscar(f => f.Documento == fornecedor.Documento).Result.Any())
				{
					Notificar("Já existe um fornecedor com este documento informado.");
					return false;
				}

				await _fornecedorRepository.Adicionar(fornecedor);
				return true;
			}

			public async Task<bool> Atualizar(Fornecedor fornecedor)
			{
				if (!ExecutarValidacao(new FornecedorValidation(), fornecedor)) return false;

				if (_fornecedorRepository.Buscar(f => f.Documento == fornecedor.Documento && f.Id != fornecedor.Id).Result.Any())
				{
					Notificar("Já existe um fornecedor com este documento infomado.");
					return false;
				}

				await _fornecedorRepository.Atualizar(fornecedor);
				return true;
			}

			public async Task AtualizarEndereco(Endereco endereco)
			{
				if (!ExecutarValidacao(new EnderecoValidation(), endereco)) return;

				await _enderecoRepository.Atualizar(endereco);
			}

			public async Task<bool> Remover(Guid id)
			{
				if (_fornecedorRepository.ObterFornecedorProdutosEndereco(id).Result.Produtos.Any())
				{
					Notificar("O fornecedor possui produtos cadastrados!");
					return false;
				}

				var endereco = await _enderecoRepository.ObterEnderecoPorFornecedor(id);

				if (endereco != null)
				{
					await _enderecoRepository.Remover(endereco.Id);
				}

				await _fornecedorRepository.Remover(id);
				return true;
			}

			public void Dispose()
			{
				_fornecedorRepository?.Dispose();
				_enderecoRepository?.Dispose();
			}
		}
	}

criada a class ProdutoService.cs

using System;
using System.Threading.Tasks;
using DevIO.Business.Intefaces;
using DevIO.Business.Models;
using DevIO.Business.Models.Validations;

namespace DevIO.Business.Services
{
	public class ProdutoService : BaseService, IProdutoService
	{
		private readonly IProdutoRepository _produtoRepository;
		private readonly IUser _user;

		public ProdutoService(IProdutoRepository produtoRepository,
							  INotificador notificador, 
							  IUser user) : base(notificador)
		{
			_produtoRepository = produtoRepository;
			_user = user;
		}

		public async Task Adicionar(Produto produto)
		{
			if (!ExecutarValidacao(new ProdutoValidation(), produto)) return;

			//var user = _user.GetUserId();

			await _produtoRepository.Adicionar(produto);
		}

		public async Task Atualizar(Produto produto)
		{
			if (!ExecutarValidacao(new ProdutoValidation(), produto)) return;

			await _produtoRepository.Atualizar(produto);
		}

		public async Task Remover(Guid id)
		{
			await _produtoRepository.Remover(id);
		}

		public void Dispose()
		{
			_produtoRepository?.Dispose();
		}
	}
}

criada a class BaseService.cs

using DevIO.Business.Intefaces;
using DevIO.Business.Models;
using DevIO.Business.Notificacoes;
using FluentValidation;
using FluentValidation.Results;

namespace DevIO.Business.Services
{
	public abstract class BaseService
	{
		private readonly INotificador _notificador;

		protected BaseService(INotificador notificador)
		{
			_notificador = notificador;
		}

		protected void Notificar(ValidationResult validationResult)
		{
			foreach (var error in validationResult.Errors)
			{
				Notificar(error.ErrorMessage);
			}
		}

		protected void Notificar(string mensagem)
		{
			_notificador.Handle(new Notificacao(mensagem));
		}

		protected bool ExecutarValidacao<TV, TE>(TV validacao, TE entidade) where TV : AbstractValidator<TE> where TE : Entity
		{
			var validator = validacao.Validate(entidade);

			if(validator.IsValid) return true;

			Notificar(validator);

			return false;
		}
	}
}

DevIo.Bunsiness

Criada a pasta Interfaces contento as entidades 

criada a class IEnderecoRepository.cs

using System;
using System.Threading.Tasks;
using DevIO.Business.Models;

namespace DevIO.Business.Intefaces
{
	public interface IEnderecoRepository : IRepository<Endereco>
	{
		Task<Endereco> ObterEnderecoPorFornecedor(Guid fornecedorId);
	}
}

criada a class IFornecedorRepository.cs

using System;
using System.Threading.Tasks;
using DevIO.Business.Models;

namespace DevIO.Business.Intefaces
{
	public interface IFornecedorRepository : IRepository<Fornecedor>
	{
		Task<Fornecedor> ObterFornecedorEndereco(Guid id);
		Task<Fornecedor> ObterFornecedorProdutosEndereco(Guid id);
	}
}

criada a class IFornecedorRepository.cs

using System;
using System.Threading.Tasks;
using DevIO.Business.Models;

namespace DevIO.Business.Intefaces
{
	public interface IFornecedorService : IDisposable
	{
		Task<bool> Adicionar(Fornecedor fornecedor);
		Task<bool> Atualizar(Fornecedor fornecedor);
		Task<bool> Remover(Guid id);

		Task AtualizarEndereco(Endereco endereco);
	}
}

criada a class IProdutoRepository.cs

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using DevIO.Business.Models;

namespace DevIO.Business.Intefaces
{
	public interface IProdutoRepository : IRepository<Produto>
	{
		Task<IEnumerable<Produto>> ObterProdutosPorFornecedor(Guid fornecedorId);
		Task<IEnumerable<Produto>> ObterProdutosFornecedores();
		Task<Produto> ObterProdutoFornecedor(Guid id);
	}
}

criada a class IProdutoService.cs

using System;
using System.Threading.Tasks;
using DevIO.Business.Models;

namespace DevIO.Business.Intefaces
{
	public interface IProdutoService : IDisposable
	{
		Task Adicionar(Produto produto);
		Task Atualizar(Produto produto);
		Task Remover(Guid id);
	}
}

criada a class IRepository.cs

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading.Tasks;
using DevIO.Business.Models;

namespace DevIO.Business.Intefaces
{
	public interface IRepository<TEntity> : IDisposable where TEntity : Entity
	{
		Task Adicionar(TEntity entity);
		Task<TEntity> ObterPorId(Guid id);
		Task<List<TEntity>> ObterTodos();
		Task Atualizar(TEntity entity);
		Task Remover(Guid id);
		Task<IEnumerable<TEntity>> Buscar(Expression<Func<TEntity, bool>> predicate);
		Task<int> SaveChanges();
	}
}

criada a class IUser.cs

using System;
using System.Collections.Generic;
using System.Security.Claims;

namespace DevIO.Business.Intefaces
{
	public interface IUser
	{
		string Name { get; }
		Guid GetUserId();
		string GetUserEmail();
		bool IsAuthenticated();
		bool IsInRole(string role);
		IEnumerable<Claim> GetClaimsIdentity();
	}
}

criada a class INotificador.cs

using System.Collections.Generic;
using DevIO.Business.Notificacoes;

namespace DevIO.Business.Intefaces
{
	public interface INotificador
	{
		bool TemNotificacao();
		List<Notificacao> ObterNotificacoes();
		void Handle(Notificacao notificacao);
	}
}

DevIo.Data

Criada a pasta Context contento as entidades 

criada a class MeuDbContext.cs

using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using DevIO.Business.Models;
using Microsoft.EntityFrameworkCore;

namespace DevIO.Data.Context
{
	public class MeuDbContext : DbContext
	{
		public MeuDbContext(DbContextOptions<MeuDbContext> options) : base(options) { }

		public DbSet<Produto> Produtos { get; set; }
		public DbSet<Endereco> Enderecos { get; set; }
		public DbSet<Fornecedor> Fornecedores { get; set; }

		protected override void OnModelCreating(ModelBuilder modelBuilder)
		{
			foreach (var property in modelBuilder.Model.GetEntityTypes()
				.SelectMany(e => e.GetProperties()
					.Where(p => p.ClrType == typeof(string))))
				property.SetColumnType("varchar(100)");

			modelBuilder.ApplyConfigurationsFromAssembly(typeof(MeuDbContext).Assembly);

			foreach (var relationship in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys())) relationship.DeleteBehavior = DeleteBehavior.ClientSetNull;

			base.OnModelCreating(modelBuilder);
		}

		public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
		{
			foreach (var entry in ChangeTracker.Entries().Where(entry => entry.Entity.GetType().GetProperty("DataCadastro") != null))
			{
				if (entry.State == EntityState.Added)
				{
					entry.Property("DataCadastro").CurrentValue = DateTime.Now;
				}

				if (entry.State == EntityState.Modified)
				{
					entry.Property("DataCadastro").IsModified = false;
				}
			}

			return base.SaveChangesAsync(cancellationToken);
		}
	}
}

DevIo.Data

Criada a pasta Repository contento as entidades 

criada a class FornecedorRepository.cs

using System; using System.Threading.Tasks; using DevIO.Business.Intefaces; using DevIO.Business.Models; using DevIO.Data.Context; using Microsoft.EntityFrameworkCore;

namespace DevIO.Data.Repository
{
	public class FornecedorRepository : Repository<Fornecedor>, IFornecedorRepository
	{
		public FornecedorRepository(MeuDbContext context) : base(context)
		{
		}

		public async Task<Fornecedor> ObterFornecedorEndereco(Guid id)
		{
			return await Db.Fornecedores.AsNoTracking()
				.Include(c => c.Endereco)
				.FirstOrDefaultAsync(c => c.Id == id);
		}

		public async Task<Fornecedor> ObterFornecedorProdutosEndereco(Guid id)
		{
			return await Db.Fornecedores.AsNoTracking()
				.Include(c => c.Produtos)
				.Include(c => c.Endereco)
				.FirstOrDefaultAsync(c => c.Id == id);
		}
	}
}

criada a class EnderecoRepository.cs

using System;
using System.Threading.Tasks;
using DevIO.Business.Intefaces;
using DevIO.Business.Models;
using DevIO.Data.Context;
using Microsoft.EntityFrameworkCore;

namespace DevIO.Data.Repository
{
	public class EnderecoRepository : Repository<Endereco>, IEnderecoRepository
	{
		public EnderecoRepository(MeuDbContext context) : base(context) { }

		public async Task<Endereco> ObterEnderecoPorFornecedor(Guid fornecedorId)
		{
			return await Db.Enderecos.AsNoTracking()
				.FirstOrDefaultAsync(f => f.FornecedorId == fornecedorId);
		}
	}
}

criada a class ProdutoRepository.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DevIO.Business.Intefaces;
using DevIO.Business.Models;
using DevIO.Data.Context;
using Microsoft.EntityFrameworkCore;

namespace DevIO.Data.Repository
{
	public class ProdutoRepository : Repository<Produto>, IProdutoRepository
	{
		public ProdutoRepository(MeuDbContext context) : base(context) { }

		public async Task<Produto> ObterProdutoFornecedor(Guid id)
		{
			return await Db.Produtos.AsNoTracking().Include(f => f.Fornecedor)
				.FirstOrDefaultAsync(p => p.Id == id);
		}

		public async Task<IEnumerable<Produto>> ObterProdutosFornecedores()
		{
			return await Db.Produtos.AsNoTracking().Include(f => f.Fornecedor)
				.OrderBy(p => p.Nome).ToListAsync();
		}

		public async Task<IEnumerable<Produto>> ObterProdutosPorFornecedor(Guid fornecedorId)
		{
			return await Buscar(p => p.FornecedorId == fornecedorId);
		}
	}
}

criada a class Repository.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using DevIO.Business.Intefaces;
using DevIO.Business.Models;
using DevIO.Data.Context;
using Microsoft.EntityFrameworkCore;

namespace DevIO.Data.Repository
{
	public abstract class Repository<TEntity> : IRepository<TEntity> where TEntity : Entity, new()
	{
		protected readonly MeuDbContext Db;
		protected readonly DbSet<TEntity> DbSet;

		protected Repository(MeuDbContext db)
		{
			Db = db;
			DbSet = db.Set<TEntity>();
		}

		public async Task<IEnumerable<TEntity>> Buscar(Expression<Func<TEntity, bool>> predicate)
		{
			return await DbSet.AsNoTracking().Where(predicate).ToListAsync();
		}

		public virtual async Task<TEntity> ObterPorId(Guid id)
		{
			return await DbSet.FindAsync(id);
		}

		public virtual async Task<List<TEntity>> ObterTodos()
		{
			return await DbSet.ToListAsync();
		}

		public virtual async Task Adicionar(TEntity entity)
		{
			DbSet.Add(entity);
			await SaveChanges();
		}

		public virtual async Task Atualizar(TEntity entity)
		{
			DbSet.Update(entity);
			await SaveChanges();
		}

		public virtual async Task Remover(Guid id)
		{
			DbSet.Remove(new TEntity { Id = id });
			await SaveChanges();
		}

		public async Task<int> SaveChanges()
		{
			return await Db.SaveChangesAsync();
		}

		public void Dispose()
		{
			Db?.Dispose();
		}
	}
}

DevIo.Data

criada a pasta Mapping

criada a class FornecedorMapping.cs

using DevIO.Business.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace DevIO.Data.Mappings
{
	public class FornecedorMapping : IEntityTypeConfiguration<Fornecedor>
	{
		public void Configure(EntityTypeBuilder<Fornecedor> builder)
		{
			builder.HasKey(p => p.Id);

			builder.Property(p => p.Nome)
				.IsRequired()
				.HasColumnType("varchar(200)");

			builder.Property(p => p.Documento)
				.IsRequired()
				.HasColumnType("varchar(14)");

			// 1 : 1 => Fornecedor : Endereco
			builder.HasOne(f => f.Endereco)
				.WithOne(e => e.Fornecedor);

			// 1 : N => Fornecedor : Produtos
			builder.HasMany(f => f.Produtos)
				.WithOne(p => p.Fornecedor)
				.HasForeignKey(p => p.FornecedorId);

			builder.ToTable("Fornecedores");
		}
	}
}

criada a class ProdutoMapping.cs

using DevIO.Business.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace DevIO.Data.Mappings
{
	public class ProdutoMapping : IEntityTypeConfiguration<Produto>
	{
		public void Configure(EntityTypeBuilder<Produto> builder)
		{
			builder.HasKey(p => p.Id);

			builder.Property(p => p.Nome)
				.IsRequired()
				.HasColumnType("varchar(200)");

			builder.Property(p => p.Descricao)
				.IsRequired()
				.HasColumnType("varchar(1000)");

			builder.Property(p => p.Imagem)
				.IsRequired()
				.HasColumnType("varchar(100)");

			builder.ToTable("Produtos");
		}
	}
}

criada a class EnderecoMapping.cs

using DevIO.Business.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace DevIO.Data.Mappings
{
	public class EnderecoMapping : IEntityTypeConfiguration<Endereco>
	{
		public void Configure(EntityTypeBuilder<Endereco> builder)
		{
			builder.HasKey(p => p.Id);

			builder.Property(c => c.Logradouro)
				.IsRequired()
				.HasColumnType("varchar(200)");

			builder.Property(c => c.Numero)
				.IsRequired()
				.HasColumnType("varchar(50)");

			builder.Property(c => c.Cep)
				.IsRequired()
				.HasColumnType("varchar(8)");

			builder.Property(c => c.Complemento)
				.HasColumnType("varchar(250)");

			builder.Property(c => c.Bairro)
				.IsRequired()
				.HasColumnType("varchar(100)");

			builder.Property(c => c.Cidade)
				.IsRequired()
				.HasColumnType("varchar(100)");

			builder.Property(c => c.Estado)
				.IsRequired()
				.HasColumnType("varchar(50)");

			builder.ToTable("Enderecos");
		}
	}
}

DevIo.Data

Criadando as migrations

Habilitando Migrações

intalar o pacote Microsoft.EntityFrameworkCore.Design e Microsoft.EntityFrameworkCore.Tools

dotnet tool install --global dotnet-ef --version 3.1.5

Comando no Package Nuget Console

get-help entityframework
dotnet ef migrations add MeuDbContextModelSnapshot
dotnet ef migrations add MeuDbContextModelSnapshot -p .\EFCore\EFCore.csproj

Add-Migration MeuDbContextModelSnapshot
Update-Database

Aplicando a migração no Banco de Dados

dotnet ef database update -p .\EFCore\EFCore.csproj -v
dotnet ef migrations add AdicionarEmail -p .\EFCore\EFCore.csproj -v

manter o foco para prosseguir para API :)

nesse mesmo github a um repository sobre Entity Framework Core 

gerada a class MeuDbContextModelSnapshot.cs

// <auto-generated />
using System;
using DevIO.Data.Context;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;

namespace DevIO.Data.Migrations
{
	[DbContext(typeof(MeuDbContext))]
	partial class MeuDbContextModelSnapshot : ModelSnapshot
	{
		protected override void BuildModel(ModelBuilder modelBuilder)
		{
#pragma warning disable 612, 618
			modelBuilder
				.HasAnnotation("ProductVersion", "2.2.4-servicing-10062")
				.HasAnnotation("Relational:MaxIdentifierLength", 128)
				.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);

			modelBuilder.Entity("DevIO.Business.Models.Endereco", b =>
				{
					b.Property<Guid>("Id")
						.ValueGeneratedOnAdd();

					b.Property<string>("Bairro")
						.IsRequired()
						.HasColumnType("varchar(100)");

					b.Property<string>("Cep")
						.IsRequired()
						.HasColumnType("varchar(8)");

					b.Property<string>("Cidade")
						.IsRequired()
						.HasColumnType("varchar(100)");

					b.Property<string>("Complemento")
						.HasColumnType("varchar(250)");

					b.Property<string>("Estado")
						.IsRequired()
						.HasColumnType("varchar(50)");

					b.Property<Guid>("FornecedorId");

					b.Property<string>("Logradouro")
						.IsRequired()
						.HasColumnType("varchar(200)");

					b.Property<string>("Numero")
						.IsRequired()
						.HasColumnType("varchar(50)");

					b.HasKey("Id");

					b.HasIndex("FornecedorId")
						.IsUnique();

					b.ToTable("Enderecos");
				});

			modelBuilder.Entity("DevIO.Business.Models.Fornecedor", b =>
				{
					b.Property<Guid>("Id")
						.ValueGeneratedOnAdd();

					b.Property<bool>("Ativo");

					b.Property<string>("Documento")
						.IsRequired()
						.HasColumnType("varchar(14)");

					b.Property<string>("Nome")
						.IsRequired()
						.HasColumnType("varchar(200)");

					b.Property<int>("TipoFornecedor");

					b.HasKey("Id");

					b.ToTable("Fornecedores");
				});

			modelBuilder.Entity("DevIO.Business.Models.Produto", b =>
				{
					b.Property<Guid>("Id")
						.ValueGeneratedOnAdd();

					b.Property<bool>("Ativo");

					b.Property<DateTime>("DataCadastro");

					b.Property<string>("Descricao")
						.IsRequired()
						.HasColumnType("varchar(1000)");

					b.Property<Guid>("FornecedorId");

					b.Property<string>("Imagem")
						.IsRequired()
						.HasColumnType("varchar(100)");

					b.Property<string>("Nome")
						.IsRequired()
						.HasColumnType("varchar(200)");

					b.Property<decimal>("Valor");

					b.HasKey("Id");

					b.HasIndex("FornecedorId");

					b.ToTable("Produtos");
				});

			modelBuilder.Entity("DevIO.Business.Models.Endereco", b =>
				{
					b.HasOne("DevIO.Business.Models.Fornecedor", "Fornecedor")
						.WithOne("Endereco")
						.HasForeignKey("DevIO.Business.Models.Endereco", "FornecedorId");
				});

			modelBuilder.Entity("DevIO.Business.Models.Produto", b =>
				{
					b.HasOne("DevIO.Business.Models.Fornecedor", "Fornecedor")
						.WithMany("Produtos")
						.HasForeignKey("FornecedorId");
				});
#pragma warning restore 612, 618
		}
	}
}

gerada a class 20190503042709_Initial.cs

using System;
using Microsoft.EntityFrameworkCore.Migrations;

namespace DevIO.Data.Migrations
{
	public partial class Initial : Migration
	{
		protected override void Up(MigrationBuilder migrationBuilder)
		{
			migrationBuilder.CreateTable(
				name: "Fornecedores",
				columns: table => new
				{
					Id = table.Column<Guid>(nullable: false),
					Nome = table.Column<string>(type: "varchar(200)", nullable: false),
					Documento = table.Column<string>(type: "varchar(14)", nullable: false),
					TipoFornecedor = table.Column<int>(nullable: false),
					Ativo = table.Column<bool>(nullable: false)
				},
				constraints: table =>
				{
					table.PrimaryKey("PK_Fornecedores", x => x.Id);
				});

			migrationBuilder.CreateTable(
				name: "Enderecos",
				columns: table => new
				{
					Id = table.Column<Guid>(nullable: false),
					FornecedorId = table.Column<Guid>(nullable: false),
					Logradouro = table.Column<string>(type: "varchar(200)", nullable: false),
					Numero = table.Column<string>(type: "varchar(50)", nullable: false),
					Complemento = table.Column<string>(type: "varchar(250)", nullable: true),
					Cep = table.Column<string>(type: "varchar(8)", nullable: false),
					Bairro = table.Column<string>(type: "varchar(100)", nullable: false),
					Cidade = table.Column<string>(type: "varchar(100)", nullable: false),
					Estado = table.Column<string>(type: "varchar(50)", nullable: false)
				},
				constraints: table =>
				{
					table.PrimaryKey("PK_Enderecos", x => x.Id);
					table.ForeignKey(
						name: "FK_Enderecos_Fornecedores_FornecedorId",
						column: x => x.FornecedorId,
						principalTable: "Fornecedores",
						principalColumn: "Id",
						onDelete: ReferentialAction.Restrict);
				});

			migrationBuilder.CreateTable(
				name: "Produtos",
				columns: table => new
				{
					Id = table.Column<Guid>(nullable: false),
					FornecedorId = table.Column<Guid>(nullable: false),
					Nome = table.Column<string>(type: "varchar(200)", nullable: false),
					Descricao = table.Column<string>(type: "varchar(1000)", nullable: false),
					Imagem = table.Column<string>(type: "varchar(100)", nullable: false),
					Valor = table.Column<decimal>(nullable: false),
					DataCadastro = table.Column<DateTime>(nullable: false),
					Ativo = table.Column<bool>(nullable: false)
				},
				constraints: table =>
				{
					table.PrimaryKey("PK_Produtos", x => x.Id);
					table.ForeignKey(
						name: "FK_Produtos_Fornecedores_FornecedorId",
						column: x => x.FornecedorId,
						principalTable: "Fornecedores",
						principalColumn: "Id",
						onDelete: ReferentialAction.Restrict);
				});

			migrationBuilder.CreateIndex(
				name: "IX_Enderecos_FornecedorId",
				table: "Enderecos",
				column: "FornecedorId",
				unique: true);

			migrationBuilder.CreateIndex(
				name: "IX_Produtos_FornecedorId",
				table: "Produtos",
				column: "FornecedorId");
		}

		protected override void Down(MigrationBuilder migrationBuilder)
		{
			migrationBuilder.DropTable(
				name: "Enderecos");

			migrationBuilder.DropTable(
				name: "Produtos");

			migrationBuilder.DropTable(
				name: "Fornecedores");
		}
	}
}

gerada a class 20200507181203_inicial.cs

using Microsoft.EntityFrameworkCore.Migrations;

namespace DevIO.Data.Migrations
{
	public partial class inicial : Migration
	{
		protected override void Up(MigrationBuilder migrationBuilder)
		{

		}

		protected override void Down(MigrationBuilder migrationBuilder)
		{

		}
	}
}





Agora vamos focar na Criação da camada de API

A camada de acesso a dados e negocio foram feita surpeficialmente visando o foco na camada da aplicação

blank Solution 'MinhaApiCompleta' >

Add New Project

Escolher ASP.NET Core Web Aplication

DevIo.Api
C:\Users\Alfredo\source\repos\API\src\DevIO.Api

create, escolher o templete

API
changer > autentication

implementar o relacioanmentos das camadas

DevIo.API> Depedencias > botao direito > AddReference

Reference Manager - DevIo.API

selecionar 
	DevIo.Bunsiness
	DevIo.Data
ok

DevIo.API> > botao direito >

Set as StaupUp Project

Implementando as DTOs > DevIo.API> > botao direito > Criar pasta ViewModels

criar as class FornercedorViewModel.cs

FornercedorViewModel.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace DevIO.Api.ViewModels
{
	public class FornecedorViewModel
	{
		[Key]
		public Guid Id { get; set; }

		[Required(ErrorMessage = "O campo {0} é obrigatório")]
		[StringLength(100, ErrorMessage = "O campo {0} precisa ter entre {2} e {1} caracteres", MinimumLength = 2)]
		public string Nome { get; set; }

		[Required(ErrorMessage = "O campo {0} é obrigatório")]
		[StringLength(14, ErrorMessage = "O campo {0} precisa ter entre {2} e {1} caracteres", MinimumLength = 11)]
		public string Documento { get; set; }

		public int TipoFornecedor { get; set; }

		public EnderecoViewModel Endereco { get; set; }

		public bool Ativo { get; set; }

		public IEnumerable<ProdutoViewModel> Produtos { get; set; }
	}
}

EnderecoViewModel.cs

using System;
using System.ComponentModel.DataAnnotations;

namespace DevIO.Api.ViewModels
{
	public class EnderecoViewModel
	{
		[Key]
		public Guid Id { get; set; }

		[Required(ErrorMessage = "O campo {0} é obrigatório")]
		[StringLength(200, ErrorMessage = "O campo {0} precisa ter entre {2} e {1} caracteres", MinimumLength = 2)]
		public string Logradouro { get; set; }

		[Required(ErrorMessage = "O campo {0} é obrigatório")]
		[StringLength(50, ErrorMessage = "O campo {0} precisa ter entre {2} e {1} caracteres", MinimumLength = 1)]
		public string Numero { get; set; }

		public string Complemento { get; set; }

		[Required(ErrorMessage = "O campo {0} é obrigatório")]
		[StringLength(100, ErrorMessage = "O campo {0} precisa ter entre {2} e {1} caracteres", MinimumLength = 2)]
		public string Bairro { get; set; }

		[Required(ErrorMessage = "O campo {0} é obrigatório")]
		[StringLength(8, ErrorMessage = "O campo {0} precisa ter {1} caracteres", MinimumLength = 8)]
		public string Cep { get; set; }

		[Required(ErrorMessage = "O campo {0} é obrigatório")]
		[StringLength(100, ErrorMessage = "O campo {0} precisa ter entre {2} e {1} caracteres", MinimumLength = 2)]
		public string Cidade { get; set; }

		[Required(ErrorMessage = "O campo {0} é obrigatório")]
		[StringLength(50, ErrorMessage = "O campo {0} precisa ter entre {2} e {1} caracteres", MinimumLength = 2)]
		public string Estado { get; set; }

		public Guid FornecedorId { get; set; }
	}
}

ProdutoViewModel.cs

using System;
using System.ComponentModel.DataAnnotations;

namespace DevIO.Api.ViewModels
{
	public class ProdutoViewModel
	{
		[Key]
		public Guid Id { get; set; }

		[Required(ErrorMessage = "O campo {0} é obrigatório")]

		public Guid FornecedorId { get; set; }

		[Required(ErrorMessage = "O campo {0} é obrigatório")]
		[StringLength(200, ErrorMessage = "O campo {0} precisa ter entre {2} e {1} caracteres", MinimumLength = 2)]
		public string Nome { get; set; }

		[Required(ErrorMessage = "O campo {0} é obrigatório")]
		[StringLength(1000, ErrorMessage = "O campo {0} precisa ter entre {2} e {1} caracteres", MinimumLength = 2)]
		public string Descricao { get; set; }

		public string ImagemUpload { get; set; }

		public string Imagem { get; set; }

		[Required(ErrorMessage = "O campo {0} é obrigatório")]
		public decimal Valor { get; set; }

		[ScaffoldColumn(false)]
		public DateTime DataCadastro { get; set; }

		public bool Ativo { get; set; }

		[ScaffoldColumn(false)]
		public string NomeFornecedor { get; set; }
	}
}

ProdutoImagemViewModel.cs

using System;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Http;

namespace DevIO.Api.ViewModels
{
	//[ModelBinder(typeof(JsonWithFilesFormDataModelBinder), Name = "produto")]
	public class ProdutoImagemViewModel
	{
		[Key]
		public Guid Id { get; set; }

		[Required(ErrorMessage = "O campo {0} é obrigatório")]

		public Guid FornecedorId { get; set; }

		[Required(ErrorMessage = "O campo {0} é obrigatório")]
		[StringLength(200, ErrorMessage = "O campo {0} precisa ter entre {2} e {1} caracteres", MinimumLength = 2)]
		public string Nome { get; set; }

		[Required(ErrorMessage = "O campo {0} é obrigatório")]
		[StringLength(1000, ErrorMessage = "O campo {0} precisa ter entre {2} e {1} caracteres", MinimumLength = 2)]
		public string Descricao { get; set; }

		public IFormFile ImagemUpload { get; set; }

		public string Imagem { get; set; }

		[Required(ErrorMessage = "O campo {0} é obrigatório")]
		public decimal Valor { get; set; }

		[ScaffoldColumn(false)]
		public DateTime DataCadastro { get; set; }

		public bool Ativo { get; set; }

		[ScaffoldColumn(false)]
		public string NomeFornecedor { get; set; }
	}
}

UserViewModel.cs

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace DevIO.Api.ViewModels
{
	public class RegisterUserViewModel
	{
		[Required(ErrorMessage = "O campo {0} é obrigatório")]
		[EmailAddress(ErrorMessage = "O campo {0} está em formato inválido")]
		public string Email { get; set; }

		[Required(ErrorMessage = "O campo {0} é obrigatório")]
		[StringLength(100, ErrorMessage = "O campo {0} precisa ter entre {2} e {1} caracteres", MinimumLength = 6)]
		public string Password { get; set; }

		[Compare("Password", ErrorMessage = "As senhas não conferem.")]
		public string ConfirmPassword { get; set; }
	}

	public class LoginUserViewModel
	{
		[Required(ErrorMessage = "O campo {0} é obrigatório")]
		[EmailAddress(ErrorMessage = "O campo {0} está em formato inválido")]
		public string Email { get; set; }

		[Required(ErrorMessage = "O campo {0} é obrigatório")]
		[StringLength(100, ErrorMessage = "O campo {0} precisa ter entre {2} e {1} caracteres", MinimumLength = 6)]
		public string Password { get; set; }
	}

	public class UserTokenViewModel
	{
		public string Id { get; set; }
		public string Email { get; set; }
		public IEnumerable<ClaimViewModel> Claims { get; set; }
	}

	public class LoginResponseViewModel
	{
		public string AccessToken { get; set; }
		public double ExpiresIn { get; set; }
		public UserTokenViewModel UserToken { get; set; }
	}

	public class ClaimViewModel
	{
		public string Value { get; set; }
		public string Type { get; set; }
	}
}

DevIo.API > Criar pasta Controllers

Criar class Abastrata MainController.cs  baseada nas ViewModels

Class Abastrata MainController.cs

//ao criar uma class abstrata a mesma só pode ser herdada e não implementada	
public abstract class MainController : ControllerBase

implementando rota MainController.cs

[ApiController]
public abstract class MainController : ControllerBase{}

[Route("api/fornecedores")]
public class FornecedoresController : MainController{}

implementando metodo ObterTodos MainController.cs

[Route("api/fornecedores")]
public class FornecedoresController : MainController{

public async Task<IEnumerable<FornecedorViewModel>> ObterTodos()
{

	return Ok();
}}

MainController.cs

using System;
using System.Linq;
using DevIO.Business.Intefaces;
using DevIO.Business.Notificacoes;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;

namespace DevIO.Api.Controllers
{
	[ApiController]
	public abstract class MainController : ControllerBase
	{
		private readonly INotificador _notificador;
		public readonly IUser AppUser;

		protected Guid UsuarioId { get; set; }
		protected bool UsuarioAutenticado { get; set; }

		protected MainController(INotificador notificador, 
								 IUser appUser)
		{
			_notificador = notificador;
			AppUser = appUser;

			if (appUser.IsAuthenticated())
			{
				UsuarioId = appUser.GetUserId();
				UsuarioAutenticado = true;
			}
		}

		protected bool OperacaoValida()
		{
			return !_notificador.TemNotificacao();
		}

		protected ActionResult CustomResponse(object result = null)
		{
			if (OperacaoValida())
			{
				return Ok(new
				{
					success = true,
					data = result
				});
			}

			return BadRequest(new
			{
				success = false,
				errors = _notificador.ObterNotificacoes().Select(n => n.Mensagem)
			});
		}

		protected ActionResult CustomResponse(ModelStateDictionary modelState)
		{
			if(!modelState.IsValid) NotificarErroModelInvalida(modelState);
			return CustomResponse();
		}

		protected void NotificarErroModelInvalida(ModelStateDictionary modelState)
		{
			var erros = modelState.Values.SelectMany(e => e.Errors);
			foreach (var erro in erros)
			{
				var errorMsg = erro.Exception == null ? erro.ErrorMessage : erro.Exception.Message;
				NotificarErro(errorMsg);
			}
		}

		protected void NotificarErro(string mensagem)
		{
			_notificador.Handle(new Notificacao(mensagem));
		}
	}
}

criar class FornecedorRepository.cs para desacolplamento

public class FornecedoresController : MainController{}

injetar o repositorio FornecedorRepository.cs atraves da injeção de depedencia na FornecedorRepository.cs

[Route("api/fornecedores")]
public class FornecedoresController : MainController
{
	//injetando o repositorio
	private readonly IFornecedorRepository _fornecedorRepository;
	private readonly IFornecedorService _fornecedorService;
	private readonly IEnderecoRepository _enderecoRepository;
	private readonly IMapper _mapper;

	//passando a injeçao de depecia no construtor
	public FornecedoresController(IFornecedorRepository fornecedorRepository, 
	{	
		_fornecedorRepository = fornecedorRepository;				
	}	
 }

criar uma variavel para passar

public async Task<FornecedorViewModel>ObterPorId()
{
	var fornecedor = await _fonercedorRepository.ObterTodos();

	return fornecedor;
}

usar automap

public async Task<ActionResult> ObterPorId() { var fornecedor = await _fonercedorRepository.ObterTodos();

	return fornecedor;
}

configurando o automap

package manager console: install-package Automap.Extensions.Microsoft.DepedencyInjection

staup.cs

public static void	ConfigureServices(IServiceCollection services)
{
	services.addAutoMapper(typeof(startup));
}

DevIo.Api > criar pasta Configuration

criar class AutomapperConfig.cs

AutomapperConfig.cs

using AutoMapper;
using DevIO.Api.ViewModels;
using DevIO.Business.Models;

namespace DevIO.Api.Configuration
{
	public class AutomapperConfig : Profile
	{
		public AutomapperConfig()
		{
			//DE forncedor PARA fornecedorviewModel
			CreateMap<Fornecedor, FornecedorViewModel>().ReverseMap();
			CreateMap<Endereco, EnderecoViewModel>().ReverseMap();
			CreateMap<ProdutoViewModel, Produto>();

			CreateMap<ProdutoImagemViewModel, Produto>().ReverseMap();

			CreateMap<Produto, ProdutoViewModel>()
				.ForMember(dest => dest.NomeFornecedor, opt => opt.MapFrom(src => src.Fornecedor.Nome));
		}
	}
}

injetar o automap por depedencia e injetar no construtor FornecedorController.cs

 private readonly IMapper _mapper;

    public FornecedoresController(IFornecedorRepository fornecedorRepository, 
                                  IMapper mapper, 
                                  IFornecedorService fornecedorService,
                                  INotificador notificador, 
                                  IEnderecoRepository enderecoRepository,
                                  IUser user) : base(notificador, user)
    {
        _fornecedorRepository = fornecedorRepository;
        _mapper = mapper;
        _fornecedorService = fornecedorService;
        _enderecoRepository = enderecoRepository;
    }

    [AllowAnonymous]
    [HttpGet]
    public async Task<IEnumerable<FornecedorViewModel>> ObterTodos()
    {
        return _mapper.Map<IEnumerable<FornecedorViewModel>>(await _fornecedorRepository.ObterTodos());
    }

criar a class DependencyInjectionConfig.cs

using DevIO.Api.Extensions;
using DevIO.Business.Intefaces;
using DevIO.Business.Notificacoes;
using DevIO.Business.Services;
using DevIO.Data.Context;
using DevIO.Data.Repository;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace DevIO.Api.Configuration
{
	public static class DependencyInjectionConfig
	{
		public static IServiceCollection ResolveDependencies(this IServiceCollection services)
		{
			//resolvendo q o Repository está recebendo injecção de depedencia do MeuDbContext
			services.AddScoped<MeuDbContext>();
			services.AddScoped<IProdutoRepository, ProdutoRepository>();
			services.AddScoped<IFornecedorRepository, FornecedorRepository>();
			services.AddScoped<IEnderecoRepository, EnderecoRepository>();

			services.AddScoped<INotificador, Notificador>();
			services.AddScoped<IFornecedorService, FornecedorService>();
			services.AddScoped<IProdutoService, ProdutoService>();

			services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
			services.AddScoped<IUser, AspNetUser>();

			services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();

			return services;
		}
	}
}

configurar o entinty framework e criar a connection na entidade Statup.cs

public void ConfigureServices(IServiceCollection services) { //adicionando o extention metodo do entity framework e as options pegando o configurantion passando a string de conexao services.AddDbContext(options => { options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")); });

 services.AddAutoMapper(typeof(Startup));

 services.ResolveDependencies();

}

configurar a connection na class de configuração appsettings.json

{ "ConnectionStrings": { "DefaultConnection": "Server=(localdb)\mssqllocaldb;Database=MinhaAppMvcCore;Trusted_Connection=True;MultipleActiveResultSets=true" } }

fornecedorController.cs

using System.Collections.Generic;
using System.Threading.Tasks;
using AutoMapper;
using DevIO.Api.ViewModels;
using DevIO.Business.Intefaces;
using Microsoft.AspNetCore.Mvc;

namespace DevIO.Api.V1.Controllers
{
	[Route("api/fornecedores")]
	public class FornecedoresController : MainController
	{
		private readonly IFornecedorRepository _fornecedorRepository;
		private readonly IMapper _mapper;

		public FornecedoresController(IFornecedorRepository fornecedorRepository, 
									  IMapper mapper, 
		{
			_fornecedorRepository = fornecedorRepository;
			_mapper = mapper;
		}

	public async Task<IEnumerable<FornecedorViewModel>>ObterPorId()
		{
			var fornecedor = _mapper.Map<IEnumerable<FornecedorViewModel>>(await_fornecedorRepository.ObterTodos());

			return fornecedor;
		}

gerar a migration para o banco

baixar depedentia EntityFrameworkTools
DevIo.Data > package manager console> update-database -Context MeuDbContext -verbose

configurando a controller para o processo de CRUD FornecedoresController.cs

	public async Task<IEnumerable<FornecedorViewModel>> ObterTodos()
    {
        return _mapper.Map<IEnumerable<FornecedorViewModel>>(await _fornecedorRepository.ObterTodos());
    }

FornecedoresController.cs

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using AutoMapper;
using DevIO.Api.Controllers;
using DevIO.Api.Extensions;
using DevIO.Api.ViewModels;
using DevIO.Business.Intefaces;
using DevIO.Business.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace DevIO.Api.V1.Controllers
{
	[Authorize]
	[ApiVersion("1.0")]
	[Route("api/v{version:apiVersion}/fornecedores")]
	public class FornecedoresController : MainController
	{
		private readonly IFornecedorRepository _fornecedorRepository;
		private readonly IFornecedorService _fornecedorService;
		private readonly IEnderecoRepository _enderecoRepository;
		private readonly IMapper _mapper;

		public FornecedoresController(IFornecedorRepository fornecedorRepository, 
									  IMapper mapper, 
									  IFornecedorService fornecedorService,
									  INotificador notificador, 
									  IEnderecoRepository enderecoRepository,
									  IUser user) : base(notificador, user)
		{
			_fornecedorRepository = fornecedorRepository;
			_mapper = mapper;
			_fornecedorService = fornecedorService;
			_enderecoRepository = enderecoRepository;
		}

		[AllowAnonymous]
		[HttpGet]
		public async Task<IEnumerable<FornecedorViewModel>> ObterTodos()
		{
			return _mapper.Map<IEnumerable<FornecedorViewModel>>(await _fornecedorRepository.ObterTodos());
		}

		[HttpGet("{id:guid}")]
		public async Task<ActionResult<FornecedorViewModel>> ObterPorId(Guid id)
		{
			var fornecedor = await ObterFornecedorProdutosEndereco(id);

			if (fornecedor == null) return NotFound();

			return fornecedor;
		}

		[ClaimsAuthorize("Fornecedor","Adicionar")]
		[HttpPost]
		public async Task<ActionResult<FornecedorViewModel>> Adicionar(FornecedorViewModel fornecedorViewModel)
		{
			if (!ModelState.IsValid) return CustomResponse(ModelState);

			await _fornecedorService.Adicionar(_mapper.Map<Fornecedor>(fornecedorViewModel));

			return CustomResponse(fornecedorViewModel);
		}

		[ClaimsAuthorize("Fornecedor", "Atualizar")]
		[HttpPut("{id:guid}")]
		public async Task<ActionResult<FornecedorViewModel>> Atualizar(Guid id, FornecedorViewModel fornecedorViewModel)
		{
			if (id != fornecedorViewModel.Id)
			{
				NotificarErro("O id informado não é o mesmo que foi passado na query");
				return CustomResponse(fornecedorViewModel);
			}

			if (!ModelState.IsValid) return CustomResponse(ModelState);

			await _fornecedorService.Atualizar(_mapper.Map<Fornecedor>(fornecedorViewModel));

			return CustomResponse(fornecedorViewModel);
		}

		[ClaimsAuthorize("Fornecedor", "Excluir")]
		[HttpDelete("{id:guid}")]
		public async Task<ActionResult<FornecedorViewModel>> Excluir(Guid id)
		{
			var fornecedorViewModel = await ObterFornecedorEndereco(id);

			if (fornecedorViewModel == null) return NotFound();

			await _fornecedorService.Remover(id);

			return CustomResponse(fornecedorViewModel);
		}

		[HttpGet("endereco/{id:guid}")]
		public async Task<EnderecoViewModel> ObterEnderecoPorId(Guid id)
		{
			return _mapper.Map<EnderecoViewModel>(await _enderecoRepository.ObterPorId(id));
		}

		[ClaimsAuthorize("Fornecedor", "Atualizar")]
		[HttpPut("endereco/{id:guid}")]
		public async Task<IActionResult> AtualizarEndereco(Guid id, EnderecoViewModel enderecoViewModel)
		{
			if (id != enderecoViewModel.Id)
			{
				NotificarErro("O id informado não é o mesmo que foi passado na query");
				return CustomResponse(enderecoViewModel);
			}

			if (!ModelState.IsValid) return CustomResponse(ModelState);

			await _fornecedorService.AtualizarEndereco(_mapper.Map<Endereco>(enderecoViewModel));

			return CustomResponse(enderecoViewModel);
		}

		private async Task<FornecedorViewModel> ObterFornecedorProdutosEndereco(Guid id)
		{
			return _mapper.Map<FornecedorViewModel>(await _fornecedorRepository.ObterFornecedorProdutosEndereco(id));
		}

		private async Task<FornecedorViewModel> ObterFornecedorEndereco(Guid id)
		{
			return _mapper.Map<FornecedorViewModel>(await _fornecedorRepository.ObterFornecedorEndereco(id));
		}
	}
}

ProdutosController.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using AutoMapper;
using DevIO.Api.Controllers;
using DevIO.Api.Extensions;
using DevIO.Api.ViewModels;
using DevIO.Business.Intefaces;
using DevIO.Business.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace DevIO.Api.V1.Controllers
{
	[Authorize]
	[ApiVersion("1.0")]
	[Route("api/v{version:apiVersion}/produtos")]
	public class ProdutosController : MainController
	{
		private readonly IProdutoRepository _produtoRepository;
		private readonly IProdutoService _produtoService;
		private readonly IMapper _mapper;

		public ProdutosController(INotificador notificador, 
								  IProdutoRepository produtoRepository, 
								  IProdutoService produtoService, 
								  IMapper mapper,
								  IUser user) : base(notificador, user)
		{
			_produtoRepository = produtoRepository;
			_produtoService = produtoService;
			_mapper = mapper;
		}

		[HttpGet]
		public async Task<IEnumerable<ProdutoViewModel>> ObterTodos()
		{
			return _mapper.Map<IEnumerable<ProdutoViewModel>>(await _produtoRepository.ObterProdutosFornecedores());
		}

		[HttpGet("{id:guid}")]
		public async Task<ActionResult<ProdutoViewModel>> ObterPorId(Guid id)
		{
			var produtoViewModel = await ObterProduto(id);

			if (produtoViewModel == null) return NotFound();

			return produtoViewModel;
		}

		[ClaimsAuthorize("Produto", "Adicionar")]
		[HttpPost]
		public async Task<ActionResult<ProdutoViewModel>> Adicionar(ProdutoViewModel produtoViewModel)
		{
			if (!ModelState.IsValid) return CustomResponse(ModelState);

			var imagemNome = Guid.NewGuid() + "_" + produtoViewModel.Imagem;
			if (!UploadArquivo(produtoViewModel.ImagemUpload, imagemNome))
			{
				return CustomResponse(produtoViewModel);
			}

			produtoViewModel.Imagem = imagemNome;
			await _produtoService.Adicionar(_mapper.Map<Produto>(produtoViewModel));

			return CustomResponse(produtoViewModel);
		}

		[ClaimsAuthorize("Produto", "Atualizar")]
		[HttpPut("{id:guid}")]
		public async Task<IActionResult> Atualizar(Guid id, ProdutoViewModel produtoViewModel)
		{
			if (id != produtoViewModel.Id)
			{
				NotificarErro("Os ids informados não são iguais!");
				return CustomResponse();
			}

			var produtoAtualizacao = await ObterProduto(id);

			if (string.IsNullOrEmpty(produtoViewModel.Imagem))
				produtoViewModel.Imagem = produtoAtualizacao.Imagem;

			if (!ModelState.IsValid) return CustomResponse(ModelState);

			if (produtoViewModel.ImagemUpload != null)
			{
				var imagemNome = Guid.NewGuid() + "_" + produtoViewModel.Imagem;
				if (!UploadArquivo(produtoViewModel.ImagemUpload, imagemNome))
				{
					return CustomResponse(ModelState);
				}

				produtoAtualizacao.Imagem = imagemNome;
			}

			produtoAtualizacao.FornecedorId = produtoViewModel.FornecedorId;
			produtoAtualizacao.Nome = produtoViewModel.Nome;
			produtoAtualizacao.Descricao = produtoViewModel.Descricao;
			produtoAtualizacao.Valor = produtoViewModel.Valor;
			produtoAtualizacao.Ativo = produtoViewModel.Ativo;

			await _produtoService.Atualizar(_mapper.Map<Produto>(produtoAtualizacao));

			return CustomResponse(produtoViewModel);
		}

		[ClaimsAuthorize("Produto", "Excluir")]
		[HttpDelete("{id:guid}")]
		public async Task<ActionResult<ProdutoViewModel>> Excluir(Guid id)
		{
			var produto = await ObterProduto(id);

			if (produto == null) return NotFound();

			await _produtoService.Remover(id);

			return CustomResponse(produto);
		}

		private async Task<ProdutoViewModel> ObterProduto(Guid id)
		{
			return _mapper.Map<ProdutoViewModel>(await _produtoRepository.ObterProdutoFornecedor(id));
		}

		private bool UploadArquivo(string arquivo, string imgNome)
		{
			if (string.IsNullOrEmpty(arquivo))
			{
				NotificarErro("Forneça uma imagem para este produto!");
				return false;
			}

			var imageDataByteArray = Convert.FromBase64String(arquivo);

			var filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", imgNome);

			if (System.IO.File.Exists(filePath))
			{
				NotificarErro("Já existe um arquivo com este nome!");
				return false;
			}

			System.IO.File.WriteAllBytes(filePath, imageDataByteArray);

			return true;
		}

		#region UploadAlternativo

		[ClaimsAuthorize("Produto", "Adicionar")]
		[HttpPost("Adicionar")]
		public async Task<ActionResult<ProdutoViewModel>> AdicionarAlternativo(ProdutoImagemViewModel produtoViewModel)
		{
			if (!ModelState.IsValid) return CustomResponse(ModelState);

			var imgPrefixo = Guid.NewGuid() + "_";
			if (!await UploadArquivoAlternativo(produtoViewModel.ImagemUpload, imgPrefixo))
			{
				return CustomResponse(ModelState);
			}

			produtoViewModel.Imagem = imgPrefixo + produtoViewModel.ImagemUpload.FileName;
			await _produtoService.Adicionar(_mapper.Map<Produto>(produtoViewModel));

			return CustomResponse(produtoViewModel);
		}
    
		[RequestSizeLimit(40000000)]
		//[DisableRequestSizeLimit]
		[HttpPost("imagem")]
		public ActionResult AdicionarImagem(IFormFile file)
		{
			return Ok(file);
		}

		private async Task<bool> UploadArquivoAlternativo(IFormFile arquivo, string imgPrefixo)
		{
			if (arquivo == null || arquivo.Length == 0)
			{
				NotificarErro("Forneça uma imagem para este produto!");
				return false;
			}

			var path = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", imgPrefixo + arquivo.FileName);

			if (System.IO.File.Exists(path))
			{
				NotificarErro("Já existe um arquivo com este nome!");
				return false;
			}

			using (var stream = new FileStream(path, FileMode.Create))
			{
				await arquivo.CopyToAsync(stream);
			}

			return true;
		}

		#endregion
	}
}

About

REST com ASP.NET Core WebAPI integrado ao SPA Angular 7

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C# 99.4%
  • Dockerfile 0.6%