0

[HowTo] VS Code | Crear una WebApi con Asp.Net Core en Linux

Como comente en post anterior Microsoft está entrando fuertemente al mundo OpenSource. Por esta razon hoy podemos disfrutar de Asp.Net Core en la plataforma Linux, en mi caso KUbuntu, junto a algunas herramientas muy poderosas com VS Code.

Objetivo

El objetivo de esta publicación tiene un tutorial de como debemos preparar nuestro linux para hacer uso de Asp.Net junto a una aplicacion del tipo WebApi que usaremos en post futuros.

Audiencia

Este documento está dirigido a personas que conocen muy poco o nada sobre el tema o personas que desarrollan tareas de consultoría de desarrollo o que simplemente están interesados en leer e investigar sobre la tecnología alcanzada por esta publicación.

Desarrollo

Para empezar lo que haremos es instalar Net Core es nuestro linux. Lo haré sobre mi distribución preferida que es KUbuntu. Primero necesitamos instalar las llaves de producto y actualizar el listado de paquetes en nuestra distribución linux. Abriremos una consola y ejecutamos los siguiente comandos estos 4 comandos en este orden:

curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg
sudo mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg
sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-zesty-prod zesty main" > /etc/apt/sources.list.d/dotnetdev.list'
sudo apt-get update

 

Ya ejecutado todo estamos listos para instalar:

sudo apt-get install dotnet-sdk-2.0.0

Una vez que instalamos todo y configurado estamos listso. Vamos a crear nuestra primera aplicación en linux. Crearemos una carpeta y ejecutaremos el comando dotnet que nos ayuda a crear la plantilla:

mkdir MvcMyApp
cd MvcMyApp
dotnet new mvc

Ahora podemos abrir desde VS Code que instalamos en un post anterior. Con Solo escribir “code .” se abrirar el VS Code en la carpeta donde estamos parados. Ahora necesitaremos instalar VS Code C# extensión. Lo haremos desde el icono de VS Code, lo buscaremos y lo instalaremos.

Luego de instalarlo recargamos la ventana y comenzará a instalarse algunos componentes necesarios que nos permitirá usar la depuración en VS Code.

Ahora solo nos queda presionar F5 y guala!

 

Una WebApi para ejemplos

