ASP.NET web API 2 OData クエリ オプションをサポートSupporting OData Query Options in ASP.NET Web API 2

作成者Mike Wassonby Mike Wasson

コード例では、この概要では、ASP.NET Web API 2 では、サポートの OData クエリ オプションを紹介 for ASP.NET 4.x です。This overview with code examples demonstrates the supporting OData Query Options in ASP.NET Web API 2 for ASP.NET 4.x.

OData では、OData のクエリを変更するために使用するパラメーターを定義します。OData defines parameters that can be used to modify an OData query. クライアントは、要求 URI のクエリ文字列で、これらのパラメーターを送信します。The client sends these parameters in the query string of the request URI. たとえば、クライアントに結果を並べ替えるには、$orderby パラメーターを使用してください。For example, to sort the results, a client uses the $orderby parameter:

http://localhost/Products?$orderby=Name

OData の仕様は、これらのパラメーターを呼び出すクエリ オプションします。The OData specification calls these parameters query options. プロジェクトで任意の Web API コント ローラーの OData クエリ オプションを有効にできます—コント ローラーは、OData エンドポイントである必要はありません。You can enable OData query options for any Web API controller in your project — the controller does not need to be an OData endpoint. これにより、フィルター処理およびすべての Web API アプリケーションに並べ替えなどの機能を追加する便利な方法です。This gives you a convenient way to add features such as filtering and sorting to any Web API application.

トピックを参照してください、クエリ オプションを有効にする前にOData セキュリティ ガイダンスします。Before enabling query options, please read the topic OData Security Guidance.

OData クエリ オプションを有効にします。Enabling OData Query Options

Web API には、次の OData クエリ オプションがサポートされています。Web API supports the following OData query options:

オプションOption 説明Description
$ を展開します。$expand インラインの関連エンティティを展開します。Expands related entities inline.
$filter$filter ブール条件に基づいて、結果をフィルター処理します。Filters the results, based on a Boolean condition.
$inlinecount$inlinecount 一致するエンティティの合計数を応答に含めるようにサーバーに指示します。Tells the server to include the total count of matching entities in the response. (サーバー側のページングに役立ちます。)(Useful for server-side paging.)
$orderby$orderby 結果を並べ替えます。Sorts the results.
$select$select 応答に含めるプロパティを選択します。Selects which properties to include in the response.
$skip$skip 最初の n 個の結果をスキップします。Skips the first n results.
$top$top 最初の n のみに結果を返します。Returns only the first n the results.

OData クエリ オプションを使用するには、必要があります有効に明示的にします。To use OData query options, you must enable them explicitly. 特定のコント ローラーまたは特定のアクションのために有効または、アプリケーション全体でグローバルに有効にできます。You can enable them globally for the entire application, or enable them for specific controllers or specific actions.

OData クエリ オプションをグローバルに有効にするを呼び出すEnableQuerySupport上、 HttpConfiguration起動時クラス。To enable OData query options globally, call EnableQuerySupport on the HttpConfiguration class at startup:

public static void Register(HttpConfiguration config)
{
    // ...

    config.EnableQuerySupport();

    // ...
}

EnableQuerySupportメソッドを返すコント ローラーのアクションに対してグローバルにクエリ オプションを使用できます、 IQueryable型。The EnableQuerySupport method enables query options globally for any controller action that returns an IQueryable type. クエリ オプションをアプリケーション全体に対して有効にしない場合は、ことができますの特定のコント ローラーのアクションを追加して、 [Queryable] 属性をアクション メソッド。If you don't want query options enabled for the entire application, you can enable them for specific controller actions by adding the [Queryable] attribute to the action method.

public class ProductsController : ApiController
{
    [Queryable]
    IQueryable<Product> Get() {}
}

クエリの例Example Queries

このセクションでは、OData クエリ オプションを使用してクエリの種類が表示されます。This section shows the types of queries that are possible using the OData query options. 特定の詳細については、クエリ オプションでは、OData ドキュメントを参照してくださいwww.odata.orgします。For specific details about the query options, refer to the OData documentation at www.odata.org.

$ について順に展開し、$select を参照してください$ の $select を使用して、展開と ASP.NET Web API odata $valueFor information about $expand and $select, see Using $select, $expand, and $value in ASP.NET Web API OData.

クライアント ドリブン ページングClient-Driven Paging

