C#
 Computer >> コンピューター >  >> プログラミング >> C#

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コントローラーがそれぞれ適切なレスポンスを返している様子を示しています。

C# ASP.NET Web APIでAcceptヘッダーによるバージョン管理を実装する方法

C# ASP.NET Web APIでAcceptヘッダーによるバージョン管理を実装する方法

このように、Acceptヘッダーにversionパラメーターを含める方式を採用すれば、URLを変更することなくAPIのバージョンをクライアント側で柔軟に指定でき、後方互換性を保ちながらAPIを進化させることができます。

  1. C# ASP.NET WebAPIでCORSの問題を解決する方法を徹底解説

    CORS(クロスオリジンリソースシェアリング)とはクロスオリジンリソースシェアリング(Cross-Origin Resource Sharing:CORS)は、追加のHTTPヘッダーを使用して、あるオリジンで動作しているWebアプリケーションに対し、別のオリジンにある選択されたリソースへのアクセスを許可するようブラウザに指示する仕組みです。Webアプリケーションは、自身とは異なるオリジン(ドメイン、プロトコル、ポート)のリソースを要求する際に、クロスオリジンHTTPリクエストを実行します。例として、フロントエンド(UI)とバックエンド(サービス)を持つアプリケーションを考えてみましょう。フロン

  2. C# ASP.NET Web APIのアクションメソッドからカスタム結果タイプを返す方法

    ASP.NET Web APIでは、IHttpActionResultインターフェースを実装することで、独自のカスタムクラスを結果タイプとして作成できます。IHttpActionResultインターフェースには、HttpResponseMessageインスタンスを非同期に生成する単一のメソッド ExecuteAsync が定義されています。public interface IHttpActionResult { Task<HttpResponseMessage> ExecuteAsync( CancellationToken cancellationToke