Lo que haremos ahora es crear una WebApi Rest que la usaremo en futuros ejemplos en un el tutorial de TypeScript. Vamos a necesitar tener instalado:

  • DB Browser for Sqlite (podemos instalarlos desde el gestor de software que viene con KUbuntu.
  • Postman (podemos descargarlo desde aqui https://www.getpostman.com/)

Empezaremos con crear una carpeta DemoApi y dentro ejecutaremos los comandos de creación y lo abriremos, solo hay que seguir los siguientes comando en orden:

mkdir DemoService
cd DemoService
dotnet new webapi
code .

Nuevamente nos aparecerán los warning a los que debemos darle yes.

Crearemos la base de datos con Sql DB Browser dentro de una carpeta data. La base de Datos la llamaremos DBDemoServices y corremos el script que dejare en el github dentro de la carpeta data se llama base.txt. Este script creará 2 tablas e insertara datos para hacer el demo.

En nuestro servicio usaremos Entity Framework Core como herramienta de acceso a datos. No ayudará con nuestra base de datos Sqlite. Agregaremos las siguientes lineas en nuestro archivo DemoService.csproj:

<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.0"/>

Desde la consola ejecutaremos dotnet restore para actualizar nuestros paquetes:

Comenzaremos creando nuestros modelos y nuestro DBContext. Crearemos 3 archivos, Customer.cs, CustomerType y DemoServiceContext.cs. Todos dentro de una carpeta Models con la siguiente clases dentro:

Customer.cs

using System;
using System.Collections.Generic;

namespace DemoService.Models
{
public partial class Customers
{
public int CustomerId { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string SurName { get; set; }
public string EmailAddress { get; set; }
public int? CustomerTypeId { get; set; }
public string Notes { get; set; }

public virtual CustomersTypes CustomerType { get; set; }
}
}

CustomerType.cs

using System;
using System.Collections.Generic;

namespace DemoService.Models
{
public partial class CustomersTypes
{

public CustomersTypes()
{
Customers = new HashSet<Customers>();
}

public int CustomerTypeId { get; set; }
public string Description { get; set; }

public virtual ICollection<Customers> Customers { get; set; }

}

}

DemoServiceContext.Typecs

using Microsoft.EntityFrameworkCore;
using DemoService.Models;

namespace DemoService.Models
{
public class DemoDBContext : DbContext
{
public DemoDBContext(DbContextOptions<DemoDBContext> options)
: base(options)
{
}
public virtual DbSet<Customers> Customers { get; set; }
public virtual DbSet<CustomersTypes> CustomersTypes{ get; set; }

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Filename=BDemoSevice.db;");
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Customers>(entity =>
{
entity.HasKey(e => e.CustomerId)
.HasName("PK_Customers");

entity.Property(e => e.EmailAddress).HasColumnType("varchar(150)");

entity.Property(e => e.FirstName).HasColumnType("varchar(50)");

entity.Property(e => e.MiddleName).HasColumnType("varchar(50)");

entity.Property(e => e.Notes).HasColumnType("varchar(5000)");

entity.Property(e => e.SurName).HasColumnType("varchar(50)");

entity.HasOne(d => d.CustomerType)
.WithMany(p => p.Customers)
.HasForeignKey(d => d.CustomerTypeId)
.HasConstraintName("FK_Customers_CustomersTypes");
});

modelBuilder.Entity<CustomersTypes>(entity =>
{
entity.HasKey(e => e.CustomerTypeId)
.HasName("PK_CustomersTypes");

entity.Property(e => e.CustomerTypeId).ValueGeneratedNever();

entity.Property(e => e.Description).HasColumnType("varchar(50)");
});
}

}
}

Debemos agregar en nuestro archivo Startup.cs la inyección de nuestra base de datos.

public void ConfigureServices(IServiceCollection services){
services.AddMvc();
services.AddDbContext<DemoDBContext>();
}

Ahora que tenemos todo configurado crearemos dentro de la carpeta Controllers un archivo llamado customers.cs donde tendremos nuestra api:

CustomersControllers.cs

using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using DemoService.Models;
using System.Linq;

namespace DemoService.Controllers
{
[Route("api/[controller]")]
public class CustomersController : Controller
{
private readonly DemoDBContext _context;

public CustomersController(DemoDBContext context)
{
_context = context;
}

[HttpGet]
public IEnumerable<Customers> GetAll()
{
return _context.Customers.ToList();
}

}
}

Para comprobar que funciona correctamente ejecutaremos la aplicación presionando F5 y lo invocamos con el Postman:

Bien está funcionando correctamente. Agregamos los métodos de crear, editar y eliminar y también agregaremos el CustomersTypesController.cs y un modelo que será ModeCustomerPage.cs que será para devolver páginas de Customers.

Models/ViewModelPage.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DemoService.Models;

namespace DemoService.Models
{
public class ViewModelPage
{
public int CountPages { get; set; }
public int CountCustomers { get; set; }
public int ActualPage { get; set; }
public IList<Customers> customers { get; set; }
}
}

CustomersControllers.cs

using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using DemoService.Models;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;

namespace DemoService.Controllers
{
[Route("api/[controller]")]
public class CustomersController : Controller
{
private readonly DemoDBContext _context;

public CustomersController(DemoDBContext context)
{
_context = context;
}

[HttpGet]
public IEnumerable<Customers> GetCustomers()
{
return _context.Customers;
}

[HttpGet("{id}")]
public async Task<IActionResult> GetCustomers([FromRoute] int id)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}

var customers = await _context.Customers.SingleOrDefaultAsync(m => m.CustomerId == id);

if (customers == null)
{
return NotFound();
}

return Ok(customers);
}

[HttpGet]
[Route("{numberPage}/{perPage}")]
public ViewModelPage GetCustomerPaging(int numberPage, int perPage)
{

int _customersCount = GetCustomers().Count();
int _countPages = (_customersCount / perPage) + ( _customersCount % perPage == 0 ? 0 : 1);

var page = new ViewModelPage();
page.ActualPage = numberPage;
page.CountCustomers = GetCustomers().Count();
page.CountPages = _countPages;
page.customers = GetCustomers().Skip(numberPage * perPage).Take(perPage).ToList();

return page;
}

[HttpPut("{id}")]
public async Task<IActionResult> PutCustomers([FromRoute] int id, [FromBody] Customers customers)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}

if (id != customers.CustomerId)
{
return BadRequest();
}

_context.Entry(customers).State = EntityState.Modified;

try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!CustomersExists(id))
{
return NotFound();
}
else
{
throw;
}
}

