C# ASP.NET Web APIでAcceptヘッダーによるバージョン管理を実装する方法
Acceptヘッダーは、ブラウザがサーバーに対してどのファイル形式(データ形式)でデータを受け取りたいかを伝えるためのものです。これらのファイル形式は一般的に「MIMEタイプ」と呼ばれています。MIMEとは「Multipurpose Internet Mail Extensions(多目的インターネットメール拡張)」の略称です。
Web APIのバージョン情報は、以下のようにヘッダーに含めて送信することができます。
Version=1 → StudentsV1Controller Version=2 → StudentsV2Controller
しかし、Acceptヘッダーのバージョン情報に対応した処理を実装していない状態では、プロジェクトにはStudentV1とStudentV2のコントローラーしか存在しないため、リクエスト時に404 Not Foundエラーが発生してしまいます。
そこで、DefaultHttpControllerSelectorクラスを継承した独自のCustomControllerSelectorを作成し、Acceptヘッダーのバージョン情報を処理できるようにしましょう。
CustomControllerSelectorの実装例
using System.Linq;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Dispatcher;
namespace WebAPI.Custom{
public class CustomControllerSelector : DefaultHttpControllerSelector{
private HttpConfiguration _config;
public CustomControllerSelector(HttpConfiguration config) : base(config){
_config = config;
}
public override HttpControllerDescriptor SelectController(HttpRequestMessage request){
var controllers = GetControllerMapping();
var routeData = request.GetRouteData();
var controllerName = routeData.Values["controller"].ToString();
string versionNumber = "";
var acceptHeader = request.Headers.Accept.Where(a => a.Parameters
.Count(p => p.Name.ToLower() == "version") > 0);
if (acceptHeader.Any()){
versionNumber = acceptHeader.First().Parameters
.First(p => p.Name.ToLower() == "version").Value;
}
HttpControllerDescriptor controllerDescriptor;
if (versionNumber == "1"){
controllerName = string.Concat(controllerName, "V1");
}
else if (versionNumber == "2"){
controllerName = string.Concat(controllerName, "V2");
}
if (controllers.TryGetValue(controllerName, out controllerDescriptor)){
return controllerDescriptor;
}
return null;
}
}
}デフォルトのコントローラーセレクターを差し替える
次に行うのは、デフォルトのコントローラーセレクターを独自のCustomControllerSelectorに置き換える作業です。この設定はWebApiConfig.csファイル内で行います。ここではIHttpControllerSelectorをCustomControllerSelectorで置き換えています。DefaultHttpControllerSelectorはIHttpControllerSelectorインターフェースを実装しているため、IHttpControllerSelectorを置き換えることでカスタムセレクターが適用される仕組みです。
WebApiConfig.csの実装例
public static class WebApiConfig{
public static void Register(HttpConfiguration config){
config.Services.Replace(typeof(IHttpControllerSelector), new CustomControllerSelector(config));
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}StudentV1Controllerの実装例
using DemoWebApplication.Models;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace DemoWebApplication.Controllers{
public class StudentV1Controller : ApiController{
List<StudentV1> students = new List<StudentV1>{
new StudentV1{
Id = 1,
Name = "Mark"
},
new StudentV1{
Id = 2,
Name = "John"
}
};
public IEnumerable<StudentV1> Get(){
return students;
}
public StudentV1 Get(int id){
var studentForId = students.FirstOrDefault(x => x.Id == id);
return studentForId;
}
}
}StudentV2Controllerの実装例
using DemoWebApplication.Models;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace DemoWebApplication.Controllers{
public class StudentV2Controller : ApiController{
List<StudentV2> students = new List<StudentV2>{
new StudentV2{
Id = 1,
FirstName = "Roger",
LastName = "Federer"
},
new StudentV2{
Id = 2,
FirstName = "Tom",
LastName = "Bruce"
}
};
public IEnumerable<StudentV2> Get(){
return students;
}
public StudentV2 Get(int id){
var studentForId = students.FirstOrDefault(x => x.Id == id);
return studentForId;
}
}
}動作確認
V1ではNameプロパティのみを持つシンプルなモデルを返し、V2ではFirstNameとLastNameに分割されたモデルを返しています。以下の出力結果は、Acceptヘッダーでバージョンを指定したリクエストに対して、StudentV1コントローラーとStudentV2コントローラーがそれぞれ適切なレスポンスを返している様子を示しています。


このように、Acceptヘッダーにversionパラメーターを含める方式を採用すれば、URLを変更することなくAPIのバージョンをクライアント側で柔軟に指定でき、後方互換性を保ちながらAPIを進化させることができます。
-
C# ASP.NET WebAPIでCORSの問題を解決する方法を徹底解説
CORS(クロスオリジンリソースシェアリング)とはクロスオリジンリソースシェアリング(Cross-Origin Resource Sharing:CORS)は、追加のHTTPヘッダーを使用して、あるオリジンで動作しているWebアプリケーションに対し、別のオリジンにある選択されたリソースへのアクセスを許可するようブラウザに指示する仕組みです。Webアプリケーションは、自身とは異なるオリジン(ドメイン、プロトコル、ポート)のリソースを要求する際に、クロスオリジンHTTPリクエストを実行します。例として、フロントエンド(UI)とバックエンド(サービス)を持つアプリケーションを考えてみましょう。フロン
-
C# ASP.NET Web APIのアクションメソッドからカスタム結果タイプを返す方法
ASP.NET Web APIでは、IHttpActionResultインターフェースを実装することで、独自のカスタムクラスを結果タイプとして作成できます。IHttpActionResultインターフェースには、HttpResponseMessageインスタンスを非同期に生成する単一のメソッド ExecuteAsync が定義されています。public interface IHttpActionResult { Task<HttpResponseMessage> ExecuteAsync( CancellationToken cancellationToke