[英]WebApi (ApiController) vs OData (ODataController) in ASP.Net MVC
[英]ASP .NET MVC 4 WebApi: Manually handle OData queries
我有一個使用ASP .NET MVC 4提供的WebAPI制作的Web服務。我知道WebAPI工作之上的層自動處理OData查詢 (例如$filter
, $top
, $skip
),但是如果我想要的話自己處理過濾?
我不是簡單地從我的數據庫返回數據 ,但我有另一個層添加了一些屬性,進行了一些轉換等等。因此查詢我的所有數據,轉換它們並將它們返回到WebAPI類進行OData過濾不僅僅是好的足夠。 它當然非常慢,通常是一個糟糕的想法。
那么有沒有辦法將OData查詢參數從我的WebAPI入口點傳播到我調用的函數來獲取和轉換數據?
例如,GET到/api/people?$skip=10&$top=10
會調用服務器:
public IQueryable<Person> get() {
return PersonService.get(SomethingAboutCurrentRequest.CurrentOData);
}
在PersonService
:
public IQueryable<Person> getPeople(var ODataQueries) {
IQueryable<ServerSidePerson> serverPeople = from p in dbContext.ServerSidePerson select p;
// Make the OData queries
// Skip
serverPeople = serverPeople.Skip(ODataQueries.Skip);
// Take
serverPeople = serverPeople.Take(ODataQueries.Take);
// And so on
// ...
// Then, convert them
IQueryable<Person> people = Converter.convertPersonList(serverPeople);
return people;
}
我只是偶然發現了這個老帖子,我正在添加這個答案,因為現在很容易自己處理OData查詢。 這是一個例子:
[HttpGet]
[ActionName("Example")]
public IEnumerable<Poco> GetExample(ODataQueryOptions<Poco> queryOptions)
{
var data = new Poco[] {
new Poco() { id = 1, name = "one", type = "a" },
new Poco() { id = 2, name = "two", type = "b" },
new Poco() { id = 3, name = "three", type = "c" }
};
var t = new ODataValidationSettings() { MaxTop = 2 };
queryOptions.Validate(t);
//this is the method to filter using the OData framework
//var s = new ODataQuerySettings() { PageSize = 1 };
//var results = queryOptions.ApplyTo(data.AsQueryable(), s) as IEnumerable<Poco>;
//or DIY
var results = data;
if (queryOptions.Skip != null)
results = results.Skip(queryOptions.Skip.Value);
if (queryOptions.Top != null)
results = results.Take(queryOptions.Top.Value);
return results;
}
public class Poco
{
public int id { get; set; }
public string name { get; set; }
public string type { get; set; }
}
來自URL的查詢被轉換為LINQ表達式樹,然后針對您的操作返回的IQueryable執行。 您可以分析表達式並以您想要的任何方式提供結果。 缺點是你需要實現IQueryable,這不是一件容易的事。 如果您有興趣,請查看此博客文章系列: http : //blogs.msdn.com/b/vitek/archive/2010/02/25/data-services-expressions-part-1-intro.aspx 。 它討論了WCF數據服務,但Web API使用的過濾器表達式將非常相似。
使用Web-api的一種方法是使用客戶消息處理程序http://www.asp.net/web-api/overview/working-with-http/http-message-handlers
編寫如下的自定義處理程序:
public class CustomHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
return base.SendAsync(request, cancellationToken).ContinueWith(
(task) =>
{
HttpResponseMessage response = task.Result;
var persons = response.Content.ReadAsAsync<IQueryable<Person>>().Result;
var persons2 = new List<Person>(); //This can be the modified model completely different
foreach (var item in persons)
{
item.Name = "changed"; // here you can change the data
//persons2.Add(....); //Depending on the results modify this custom model
}
//overwrite the response
response = new HttpResponseMessage<IEnumerable<Person>>(persons2);
return response;
}
);
}
}
在global.asax.cs中注冊
應用類中的方法:
static void Configure(HttpConfiguration config)
{
config.MessageHandlers.Add(new CustomHandler());
}
protected void Application_Start()
{
....
.....
//call the configure method
Configure(GlobalConfiguration.Configuration);
}
我使用WCF數據服務和asp.net mvc 3.5做了類似的事情,但它有點像kludge。
第一步是重寫路徑,以便跳過和頂部選項不會被應用兩次,一次由您運行,一次由運行時應用。
我用HttpModule進行了重寫。 在您的BeginRequest方法中,您將擁有如下代碼:
HttpApplication app = (HttpApplication)sender;
if (HttpContext.Current.Request.Path.Contains(YOUR_SVC))
{
if (app.Request.Url.Query.Length > 0)
{
//skip questionmark
string queryString = app.Request.Url.Query.Substring(1)
.Replace("$filter=", "filter=")
.Replace("$orderby=", "orderby=")
.Replace("$top=", "top=")
.Replace("$skip=", "skip=");
HttpContext.Current.RewritePath(app.Request.Path, "", queryString);
}
}
然后只需檢查查詢字符串並選擇所需的參數。
if (HttpContext.Current.Request.QueryString["filter"] != null)
var filter = HttpContext.Current.Request.QueryString["filter"] as string;
然后拆分過濾器字符串並將其解析為sql語句或任何其他db命令。 在我的案例中我使用的是NHibernate。 我還能夠限制我支持的過濾器命令,這使得事情變得更容易。 例如,我沒有進行分組。 主要是比較運算符。
OData.org上有一個過濾器運算符列表。 將字符串“and”和“or”拆分為單獨的子句。 用空格分割每個子句,你應該得到一個3元素數組,其中[0]中的屬性名稱為[1]中的運算符,[2]中的值。
這些條款將以Person為單位,但我假設您將能夠將它們轉換為可以從db中獲取正確結果的內容。
我最終放棄了這種方法,因為它不適用於POSTS。 我必須編寫自己的Linq提供程序,但編寫自己的過濾器字符串解析器使其更容易理解。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.