ASP.NET Web API の Tips (2)

ASP.NET Web API を利用する際の注意点や備忘録です。ほぼ箇条書きです。
基本的な説明は省略しています。
(ASP.NET Core Web API 版も書きました。)

例外処理

  • 戻り値が HttpResponseMessage または IHttpActionResult の場合、Request.CreateErrorResponse メソッドなどで HttpResponseMessage を生成する
  • 戻り値が HttpResponseMessage でも IHttpActionResult でもない場合、HttpResponseException を返すことで同様の効果が得られる
  • HttpError を利用して、JSON のエラー メッセージを含めることができる
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
namespace SampleWebApi.Controllers
{
public class ValuesController : ApiController
{
static readonly List<string> values = new List<string> { "value0", "value1" };
public string Get(int id)
{
if (id < 0 || values.Count <= id)
{
var message = $"No value with ID = {id}";
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.NotFound, message));
// No content:
//throw new HttpResponseException(HttpStatusCode.NotFound);
}
return values[id];
}
}
}
view raw ValuesController.cs hosted with ❤ by GitHub

公式解説: Exception Handling in ASP.NET Web API

Help Page

コードの XML ドキュメントから、ユーザー向けのヘルプ ページを自動的に生成する機能です。
Visual Studio でプロジェクトを作成するときに Web API を選択すると、Help Page もインストールされます。
あとから追加するには、NuGet で Microsoft.AspNet.WebApi.HelpPage をインストールします。

ただし、既定では機能が有効になっていません。

  • 有効にする手順:
    • プロジェクトのプロパティで、XML ドキュメントの出力を有効にする
    • HelpPageConfig.cs のコメントアウトを解除する ( // を取る)

SetDocumentationProvider

  • アクション メソッドの戻り値が HttpResponseMessage または IHttpActionResult の場合、
    [ResponseType(typeof(string))] のように属性でデータの型を指定する
  • Areas\HelpPage にソースコードがあるため、カスタマイズ可能
  • ヘルプ ページ (Help/Index) を既定のページに設定するには、HelpPageAreaRegistration.cs でルーティングの設定を追加するとよい
  • ASP.NET Core Web API では、Help Page を使えない
    • Swashbuckle (Swagger の .NET 向け実装) を使う

HelpPage

公式解説: Creating Help Pages for ASP.NET Web API

Web API の呼び出し

.NET アプリケーションから Web API を呼び出すには、HttpClient クラスを利用するとよいでしょう。
また、サービス側で実装されたカスタム データ型も、サービス コントラクトとして利用できます。
すなわち、応答メッセージに対して response.Content.ReadAsAsync<T>() を呼び出せば T 型としてデシリアライズできます。

using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace UnitTest.Client
{
public static class HttpHelper
{
public static readonly Uri BaseUri = new Uri("http://localhost:1961/");
async public static Task<T> GetAsync<T>(string uri)
{
using (var http = new HttpClient { BaseAddress = BaseUri })
{
var response = await http.GetAsync(uri);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsAsync<T>();
}
}
}
}
view raw HttpHelper.cs hosted with ❤ by GitHub

公式解説: Call a Web API From a .NET Client (C#)

CORS

  • NuGet で Microsoft.AspNet.WebApi.Cors をインストールする
  • WebApiConfig.cs で config.EnableCors メソッドを呼び出すことで機能を有効にする
    • 引数に EnableCorsAttribute を渡すとグローバルに設定できる
    • コントローラー、アクションのレベルでは [EnableCors] を指定する

CORS が機能しているかどうかをテストする方法については ASP.NET Core Web API の Tips に書きました。

公式解説: Enabling Cross-Origin Requests in ASP.NET Web API 2

JSONP

未検証。

  • MediaTypeFormatter を利用する
    • WebApiContrib.Formatting.Jsonp など

フォーマット

ASP.NET Web API は、既定で JSON と XML をサポートします。
要求の Accept ヘッダーに何が指定されているかで結果のフォーマットが変わります。
Google Chrome 上で Web API を直接呼び出すと結果が XML 形式で返ってきます。
これは、要求の Accept ヘッダーに application/xml が含まれているためと考えられます。
これを JSON 形式にするには、text/html が含まれている場合に JSON を返す設定や XML 形式を無効にする設定が考えられます。

using System;
using System.Net.Http.Formatting;
using System.Web.Http;
using System.Web.Http.Cors;
namespace SampleWebApi
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// CORS の有効化
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
// XML 形式は有効のまま。HTML が要求されたら JSON を返します。
config.Formatters.JsonFormatter.MediaTypeMappings.Add(new RequestHeaderMapping("Accept", "text/html", StringComparison.InvariantCultureIgnoreCase, true, "application/json"));
// XML 形式の無効化 その1
//config.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
// XML 形式の無効化 その2
//config.Formatters.Remove(config.Formatters.XmlFormatter);
// 以下略
}
}
}
view raw WebApiConfig.cs hosted with ❤ by GitHub

