2015-08-14 11 views
9

Fino ad ora, ho avuto un metodo GET che sembrava il seguente:Aggiungere un'intestazione di risposta personalizzata in ApiController

protected override async Task<IHttpActionResult> GetAll(QueryData query) 
{ 
    // ... Some operations 

    //LINQ Expression based on the query parameters 
    Expression<Func<Entity, bool>> queryExpression = BuildQueryExpression(query); 

    //Begin to count all the entities in the repository 
    Task<int> countingEntities = repo.CountAsync(queryExpression); 

    //Reads an entity that will be the page start 
    Entity start = await repo.ReadAsync(query.Start); 

    //Reads all the entities starting from the start entity 
    IEnumerable<Entity> found = await repo.BrowseAllAsync(start, queryExpression); 

    //Truncates to page size 
    found = found.Take(query.Size); 

    //Number of entities returned in response 
    int count = found.Count(); 

    //Number of total entities (without pagination) 
    int total = await countingEntities; 

    return Ok(new { 
      Total = total, 
      Count = count, 
      Last = count > 0 ? GetEntityKey(found.Last()) : default(Key), 
      Data = found.Select(e => IsResourceOwner(e) ? MapToOwnerDTO(e) : MapToDTO(e)).ToList() 
    }); 
} 

Il tutto ha funzionato come un fascino ed è stato bello. Tuttavia, mi è stato detto di recente di inviare la risposta metadata (ovvero, Total, Count e Last proprietà) come intestazioni personalizzate di risposta anziché il corpo della risposta.

Non riesco ad accedere a Response da ApiController. Ho pensato a un filtro o attributo, ma come avrei ottenuto i valori dei metadati?

Posso mantenere tutte queste informazioni sulla risposta e quindi disporre di un filtro che deserializza la risposta prima di essere inviata al client e creane una nuova con le intestazioni, ma ciò sembra problematico e negativo.

C'è un modo per aggiungere intestazioni personalizzate direttamente da questo metodo su un ApiController?

+1

Dovrebbe essere semplice come [che] (http://stackoverflow.com/questions/13487012/mvc-4-web-api-add-custom-response-http-header) – Andrei

+0

@Andrei non ho una proprietà 'HttpContext', ma ho uno' ActionContext'. Tuttavia, la proprietà 'Response' di quell'oggetto è' null' e non posso operare con esso. –

+0

è necessario utilizzare ActionContext.Request.CreateResponse() per creare effettivamente una risposta e quindi impostare valori in risposta come un oggetto fortemente tipizzato anziché stringhe – harishr

risposta

10

ho inserito, ecco la mia risposta completa.

Sarà necessario creare un filtro personalizzato e applicarlo al controller.

public class CustomHeaderFilter : ActionFilterAttribute 
{ 
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) 
    { 
     var count = actionExecutedContext.Request.Properties["Count"]; 
     actionExecutedContext.Response.Content.Headers.Add("totalHeader", count); 
    } 
} 

nel controller

public class AddressController : ApiController 
     { 
      public async Task<Address> Get() 
      { 
       Request.Properties["Count"] = "123"; 
      } 
    } 
+2

Funziona perfettamente ma è il modo corretto per farlo? I miei metadati dovrebbero essere una proprietà della risposta, non la richiesta. Voglio dire, funziona come una soluzione, ma è concettualmente giusto? –

+2

Sembra doppio lavoro per me. Puoi aggiungere un'intestazione [direttamente] (https://stackoverflow.com/a/45489505/2156743) – Nikola

+0

@Nikola ma poi perdi la risposta fortemente tipizzata, che l'OP non ha usato ma è ancora un'opzione con questo approccio . Sto lavorando a un progetto Web API e non utilizzare tipi forti sta causando problemi - per uno non possiamo generare facilmente swagger corretto. Evitare di restituire risposte non tipizzate se è possibile –

-2

è possibile utilizzare un ActionFilter personalizzato che vi permetterà di inviare le intestazioni personalizzate e accedere al HttpContext: commenti

public class AddCustomHeaderFilter : ActionFilterAttribute 
{ 
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) 
    { 
     actionExecutedContext.Response.Content.Headers.Add("name", "value"); 
    } 
} 
+0

Ma come potrei ottenere i" valori "delle intestazioni? –

+0

Domande interessanti. Sembra che tu possa impostare la proprietà Request.Properties ["Count"] = "123" nel controller e utilizzarla nel filtro. – Yousuf

+0

Nel filtro, è possibile accedervi tramite actionContext.Request.Properties ["Count"] – Yousuf

8

È possibile aggiungere in modo esplicito intestazioni personalizzate in un metodo in questo modo:

[HttpGet] 
[Route("home/students")] 
public HttpResponseMessage GetStudents() 
{ 
     // Get students from Database 

     // Create the response 
     var response = Request.CreateResponse(HttpStatusCode.OK, studends); 

     // Set headers for paging 
     response.Headers.Add("X-Students-Total-Count", studends.Count()); 

     return response; 
} 

Per ulteriori informazioni leggere questo articolo: http://www.jerriepelser.com/blog/paging-in-aspnet-webapi-http-headers/

+0

Lo sto facendo, ma le intestazioni vengono rimosse – weagle08

+1

@ weagle08 La tua richiesta passa attraverso i proxy? Se è così puoi leggere questo: http://stackoverflow.com/questions/20820572/under-what-conditions-are-http-request-headers-removed-by-proxies – Seagull

+0

Ha funzionato per me ma nessun proxy è coinvolto nella nostra connessione – Darren

0

Quello che è necessario:

public async Task<IHttpActionResult> Get() 
{ 
    var response = Request.CreateResponse(); 
    response.Headers.Add("Lorem", "ipsum"); 

    return base.ResponseMessage(response); 
} 

Spero che questo risponda alla tua domanda.