return NoContent();
}

[HttpPost]
public  IActionResult PostCustomers([FromBody] Customers customers)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}

_context.Customers.Add(customers);
_context.SaveChanges();

return CreatedAtAction("GetCustomers", new { id = customers.CustomerId }, customers);
}

[HttpDelete("{id}")]
public async Task<IActionResult> DeleteCustomers([FromRoute] int id)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}

var customers = await _context.Customers.SingleOrDefaultAsync(m => m.CustomerId == id);
if (customers == null)
{
return NotFound();
}

_context.Customers.Remove(customers);
await _context.SaveChangesAsync();

return Ok(customers);
}

private bool CustomersExists(int id)
{
return _context.Customers.Any(e => e.CustomerId == id);
}

}
}

CustomersTypesControllers.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using DemoService.Models;

namespace DemoService.Controllers
{

[Route("api/[controller]")]
public class CustomersTypesController : Controller
{
private readonly DemoDBContext _context;

public CustomersTypesController(DemoDBContext context)
{
_context = context;
}

[HttpGet]
public IEnumerable<CustomersTypes> GetCustomersTypes()
{
return _context.CustomersTypes;
}

[HttpGet("{id}")]
public async Task<IActionResult> GetCustomersTypes([FromRoute] int id)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}

var customersTypes = await _context.CustomersTypes.SingleOrDefaultAsync(m => m.CustomerTypeId == id);

if (customersTypes == null)
{
return NotFound();
}

return Ok(customersTypes);
}

[HttpPut("{id}")]
public async Task<IActionResult> PutCustomersTypes([FromRoute] int id, [FromBody] CustomersTypes customersTypes)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}

if (id != customersTypes.CustomerTypeId)
{
return BadRequest();
}

_context.Entry(customersTypes).State = EntityState.Modified;

try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!CustomersTypesExists(id))
{
return NotFound();
}
else
{
throw;
}
}

return NoContent();
}

[HttpPost]
public async Task<IActionResult> PostCustomersTypes([FromBody] CustomersTypes customersTypes)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}

_context.CustomersTypes.Add(customersTypes);
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateException)
{
if (CustomersTypesExists(customersTypes.CustomerTypeId))
{
return new StatusCodeResult(StatusCodes.Status409Conflict);
}
else
{
throw;
}
}

return CreatedAtAction("GetCustomersTypes", new { id = customersTypes.CustomerTypeId }, customersTypes);
}

[HttpDelete("{id}")]
public async Task<IActionResult> DeleteCustomersTypes([FromRoute] int id)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}

var customersTypes = await _context.CustomersTypes.SingleOrDefaultAsync(m => m.CustomerTypeId == id);
if (customersTypes == null)
{
return NotFound();
}

_context.CustomersTypes.Remove(customersTypes);
await _context.SaveChangesAsync();

return Ok(customersTypes);
}

private bool CustomersTypesExists(int id)
{
return _context.CustomersTypes.Any(e => e.CustomerTypeId == id);
}
}
}

Listo nuestra aplicación está completa ahora probaremos un post con el postman.

Conclusión

Hemos instalado y configurado .Net Core y Asp.Net Core en nuestro linux. También hicimos una pequeña base de datos y nos conectamos a ella por medio de WebApi para tener servicio Rest. Estos servicios rest los usaremos en otros post para algunos ejemplo. Pueden descargar el código complete de GitHub desde esta url https://github.com/withoutdebugger/DemoService

 

 

Fernando Sonego

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *