ASP .NET MVC 4的WebAPI:手工处理的OData查询(ASP .NET MVC 4

2019-06-24 20:48发布

我使用ASP .NET MVC提供4.我知道其中的WebAPI自动工作在顶部层处理的OData查询 (如的WebAPI Web服务由$filter$top$skip ),但如果我想要什么由我自己来处理过滤?

我不只是从我的数据库返回的数据 ,但我已经它增加了一些特性,另一层做一些转换等,所以查询我所有的数据,将它们转换并把他们送回了OData的滤波的WebAPI类不是刚刚好足够。 这当然非常慢的,一般一个糟糕的主意。

那么,有没有办法从我的WebAPI入口点函数的OData查询参数我叫获取和转换数据?

例如,一个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;
}

Answer 1:

我只是碰到这种旧后迷迷糊糊的我加入这个答案,因为它是现在很容易处理的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; }
}


Answer 2:

从URL查询被转换成一个LINQ表达式树,然后对你的IQueryable操作返回执行。 您可以分析表达和提供任何你想要的结果。 缺点是,你需要实现IQueryable的是不是超级简单。 看看这篇博客系列,如果你有兴趣: http://blogs.msdn.com/b/vitek/archive/2010/02/25/data-services-expressions-part-1-intro.aspx 。 它谈论WCF数据服务,但由Web API使用的过滤器表达式将是非常相似的。



Answer 3:

一个与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);
 }


Answer 4:

我做了这样的事情与WCF Data Services和asp.net的MVC 3.5,但它是一个有点杂牌的。

第一步是重写的路径,这样的跳跃和顶部的选项不要被运行时应用了两次,一次由你和一次。

我做了一个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语句或任何其他数据库的命令。 我在我的情况下使用NHibernate。 我也能够限制我支持哪些过滤命令这使事情变得更容易。 我没有例如做分组。 大多只是比较操作符。

有在过滤器运算符的列表OData.org 。 由“与”和“或”成单独的条款分割的字符串。 由空间分割每个子句,你应该得到与该属性名称的3元件阵列中[0]操作[1],并在值[2]。

该条款将在人的方面,但我假设你就可以将它们转换到的东西,会拉正确的结果出来的分贝。

最后我放弃这种方法,因为它不会上岗工作。 我不得不写我自己的LINQ提供程序,但写我自己的过滤字符串解析器作出更容易理解。



文章来源: ASP .NET MVC 4 WebApi: Manually handle OData queries