One Web API Controller to control all models

api-design asp.net-core-mvc asp.net-core-webapi c# entity-framework-core

Question

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.

1
3
4/24/2017 9:23:15 PM

Accepted Answer

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);

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

1
4/25/2017 7:36:13 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow