WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

OData で ODataQueryOptions 使用

by WebSurfer 2020年4月12日 17:11

Open Data Protocol (OData) を利用した ASP.NET Web API アプリで、ODataQueryOptions<TEntity> を引数に持つアクションメソッドを作る話を備忘録として書いておきます。

Open Data Protocol (OData)

OData を利用した ASP.NET Web API アプリの作り方は、.NET Framework ベースの場合は Microsoft のドキュメント Create an OData v4 Endpoint Using ASP.NET Web API に、Core ベースの場合は Experimenting with OData in ASP.NET Core 3.1 にあります。

(ちなみに、OData を利用するメリットですが、Creating an OData v4 API with ASP.NET Core 2.0 に書いてありますように、"the payload size and the querying of the data from the database" ということだそうです。確かにその通りだと思いました。OData に興味があれば読んでみることをお勧めします)

上に紹介した記事には書かれていませんが、Microsoft のドキュメント Invoking Query Options Directly によると、Advanced Scenarios(多分、より細かなコントロールが可能ということだと思います)として、ODataQueryOptions<TEntity> を引数に持つアクションメソッドを利用するオプションがあるそうです。

(注:記事に書いてある [Queryable] 属性は OData v3 の場合で、OData v4 または Core の場合は [EnableQuery] 属性になるようです)

ハマったのは、上の記事のコード results as IQueryable<Product> が null になってしまう場合があるということです。例えばこの記事では $select=name とした場合がそれです。

普通にアクションメソッドに [EnableQuery] 属性を付与する場合は以下のようにします。それだけで OData が有効になり、クエリ文字列に $select とか $top などを指定すればそれに従って JSON 文字列が返ってきます。

using System.Linq;
using Microsoft.AspNetCore.Mvc;
using ODataCore3API.DAL;
using ODataCore3API.Models;

using Microsoft.AspNet.OData;
using Microsoft.AspNet.OData.Query;

namespace ODataCore3API.Controllers
{
    [Produces("application/json")]
    public class ProductController : ODataController
    {
        private readonly ProductContext _context;

        public ProductController(ProductContext context)
        {
            _context = context;
        }

        [HttpGet]
        [EnableQuery]
        public IQueryable<Product> GetProduct()
        {
            return _context.Product.AsQueryable();
        }
    }
}

クエリ文字列を $select=name としても、期待通りの JSON 文字列が、この記事の上にある画像の通り返ってきます。アクションメソッドの戻り値を IQueryable<Product> としていますが、返ってくる JSON 文字列は IQueryable<Product> をデシリアライズしたものではないことに注目してください。OData がどこかでその違いを吸収しているようです。

[EnableQuery] 属性を削除して ODataQueryOptions<TEntity> を引数に持つアクションメソッドを使う場合、かつ $select=name でも対応できるようにするには以下のようにします。コメントに注目してください。

// ODataQueryOptions<Product> を引数に持つバージョン
[HttpGet]
public IActionResult GetProduct(
                ODataQueryOptions<Product> opts)
{
    IQueryable results = 
        opts.ApplyTo(_context.Product.AsQueryable());

    // 以下はダメ。$select=name としたとき null になる
    // return results as IQueryable<Product>;

    // アクションメソッドの戻り値を IActionResult とし
    // 以下のようにすれば $select=name でも OK
    return Ok(results);
}

上のコードは OData Query Options という記事を参考にしました。$select=name とした場合でも、この記事の上にある画像のとおり期待した JSON 文字列が返ってきます。

results as IQueryable<Product> が null になるのは考えてみれば当たり前だったのですが、そこに気が付かず半日ぐらいハマってしまった次第です。(笑)

Tags: , , ,

Web API

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年3月  >>
252627282912
3456789
10111213141516
17181920212223
24252627282930
31123456

View posts in large calendar