web-dev-qa-db-ja.com

異なるコントローラーへのCreatedAtRouteルーティング

属性ルーティングを使用してネストされたルートを作成する新しいwebapiを作成しています:

_    // 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);
    }
_

ただし、ネストされていないルートを返します:

_/api/Messages/{id}
_

これは、メッセージコントローラーで定義されます。ただし、上記のCreatedAtRoute呼び出しはこのルートを解決せず、代わりにスローします。何か間違ったことをしたか、別のAPIコントローラーへのルーティングをサポートしていませんか? n.b.ヒットしようとしているルートは属性ルートではなく、デフォルトのルートです。

例外は次のとおりです。

メッセージ:「エラーが発生しました。」 ExceptionMessage: "UrlHelper.Linkはnullを返してはいけません。" ExceptionType: "System.InvalidOperationException" StackTrace: "System.Web.Http.Results.CreatedAtRouteNegotiatedContentResult1.Execute() at System.Web.Http.Results.CreatedAtRouteNegotiatedContentResult 1.ExecuteAsync(CancellationToken cancelToken)at System.Web.Http.Controllers.ApiControllerActionInvoker.d__0.MoveNext()- -例外がスローされた前の場所からのスタックトレースの終了--- System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)at System.Runtime.CompilerServices。 System.Web.Http.Dispatcher.HttpControllerDispatcher.d__0.MoveNext()で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() "

これがサポートされていない場合、201を返す標準的な方法は何ですか?リファクタリングを安全に行うことはできますか?

36
DanH

親愛なる、これは私自身の質問に答えるための新しい記録かもしれません。

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

トリックを行います。つまり、明示的にコントローラーを指定します。例外がUrlHelperに関連していることを確認し、そのドキュメントを読んで、これを実行しました...

51
DanH

パーティーに遅れたが、別の答え。ルーティング先のアクションも属性ルーティングを使用する場合、ルートに名前を付けてCreatedAtRouteメソッドに渡すことができます。これは、NameRouteプロパティを設定することにより行われます。投稿例に従って、次のアクションを検討してください。

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

ルート属性[Route("api/messages/{id}", Name="GetMessage")]Nameプロパティが_"GetMessage"_に設定されていることに注意してください。これを行うことで、CreatedAtRouteアクションからPostChannelMessageメソッドを呼び出し、次のようにルート名を渡すことができます。

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

これは私が遭遇したシナリオであり、私の検索はここにつながったので、他の誰かに役立つ場合に備えてこの代替答えを投稿すると思いました。

36
ceej

上記の答えに追加するだけです:属性ルーティング:

パラメーター名に気付いたので、パラメーターに正しい名前を付ける必要があることに気付くまでに1時間かかりました。そうしないと、URLヘルパーはnullを返します。

つまり、次のようなアクションメソッドがある場合:

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

次に、戻り値は次のようになります。

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

より単純な例では、Idプロパティが私を追い出し続けたので、この小さな問題で他の人の時間を節約するために、この回答でそれをさらに拡張すると思いました。

詳細については、このより複雑な例を参照してください。

属性ルーティングとCreatedAtRoute

2
IbrarMumtaz