# 5.4 Creando el servicio Productos

### Creando el controlador para los productos

Creamos nuestro servicio para los productos.

1. Da clic con el botón derecho de mouse sobre la carpeta Controller. Luego da clic en **Agregar -> Nuevo elemento con scaffold...**
2. &#x20;Seleccionamos la opción **Controlador de API con acciones que usan Entity Framework** y damos clic en el botón **Agregar**
3. En Clase de Modelo seleccionamos nuestra clase **Producto.**
4. El nombre del controlador le llamamos **ProductosController** y damos clic en **Agregar**

### Creando la clase de acceso a Datos para los productos

Creamos nuestra clase **ProductoDAO** en nuestra carpeta **DAO,** puedes copiar el código de tu clase CategoriaDAO y con la opción **Buscar y Remplazar** puedes remplazar la palabra categoria por Producto. O puedes copiar el código generado en cada método del controlador a tu clase ProductoDAO

{% code title="ProductoDAO.cs" %}

```csharp
public class ProductoDAO
{
    private readonly CaducaContext contexto;
    private readonly LocService localizacion;
    
    /// <summary>
    /// Mensaje de error personalizado
    /// </summary>
    public CustomError customError;

    /// <summary>
    /// Clase para acceso a la base de datos
    /// </summary>
    /// <param name="context"></param>
    public ProductoDAO(CaducaContext context, LocService locService)
    {
        this.contexto = context;
        this.localizacion = locService;
    }

    /// <summary>
    /// Obtiene todas las Productos
    /// </summary>
    /// <returns></returns>
    public List<Producto> ObtenerTodo()
    {
        return contexto.Producto.ToList();
    }

    /// <summary>
    /// Obtiene una Producto por us Id
    /// </summary>
    /// <param name="id">Id de la Producto</param>
    /// <returns></returns>
    public async Task<Producto> ObtenerPorIdAsync(int id)
    {
        return await contexto.Producto.FindAsync(id);
    }

    /// <summary>
    /// Permite agregar una nueva Producto
    /// </summary>
    /// <param name="Producto"></param>
    /// <returns></returns>
    public async Task<bool> AgregarAsync(Producto Producto)
    {
        Producto registroRepetido;
        try
        {
            registroRepetido = contexto.Producto.
                  FirstOrDefault(c => c.Nombre == Producto.Nombre);
            if (registroRepetido != null)
            {
                 customError = new CustomError(400, 
                         String.Format(this.localizacion
                             .GetLocalizedHtmlString("Repeteaded"), 
                                           "Producto",
                                           "nombre"), "Nombre");
                 return false;
            }
            registroRepetido = contexto.Producto.
                    FirstOrDefault(c => c.Clave == Producto.Clave);
            if (registroRepetido != null)
            {
                 customError = new CustomError(400, 
                         String.Format(this.localizacion
                             .GetLocalizedHtmlString("Repeteaded"), 
                                         "Producto", 
                                         "clave"), "Clave");
                 return false;
            }

            contexto.Producto.Add(Producto);
            await contexto.SaveChangesAsync();
        }
        catch (Exception ex)
        {
                Console.WriteLine(ex.Message);
                return false;
        }
        return true;
    }

    /// <summary>
    /// Modidica una Producto
    /// </summary>
    /// <param name="Producto">Datos de la Producto</param>
    /// <returns></returns>
    public async Task<bool> ModificarAsync(Producto Producto)
    {
        Producto registroRepetido;
        try
        {
            //Se busca si existe una Producto con el mismo nombre 
            //pero diferente Id
            registroRepetido = contexto.Producto
                            .FirstOrDefault(
                                   c => c.Nombre == Producto.Nombre
                                   && c.Id != Producto.Id);
            if (registroRepetido != null)
            {
               customError = new CustomError(400, 
                        String.Format(this.localizacion
                            .GetLocalizedHtmlString("Repeteaded"), 
                                    "Producto", "nombre"), "Nombre");
               return false;
             }
             registroRepetido = contexto.Producto
                         .FirstOrDefault(
                             c => c.Clave == Producto.Clave
                             && c.Id != Producto.Id);
             if (registroRepetido != null)
             {
                 customError = new CustomError(400, 
                            String.Format(this.localizacion
                                .GetLocalizedHtmlString("Repeteaded"),
                                    "Producto", "clave"), "Clave");
                 return false;
              }
              contexto.Entry(Producto).State = EntityState.Modified;
              await contexto.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!ExisteProducto(Producto.Id))
            {
                 return false;
            }
        }
        return true;
    }

    /// <summary>
    /// Permite borrar una Producto por Id
    /// </summary>
    /// <param name="id">Id de la Producto</param>
    /// <returns></returns>
    public async Task<bool> BorraAsync(int id)
    {
        var Producto = await ObtenerPorIdAsync(id);
        if (Producto == null)
        {
            customError = new CustomError(404, 
                String.Format(this.localizacion
                    .GetLocalizedHtmlString("NotFound"), 
                                            "El Producto"), "Id");
            return false;
        }

        contexto.Producto.Remove(Producto);
        await contexto.SaveChangesAsync();
        return true;
    }

    private bool ExisteProducto(int id)
    {
        return contexto.Producto.Any(e => e.Id == id);
    }
}
```

