2015-06-17 12 views
10

Voglio creare un gestore di immagini, ma io sono lacerati tra l'utilizzo Web API 2 o semplicemente un normale Generic Handler (ashx)Web Api 2 o Generic Handler per servire le immagini?

ho implementato sia in passato, ma quale è la più corretta. Ho trovato un vecchio post SO LINK ma è ancora veramente rilevante?

risposta

6

WebApi è completamente in grado e lo preferisco. L'altra risposta è giusta che JSON e XML sono predefiniti, ma è possibile aggiungere il proprio MediaFormatter e servire qualsiasi tipo di contenuto per qualsiasi modello. Ciò consente di eseguire la negoziazione del contenuto e fornire contenuti diversi in base all'intestazione Accept o all'estensione del file. Facciamo finta che il nostro modello sia un "utente". Immagina di chiedere un "Utente" come json, xml, jpg, pdf. Con WebApi, possiamo usare le estensioni di file o l'intestazione Accept e chiedere/Users/1 o Users/1.json per JSON, Users/1.jpg per jpg, Users/1.xml per xml, /Users/1.pdf per pdf, ecc. Tutti questi potrebbero anche essere/Users/1 con diverse intestazioni Accept con qualità in modo che i tuoi clienti possano chiedere gli utenti/1 con un header Accept che chiede prima jpg, ma ricade in png.

Ecco un esempio di come creare un formattatore per .jpg.

public class JpegFormatter : MediaTypeFormatter 
{ 
    public JpegFormatter() 
    { 
     //this allows a route with extensions like /Users/1.jpg 
     this.AddUriPathExtensionMapping(".jpg", "image/jpeg"); 

     //this allows a normal route like /Users/1 and an Accept header of image/jpeg 
     this.SupportedMediaTypes.Add(new MediaTypeHeaderValue("image/jpeg")); 
    } 

    public override bool CanReadType(Type type) 
    { 
     //Can this formatter read binary jpg data? 
     //answer true or false here 
     return false; 
    } 

    public override bool CanWriteType(Type type) 
    { 
     //Can this formatter write jpg binary if for the given type? 
     //Check the type and answer. You could use the same formatter for many different types. 
     return type == typeof(User); 
    } 

    public override async Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, 
     TransportContext transportContext) 
    { 
     //value will be whatever model was returned from your controller 
     //you may need to check data here to know what jpg to get 

     var user = value as User; 
     if (null == user) 
     { 
      throw new NotFoundException(); 
     } 

     var stream = SomeMethodToGetYourStream(user); 

     await stream.CopyToAsync(writeStream); 
    } 
} 

Ora dobbiamo registrare il nostro formattatore (in genere App_Start/WebApiConfig.cs)

public static class WebApiConfig 
{ 
    public static void Register(HttpConfiguration config) 
    { 
     ... 

     //typical route configs to allow file extensions 
     config.Routes.MapHttpRoute("ext", "{controller}/{id}.{ext}"); 
     config.Routes.MapHttpRoute("default", "{controller}/{id}", new { id = RouteParameter.Optional }); 

     //remove any default formatters such as xml 
     config.Formatters.Clear(); 

     //order of formatters matter! 
     //let's put JSON in as the default first 
     config.Formatters.Add(new JsonMediaTypeFormatter()); 

     //now we add our custom formatter 
     config.Formatters.Add(new JpegFormatter()); 
    } 
} 

E, infine, il nostro controller

public class UsersController : ApiController 
{ 
    public IHttpActionResult Get(int id) 
    { 
     var user = SomeMethodToGetUsersById(id); 

     return this.Ok(user); 
    } 
} 

Il controller non dovrà cambiare quando si aggiungono diversi formattatori. Restituisce semplicemente il modello e quindi i formattatori eseguono il kick in un secondo momento nella pipeline. Adoro i formattatori in quanto fornisce una così ricca API. Puoi leggere ulteriori informazioni sui formattatori su WebApi website.

+0

per favore dimmi qual'è l'output di '' quando il formattatore predefinito è JSON? Penso che la risposta basata sul tuo esempio sopra sia che non funzionerà – Dalorzo

+1

Ho risposto a questa stessa domanda sulla tua risposta, ma per rispondere anche a questo: Il formattatore predefinito verrebbe eseguito qui e sarà json. Questo è un problema HTML che non è in grado di esprimere un'intestazione Accept in un tag immagine. Per questo motivo, è necessario aggiungere un'estensione di file 'src = '/ api/image/getImg.jpg''. Questo verrà quindi indirizzato a JpegFormatter. Qualsiasi client in grado di impostare le intestazioni può semplicemente inserire l'intestazione Accept in image/jpeg e il formattatore verrà eseguito. – ManOVision

