简体   繁体   中英

One Web API Controller to control all models

I am creating a MVC Core 1.0.1 project that will include both API and Web. So i have created my models and now i want to create CRUD operations within a single controller instead of scaffolding each model. I have created an ApiController that looks like this

[Consumes("application/json")]
[Produces("application/json")]
[Route("/api/{resource}")]
public class ApiController : Controller
{
    private readonly MasterContext _context;

    public ApiController(MasterContext context)
    {
        _context = context;
    }

    [HttpPost]
    public IActionResult Create(string resource, [FromBody] object body)
    {
        //_context.Add();
        return Ok("ok api Create");

    }

    [HttpGet("{id?}")]
    public IActionResult Read(string resource, int? id)
    {
        return Ok("ok api get Read");
    }
    [HttpPatch("{id}")]
    public IActionResult Update(string resource, [FromBody] object body)
    {
        //_context.Update();
        return Ok("ok api Update");
    }
    [HttpDelete("{id}")]
    public IActionResult Delete(string resource, [FromBody] object body)
    {
        return Ok("ok api Delete");
    }
}

This way i have a method for each HTTP method that i need (Post, Get, Patch, Delete), in the resource i have the model as a string and in body i have the body of the request as an object. Before working with entity framework to do the requested operation, i have to find the model according to resource and convert the object body to that class.

Any suggestions how to do that? A colleague has done this using Python, can this be done using c# and what downside will the result have? For example, i presume model validation will be hard to accomplish.

Yes, it's possible. Let's say we have this DbContext:

public partial class FooContext : DbContext
{
    //has "MyAssembly.Blog" type
    public virtual DbSet<Blog> Blog { get; set; }
}        

To save a new entity in database we should find Blog type first. Having the type, it's easy to deserialize object and save it:

//you called POST /blog
string resource = "blog";
string body = "{...}";

var context = new FooContext();

IEntityType entityType = context.Model
    .GetEntityTypes()
    .First(x => x.Name.EndsWith($".{resource}", StringComparison.OrdinalIgnoreCase));

//This type should be "MyAssembly.Blog" - exact entity CLR type.
//Another option to get this CLR type is assembly scan.
Type type = entityType.ClrType;

//having type, it is possible to create instance
object entity = JsonConvert.DeserializeObject("body", type);
//var entity = Activator.CreateInstance(type);

context.Entry(entity).State = EntityState.Added;
context.SaveChanges();

To read an entity by ID from database, use non-generic DbContext.Find

var entityFromDb = context.Find(type, id);

PS I think a generic ApiController is generally bad idea. It's bulky and it brings a huge unnecessary complexity but small benefits.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM