asp.net-web-api
Asp.net Web APIを使用したOData
サーチ…
ODataパッケージのインストール
[ツール]メニューから、[NuGet Package Manager]、[Package Manager Console]の順に選択します。 [パッケージマネージャコンソール]ウィンドウで、次のように入力します。
Install-Package Microsoft.AspNet.Odata
このコマンドは、最新のOData NuGetパッケージをインストールします。
エンティティフレームワークを有効にする
このチュートリアルでは、Entity Framework(EF)コードファーストを使用してバックエンドデータベースを作成します。
Web API ODataにはEFは必要ありません。データベースエンティティをモデルに変換できるデータアクセスレイヤーを使用します。
まず、EF用のNuGetパッケージをインストールします。 [ ツール ]メニューから、[ NuGet Package Manager ]、[ Package Manager Console ]の順に選択します。 [パッケージマネージャコンソール]ウィンドウで、次のように入力します。
Install-Package EntityFramework
Web.configファイルを開き、 configSections要素の後に、 構成要素内に次のセクションを追加します。
<configuration>
<configSections>
<!-- ... -->
</configSections>
<!-- Add this: -->
<connectionStrings>
<add name="ProductsContext" connectionString="Data Source=(localdb)\v11.0;
Initial Catalog=ProductsContext; Integrated Security=True; MultipleActiveResultSets=True;
AttachDbFilename=|DataDirectory|ProductsContext.mdf"
providerName="System.Data.SqlClient" />
</connectionStrings>
この設定は、LocalDBデータベースの接続文字列を追加します。このデータベースは、アプリケーションをローカルで実行するときに使用されます。
次に、 ProductsContextという名前のクラスをModelsフォルダに追加します。
using System.Data.Entity;
namespace ProductService.Models
{
public class ProductsContext : DbContext
{
public ProductsContext()
: base("name=ProductsContext")
{
}
public DbSet<Product> Products { get; set; }
}
}
コンストラクタでは、 "name = ProductsContext"は接続文字列の名前を示します。
ODataエンドポイントの構成
App_Start / WebApiConfig.csファイルを開きます。次のusingステートメントを追加します。
using ProductService.Models;
using System.Web.OData.Builder;
using System.Web.OData.Extensions;
次に、 Registerメソッドに次のコードを追加します。
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// New code:
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("Products");
config.MapODataServiceRoute(
routeName: "ODataRoute",
routePrefix: null,
model: builder.GetEdmModel());
}
}
このコードは2つのことを行います:
- エンティティデータモデル(EDM)を作成します。
- ルートを追加します。
EDMはデータの抽象モデルです。 EDMは、サービスメタデータ文書の作成に使用されます。 ODataConventionModelBuilderクラスは、デフォルトの命名規則を使用してEDMを作成します。このアプローチでは、最小のコードが必要です。 EDMをより詳細に制御したい場合は、 ODataModelBuilderクラスを使用して、プロパティ、キー、およびナビゲーションプロパティを明示的に追加してEDMを作成できます。
ルートは、HTTP要求をエンドポイントにルーティングする方法をWeb APIに指示します。 OData v4ルートを作成するには、 MapODataServiceRoute拡張メソッドを呼び出します。
アプリケーションに複数のODataエンドポイントがある場合は、それぞれに個別のルートを作成します。各ルートに固有のルート名と接頭辞を付けます。
ODataコントローラを追加する
コントローラは、HTTP要求を処理するクラスです。 ODataサービス内の各エンティティセットに対して個別のコントローラを作成します。このチュートリアルでは、Productエンティティ用に1つのコントローラを作成します。
ソリューションエクスプローラで、[コントローラ]フォルダを右クリックし、[ 追加] > [ クラス ]を選択します。 ProductsControllerクラスに名前を付けます。
OData v3のこのチュートリアルのバージョンでは、コントローラの追加足場が使用されています。現在、OData v4のための足場はありません。
ProductsController.csのボイラープレートコードを次のものに置き換えます。
using ProductService.Models;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.OData;
namespace ProductService.Controllers
{
public class ProductsController : ODataController
{
ProductsContext db = new ProductsContext();
private bool ProductExists(int key)
{
return db.Products.Any(p => p.Id == key);
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
}
コントローラは、 ProductsContextクラスを使用して、EFを使用してデータベースにアクセスします。コントローラはDisposeメソッドをオーバーライドしてProductsContextを破棄します。
これがコントローラの開始点です。次に、すべてのCRUD操作のメソッドを追加します。
エンティティセットでのCRUDの実行
エンティティセットのクエリ
ProductsControllerに次のメソッドを追加します。
[EnableQuery]
public IQueryable<Product> Get()
{
return db.Products;
}
[EnableQuery]
public SingleResult<Product> Get([FromODataUri] int key)
{
IQueryable<Product> result = db.Products.Where(p => p.Id == key);
return SingleResult.Create(result);
}
パラメータのないバージョンのGetメソッドは、Productsコレクション全体を返します。キーパラメータを持つGetメソッドは、そのキー(この例ではIdプロパティ)によって製品を検索します。
[EnableQuery]属性を使用すると、クライアントは$ filter、$ sort、$ pageなどのクエリオプションを使用してクエリを変更できます。詳細については、「 ODataクエリオプションのサポート」を参照してください。
エンティティセットへのエンティティの追加
クライアントが新しい製品をデータベースに追加できるようにするには、 ProductsControllerに次のメソッドを追加します。
public async Task<IHttpActionResult> Post(Product product)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Products.Add(product);
await db.SaveChangesAsync();
return Created(product);
}
エンティティの更新
ODataは、エンティティ、PATCHおよびPUTを更新するための2つの異なるセマンティクスをサポートしています。
- PATCHは部分的な更新を実行します。クライアントは、更新するプロパティのみを指定します。
- PUTはエンティティ全体を置き換えます。
PUTの欠点は、クライアントが変更されていない値を含め、エンティティ内のすべてのプロパティの値を送信する必要があることです。 OData仕様には、PATCHが推奨されています。
いずれの場合も、PATCHメソッドとPUTメソッドのコードは次のとおりです。
public async Task<IHttpActionResult> Patch([FromODataUri] int key, Delta<Product> product)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var entity = await db.Products.FindAsync(key);
if (entity == null)
{
return NotFound();
}
product.Patch(entity);
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!ProductExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(entity);
}
public async Task<IHttpActionResult> Put([FromODataUri] int key, Product update)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (key != update.Id)
{
return BadRequest();
}
db.Entry(update).State = EntityState.Modified;
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!ProductExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(update);
}
PATCHの場合、コントローラーはDelta <T>タイプを使用して変更を追跡します。
エンティティの削除
クライアントがデータベースから製品を削除できるようにするには、 ProductsControllerに次のメソッドを追加します。
public async Task<IHttpActionResult> Delete([FromODataUri] int key)
{
var product = await db.Products.FindAsync(key);
if (product == null)
{
return NotFound();
}
db.Products.Remove(product);
await db.SaveChangesAsync();
return StatusCode(HttpStatusCode.NoContent);
}