2012-04-26 13 views
16

Si supponga che ho questo modelloasp web API implementazione di patch

public partial class Todo 
{ 
    public int id { get; set; } 
    public string content { get; set; } 
    public bool done { get; set; } 
} 

e trasmetto questa come dati JSON per il mio controller come una richiesta di patch. Questa è la mera azione di commutare una casella di controllo. Penso che abbia senso che voglio solo inviarlo al mio server, e non all'intero modello.

{ "id":1, "done" : true } 

Che aspetto deve avere il controller WebApi per elaborare correttamente questa semplice richiesta di patch JSON? Dovrei usare web api per questo, o dovrei usare un approccio più in stile rpc con mvc?

Sembra una cosa molto semplice da fare, ma non riesco a farlo bene! Penso che potrebbe essere necessario utilizzare un parametro diverso nel mio metodo di controllo, ma non sono sicuro.

Grazie per il vostro tempo.

+0

È possibile utilizzare JsonPatch supportato da ASP.NET, ASP.NET Core e PCL per Xamarin. https://github.com/KevinDockx/JsonPatch. Un buon articolo può essere trovato qui http://benfoster.io/blog/aspnet-core-json-patch-partial-api-updates –

+0

Questo è un altro problema, penso. Il mio modello non è basato su JSON. Come dovrebbe accadere l'aggiornamento di stato effettivo dovrebbe essere fino all'implementatore. Non voglio dover tradurre alcune specifiche RFC in una query SQL o mutazioni di entità. –

risposta

11

È possibile trovare la funzione PATCH nel pacchetto Nuget di pre-rilascio OData: Microsoft.AspNet.WebApi.OData.

informazioni come è possibile utilizzarlo per creare un'azione per la gestione delle patch può essere trovato nelle aggiornamenti parziali (richieste patch) sezione del post sul blog su OData support in ASP.NET Web API.

+1

Guarda questo esempio per fare patch attraverso il serializer json.net senza dipendere dai formati di filo di OData - https: //aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/DeltaJsonDeserialization/ –

1

ASP.NET Web API sembra mancare UpdateModel, TryUpdateModel, ecc

In ASP.NET MVC, li si potrebbe usare per ottenere l'effetto desiderato. Ho creato uno work item nello stack Web ASP.NET per il quale si può votare e se ottiene abbastanza voti, sarà implementato.

12

La modifica del metodo in PATCH non modifica il comportamento dell'API Web in alcun modo. Non esiste un meccanismo incorporato per eseguire aggiornamenti parziali. Uno dei motivi per cui non esiste un metodo PATCH per così tanto tempo è che non esiste un tipo di media ubiquo per l'applicazione di patch alle risorse.

In secondo luogo, stai chiedendo all'API Web di eseguire la serializzazione degli oggetti per te, quindi non esiste un tale concetto di applicazione di un oggetto parzialmente aggiornato. Ci sono così tante convenzioni da concordare, che cosa significa un valore nullo, che dire di un valore vuoto, come posso dire "non aggiornare questo DateTime". Che dire degli oggetti correlati, oggetti figlio? Come si fa a cancellare un elemento figlio? A meno che il team CLR non implementa un concetto di un tipo che contiene solo un sottoinsieme di membri di un altro tipo, gli aggiornamenti parziali e la serializzazione degli oggetti non andranno bene insieme.

Aliostad indica UpdateModel e ciò è possibile quando si aggiorna da un modulo HTML poiché il tipo di supporto application/x-www-form-urlencoded consente esplicitamente un insieme arbitrario di coppie di valori nome. Non esiste alcuna "serializzazione dell'oggetto" in corso. È solo una corrispondenza tra i nomi del modulo che corrispondono ai nomi sull'oggetto Model.

Per quanto mi riguarda, ho creato un nuovo tipo di supporto che utilizzo per eseguire aggiornamenti parziali che funzionano come un modulo ma che sono più avanzati perché possono gestire i dati gerarchici e mantenere un ordine agli aggiornamenti.

+0

+1. Questo file multimediale di formattazione può essere incluso nel web api contrib? Questo è uno scenario comune e posso immaginare che tale funzionalità venga spesso richiesta. – Aliostad

+0

Grazie per la tua risposta, quale sarebbe l'approccio giusto se volessi aggiornare solo un campo del mio modello (il campo "spuntato" in questo scenario)? Dovrei abbandonare web api? come posso fare questo senza perdere la convalida del mio modello? È difficile credere che un'azione così semplice non sarebbe possibile con "le latest dei latests" nelle tecnologie asp.net –

+0

Ho modificato la mia domanda per descrivere meglio il problema. –

0

Ho utilizzato Microsoft.AspNet.WebApi.OData per il mio progetto e ho avuto alcuni problemi con JSON (lavorando con numeri nel mio caso). Inoltre, il pacchetto OData ha alcune dipendenze che, dal mio punto di vista, sono troppo grandi per una singola funzione (~ 7 MB con tutte le dipendenze).

Così ho sviluppato una libreria semplice che fa quello che stai chiedendo: SimplePatch.

Come utilizzare

Installare il pacchetto utilizzando:

Install-Package SimplePatch 

Poi nel controller:

[HttpPatch] 
public IHttpActionResult PatchOne(Delta<Todo> todo) 
{ 
    if (todo.TryGetPropertyValue(nameof(Todo.id), out int id)) { 
     // Entity to update (from your datasource) 
     var todoToPatch = Todos.FirstOrDefault(x => x.id == id); 
     if (todoToPatch == null) return BadRequest("Todo not found"); 

     todo.Patch(todoToPatch);  

     // Now todoToPatch is updated with new values    
    } else { 
     return BadRequest(); 
    }  

    return Ok(); 
} 

la libreria di supporto massiccia patch di troppo:

[HttpPatch] 
public IHttpActionResult PatchMultiple(DeltaCollection<Todo> todos) 
{ 
    foreach (var todo in todos) 
    { 
     if (todo.TryGetPropertyValue(nameof(Todo.id), out int id)) 
     { 
      // Entity to update (from your datasource) 
      var entityToPatch = Todos.FirstOrDefault(x => x.id == Convert.ToInt32(id)); 
      if (entityToPatch == null) return BadRequest("Todo not found (Id = " + id + ")"); 

      person.Patch(entityToPatch); 
     } 
     else 
     { 
      return BadRequest("Id property not found for a todo"); 
     } 
    } 

    return Ok(); 
} 

Se si utilizza Entity Framework, è necessario aggiungere solo due righe di codice dopo la chiamata al metodo Patch:

entity.Patch(entityToPatch); 

dbContext.Entry(entityToPatch).State = EntityState.Modified; 
dbContext.SaveChanges(); 

Inoltre, è possibile escludere alcune proprietà di essere aggiornato quando il metodo Patch viene chiamato. Global.asax o Startup.cs

DeltaConfig.Init((cfg) => 
{ 
    cfg.ExcludeProperties<Todo>(x => x.id); 
}); 

Questo è utile quando si lavora con un ente e non si desidera creare un modello.

Problemi correlati