はじめに
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)
);
2. Web プロジェクトの作成
ASP.NET Core Web API プロジェクトを作成します。ターゲット フレームワークとして [ASP.NET Core 5.0] を選択します。
3. NuGet パッケージ
[NuGet パッケージの管理] を開き、[プレリリースを含める] にチェックを入れ、次の 2 つの NuGet パッケージを追加します。
- Microsoft.AspNetCore.OData
- Microsoft.EntityFrameworkCore.SqlServer
次の図は、これらのパッケージをプロジェクトに正常に追加したときの状態を示しています。
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 の設定に従って適宜変更してください。
"ConnectionStrings": {
"AppDb": "data source=(localdb)\\ProjectsV13;Initial Catalog=Northwind;integrated security=true"
}
Startup の設定
Startup クラスの ConfigureServices メソッドにマークされている行を追加します。
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 メソッドを追加します。
private static IEdmModel GetEdmModel()
{
var builder = new ODataConventionModelBuilder();
builder.EntitySet<TodoItem>("TodoItems");
return builder.GetEdmModel();
}
今回は Swagger は使用しないため Startup クラスの Swagger に関連するコードを削除またはコメントアウトして無効にします。
public void ConfigureServices(IServiceCollection services)
{
...
- services.AddSwaggerGen(c =>
- {
- c.SwaggerDoc("v1", new OpenApiInfo { Title = "ODataService2", Version = "v1" });
- });
}
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