+0

@ManOVision, grazie per la tua risposta, questo è esattamente come l'ho fatto in passato. E penso che nello scenario che voglio usarlo la tua soluzione è probabilmente la migliore. – R4nc1d

6

Quello corretto è ashx il motivo è il tipo di contenuto . Se si utilizza Web Api, il tipo di contenuto a.k.a formattatore multimediale (formato) della risposta è quello definito per tutti i servizi che significa JSON, XML o oData.

//Global Asax, Web Api register methods is used to defined WebApi formatters 

config.Formatters.Insert(0, new System.Net.Http.Formatting.JsonMediaTypeFormatter());

Tuttavia l'immagine è una binaria quindi è necessario inviare l'immagine nel suo formato originale e non come JSON o XML

response.AddHeader("content-type", "image/png");

response.BinaryWrite(imageContent); 
response.Flush(); 

Ecco perché il ashx è lo strumento giusto per quel lavoro.

Un ulteriore vantaggio è che si ha maggiore controllo sull'output senza la necessità di codificare un nuovo "formattatore" (il modo di rendere WebApi per risolvere questo problema) per ogni tipo di immagine che si desidera restituire facendo qualcosa come in ASHX File:

var png = Image.FromFile("some.png"); 
png.Save("a.gif", var png = Image.FromFile("some.png"); 
png.Save("a.gif", ImageFormat.Gif); //Note you can save the new image into a MemoryStream to return it later in the same method. 

E avete un'ampia varietà di tipi di giocare con:

https://msdn.microsoft.com/en-us/library/system.drawing.imaging.imageformat(v=vs.110).aspx

Importa nt: È chiaro per tutti noi che sia WebApi e Ashx possono restituire immagini. Non sto dicendo in alcun modo che non puoi raggiungere questo obiettivo con WebApi, tutto quello che sto dicendo è perché credo che Ashx sia la scelta giusta.

+0

WebAPI non ha alcun problema nel gestire il formato binario, tutto ciò che serve è creare un formattatore. –

+1

Eppure inciderete su tutti gli instradamenti sotto quel formattatore invece di un singolo metodo che restituisce un'immagine. Non ho detto che non è possibile non solo lo strumento giusto – Dalorzo

+0

Se si desidera inviare il formato binario, si desidera influenzare tutte le rotte che lo restituiscono. Non capisco il tuo punto. –

1

Sono un grande fan di flessibilità e personalizzazione. Io personalmente andrei per httpHandler. Quindi, per rispondere alla tua domanda, dipende davvero dalle tue esigenze.

Prima cosa WebAPI è il risultato dell'evoluzione dalle chiamate http (GET/POST) ai servizi Web e la necessità di poter trasferire i dati a un costo inferiore rispetto ai servizi Web. HttpHandlers ha utilizzato lo stesso concetto molto tempo prima delle web apis. Fondamentalmente gli apis web non sono altro che una pagina http senza la sua interfaccia utente (se lo si desidera).

Poche cose hanno bisogno di sapere prima di scegliere HttpHandler o Api Web tempo

  1. sviluppo - se si conosce entrambi molto bene e ciò che avrà meno tempo per voi di implementare
  2. Come ManOVision menzionato nella sua risposta, l'utente di routing/1 è ancora possibile implementare con codice semplice e httphandler in modo da non aver realmente bisogno di API Web per questo. solo tu potresti dover raddrizzare manualmente il codice aggiungendo un po 'di tempo allo sviluppo
  3. Flessibilità, personalmente mi piace questa parte dato che sarò in grado di controllare il tipo di contenuto di risposta che voglio a seconda dei dati forniti dall'utente. Non ho bisogno di eseguire controlli di sessione e reindirizzare a qualsiasi pagina. Posso ancora controllare questo comportamento per quello che voglio. anche le API Web possono essere eseguite, ma per lo più le cose vengono prese in fase di esecuzione da sole per la configurazione che abbiamo implementato nello sviluppo.
  4. La pagina Web di rendering è la stessa per entrambi. Sebbene httphandler sia facile, quindi perché usare l'API Web?

Ci potrebbe essere più confronto (come manager, penso anche dal punto di vista gestionale e non completamente tecnico), quindi potrebbe essere necessario valutare le opzioni e decidere cosa fare. Poiché il file del gestore è in ogni caso il fondamento dell'API web, direi che dà più potere allo sviluppatore di quanto non faccia la web api. proprio come un socket http farebbe più di httphandler.

Problemi correlati