大きなエンティティ セットの場合は、クライアントは、結果の数を制限する可能性があります。For large entity sets, the client might want to limit the number of results. たとえば、クライアントは、結果の次のページを取得する [次へ] のリンク時に 10 個のエントリを表示する可能性があります。For example, a client might show 10 entries at a time, with "next" links to get the next page of results. これを行うには、クライアントは、$top、$skip オプションを使用します。To do this, the client uses the $top and $skip options.

http://localhost/Products?$top=10&$skip=20

$Top オプションは、返される項目の最大数と、$skip オプションは、スキップするエントリの数を示します。The $top option gives the maximum number of entries to return, and the $skip option gives the number of entries to skip. 前の例では、21 ~ 30 のエントリをフェッチします。The previous example fetches entries 21 through 30.

フィルター処理Filtering

$Filter オプションは、ブール式を適用することで、結果をフィルター処理クライアントを使用できます。The $filter option lets a client filter the results by applying a Boolean expression. フィルター式は非常に強力です。論理演算子および算術演算子、文字列関数、および日付関数が含まれます。The filter expressions are quite powerful; they include logical and arithmetic operators, string functions, and date functions.

"Toys"に等しいすべての製品のカテゴリを返します。Return all products with category equal to "Toys". http://localhost/Products?$filter=Category eq 'Toys'http://localhost/Products?$filter=Category eq 'Toys'
すべての製品の価格が 10 よりも小さいかを返します。Return all products with price less than 10. http://localhost/Products?$filter=Price lt 10http://localhost/Products?$filter=Price lt 10
論理演算子 : すべての製品を返す価格、> = 5 と価格 < 15 を = です。Logical operators: Return all products where price >= 5 and price <= 15. http://localhost/Products?$filter=Price ge 5 と価格 le 15http://localhost/Products?$filter=Price ge 5 and Price le 15
文字列関数。すべての製品"zz"の名前を返します。String functions: Return all products with "zz" in the name. http://localhost/Products?$filter=substringof('zz',Name)
日付関数:2005 より後に、すべての製品の ReleaseDate を返します。Date functions: Return all products with ReleaseDate after 2005. http://localhost/Products?$filter=year(ReleaseDate) gt 2005http://localhost/Products?$filter=year(ReleaseDate) gt 2005

並べ替えSorting

結果を並べ替えるには、$orderby フィルターを使用します。To sort the results, use the $orderby filter.

価格で並べ替えます。Sort by price. http://localhost/Products?$orderby=Price
降順 (最低に最高) の価格で並べ替えます。Sort by price in descending order (highest to lowest). http://localhost/Products?$orderby=Price desc
カテゴリ別に並べ替えるし、価格のカテゴリ内の降順で並べ替えます。Sort by category, then sort by price in descending order within categories. http://localhost/odata/Products?$orderby=Category,Price desc

サーバー ドリブン ページングServer-Driven Paging

送信しない場合は、データベースには、何百万もレコードにはが含まれています、すべて 1 つのペイロードにします。If your database contains millions of records, you don't want to send them all in one payload. これを防ぐためには、サーバーは、1 つの応答で送信するエントリの数を制限できます。To prevent this, the server can limit the number of entries that it sends in a single response. サーバーのページングを有効にするには設定、 PageSizeプロパティ、 Queryable属性。To enable server paging, set the PageSize property in the Queryable attribute. 値は、返される項目の最大数です。The value is the maximum number of entries to return.

[Queryable(PageSize=10)]
public IQueryable<Product> Get() 
{
    return products.AsQueryable();
}

コント ローラーには、OData 形式が返された場合、応答本文にはデータの次のページへのリンクが含まれます。If your controller returns OData format, the response body will contain a link to the next page of data:

{
  "odata.metadata":"http://localhost/$metadata#Products",
  "value":[
    { "ID":1,"Name":"Hat","Price":"15","Category":"Apparel" },
    { "ID":2,"Name":"Socks","Price":"5","Category":"Apparel" },
    // Others not shown
  ],
  "odata.nextLink":"http://localhost/Products?$skip=10"
}

クライアントは、次のページをフェッチするのにこのリンクを使用できます。The client can use this link to fetch the next page. 結果セット内のエントリの合計数については、クライアント設定できます $inlinecount クエリ オプション値を持つ"allpages"。To learn the total number of entries in the result set, the client can set the $inlinecount query option with the value "allpages".