{% endcode %}

### Modificando el controller

Modificamos nuestra clase controller para que reciba como parámetro el objeto LocService y que tome nuestra clase ProductoDAO

{% code title="ProductosController.cs" %}

```csharp
/// <summary>
/// Servicios para los productos
/// </summary>
[Route("api/[controller]")]
[ApiController]
public class ProductosController : ControllerBase
{
	private readonly LocService _localizer;
	private readonly CaducaContext _context;
	private ProductoDAO productoDAO;
	/// <summary>
	/// Constructor
	/// </summary>
	/// <param name="context"></param>
	/// <param name="localize"></param>
	public ProductosController(CaducaContext context, 
	                           LocService localize)
	{
		_context = context;
		productoDAO = new ProductoDAO(context, localize);
	}

	/// <summary>
	/// Obtener todos los productos
	/// </summary>
	/// <returns></returns>
	// GET: api/Productos
	[HttpGet]
	public IEnumerable<Producto> GetProducto()
	{
		return productoDAO.ObtenerTodo();
	}

	/// <summary>
	/// Obtener un producto por su Id
	/// </summary>
	/// <param name="id"></param>
	/// <returns></returns>
	// GET: api/Productos/5
	[HttpGet("{id}")]
	public async Task<IActionResult> GetProducto([FromRoute] int id)
	{
		var producto = await productoDAO.ObtenerPorIdAsync(id);

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

		return Ok(producto);
	}

	/// <summary>
	/// Actualizar un producto
	/// </summary>
	/// <param name="id">Id del producto</param>
	/// <param name="producto">Datos del producto</param>
	/// <returns></returns>
	// PUT: api/Productos/5
	[HttpPut("{id}")]
	public async Task<IActionResult> PutProducto([FromRoute] int id,
	                                  [FromBody] Producto producto)
	{
		if (!ModelState.IsValid)
		{
			return BadRequest(ModelState);
		}

		if (id != producto.Id)
		{
			return BadRequest();
		}

		if (!await productoDAO.ModificarAsync(producto))
		{
			return StatusCode(productoDAO.customError.StatusCode,
							  productoDAO.customError.Message);
		}

		return NoContent();

	}

	/// <summary>
	/// Agregar un producto
	/// </summary>
	/// <param name="producto">Datos del producto a agregar</param>
	/// <returns></returns>
	// POST: api/Productos
	[HttpPost]
	public async Task<IActionResult> PostProducto(
	              [FromBody] Producto producto)
	{
		if (!await productoDAO.AgregarAsync(producto))
		{
			return StatusCode(productoDAO.customError.StatusCode,
							  productoDAO.customError.Message);
		}

		return CreatedAtAction("GetProducto", 
		       new { id = producto.Id }, producto);
	}

	/// <summary>
	/// Borrar un producto
	/// </summary>
	/// <param name="id"></param>
	/// <returns></returns>
	// DELETE: api/Productos/5
	[HttpDelete("{id}")]
	public async Task<IActionResult> DeleteProducto(
	                                            [FromRoute] int id)
	{
		if (!ModelState.IsValid)
		{
			return BadRequest(ModelState);
		}
		if (!await productoDAO.BorraAsync(id))
		{
			return StatusCode(productoDAO.customError.StatusCode,
							  productoDAO.customError.Message);
		}
		return Ok();
	}

}
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://abi.gitbook.io/net-core/5.-agregando-el-servicio-para-los-productos/5.4-creando-el-servicio-productos.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