解説: How do I get ASP.NET Web API to return JSON instead of XML using Chrome?

 

前回: ASP.NET Web API の Tips (1)

作成したサンプル

バージョン情報

  • .NET Framework 4.5
  • ASP.NET Web API 5.2.3
  • ASP.NET MVC 5.2.3
  • ASP.NET Web API Help Page 5.2.3
  • ASP.NET Web API CORS 5.2.3

参照

カテゴリー: .NET Framework. タグ: , . 1 Comment »

ASP.NET Web API の Tips (1)

ASP.NET Web API を利用する際の注意点や備忘録です。ほぼ箇条書きです。
基本的な説明は省略しています。
(ASP.NET Core Web API 版も書きました。)

ルーティング

WebApiConfig.cs にルーティングの設定が記述されています。
既定のテンプレートは api/{controller}/{id} となっており、REST スタイルを想定したものとなっています。
ただし、ASP.NET MVC と同様に {action} も利用可能であり、RPC スタイルの API も構成できます。

  • [RoutePrefix], [Route], [ActionName] などの属性を利用することで柔軟に構成できる
  • [Route] を複数設定できる

公式解説: Web API Routing

HTTP メソッド

  • 主に REST スタイルの場合、Get、Post などのメソッド名で解決される (CoC)。
    この場合、[HttpGet] などの属性を指定する必要はない
  • 主に RPC スタイルで任意のアクション名を利用するには、[HttpGet] などの属性を指定する

引数

  • DateTime, Guid などの型も扱える
  • 引数の [FromBody] は、エンティティ型なら付ける必要はない
  • ルーティングで {i:int:range(0,100)} のような制約を追加できる
  • 引数に既定値を指定すると、URL のパラメーターを省略可能
    • ルーティングで指定する場合は {i:int?} のようにする
    • range などを使う場合、省略可能にできない
      • int? と range は同時に指定できない
  • 引数で / を使う場合、引数名の前に * を指定する (下の DateTime 型の例)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
namespace SampleWebApi.Controllers
{
[RoutePrefix("api/Random")]
[Route("{action}")]
public class RandomController : ApiController
{
static readonly Random random = new Random();
[HttpGet]
[Route("Echo/{i:int?}")]
public int Echo(int i = 123) => i;
[HttpGet]
[Route("NewDoubles/{count:int:range(0,64)}")]
public double[] NewDoubles(int count) =>
Enumerable.Range(0, count)
.Select(i => random.NextDouble())
.ToArray();
[HttpGet]
[Route(@"NewDateTime/{date:datetime:regex(\d{4}-\d{2}-\d{2})}")]
[Route(@"NewDateTime/{*date:datetime:regex(\d{4}/\d{2}/\d{2})}")]
public DateTime NewDateTime(DateTime date) => date + TimeSpan.FromHours(24 * random.NextDouble());
[HttpGet]
public Guid NewUuid() => Guid.NewGuid();
}
}
view raw RandomController.cs hosted with ❤ by GitHub

公式解説: Attribute Routing in ASP.NET Web API 2

戻り値

戻り値として、通常のデータ型以外に次のものを指定できます。

  • HttpResponseMessage
    • 生の応答データ
  • IHttpActionResult
    • HttpResponseMessage をラップしたインターフェイス

これらを利用することにより、応答データを柔軟に設定できます。

  • JSON や XML に限らず、テキストや画像などの任意の形式のコンテンツを返せる
  • 主な IHttpActionResult の実装は System.Web.Http.Results 名前空間で定義されている

以下は、テキスト (Content-Type: text/plain) を返す例です。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Description;
namespace SampleWebApi.Controllers
{
[RoutePrefix("api")]
public class RandomTextController : ApiController
{
static readonly Random random = new Random();
[HttpGet]
[Route("NewBytes1/{count:int:range(0,64)}")]
[ResponseType(typeof(string))]
public HttpResponseMessage NewBytes1(int count)
{
var content = CreateBytesString(count);
var response = Request.CreateResponse();
response.Content = new StringContent(content);
return response;
}
[HttpGet]
[Route("NewBytes2/{count:int:range(0,64)}")]
[ResponseType(typeof(string))]
public IHttpActionResult NewBytes2(int count)
{
var content = CreateBytesString(count);
return new TextResult(content, Request);
}
static string CreateBytesString(int count)
{
var bytes = new byte[count];
random.NextBytes(bytes);
return string.Join("\n", bytes);
}
}
public class TextResult : IHttpActionResult
{
public string Content { get; }
public HttpRequestMessage Request { get; }
public TextResult(string content, HttpRequestMessage request)
{
Content = content;
Request = request;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = Request.CreateResponse();
response.Content = new StringContent(Content);
return Task.FromResult(response);
}
}
}

公式解説: Action Results in Web API 2

 

次回: ASP.NET Web API の Tips (2)

作成したサンプル

バージョン情報

  • .NET Framework 4.5
  • ASP.NET Web API 5.2.3

参照

カテゴリー: .NET Framework. タグ: , . 3 Comments »