Demostración de cómo agregar funcionalidades básicas de consulta a tu Web API con OData en .NET Core
Selecciona ASP.NET Core Web Application como tipo de proyecto
Indica el nombre del proyecto, el de la solución y la ubicación de la misma.
Selecciona la plantilla API e indicar las características del proyecto
Navega por el repositorio en este punto de la historia, aquí.
Puedes ver los cambios específicos en este commit.
Crea una carpeta llamada Core y dentro de esta, una llamada Models, aquí crearemos los siguientes modelos de datos.
CommunityMembers:
namespace API.Core.Models
{
public class CommunityMember
{
public int CommunityId { get; set; }
public Community Community { get; set; }
public int MemberId { get; set; }
public Member Member { get; set; }
}
}
Community:
using System.Collections.Generic;
namespace API.Core.Models
{
public class Community
{
public int CommunityId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<CommunityMember> CommunityMembers { get; set; }
}
}
Technology:
using System.Collections.Generic;
namespace API.Core.Models
{
public class Technology
{
public int TechnologyId { get; set; }
public string Name { get; set; }
public ICollection<Member> Members { get; set; }
}
}
Member:
using System.Collections.Generic;
namespace API.Core.Models
{
public class Member
{
public int MemberId { get; set; }
public string Name { get; set; }
public double Salary { get; set; }
public int TechnologyId { get; set; }
public Technology Technology { get; set; }
public ICollection<CommunityMember> CommunityMembers { get; set; }
}
}
Navega por el repositorio en este punto de la historia, aquí.
Puedes ver los cambios específicos en este commit.
Dentro de la carpeta Core agrega una clase llamada ApplicationDbContext
, en ella se configura una relación muchos a muchos entre los modelos Community
y Member
using API.Core.Models;
using Microsoft.EntityFrameworkCore;
namespace API.Core
{
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public DbSet<Community> Communities { get; set; }
public DbSet<Technology> Technologies { get; set; }
public DbSet<Member> Members { get; set; }
public DbSet<CommunityMember> CommunityMembers { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<CommunityMember>()
.HasKey(cm => new { cm.CommunityId, cm.MemberId });
modelBuilder.Entity<CommunityMember>()
.HasOne(cm => cm.Community)
.WithMany(c => c.CommunityMembers)
.HasForeignKey(cm => cm.CommunityId);
modelBuilder.Entity<CommunityMember>()
.HasOne(cm => cm.Member)
.WithMany(m => m.CommunityMembers)
.HasForeignKey(cm => cm.MemberId);
}
}
}
Navega por el repositorio en este punto de la historia, aquí.
Puedes ver los cambios específicos en este commit.
En el proyecto API
es necesario agregar un objeto JSON en el archivo appsettings.json
para la cadena de conexión a la base de datos.
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"SqlServerConnection": "Server=(localdb)\\MSSQLLocalDB;Database=WebApiWithODataDemoDB;Trusted_Connection=True;ConnectRetryCount=0"
}
}
Navega por el repositorio en este punto de la historia, aquí.
Puedes ver los cambios específicos en este commit.
En el método ConfigureServices
de la clase Startup
agregamos el ApplicationDbContext
, configurando el tipo de base de datos a utilizar e indicándole la cadena de conexión.
using API.Core;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace API
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<ApplicationDbContext>(opt =>
{
opt.UseSqlServer(Configuration.GetConnectionString("SqlServerConnection"));
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
}
}
Navega por el repositorio en este punto de la historia, aquí.
Puedes ver los cambios específicos en este commit.
Vamos a agregar datos iniciales a los modelos para esta demostración, desde el ApplicationDbContext
en el método OnModelCreating
.
#region Data Seed
modelBuilder.Entity<Community>().HasData(
new Community() { CommunityId = 1, Name = "La Comarca", Description = "Somos una comunidad amante de la creatividad y la tecnología en sus diferentes fases que busca fomentar, inspirar y motivar el desarrollo personal y profesional de personas interesadas. Sin importar la tecnología o el sector, siempre estamos unidos. La Comarca reúne la creatividad de diferentes sectores e industrias en un mismo entorno, con la visión de ayudar a crecer profesionalmente a nuevos líderes de la innovación." },
new Community() { CommunityId = 2, Name = "Mujeres TICs RD", Description = "Somos una comunidad de mujeres apasionadas por la tecnología, profesionales en distintas áreas de las TIC que buscan inspirar, motivar, involucrar y educar a más chicas en el área, a través de acciones de capacitación y coaching para niñas y mujeres interesadas." },
new Community() { CommunityId = 3, Name = ".NET Dominicana", Description = ".NET Dominicana es una comunidad abierta a todos los desarrolladores en el país interesados en aprender y expandir sus conocimientos sobre las tecnologías Microsoft .NET y todo lo que tiene para ofrecer, todos los meses realizamos eventos elegidos por la comunidad. \n El objetivo es hacer nuevos amigos, aprender algo nuevo cada mes de los miembros de nuestra comunidad y compartir esto con nuestro entorno tecnológico." },
new Community() { CommunityId = 4, Name = "Aprendiendo BD con SQL Server", Description = "Somos un grupo amante de las tecnologías propias del área de datos, desde la administración hasta analítica avanzada." },
new Community() { CommunityId = 5, Name = "Linux Dominicana", Description = "Un lugar donde tratar temas relacionados al Open Source, Software Libre y distribuciones GNU/Linux." },
new Community() { CommunityId = 6, Name = "UI / UX Dominicana", Description = "Usergroup de Experiencia de Usuario y Diseño de Interfaces de República Dominicana." },
new Community() { CommunityId = 7, Name = "Developers Dominicanos", Description = "Esta es una comunidad de desarrolladores dominicanos, para conocer quiénes somos, en qué estamos, y de paso compartir temas, ayudarnos unos a otros a solucionar problemas que no encontremos en MSDN o StackOverflow, como por ejemplo problemas relevantes al desarrollo local, y publicar ofertas de trabajo." },
new Community() { CommunityId = 8, Name = "GDG Santo Domingo", Description = "Google Developer Groups Santo Domingo" },
new Community() { CommunityId = 9, Name = "Agile Dominicana", Description = "Somos un grupo de apasionados que deseamos compartir y promover los conocimientos de metodologias agiles para el beneficio de la comunidad." },
new Community() { CommunityId = 10, Name = "fria.js", Description = "Vamos a beber cerveza y tal vez hablar de JavaScript." },
new Community() { CommunityId = 11, Name = "TECHNOLOGY INNOVATION SUMMIT", Description = "Es un evento de tecnología donde los participantes aprenden acerca de los temas tecnológicos de vanguardia, y donde pueden conocer otras personas que compartan sus intereses." },
new Community() { CommunityId = 12, Name = "Caribbean Developers Conference", Description = "CDC reune a profesionales de software y emprendedores de diferentes idiomas, plataformas e industrias. \n Los participantes tienen la oportunidad de compartir, participar y aprender sobre temas de tendencias que están configurando el futuro de las TI y las empresas, hoy." },
new Community() { CommunityId = 13, Name = "CodeCampSDQ", Description = "CodeCampSDQ es una conferencia técnica con el objetivo primordial de educar a la comunidad de profesionales de TI en el Caribe en temas como: Desarrollo móvil y Web, Cloud Computing, DevOps, servicios cognitivos, entre otros." },
new Community() { CommunityId = 14, Name = "Hackers and Founders", Description = "Formado por emprendedores, H / F da cabida a programadores, desarrolladores de tecnología, emprendedores y todos aquellos amantes de las tecnologías que buscan emprender un proyecto y no saben por dónde empezar.Todo se trata del “networking” ¿Quiénes ampliar tu red de contactos ? entonces “Hackers & Founders” es donde debes estar." },
new Community() { CommunityId = 15, Name = "Open Saturday Conference", Description = "Surge como una iniciativa a compartir conocimientos sobre herramientas FOSS entre jóvenes profesionales, con el fin de aumentar la calidad de los servicios técnicos." },
new Community() { CommunityId = 16, Name = "Mujeres Cambiando el Mundo", Description = "“Mujeres Cambiando el Mundo - MCM”, o su versión en inglés “Women Changing the World - WCW”, con el lema: Por más chicas en Ciencia y Tecnología!. Busca a través de una serie de charlas y paneles, poder ayudar a las chicas a que vean la carrera de tecnología como una oportunidad, de que ellas tienen espacio y que pueden desarrollarse y llegar tan lejos como se lo propongan." },
new Community() { CommunityId = 17, Name = "Oddo Dominicana", Description = "Odoo Dominicana es una comunidad, que reúne personas de diferentes disciplinas de negocios, con la finalidad de compartir el conocimiento en el desarrollo de soluciones tecnológicas que faciliten los procesos en las empresas." },
new Community() { CommunityId = 18, Name = "Python Dominicana", Description = "Python Interest Group in the Dominican Republic If you want to enjoy discounts on o'reilly just use the 50% Discount with the ebooks and 40% with the printed media using the code PCBW on your purchases at http://shop.oreilly.com/" },
new Community() { CommunityId = 19, Name = "OWASP RD", Description = "Capitulo de Owasp Republica Dominicana " }
);
modelBuilder.Entity<Technology>().HasData(
new Technology() { TechnologyId = 1, Name = "Microsoft" },
new Technology() { TechnologyId = 2, Name = "Linux" },
new Technology() { TechnologyId = 3, Name = "Kotlin" },
new Technology() { TechnologyId = 4, Name = "Python" },
new Technology() { TechnologyId = 5, Name = "Javascript" },
new Technology() { TechnologyId = 6, Name = "Sketch" },
new Technology() { TechnologyId = 7, Name = "Docker" },
new Technology() { TechnologyId = 8, Name = "Xamarin" }
);
modelBuilder.Entity<Member>().HasData(
new Member() { MemberId = 1, Name = "Andres Pineda", Salary = 200000, TechnologyId = 1 },
new Member() { MemberId = 2, Name = "Claudio Sanchez", Salary = 188300, TechnologyId = 1 },
new Member() { MemberId = 3, Name = "Victor Recio", Salary = 180000, TechnologyId = 2 },
new Member() { MemberId = 4, Name = "Stanley Lara", Salary = 163500, TechnologyId = 1 },
new Member() { MemberId = 5, Name = "Shailyn Ortíz", Salary = 151000, TechnologyId = 4 },
new Member() { MemberId = 6, Name = "Yulissa Mateo", Salary = 150000, TechnologyId = 1 },
new Member() { MemberId = 7, Name = "Ángel García", Salary = 140000, TechnologyId = 1 },
new Member() { MemberId = 8, Name = "Luis Matos", Salary = 131900, TechnologyId = 8 },
new Member() { MemberId = 9, Name = "Charlin Agramonte", Salary = 145000, TechnologyId = 8 },
new Member() { MemberId = 10, Name = "Jearel Alcántara", Salary = 120000, TechnologyId = 2 },
new Member() { MemberId = 11, Name = "Leomaris Reyes", Salary = 120000, TechnologyId = 8 },
new Member() { MemberId = 12, Name = "Yhorby Matías", Salary = 130200, TechnologyId = 1 },
new Member() { MemberId = 13, Name = "Emmanuel Toribio", Salary = 150000, TechnologyId = 1 },
new Member() { MemberId = 14, Name = "Kenny Beltre", Salary = 120000, TechnologyId = 6 },
new Member() { MemberId = 15, Name = "Saira Isaac Hermandez", Salary = 145000, TechnologyId = 2 },
new Member() { MemberId = 16, Name = "Adonis Mendoza", Salary = 110000, TechnologyId = 5 }
);
modelBuilder.Entity<CommunityMember>().HasData(
new CommunityMember() { CommunityId = 12, MemberId = 1 },
new CommunityMember() { CommunityId = 13, MemberId = 1 },
new CommunityMember() { CommunityId = 14, MemberId = 1 },
new CommunityMember() { CommunityId = 18, MemberId = 1 },
new CommunityMember() { CommunityId = 12, MemberId = 2 },
new CommunityMember() { CommunityId = 13, MemberId = 2 },
new CommunityMember() { CommunityId = 14, MemberId = 2 },
new CommunityMember() { CommunityId = 5, MemberId = 3 },
new CommunityMember() { CommunityId = 14, MemberId = 3 },
new CommunityMember() { CommunityId = 15, MemberId = 3 },
new CommunityMember() { CommunityId = 1, MemberId = 4 },
new CommunityMember() { CommunityId = 2, MemberId = 4 },
new CommunityMember() { CommunityId = 4, MemberId = 4 },
new CommunityMember() { CommunityId = 11, MemberId = 4 },
new CommunityMember() { CommunityId = 14, MemberId = 4 },
new CommunityMember() { CommunityId = 5, MemberId = 5 },
new CommunityMember() { CommunityId = 11, MemberId = 5 },
new CommunityMember() { CommunityId = 1, MemberId = 5 },
new CommunityMember() { CommunityId = 18, MemberId = 5 },
new CommunityMember() { CommunityId = 1, MemberId = 6 },
new CommunityMember() { CommunityId = 2, MemberId = 6 },
new CommunityMember() { CommunityId = 12, MemberId = 6 },
new CommunityMember() { CommunityId = 13, MemberId = 6 },
new CommunityMember() { CommunityId = 14, MemberId = 6 },
new CommunityMember() { CommunityId = 15, MemberId = 6 },
new CommunityMember() { CommunityId = 16, MemberId = 6 },
new CommunityMember() { CommunityId = 1, MemberId = 7 },
new CommunityMember() { CommunityId = 2, MemberId = 7 },
new CommunityMember() { CommunityId = 3, MemberId = 7 },
new CommunityMember() { CommunityId = 11, MemberId = 7 },
new CommunityMember() { CommunityId = 12, MemberId = 7 },
new CommunityMember() { CommunityId = 13, MemberId = 7 },
new CommunityMember() { CommunityId = 1, MemberId = 8 },
new CommunityMember() { CommunityId = 2, MemberId = 8 },
new CommunityMember() { CommunityId = 3, MemberId = 8 },
new CommunityMember() { CommunityId = 4, MemberId = 8 },
new CommunityMember() { CommunityId = 12, MemberId = 8 },
new CommunityMember() { CommunityId = 13, MemberId = 8 },
new CommunityMember() { CommunityId = 14, MemberId = 8 },
new CommunityMember() { CommunityId = 2, MemberId = 9 },
new CommunityMember() { CommunityId = 3, MemberId = 9 },
new CommunityMember() { CommunityId = 4, MemberId = 9 },
new CommunityMember() { CommunityId = 12, MemberId = 9 },
new CommunityMember() { CommunityId = 13, MemberId = 9 },
new CommunityMember() { CommunityId = 14, MemberId = 9 },
new CommunityMember() { CommunityId = 1, MemberId = 10 },
new CommunityMember() { CommunityId = 18, MemberId = 10 },
new CommunityMember() { CommunityId = 5, MemberId = 10 },
new CommunityMember() { CommunityId = 2, MemberId = 11 },
new CommunityMember() { CommunityId = 3, MemberId = 11 },
new CommunityMember() { CommunityId = 12, MemberId = 11 },
new CommunityMember() { CommunityId = 16, MemberId = 11 },
new CommunityMember() { CommunityId = 3, MemberId = 12 },
new CommunityMember() { CommunityId = 5, MemberId = 12 },
new CommunityMember() { CommunityId = 11, MemberId = 12 },
new CommunityMember() { CommunityId = 12, MemberId = 12 },
new CommunityMember() { CommunityId = 13, MemberId = 12 },
new CommunityMember() { CommunityId = 1, MemberId = 13 },
new CommunityMember() { CommunityId = 2, MemberId = 13 },
new CommunityMember() { CommunityId = 3, MemberId = 13 },
new CommunityMember() { CommunityId = 11, MemberId = 13 },
new CommunityMember() { CommunityId = 12, MemberId = 13 },
new CommunityMember() { CommunityId = 13, MemberId = 13 },
new CommunityMember() { CommunityId = 1, MemberId = 14 },
new CommunityMember() { CommunityId = 2, MemberId = 14 },
new CommunityMember() { CommunityId = 6, MemberId = 14 },
new CommunityMember() { CommunityId = 12, MemberId = 14 },
new CommunityMember() { CommunityId = 13, MemberId = 14 },
new CommunityMember() { CommunityId = 14, MemberId = 14 },
new CommunityMember() { CommunityId = 15, MemberId = 14 },
new CommunityMember() { CommunityId = 16, MemberId = 14 },
new CommunityMember() { CommunityId = 1, MemberId = 15 },
new CommunityMember() { CommunityId = 2, MemberId = 15 },
new CommunityMember() { CommunityId = 12, MemberId = 15 },
new CommunityMember() { CommunityId = 13, MemberId = 15 },
new CommunityMember() { CommunityId = 14, MemberId = 15 },
new CommunityMember() { CommunityId = 15, MemberId = 15 },
new CommunityMember() { CommunityId = 16, MemberId = 15 },
new CommunityMember() { CommunityId = 19, MemberId = 15 },
new CommunityMember() { CommunityId = 1, MemberId = 16 },
new CommunityMember() { CommunityId = 2, MemberId = 16 },
new CommunityMember() { CommunityId = 3, MemberId = 16 },
new CommunityMember() { CommunityId = 4, MemberId = 16 },
new CommunityMember() { CommunityId = 10, MemberId = 16 }
);
#endregion Data Seed
Navega por el repositorio en este punto de la historia, aquí.
Puedes ver los cambios específicos en este commit.
Luego de ejecutar el el comando add-migration InitialModel
en el Package Manager Console se creará un folder llamado Migration.
Navega por el repositorio en este punto de la historia, aquí.
Puedes ver los cambios específicos en este commit.
Vamos a crear los controladores para los modelos creados anteriormente.
CommunitiesController:
using API.Core; using API.Core.Models; using Microsoft.AspNet.OData; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks;
namespace API.Controllers { [Route("api/[controller]")][apicontroller] public class CommunitiesController : ControllerBase { private readonly ApplicationDbContext _context;
public CommunitiesController(ApplicationDbContext context)
{
_context = context;
}
// GET: api/Communities
[HttpGet]
[EnableQuery()]
public IEnumerable<Community> GetCommunities()
{
return _context.Communities;
}
// GET: api/Communities/5
[HttpGet("{id}")]
public async Task<ActionResult<Community>> GetCommunity(int id)
{
var community = await _context.Communities.FindAsync(id);
if (community == null)
{
return NotFound();
}
return community;
}
// PUT: api/Communities/5
[HttpPut("{id}")]
public async Task<IActionResult> PutCommunity(int id, Community community)
{
if (id != community.CommunityId)
{
return BadRequest();
}
_context.Entry(community).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!CommunityExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
// POST: api/Communities
[HttpPost]
public async Task<ActionResult<Community>> PostCommunity(Community community)
{
_context.Communities.Add(community);
await _context.SaveChangesAsync();
return CreatedAtAction("GetCommunity", new { id = community.CommunityId }, community);
}
// DELETE: api/Communities/5
[HttpDelete("{id}")]
public async Task<ActionResult<Community>> DeleteCommunity(int id)
{
var community = await _context.Communities.FindAsync(id);
if (community == null)
{
return NotFound();
}
_context.Communities.Remove(community);
await _context.SaveChangesAsync();
return community;
}
private bool CommunityExists(int id)
{
return _context.Communities.Any(e => e.CommunityId == id);
}
}
}
**CommunityMembersController**:
```Csharp
using API.Core;
using API.Core.Models;
using Microsoft.AspNet.OData;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace API.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class CommunityMembersController : ControllerBase
{
private readonly ApplicationDbContext _context;
public CommunityMembersController(ApplicationDbContext context)
{
_context = context;
}
// GET: api/CommunityMembers
[HttpGet]
[EnableQuery()]
public IEnumerable<CommunityMember> GetCommunityMembers()
{
return _context.CommunityMembers;
}
// GET: api/CommunityMembers/5
[HttpGet("{id}")]
public async Task<ActionResult<CommunityMember>> GetCommunityMember(int id)
{
var communityMember = await _context.CommunityMembers.FindAsync(id);
if (communityMember == null)
{
return NotFound();
}
return communityMember;
}
// PUT: api/CommunityMembers/5
[HttpPut("{id}")]
public async Task<IActionResult> PutCommunityMember(int id, CommunityMember communityMember)
{
if (id != communityMember.CommunityId)
{
return BadRequest();
}
_context.Entry(communityMember).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!CommunityMemberExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
// POST: api/CommunityMembers
[HttpPost]
public async Task<ActionResult<CommunityMember>> PostCommunityMember(CommunityMember communityMember)
{
_context.CommunityMembers.Add(communityMember);
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateException)
{
if (CommunityMemberExists(communityMember.CommunityId))
{
return Conflict();
}
else
{
throw;
}
}
return CreatedAtAction("GetCommunityMember", new { id = communityMember.CommunityId }, communityMember);
}
// DELETE: api/CommunityMembers/5
[HttpDelete("{id}")]
public async Task<ActionResult<CommunityMember>> DeleteCommunityMember(int id)
{
var communityMember = await _context.CommunityMembers.FindAsync(id);
if (communityMember == null)
{
return NotFound();
}
_context.CommunityMembers.Remove(communityMember);
await _context.SaveChangesAsync();
return communityMember;
}
private bool CommunityMemberExists(int id)
{
return _context.CommunityMembers.Any(e => e.CommunityId == id);
}
}
}
MembersController:
using API.Core;
using API.Core.Models;
using Microsoft.AspNet.OData;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace API.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class MembersController : ControllerBase
{
private readonly ApplicationDbContext _context;
public MembersController(ApplicationDbContext context)
{
_context = context;
}
// GET: api/Members
[HttpGet]
[EnableQuery()]
public IEnumerable<Member> GetMembers()
{
return _context.Members;
}
// GET: api/Members/5
[HttpGet("{id}")]
public async Task<ActionResult<Member>> GetMember(int id)
{
var member = await _context.Members.FindAsync(id);
if (member == null)
{
return NotFound();
}
return member;
}
// PUT: api/Members/5
[HttpPut("{id}")]
public async Task<IActionResult> PutMember(int id, Member member)
{
if (id != member.MemberId)
{
return BadRequest();
}
_context.Entry(member).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MemberExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
// POST: api/Members
[HttpPost]
public async Task<ActionResult<Member>> PostMember(Member member)
{
_context.Members.Add(member);
await _context.SaveChangesAsync();
return CreatedAtAction("GetMember", new { id = member.MemberId }, member);
}
// DELETE: api/Members/5
[HttpDelete("{id}")]
public async Task<ActionResult<Member>> DeleteMember(int id)
{
var member = await _context.Members.FindAsync(id);
if (member == null)
{
return NotFound();
}
_context.Members.Remove(member);
await _context.SaveChangesAsync();
return member;
}
private bool MemberExists(int id)
{
return _context.Members.Any(e => e.MemberId == id);
}
}
}
TechnologiesController:
using API.Core;
using API.Core.Models;
using Microsoft.AspNet.OData;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace API.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class TechnologiesController : ControllerBase
{
private readonly ApplicationDbContext _context;
public TechnologiesController(ApplicationDbContext context)
{
_context = context;
}
// GET: api/Technologies
[HttpGet]
[EnableQuery()]
public IEnumerable<Technology> GetTechnologies()
{
return _context.Technologies;
}
// GET: api/Technologies/5
[HttpGet("{id}")]
public async Task<ActionResult<Technology>> GetTechnology(int id)
{
var technology = await _context.Technologies.FindAsync(id);
if (technology == null)
{
return NotFound();
}
return technology;
}
// PUT: api/Technologies/5
[HttpPut("{id}")]
public async Task<IActionResult> PutTechnology(int id, Technology technology)
{
if (id != technology.TechnologyId)
{
return BadRequest();
}
_context.Entry(technology).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TechnologyExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
// POST: api/Technologies
[HttpPost]
public async Task<ActionResult<Technology>> PostTechnology(Technology technology)
{
_context.Technologies.Add(technology);
await _context.SaveChangesAsync();
return CreatedAtAction("GetTechnology", new { id = technology.TechnologyId }, technology);
}
// DELETE: api/Technologies/5
[HttpDelete("{id}")]
public async Task<ActionResult<Technology>> DeleteTechnology(int id)
{
var technology = await _context.Technologies.FindAsync(id);
if (technology == null)
{
return NotFound();
}
_context.Technologies.Remove(technology);
await _context.SaveChangesAsync();
return technology;
}
private bool TechnologyExists(int id)
{
return _context.Technologies.Any(e => e.TechnologyId == id);
}
}
}
Navega por el repositorio en este punto de la historia, aquí.
Puedes ver los cambios específicos en este [commit]https://github.com/robertlluberes/WebApiWithODataDemo/commit/e98f72861a40c4f7db50dc8bd90b8d60743c49a1).
Para poder utilizar OData
en nuestro proyecto es necesario instalar su paquete desde el Package Manager Consoler con el siguiente comando:
install-package Microsoft.AspNetCore.Odata
Navega por el repositorio en este punto de la historia, aquí.
Puedes ver los cambios específicos en este commit.
Es necesario indicarle a nuestra API que utilice los servicios de OData, desde la clase Startup
en el método ConfigureServices
using API.Core;
using Microsoft.AspNet.OData.Extensions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace API
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<ApplicationDbContext>(opt =>
{
opt.UseSqlServer(Configuration.GetConnectionString("SqlServerConnection"));
});
services.AddOData();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
}
}
Navega por el repositorio en este punto de la historia, aquí.
Puedes ver los cambios específicos en este commit.
Para poder utilizar las opciones de consultas de OData (Query string), es necesario habilitar inyección de dependencia en las consultas HTTP, en el método Configure
de la clase Startup
.
using API.Core;
using Microsoft.AspNet.OData.Extensions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace API
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<ApplicationDbContext>(opt =>
{
opt.UseSqlServer(Configuration.GetConnectionString("SqlServerConnection"));
});
services.AddOData();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc(routeBuilder =>
{
routeBuilder.EnableDependencyInjection();
});
}
}
}
Navega por el repositorio en este punto de la historia, aquí.
Puedes ver los cambios específicos en este commit.
Ahora es necesario configurar las funcionalidades que estarán disponible al momento de utilizar OData.
En este caso estamos habilitando:
using API.Core;
using Microsoft.AspNet.OData.Extensions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace API
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<ApplicationDbContext>(opt =>
{
opt.UseSqlServer(Configuration.GetConnectionString("SqlServerConnection"));
});
services.AddOData();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc(routeBuilder =>
{
routeBuilder.EnableDependencyInjection();
routeBuilder.Expand().Filter().OrderBy().MaxTop(100).Select();
});
}
}
}
Navega por el repositorio en este punto de la historia, aquí.
Puedes ver los cambios específicos en este commit.
Por ultimo, para poder realizar las consultas con OData sobre un controlador, es necesario colocarle en decorador [EnableQuery()]
.
Navega por el repositorio en este punto de la historia, aquí.
Puedes ver los cambios específicos en este commit.