2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ASP.NET Core 5 Web API に OData のクエリ オプションを実装する

Last updated at Posted at 2021-02-09

はじめに

Microsoft は、ASP.NET Core 5 で OData を利用するための ASP.NET Core OData 8.0 Preview for .NET 5 をリリースしました。OData クエリ オプションの実装に関する日本語の記事が見つからなかったため、内容、実装手順をまとめます。

OData とは

OData は開発者に組み込みのクエリ機能を提供する REST スタイルのサービスを作成するための標準サービスです。データのページング、並べ替え、フィルターなどのクエリ オプションをすばやく簡単に実装することができます。
代表的なクエリ オプションは以下の通りです。

環境

  • ASP.NET Core 5.0
  • Microsoft.AspNetCore.OData 8.0.0-preview3 (2020/12/17)
  • Entity Framework Core 5.0.2
  • Visual Studio Community 2019 Version 16.8.4
  • Windows 10
  • SQL Server 2016

実装手順

1. テーブルの作成

今回は SQL Server の Northwind というデータベースに TodoItems というテーブルが作成されていることを前提に説明します。適宜読み替えてください。

create table [dbo].[TodoItems] (
  [Id] int not null
  , [Name] varchar(20) not null
  , [IsComplete] bit not null
  , primary key (Id)
);

image.png

2. Web プロジェクトの作成

ASP.NET Core Web API プロジェクトを作成します。ターゲット フレームワークとして [ASP.NET Core 5.0] を選択します。
image.png

3. NuGet パッケージ

[NuGet パッケージの管理] を開き、[プレリリースを含める] にチェックを入れ、次の 2 つの NuGet パッケージを追加します。

  • Microsoft.AspNetCore.OData
  • Microsoft.EntityFrameworkCore.SqlServer

次の図は、これらのパッケージをプロジェクトに正常に追加したときの状態を示しています。
image.png

4. クラスの作成、Startup の設定

モデル クラスの追加

TodoItem という名前のモデル クラスを追加します。

public class TodoItem
{
    public int Id { get; set; }
    public string Name { get; set; }
    public bool IsComplete { get; set; }
}

データベース コンテキストの追加

TodoContext という名前のデータベース コンテキスト クラスを追加します。

public class TodoContext : DbContext
{
    public TodoContext(DbContextOptions<TodoContext> options)
        : base(options)
    {
    }

    public DbSet<TodoItem> TodoItems { get; set; }
}

接続文字列の追加

appsettings.json に接続文字列を追加します。
接続文字列は SQL Server の設定に従って適宜変更してください。

appsettings.json
"ConnectionStrings": {
  "AppDb": "data source=(localdb)\\ProjectsV13;Initial Catalog=Northwind;integrated security=true"
}

Startup の設定

Startup クラスの ConfigureServices メソッドにマークされている行を追加します。

Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

+   services.AddDbContext<TodoContext>(o => 
+       o.UseSqlServer(Configuration.GetConnectionString("AppDb")));

+   services.AddOData(o =>
+   {
+       o.AddModel("odata", GetEdmModel());
+       o.Select();
+       o.Filter();
+       o.OrderBy();
+       o.Count();
+       o.MaxTop = 100;
+   });

    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "ODataService3", Version = "v1" });
    });
}

Startup クラスに GetEdmModel メソッドを追加します。

Startup.cs
private static IEdmModel GetEdmModel()
{
    var builder = new ODataConventionModelBuilder();
    builder.EntitySet<TodoItem>("TodoItems");
    return builder.GetEdmModel();
}

今回は Swagger は使用しないため Startup クラスの Swagger に関連するコードを削除またはコメントアウトして無効にします。

Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    ...

-   services.AddSwaggerGen(c =>
-   {
-       c.SwaggerDoc("v1", new OpenApiInfo { Title = "ODataService2", Version = "v1" });
-   });
}
Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
-       app.UseSwagger();
-       app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "ODataService2 v1"));
    }

    app.UseHttpsRedirection();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

コントローラーの作成

TodoItemsController というコントローラー クラスを追加します。

public class TodoItemsController : ODataController
{
    private TodoContext db;

    public TodoItemsController(TodoContext db)
    {
        this.db = db;
    }

    [EnableQuery]
    public IActionResult Get()
    {
        return Ok(db.TodoItems);
    }

    [EnableQuery]
    public IActionResult Get(int key)
    {
        return Ok(db.TodoItems.FirstOrDefault
                    (c => c.Id == key));
    }

