2013-01-23 11 views
5

Essendo nuovo su MVC4 + Entity + WebAPI Ero frustrato per avere semplicemente GET, gestori di controller POST e associazioni personalizzate per i modelli di dati.Come generare (auto) un controller webapi per MVC + Entity o interrogare genericamente tutti i tipi

Quello che immagino mi stia chiedendo c'è uno strumento di generazione, ad esempio, rendere il tuo controller di classe dalla classe dati in modo da poter semplicemente eseguire semplici comandi GET direttamente dai dati?

Qual è l'approccio per fare un'API RESTful generico in modo comandi potrebbero essere realizzati come tali

GET api/1.0/{genericdatatype}/{id}

dove il tipo di dati generico può essere qualsiasi modello e nessun controller specifico? Dire che non ho bisogno di PUT (gestito tramite l'app MVC) quindi non ho davvero bisogno di validazione POST ecc.

+0

Immagino che la ragione iniziale che volevo fosse perché avevo degli sviluppatori front-end in attesa di iniziare a integrare i servizi. Sarebbe stato grandioso se avessi potuto "spaccare" un'API CRUD di base senza alcun lavoro. Ma, se sei disposto a rinunciare a RDB (e utilizzare solo per la conservazione a freddo) e andare in un negozio di documenti, il problema è alleviato. – FlavorScape

+0

vedere la mia risposta aggiornata di seguito: OData. – FlavorScape

risposta

3

C'è uno strumento/pacchetto chiamato MVC Scaffolding che costruirà i controller in base ai modelli.

http://mvcscaffolding.codeplex.com/

http://blog.stevensanderson.com/2011/01/13/scaffold-your-aspnet-mvc-3-project-with-the-mvcscaffolding-package/

Per quanto riguarda il pezzo generica, che è un processo molto lungo e difficile, che avrebbe preso un bel po 'di tempo. Mi piacerebbe vederlo anche se qualcuno ha una buona risposta per questo.

EDIT: Ho trascorso un po 'di tempo aggiuntivo a esaminare il pezzo generico. Sembra che qualcun altro abbia avuto un pensiero simile e ha posto una domanda quasi identica qui: Generic Web Api controller to support any model.

Alla fine della giornata, esprimono alcune preoccupazioni eccellenti in quella conversazione. Come gestisci diversi tipi di ID? Avrebbero sempre bisogno di essere stringhe e poi analizzati? E una volta entrati in più regole aziendali sospetto che avresti un livello aziendale molto complicato dietro al controller. Detto questo, direi che è meglio attenersi a un'armatura diritta anziché costruire un'API generica. Certo, probabilmente potrebbe essere fatto, ma a che costo in tempo e codice di analisi pazzo dietro l'API? Solo i miei pensieri

+0

MVC4 + Entity è essenzialmente uno scaffolding ... Quello che sto cercando è uno strumento per abilitare generici comandi di resto (possibilmente generati) dal modello Entity Framework. Hai tutti i modelli, non capisco perché dovresti aggiungere manualmente un controller per rendere ogni tipo di dati. – FlavorScape

+0

Se si utilizza lo scaffolding, esiste una API Web specifica sul pacchetto di installazione WebApi.Scaffolding http://webapiscaffolding.codeplex.com/ –

+0

@FlavorScape Ho aggiunto un collegamento di conversazione di overflow dello stack aggiuntivo. Alla fine della giornata, penso che quel tipo di controller API generico sarebbe probabilmente più un problema che ne vale la pena. –

2

Probabilmente questa risposta è troppo tardi per il poster originale, ma forse altri possono usarlo.

Ho appena cucinato questo controller di base API generico per MVC 5 codici prime operazioni CRUD:

using System; 
using System.Collections.Generic; 
using System.Data; 
using System.Data.Entity; 
using System.Data.Entity.Infrastructure; 
using System.Linq; 
using System.Net; 
using System.Net.Http; 
using System.Web.Http; 
using My.Models; 
using System.Data.Entity.Validation; 

namespace My.Controllers.Api 
{ 
    public abstract class CrudController<TEntity> 
    : ApiController where TEntity : class 
    { 
    private readonly MyContext _db = new MyContext(); 
    private readonly DbSet<TEntity> _dbSet; 

    protected CrudController(Func<MyContext, DbSet<TEntity>> dbSet) 
    { 
     _db = new EtlContext(); 
     _dbSet = dbSet(_db); 
    } 

    public IEnumerable<TEntity> Get() 
    { 
     return _dbSet.AsEnumerable(); 
    } 

    public HttpResponseMessage Post(TEntity entity) 
    { 
     try 
     { 
     if (!ModelState.IsValid) 
      return Request.CreateResponse(HttpStatusCode.BadRequest); 

     _db.Entry(entity).State = EntityState.Added; 

     _db.SaveChanges(); 

     return Request.CreateResponse(HttpStatusCode.Created); 
     } 
     catch (DbEntityValidationException) 
     { 
     return Request.CreateResponse(HttpStatusCode.BadRequest); 
     } 
     catch (DbUpdateException) 
     { 
     return Request.CreateResponse(HttpStatusCode.Conflict); 
     } 
    } 

    public HttpResponseMessage Put(TEntity entity) 
    { 
     try 
     { 
     if (!ModelState.IsValid) 
      return Request.CreateResponse(HttpStatusCode.BadRequest); 

     _db.Entry(entity).State = EntityState.Modified; 

     _db.SaveChanges(); 

     return Request.CreateResponse(HttpStatusCode.OK); 
     } 
     catch (DbEntityValidationException) 
     { 
     return Request.CreateResponse(HttpStatusCode.BadRequest); 
     } 
     catch (DbUpdateConcurrencyException) 
     { 
     return Request.CreateResponse(HttpStatusCode.NotFound); 
     } 
     catch (DbUpdateException) 
     { 
     return Request.CreateResponse(HttpStatusCode.Conflict); 
     } 
    } 

    public HttpResponseMessage Delete(TEntity entity) 
    { 
     try 
     { 
     _db.Entry(entity).State = EntityState.Deleted; 

     _db.SaveChanges(); 

     return Request.CreateResponse(HttpStatusCode.OK); 
     } 
     catch (DbUpdateConcurrencyException) 
     { 
     return Request.CreateResponse(HttpStatusCode.NotFound); 
     } 
    } 

    protected override void Dispose(bool disposing) 
    { 
     _db.Dispose(); 
     base.Dispose(disposing); 
    } 
    } 
} 

dovevo ancora fare sottoclassi per ogni DbSet come questo:

public class CustomersController 
    : CrudController<Customer> 
{ 
    public CustomersController() 
    : base(db => db.Customers) 
    {} 
} 

public class ProductsController 
    : CrudController<Product> 
{ 
    public ProductsController() 
    : base(db => db.Products) 
    {} 
} 

per fare questo lavoro di instradamento:

config.Routes.MapHttpRoute(
    name: "DefaultApi", 
    routeTemplate: "api/{controller}", 
); 
1

Sto offrendo un'alternativa che il nostro team ha adottato. OData. È un modo rapido per costruire il tuo modello RESTful iniziale, con più enfasi sulle query rispetto a CRUD, rende i dati disponibili senza dover costruire manualmente gli endpoint manualmente. Ora sto facendo il front-end per un progetto che ha OData sul server Web API e questo funziona brillantemente per liberare gli sviluppatori di back-end per lavorare su argomenti più urgenti rispetto agli endpoint delle collezioni.

Funziona anche con Entity framework.