私は私の.NET Core Web APIコントローラでHTTPステータスコードと共にJSONを返す正しい方法を探しています。私はこのようにそれを使うのに使います:
public IHttpActionResult GetResourceData()
{
return this.Content(HttpStatusCode.OK, new { response = "Hello"});
}
これは4.6 MVCアプリケーションでしたが、今では.NET Coreで私はこれを持っていないようですIHttpActionResult
私はActionResult
を持っていて、このように使用します:
public ActionResult IsAuthenticated()
{
return Ok(Json("123"));
}
しかし、サーバーからの応答は下の画像のように奇妙です。
Web API 2で行ったように、Web APIコントローラーにHTTPステータスコードを付けてJSONを返すようにしたいだけです。
JsonResult
で応答する最も基本的なバージョンは以下のとおりです。
// GET: api/authors
[HttpGet]
public JsonResult Get()
{
return Json(_authorRepository.List());
}
ただし、自分のレスポンスコードを明示的に処理することはできないため、これは問題の解決には役立ちません。
ステータスの結果を制御する方法は、
ActionResult
を返す必要があることです。ここでStatusCodeResult
型を利用することができます。
例えば:
// GET: api/authors/search?namelike=foo
[HttpGet("Search")]
public IActionResult Search(string namelike)
{
var result = _authorRepository.GetByNameSubstring(namelike);
if (!result.Any())
{
return NotFound(namelike);
}
return Ok(result);
}
上記の例は両方とも、マイクロソフトのドキュメントから入手できる優れたガイドからのものです。 レスポンスデータのフォーマット
私がよく出くわす問題は、VSの "New Project"テンプレートのデフォルト設定をそのまま使うのではなく、自分のWebAPIをよりきめ細かく制御したいということです。
いくつかの基本を理解していることを確認しましょう。
ASP.NET Core WebAPIがステータスコードを完全に制御しながらJSONシリアル化オブジェクトで応答するようにするには、まずStartup.cs
にあるConfigureServices
メソッドにAddMvc()
サービスを含めたことを確認することから始めます。
AddMvc()
が他のリクエストタイプへの応答と共にJSON用のInput/Output Formatterを自動的に含むことに注意することは重要です。
プロジェクトが フルコントロール を必要とし、WebAPIがapplication/json
を含むさまざまな要求タイプに対してどのように動作し、他の要求タイプ(標準的なブラウザ要求など)に応答しないかなど、サービスを厳密に定義する場合次のコードで手動で定義できます。
public void ConfigureServices(IServiceCollection services)
{
// Build a customized MVC implementation, without using the default AddMvc(), instead use AddMvcCore().
// https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc/MvcServiceCollectionExtensions.cs
services
.AddMvcCore(options =>
{
options.RequireHttpsPermanent = true; // does not affect api requests
options.RespectBrowserAcceptHeader = true; // false by default
//options.OutputFormatters.RemoveType<HttpNoContentOutputFormatter>();
//remove these two below, but added so you know where to place them...
options.OutputFormatters.Add(new YourCustomOutputFormatter());
options.InputFormatters.Add(new YourCustomInputFormatter());
})
//.AddApiExplorer()
//.AddAuthorization()
.AddFormatterMappings()
//.AddCacheTagHelper()
//.AddDataAnnotations()
//.AddCors()
.AddJsonFormatters(); // JSON, or you can build your own custom one (above)
}
他のシリアル化フォーマット(protobuf、thriftなど)に応答したい場合に備えて、私はあなたがあなた自身のカスタム入出力フォーマッターを追加する方法も含んでいることに気付くでしょう。
上記のコードの大部分は、ほとんどがAddMvc()
メソッドの複製です。ただし、テンプレートを使用して出荷済みのサービスを使用するのではなく、すべてのサービスを定義することによって、各「デフォルト」サービスを独自に実装しています。私はコードブロックにリポジトリリンクを追加しました、あるいはあなたはGitHubリポジトリからAddMvc()
をチェックアウトすることができます。 。
最初の段階で実装しないのではなく、デフォルトを「元に戻す」ことでこれを解決しようとするガイドがいくつかあることに注意してください。冗長な作業、悪いコード、率直に言ってすぐに消える古い習慣です。
質問を整理するためだけに、本当にわかりやすい方法を紹介します。
public class FooController
{
[HttpPost]
public async Task<IActionResult> Create([FromBody] Object item)
{
if (item == null) return BadRequest();
var newItem = new Object(); // create the object to return
if (newItem != null) return Ok(newItem);
else return NotFound();
}
}
Content-Type
とAccept
を確認してください request 内のContent-Type
およびAccept
ヘッダーが正しく設定されていることを確認する必要があります。あなたの場合(JSON)では、それをapplication/json
に設定します。
WebAPIがデフォルトとしてJSONとして応答するようにしたい場合は、要求ヘッダーの指定内容に関係なく、 の2つの方法で を使用してそれを実行できます。
方法1 先ほどお勧めした記事( レスポンスデータのフォーマット )にあるように、コントローラ/アクションレベルで特定のフォーマットを強制することができます。私は個人的にはこのアプローチが好きではありません...しかしここでそれは完全を期すためのものです:
特定のフォーマットを強制する 可能な特定のアクションに対してレスポンスフォーマットを制限したい場合は、[Produces]フィルタを適用できます。 [Produces]フィルタは、特定のアクション(またはコントローラ)に対する応答フォーマットを指定します。ほとんどのフィルタと同様に、これはアクション、コントローラ、またはグローバルスコープで適用できます。
[Produces("application/json")] public class AuthorsController
アプリケーション用に他のフォーマッタが設定されていて、クライアントが利用可能な別のフォーマットを要求する
AuthorsController
ヘッダを提供している場合でも、[Produces]
フィルタはAccept
内のすべてのアクションにJSONフォーマットの応答を返させます。
方法2 WebAPIが要求されたフォーマットですべての要求に応答するための推奨方法。ただし、要求されたフォーマットが受け入れられない場合は、 フォールバック をデフォルト(つまりJSON)に戻します。
最初に、あなたはそれをあなたのオプションに登録する必要があります(前述のように、デフォルトの振る舞いを作り直す必要があります)。
options.RespectBrowserAcceptHeader = true; // false by default
最後に、単にサービスビルダーで定義されたフォーマッターのリストを並べ替えることによって、Webホストはデフォルトであなたがリストの一番上に位置するフォーマッター(すなわち位置0)になるでしょう。
より多くの情報はこの中で見つけることができます .NET Web開発とツールブログエントリ
最も一般的なステータスコードに対して事前定義された方法があります。
Ok(result)
はレスポンスとともに200
を返しますCreatedAtRoute
は201
+新しいリソースURLを返しますNotFound
は404
を返しますBadRequest
は400
などを返します。すべてのメソッドのリストについては、 BaseController.cs
および Controller.cs
を参照してください。
しかし、あなたが本当にカスタムコードを設定するためにStatusCode
を使うことができると主張するならば、あなたはそれがコードを読みにくくするので実際にはすべきではなく、ヘッダを設定するためにコードを繰り返す必要があります(CreatedAtRoute
のように) ).
public ActionResult IsAuthenticated()
{
return StatusCode(200, Json("123"));
}
ASP.NET Core 2.0では、Web API
(MVCと統合され、同じ基本クラスController
を使用)からオブジェクトを返す理想的な方法は次のとおりです。
public IActionResult Get()
{
return new OkObjectResult(new Item { Id = 123, Name = "Hero" });
}
それに注意してください
200 OK
ステータスコードで戻ります(Ok
型のObjectResult
)Accept
ヘッダーに基づいて返されます。 Accept: application/xml
がリクエストで送信された場合、それはXML
として返されます。何も送信されない場合、JSON
がデフォルトです。特定のステータスコード付きを送信する必要がある場合は、代わりにObjectResult
またはStatusCode
を使用してください。どちらも同じことを行い、コンテンツネゴシエーションをサポートします。
return new ObjectResult(new Item { Id = 123, Name = "Hero" }) { StatusCode = 200 };
return StatusCode( 200, new Item { Id = 123, Name = "Hero" });
特にJSONとして返すを使いたい場合は、いくつかの方法があります。
//GET http://example.com/api/test/asjson
[HttpGet("AsJson")]
public JsonResult GetAsJson()
{
return Json(new Item { Id = 123, Name = "Hero" });
}
//GET http://example.com/api/test/withproduces
[HttpGet("WithProduces")]
[Produces("application/json")]
public Item GetWithProduces()
{
return new Item { Id = 123, Name = "Hero" };
}
それに注意してください
JSON
を強制します。Json(object)
を使ってJSONを強制します。contentType = application/json
とともにProduces()
属性(これはResultFilter
です)を使用して同じことを行います。それらについての詳細は 公式ドキュメント で読んでください。 フィルタについてはこちら を参照してください。
サンプルで使用されている単純なモデルクラス
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
}
私が思いついた最も簡単な方法は次のとおりです。
return new JsonResult(result)
{
StatusCode = 201 // Status code here
};
これが私の最も簡単な解決策です。
public IActionResult InfoTag()
{
return Ok(new {name = "Fabio", age = 42, gender = "M"});
}
または
public IActionResult InfoTag()
{
return Json(new {name = "Fabio", age = 42, gender = "M"});
}
Enumを使用して404/201ステータスコードを使用する代わりに
public async Task<IActionResult> Login(string email, string password)
{
if (string.IsNullOrWhiteSpace(email) || string.IsNullOrWhiteSpace(password))
{
return StatusCode((int)HttpStatusCode.BadRequest, Json("email or password is null"));
}
var user = await _userManager.FindByEmailAsync(email);
if (user == null)
{
return StatusCode((int)HttpStatusCode.BadRequest, Json("Invalid Login and/or password"));
}
var passwordSignInResult = await _signInManager.PasswordSignInAsync(user, password, isPersistent: true, lockoutOnFailure: false);
if (!passwordSignInResult.Succeeded)
{
return StatusCode((int)HttpStatusCode.BadRequest, Json("Invalid Login and/or password"));
}
return StatusCode((int)HttpStatusCode.OK, Json("Sucess !!!"));
}
私のAsp Net Core APIアプリケーションで行うことは、ObjectResultから拡張するクラスを作成し、コンテンツとステータスコードをカスタマイズするための多くのコンストラクタを提供することです。それから私の全てのコントローラーのアクションは適切なものとしてコストラクタの一つを使います。あなたは私の実装を見てみることができます: https://github.com/melardev/AspNetCoreApiPaginatedCrud
そして
https://github.com/melardev/ApiAspCoreEcommerce
これがクラスの様子です(フルコードについては私のレポを参照してください)。
public class StatusCodeAndDtoWrapper : ObjectResult
{
public StatusCodeAndDtoWrapper(AppResponse dto, int statusCode = 200) : base(dto)
{
StatusCode = statusCode;
}
private StatusCodeAndDtoWrapper(AppResponse dto, int statusCode, string message) : base(dto)
{
StatusCode = statusCode;
if (dto.FullMessages == null)
dto.FullMessages = new List<string>(1);
dto.FullMessages.Add(message);
}
private StatusCodeAndDtoWrapper(AppResponse dto, int statusCode, ICollection<string> messages) : base(dto)
{
StatusCode = statusCode;
dto.FullMessages = messages;
}
}
Dtoをあなたのオブジェクトに置き換えたbase(dto)に注意してください。
ここで見つけた素晴らしい回答と、このreturnステートメントを試してみましたStatusCode(whatever code you wish)
を参照してください。
return Ok(new {
Token = new JwtSecurityTokenHandler().WriteToken(token),
Expiration = token.ValidTo,
username = user.FullName,
StatusCode = StatusCode(200)
});