http://localhost/Products?$inlinecount=allpages

値"allpages"応答の合計数を追加するには、サーバーに指示します。The value "allpages" tells the server to include the total count in the response:

{
  "odata.metadata":"http://localhost/$metadata#Products",
  "odata.count":"50",
  "value":[
    { "ID":1,"Name":"Hat","Price":"15","Category":"Apparel" },
    { "ID":2,"Name":"Socks","Price":"5","Category":"Apparel" },
    // Others not shown
  ]
}

Note

次のページへのリンクとインライン カウントの OData 形式が必要です。Next-page links and inline count both require OData format. 理由は、OData のリンクとカウントを保持するために、応答本文で特別なフィールドを定義します。The reason is that OData defines special fields in the response body to hold the link and count.

クエリの結果をラップすることで、次のページのリンクとインライン カウントをサポートするためにできますが、非 OData 形式の場合、 PageResult<T> オブジェクト。For non-OData formats, it is still possible to support next-page links and inline count, by wrapping the query results in a PageResult<T> object. ただし、少しコードが必要です。However, it requires a bit more code. 次に例を示します。Here is an example:

public PageResult<Product> Get(ODataQueryOptions<Product> options)
{
    ODataQuerySettings settings = new ODataQuerySettings()
    {
        PageSize = 5
    };

    IQueryable results = options.ApplyTo(_products.AsQueryable(), settings);

    return new PageResult<Product>(
        results as IEnumerable<Product>, 
        Request.GetNextPageLink(), 
        Request.GetInlineCount());
}

JSON 応答例を次に示します。Here is an example JSON response:

{
  "Items": [
    { "ID":1,"Name":"Hat","Price":"15","Category":"Apparel" },
    { "ID":2,"Name":"Socks","Price":"5","Category":"Apparel" },

    // Others not shown
    
  ],
  "NextPageLink": "http://localhost/api/values?$inlinecount=allpages&$skip=10",
  "Count": 50
}

クエリ オプションを制限します。Limiting the Query Options

クエリ オプションは、クライアントに多数のサーバーで実行されるクエリに制御を提供します。The query options give the client a lot of control over the query that is run on the server. 場合によっては、セキュリティやパフォーマンス上の理由から使用可能なオプションを制限する可能性があります。In some cases, you might want to limit the available options for security or performance reasons. [Queryable] 属性が一部の組み込みプロパティでこのします。The [Queryable] attribute has some built in properties for this. 以下に例をいくつか示します。Here are some examples.

ページングと何をサポートするために、$skip、$top、のみを許可します。Allow only $skip and $top, to support paging and nothing else:

[Queryable(AllowedQueryOptions=
    AllowedQueryOptions.Skip | AllowedQueryOptions.Top)]

特定のプロパティによってのみ、データベースでインデックス化されていないプロパティで並べ替えを防ぐために順序付けを許可します。Allow ordering only by certain properties, to prevent sorting on properties that are not indexed in the database:

[Queryable(AllowedOrderByProperties="Id")] // comma-separated list of properties

"Eq"論理関数ですがないその他の論理関数を許可します。Allow the "eq" logical function but no other logical functions:

[Queryable(AllowedLogicalOperators=AllowedLogicalOperators.Equal)]

すべての算術演算子をことはできません。Do not allow any arithmetic operators:

[Queryable(AllowedArithmeticOperators=AllowedArithmeticOperators.None)]

オプションをグローバルに制限するには作成することにより、 QueryableAttributeインスタンスとに渡して、 EnableQuerySupport関数。You can restrict options globally by constructing a QueryableAttribute instance and passing it to the EnableQuerySupport function:

var queryAttribute = new QueryableAttribute()
{
    AllowedQueryOptions = AllowedQueryOptions.Top | AllowedQueryOptions.Skip,
    MaxTop = 100
};
                
config.EnableQuerySupport(queryAttribute);

クエリ オプションを直接呼び出すInvoking Query Options Directly

使用する代わりに、 [Queryable] 属性をコント ローラーで直接クエリ オプションを呼び出すことができます。Instead of using the [Queryable] attribute, you can invoke the query options directly in your controller. これを行うには、追加、 ODataQueryOptionsコント ローラー メソッドのパラメーター。To do so, add an ODataQueryOptions parameter to the controller method. この場合、必要はありません、 [Queryable] 属性。In this case, you don't need the [Queryable] attribute.

