web-dev-qa-db-fra.com

Ajouter un en-tête de réponse personnalisé dans ApiController

Jusqu'à présent, j'avais une méthode GET qui ressemblait à ceci:

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

Cela a fonctionné comme un charme et c'était bon. Cependant, on m'a récemment demandé d'envoyer la réponse métadonnées (c'est-à-dire, les propriétés Total, Count et Last) en tant qu'en-têtes personnalisés à la place du corps de la réponse.

Je n'arrive pas à accéder à la Response à partir d'ApiController. J'ai pensé à un filtre ou à un attribut, mais comment pourrais-je obtenir les valeurs de métadonnées?

Je peux conserver toutes ces informations dans la réponse, puis disposer d'un filtre qui désérialisera la réponse avant de l'envoyer au client et en créer un nouveau avec les en-têtes, mais cela semble gênant et mauvais.

Existe-t-il un moyen d’ajouter des en-têtes personnalisés directement à partir de cette méthode sur une ApiController?

18
Matias Cicero

J'ai entré des commentaires, voici ma réponse complète. 

Vous devrez créer un filtre personnalisé et l'appliquer à votre contrôleur.

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

Dans votre contrôleur 

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

Vous pouvez explicitement ajouter des en-têtes personnalisés dans une méthode comme ceci:

[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;
}

Pour plus d'informations, lisez cet article: http://www.jerriepelser.com/blog/paging-in-aspnet-webapi-http-headers/

21
Seagull

Ce dont vous avez besoin c'est:

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

    return base.ResponseMessage(response); 
}

J'espère que cela répond à votre question. 

5
Nikola

La solution simple est de faire juste:

HttpContext.Current.Response.Headers.Add("MaxRecords", "1000");

Dans API Controller.

4
Deepak

Vous pouvez utiliser un ActionFilter personnalisé qui vous permettra d'envoyer des en-têtes personnalisés et d'accéder au HttpContext:

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