私はODataエンドポイントを立ち上げて動作させようとしているのですが、このエラーが発生しているので、グーグルでさえあまり語ることはできません。
Entity Framework EDMXコンテキスト(データベースが最初)を作成し、デザイナーに2つのモデルを生成させました。
$filter
クエリが失敗する場合を除き、すべてが正常に機能しています。
私はこれをうまく行うことができます:
http://localhost:27164/Projects(6587660)
6587660のプライマリIDでプロジェクトを取得します。
ただし、$filter
リクエストは次のようになります。
http://localhost:27164/Projects?$filter=ProjectID eq 6587660
次のエラーで失敗します。
URIで指定されたクエリが無効です。プロパティ 'ProjectID'は、$ filterクエリオプションでは使用できません。
他のプロパティ、文字列プロパティもクエリしてみました。同じエラー。
EFによって生成されたモデルには、プロパティに属性がないことを確認しました。属性はありません。
WebApiConfig.csモジュールのRegisterメソッドは次のとおりです。
using System.Web.OData.Builder;
using System.Web.OData.Extensions;
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<DB.Project>("Projects");
config.MapODataServiceRoute(
routeName: "ODataRoute",
routePrefix: null,
model: builder.GetEdmModel()
);
}
Projectsコントローラーは次のとおりです(GetProjectsは、$ filterクエリを実行するときに呼び出されるメソッドです)。
public class ProjectsController : ODataController
{
private AppContext db = new AppContext();
//I've tried decorating with that: [EnableQuery(AllowedQueryOptions = System.Web.OData.Query.AllowedQueryOptions.All, AllowedArithmeticOperators = System.Web.OData.Query.AllowedArithmeticOperators.All)] and no go
[EnableQuery]
public IQueryable<Project> GetProjects()
{
return db.Projects;
}
// GET: odata/Projects(5)
[EnableQuery]
public SingleResult<Project> GetProject([FromODataUri] int key)
{
return SingleResult.Create(db.Projects.Where(project => project.ProjectID == key));
}
/*
// PUT: odata/Projects(5)
public IHttpActionResult Put([FromODataUri] int key, Delta<Project> patch)
{
Validate(patch.GetEntity());
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
Project project = db.Projects.Find(key);
if (project == null)
{
return NotFound();
}
patch.Put(project);
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!ProjectExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(project);
}
// POST: odata/Projects
public IHttpActionResult Post(Project project)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Projects.Add(project);
db.SaveChanges();
return Created(project);
}
// PATCH: odata/Projects(5)
[AcceptVerbs("PATCH", "MERGE")]
public IHttpActionResult Patch([FromODataUri] int key, Delta<Project> patch)
{
Validate(patch.GetEntity());
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
Project project = db.Projects.Find(key);
if (project == null)
{
return NotFound();
}
patch.Patch(project);
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!ProjectExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(project);
}
// DELETE: odata/Projects(5)
public IHttpActionResult Delete([FromODataUri] int key)
{
Project project = db.Projects.Find(key);
if (project == null)
{
return NotFound();
}
db.Projects.Remove(project);
db.SaveChanges();
return StatusCode(HttpStatusCode.NoContent);
}
*/
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
private bool ProjectExists(int key)
{
return db.Projects.Count(e => e.ProjectID == key) > 0;
}
}
Database FirstでODataを使用するのはこれが初めてなので、何が原因なのかわかりません。
.NET 4.5.2上のNugetの最新のランタイムを使用しています。
WebAPI ODataのデフォルト設定は次のとおりです。クライアントはクエリで$ count、$ orderby、$ select、$ top、$ expand、$ filterを適用できません。localhost\ odata\Customers?$ orderby = Nameのようなクエリは失敗しますBadRequest、すべてのプロパティはデフォルトでソートできないため、これは6.0.0の重大な変更です
そのため、OData Model Bound Attributesを有効にする必要があります。これは、can中央の行でグローバルに行うことができます次のブロック(他の2つはコードです):
ODataModelBuilder builder = new ODataConventionModelBuilder();
config.Count().Filter().OrderBy().Expand().Select().MaxTop(null); //new line
builder.EntitySet<DB.Project>("Projects");
しかし、それはこの変更がもたらすより優れたセキュリティ/パフォーマンスを回避するキャッチオールであり、一種の仕事です。
したがって、次のようにエンティティごとに流なAPI呼び出しを使用して、ODataモデルのバインドされた属性を有効にできます。
builder.EntitySet<DB.Project>("Projects"); //your line of code
builder.EntityType<DB.Project>().Filter("ProjectID");
この回答は、あなたが投稿した問題を解決するはずですが、プロジェクトの残りの部分について包括的なソリューションを作成できるようにするには、 これらのドキュメント を確認する必要があります。もちろん、1行ですべてをキャッチするだけです!)。
「Model Bound Attribute」という名前が示唆するように、モデルの属性を介して必要なものを実現することもできます。これは(実際、主な焦点です) ドキュメント でも説明されています。
2017年2月編集:
エンティティごとに流APIなAPIにはバグがあるようです。 $expand
エンティティセットの呼び出しは、エンティティセットがFluent APIでセットアップされているにもかかわらず、元の質問にエラーがある400 Bad Requestを断続的に返します。このバグが$expand
にのみ存在するのか、他のクエリパラメーターにのみ存在するのかはわかりません。また、問題を引き起こしているのが自分のコードなのか、MSバグなのか、したがって他の人が遭遇しているのかどうかもわかりません。すぐにこれをさらに調査し、この回答を更新します。今のところ、私は1行のキャッチオールを使用しています。それはうまく機能します。
さらに編集:
docs (この更新をできるだけ理解できるようにするため)の一部を読み直したところ、(Global Config one-line-キャッチオールプラス流APIなAPI)、エンティティごとの流APIなAPIは引き続き尊重されます。
「クエリ設定は多くの場所に配置できます。優先度は最低から最高の順に設定されています:システムデフォルト(デフォルトではクエリ不可)、グローバル構成、モデルバウンド属性、Fluent API。」
したがって、多分これはあなたがしなければならないことです:one-line-catch-allを追加してから、model-bound-attributes、fluent API、またはその両方で微調整します。これをテストする必要があり、すぐに報告します...
@NickG et al:.Net Coreでの質問に答えるには、次のようなことを行います。
private static IEdmModel GetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
var products = builder.EntitySet<Product>("Products");
products.EntityType.Count().Filter().OrderBy().Expand().Select();
return builder.GetEdmModel();
}