public IQueryable<Product> Get(ODataQueryOptions opts)
{
    var settings = new ODataValidationSettings()
    {
        // Initialize settings as needed.
        AllowedFunctions = AllowedFunctions.AllMathFunctions
    };

    opts.Validate(settings);

    IQueryable results = opts.ApplyTo(products.AsQueryable());
    return results as IQueryable<Product>;
}

Web API の作成、 ODataQueryOptions URI からクエリ文字列。Web API populates the ODataQueryOptions from the URI query string. クエリを適用するには、渡す、 IQueryableApplyToメソッド。To apply the query, pass an IQueryable to the ApplyTo method. メソッドを返します別IQueryableします。The method returns another IQueryable.

高度なシナリオではない場合、 IQueryableクエリ プロバイダーを調べることができます、 ODataQueryOptionsし、別のフォームへのクエリ オプションを変換します。For advanced scenarios, if you do not have an IQueryable query provider, you can examine the ODataQueryOptions and translate the query options into another form. (たとえば、RaghuRam Nadiminti のブログの投稿を参照してください変換の OData クエリの HQL へも含まれていますが、サンプル)。(For example, see RaghuRam Nadiminti's blog post Translating OData queries to HQL, which also includes a sample.)

クエリの検証Query Validation

[Queryable] 属性は、実行する前に、クエリを検証します。The [Queryable] attribute validates the query before executing it. 検証手順がで実行される、 QueryableAttribute.ValidateQueryメソッド。The validation step is performed in the QueryableAttribute.ValidateQuery method. 検証プロセスをカスタマイズすることもできます。You can also customize the validation process.

参照してくださいOData セキュリティ ガイダンスします。Also see OData Security Guidance.

最初に、オーバーライドされている検証コントロールのいずれかのクラスが定義されている、 Web.Http.OData.Query.Validators名前空間。First, override one of the validator classes that is defined in the Web.Http.OData.Query.Validators namespace. たとえば、次の検証コントロール クラスには、$orderby オプションの 'desc' オプションが無効にします。For example, the following validator class disables the 'desc' option for the $orderby option.

public class MyOrderByValidator : OrderByQueryValidator
{
    // Disallow the 'desc' parameter for $orderby option.
    public override void Validate(OrderByQueryOption orderByOption,
                                    ODataValidationSettings validationSettings)
    {
        if (orderByOption.OrderByNodes.Any(
                node => node.Direction == OrderByDirection.Descending))
        {
            throw new ODataException("The 'desc' option is not supported.");
        }
        base.Validate(orderByOption, validationSettings);
    }
}

サブクラス、 [Queryable] をオーバーライドする属性、 ValidateQueryメソッド。Subclass the [Queryable] attribute to override the ValidateQuery method.

public class MyQueryableAttribute : QueryableAttribute
{
    public override void ValidateQuery(HttpRequestMessage request, 
        ODataQueryOptions queryOptions)
    {
        if (queryOptions.OrderBy != null)
        {
            queryOptions.OrderBy.Validator = new MyOrderByValidator();
        }
        base.ValidateQuery(request, queryOptions);
    }
}

カスタム属性を設定するかグローバルにまたはコント ローラーごと。Then set your custom attribute either globally or per-controller:

// Globally:
config.EnableQuerySupport(new MyQueryableAttribute());

// Per controller:
public class ValuesController : ApiController
{
    [MyQueryable]
    public IQueryable<Product> Get()
    {
        return products.AsQueryable();
    }
}

使用する場合ODataQueryOptionsを直接検証コントロールをオプションに設定します。If you are using ODataQueryOptions directly, set the validator on the options:

public IQueryable<Product> Get(ODataQueryOptions opts)
{
    if (opts.OrderBy != null)
    {
        opts.OrderBy.Validator = new MyOrderByValidator();
    }

    var settings = new ODataValidationSettings()
    {
        // Initialize settings as needed.
        AllowedFunctions = AllowedFunctions.AllMathFunctions
    };

    // Validate
    opts.Validate(settings);

    IQueryable results = opts.ApplyTo(products.AsQueryable());
    return results as IQueryable<Product>;
}