Reducing the amount of boilerplate code in a webapi application

I write a client and a server for the project. The essence of the project: warehouse accounting, perhaps in the future it will be expanded with the addition of accounting. That is, warehouses, documents of arrival, expense, movement, salary.

There is a scheme: C# desktop-WEB API Asp.Net Core - Database MySQL

The client sends a request to the server, the server accesses the database, and returns JSON. Via HttpClient.

MVC schema. So far, I have tested it on one plate. In the controller, I registered the API(for examples):

    // GET: api/Products
    [HttpGet]
    public async Task<ActionResult<IEnumerable<Product>>> GetProduct()
    {
        return await _context.Product.ToListAsync();
    }

    // GET: api/Products/5
    [HttpGet("{id}")]
    public async Task<ActionResult<Product>> GetProduct(int id)
    {
        var product = await _context.Product.FindAsync(id);

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

        return product;
    }
  1. Tell me, when there will be a lot of tables, and there will be a lot of query options, then you need to write each query like this(according to the type of what is in the code)?
  2. Is there any more optimal solution and am I doing everything right?

    That is, in the future, I plan to create a controller for each table and write api requests for the server in it.

Author: A K, 2019-06-03

3 answers

You are doing everything right, but for typical operations, you have come up with such a thing as scaffolding.

enter a description of the image here

This is configured as follows.

In the folder C:\Users\{username}\.nuget\packages\microsoft.visualstudio.web.codegenerators. mvc\2.2.2 \ Templates (you can have folders 2.2.1 and others) there are templates provided by microsoft by default along with the studio, for example:

@inherits Microsoft.VisualStudio.Web.CodeGeneration.Templating.RazorTemplateBase
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

@{string modelName = (Model.ClassName.EndsWith("Controller") ? Model.ClassName.Substring(0, Model.ClassName.Length - 10) : Model.ClassName);}
namespace @Model.NamespaceName
{
    [Route("api/[controller]")]
    [ApiController]
    public class @Model.ClassName : ControllerBase
    {
        // GET: api/@modelName
        [HttpGet]
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET: api/@modelName/5
        [HttpGet("{id}", Name = "Get")]
        public string Get(int id)
        {
            return "value";
        }

        // POST: api/@modelName
        [HttpPost]
        public void Post([FromBody] string value)
        {
        }

        // PUT: api/@modelName/5
        [HttpPut("{id}")]
        public void Put(int id, [FromBody] string value)
        {
        }

        // DELETE: api/ApiWithActions/5
        [HttpDelete("{id}")]
        public void Delete(int id)
        {
        }
    }
}

I recommend not to touch the default templates, and copy the Templates folder to your project and edit it there as you need:

enter image description here

Related links:

 4
Author: A K, 2019-06-04 06:35:04

Almost certainly, most tables will require the same algorithms: get entities by key, get a list of them by some attribute with pagination, etc. This means that this code needs to be somehow abstracted from the table type.

  1. You can abstract the DAL (carry away the DbContext and get the data from the controller to another location).
  2. Make some basic operations in the generalized code (for example, a basic repository that can do a simple CRUD for any table), make specific parts of the request in the heirs, building the request in parts using IQueriable.
  3. Create the filter entity and pass it to the methods of the repository, where the query will already be based on it.

Similarly, you can make the interface layer (controllers) generalized, interspersed with custom logic.

 3
Author: free_ze, 2019-06-03 12:28:18

Tell me, when there will be a lot of tables, and there will be a lot of options for requests, then you need to write each request like this(by type what's in the code)?

It depends on how many parameters are in the request. If there are few of them, it is easier to prescribe each one separately. If there are a lot of them, it is better to use DTO (Data Transfer Object) and structure the parameters in it.

That is, in the future, I plan to create a controller for each table and write the api in it requests for the server.

If you have a client that allows you to change all tables, then you may have to do just that. And then, depending on the situation, you can build a common editing point for several tables.

And, in general, this approach is often not justified. At least because not all tables need to be edited. for example, tables that store enumerations.

However, if it is quite good, you should focus on the model the subject area and already based on it to design the system.

 1
Author: Streletz, 2019-06-03 11:56:02