web-dev-qa-db-fra.com

Acheminement CreatedAtRoute vers un contrôleur différent

Je crée une nouvelle webapi en utilisant le routage d'attributs pour créer une route imbriquée comme suit:

    // PUT: api/Channels/5/Messages
    [ResponseType(typeof(void))]
    [Route("api/channels/{id}/messages")]
    public async Task<IHttpActionResult> PostChannelMessage(int id, Message message)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        if (id != message.ChannelId)
        {
            return BadRequest();
        }

        db.Messages.Add(message);
        await db.SaveChangesAsync();

        return CreatedAtRoute("DefaultApi", new { id = message.Id }, message);
    }

Je souhaite cependant retourner un itinéraire qui n'est pas imbriqué, c'est-à-dire:

/api/Messages/{id}

qui est défini sur le contrôleur de messages. Cependant, l'appel CreatedAtRoute ci-dessus ne résout pas cette route et lance plutôt. Ai-je fait quelque chose de mal ou ne prend-il pas en charge le routage vers un autre contrôleur api? n.b. la route que j'essaie de parcourir n'est pas une route attributaire, juste une route par défaut.

L'exception est:

Message: "Une erreur s'est produite." ExceptionMessage: "UrlHelper.Link ne doit pas retourner null." ExceptionType: "System.InvalidOperationException" StackTrace: "sur System.Web.Http.Results.CreatedAtRouteNegotiatedContentResult1.Execute() at System.Web.Http.Results.CreatedAtRouteNegotiatedContentResult 1.ExecuteAsync (CancellationToken annulationToken) sur System.Web.Http.Controllers.ApiController. - Fin de la trace de la pile à partir de l'emplacement précédent où l'exception a été levée --- sur System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (tâche tâche) sur System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (tâche tâche) sur System.Runtime.Comp. TaskAwaiter1.GetResult() at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter 1.GetResult () sur System.Web.Http.Dispatcher.HttpControllerDispatcher.d__0.MoveNext () "

S'il ne le prend pas en charge, quelle est la manière canonique de retourner un 201 et puis-je le faire de manière refactorisée en toute sécurité?

36
DanH

Oh mon cher, c'est peut-être un nouveau record pour répondre à ma propre question.

return CreatedAtRoute("DefaultApi", new { controller = "messages", id = message.Id }, message);

fait l'affaire. c'est-à-dire en spécifiant explicitement le contrôleur. J'ai travaillé cela en voyant que l'exception était liée à UrlHelper et en lisant ses documents ...

51
DanH

Tard dans la soirée mais une réponse alternative. Si l'action vers laquelle vous routez utilise également le routage d'attributs, vous pouvez donner un nom à l'itinéraire et le transmettre à la méthode CreatedAtRoute. Pour cela, définissez une propriété Name sur le Route. En suivant votre exemple de publication, envisagez l'action suivante.

// GET: api/Messages/5
[Route("api/messages/{id}", Name="GetMessage")]
public async Task<IHttpActionResult> GetMessage(int id)
{
    // get the message
}

Notez que la propriété Name sur l'attribut route, [Route("api/messages/{id}", Name="GetMessage")], est définie sur "GetMessage". En faisant cela, nous pouvons appeler la méthode CreatedAtRoute à partir de l'action PostChannelMessage et passer le nom de la route comme ceci:

return CreatedAtRoute("GetMessage", new { id = message.Id }, message);

C'est un scénario que j'ai rencontré et ma recherche a mené ici, alors j'ai pensé publier cette réponse alternative au cas où cela aiderait quelqu'un d'autre.

36
ceej

Ajout aux réponses ci-dessus: sur le routage des attributs:

J'ai été surpris par le nom du paramètre, il m'a fallu une heure pour réaliser que le paramètre doit être nommé correctement, sinon l'URL Helper renverra la valeur null.

c'est-à-dire si vous avez une méthode d'action comme:

[Route("api/messages/{id}", Name="GetAction")]
public IHttpActionResult GetEntity(int mySpecialUniqueId)
{
    // do some work.
}

Ensuite, le retour devrait être:

return CreatedAtRoute("GetAction", new { mySpecialUniqueId = entity.Id }, entity);

Sur les exemples les plus simples, la propriété Id n'arrêtait pas de me jeter, alors j'ai pensé que j'allais développer davantage dans cette réponse pour aider les autres à gagner du temps sur ce petit problème.

Voir cet exemple plus compliqué pour plus de détails:

Routage d'attributs et CreatedAtRoute

2
IbrarMumtaz