    public IActionResult Post([FromBody] TodoItem item)
    {
        db.TodoItems.Add(item);
        db.SaveChanges();
        return Created(item);
    }

    public IActionResult Put(int key, [FromBody] TodoItem item)
    {
        if (key != item.Id)
        {
            return BadRequest();
        }

        db.TodoItems.Update(item);
        db.SaveChanges();
        return NoContent();
    }

    public IActionResult Delete(int key)
    {
        db.TodoItems.Remove(db.TodoItems.Find(key));
        db.SaveChanges();
        return NoContent();
    }
}

5. Web API のテスト

Web API をテストするための Postman ツールのインストールは以下を参照してください。
https://docs.microsoft.com/ja-jp/aspnet/core/tutorials/first-web-api?view=aspnetcore-5.0&tabs=visual-studio#install-postman

Web API の動作をテストします。

  • TodoItems テーブルに以下のデータを追加します。
Id Name IsComplete
1 walk dog true
2 bark cat true
3 bark rabbits false
  • Web アプリを起動します。
  • GET /odata/TodoItems を送信します。

次のような応答が生成されます。

{
  "@odata.context": "https://localhost:12345/odata/$metadata#TodoItems",
  "value": [
    {
      "Id": 1,
      "Name": "walk dog",
      "IsComplete": true
    },
    {
      "Id": 2,
      "Name": "bark cat",
      "IsComplete": true
    },
    {
      "Id": 3,
      "Name": "bark rabbits",
      "IsComplete": false
    }
  ]
}

※ポート 12345 は環境によって異なる値が生成されます。

OData のクエリ オプションをテストします。

  • GET /odata/TodoItems?$select=Name を送信します。

$select クエリ オプションで指定した Name プロパティのみの応答が生成されます。

{
  "@odata.context": "https://localhost:12345/odata/$metadata#TodoItems(Name)",
  "value": [
    {
      "Name": "walk dog"
    },
    {
      "Name": "bark cat"
    },
    {
      "Name": "bark rabbits"
    }
  ]
}
  • GET /odata/TodoItems?$filter=startsWith(Name,'b') を送信します。

$filter クエリ オプションを使用して Name プロパティが「b」という文字で始まるデータを検索します。

{
  "@odata.context": "https://localhost:12345/odata/$metadata#TodoItems",
  "value": [
    {
      "Id": 2,
      "Name": "bark cat",
      "IsComplete": true
    },
    {
      "Id": 3,
      "Name": "bark rabbits",
      "IsComplete": false
    }
  ]
}
  • GET /odata/TodoItems?$orderby=Id desc&$top=1 を送信します。

$orderby および $top クエリ オプションを使用して Id プロパティの最後のデータを検索します。

{
  "@odata.context": "https://localhost:12345/odata/$metadata#TodoItems",
  "value": [
    {
      "Id": 3,
      "Name": "bark rabbits",
      "IsComplete": false
    }
  ]
}

代表的なクエリ オプションのテストは以上です。

OData のその他のクエリ オプションは以下を参照してください。
https://docs.microsoft.com/ja-jp/graph/query-parameters#odata-system-query-options

Postman を使用したその他の HTTP メソッド(Post、Put、Delete)の使用方法は以下を参照してください。
https://docs.microsoft.com/ja-jp/aspnet/core/tutorials/first-web-api?view=aspnetcore-5.0&tabs=visual-studio#test-posttodoitem-with-postman

おわりに

私は以前これらのクエリ オプションを自前で実装していました。自分で考えることは楽しかったですし勉強にもなりましたが、実用としては精度が今一つでしたし、メンテナンスにも多くの時間を要しました。

Micorosft の OData サービスを簡単に組み込めることを知って本当にうれしかったです。

当記事は以下の参考文献にある記事を整理しただけのものにはなりますが、
少しでも Web API 実装のお役に立てればうれしいです。

参考文献

クエリオプションを備えたWebAPI:
https://docs.microsoft.com/en-us/odata/webapi/first-odata-api
ASP.NET Core OData 8.0 Preview for .NET 5:
https://devblogs.microsoft.com/odata/asp-net-odata-8-0-preview-for-net-5/
Use OData Services In ASP.NET Core:
http://www.binaryintellect.net/articles/cf087a05-2694-4528-924c-bbee60ee6934.aspx
クエリ オプションを使用して応答をカスタマイズする:
https://docs.microsoft.com/ja-jp/graph/query-parameters

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?