programing

ASP .NET MVC 4 WebApi : OData 쿼리를 수동으로 처리

nicescript 2021. 1. 16. 09:18
반응형

ASP .NET MVC 4 WebApi : OData 쿼리를 수동으로 처리


나는 웹 서비스를 사용하여 만든 WebAPI 내가 WebAPI가 자동으로 작동하는의 상단에 레이어가 처리하는 알 ASP .NET MVC (4)에 의해 제공을 하나로, OData 쿼리 (예 : $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;
}

나는 방금이 오래된 게시물을 우연히 발견했으며 이제 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의 쿼리는 작업이 반환하는 IQueryable에 대해 실행되는 LINQ 식 트리로 변환됩니다. 식을 분석하고 원하는 방식으로 결과를 제공 할 수 있습니다. 단점은 매우 쉽지 않은 IQueryable을 구현해야한다는 것입니다. 관심이있는 경우이 블로그 게시물 시리즈를 살펴보세요. http://blogs.msdn.com/b/vitek/archive/2010/02/25/data-services-expressions-part-1-intro.aspx . WCF 데이터 서비스에 대해 설명하지만 웹 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);
 }

I did something like this with WCF Data Services and asp.net mvc 3.5 but it was a bit of a kludge.

The first step is to rewrite the path so that the skip and top options don't get applied twice, once by you and once by the runtime.

I did the rewriting with an HttpModule. In your BeginRequest method you'd have code like this:

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);
    }
}

Then just examine the query string and pluck out the parameters you need.

if (HttpContext.Current.Request.QueryString["filter"] != null)
    var filter = HttpContext.Current.Request.QueryString["filter"] as string;

Then split the filter string and parse it into a sql statement or any other db commands. I was using NHibernate in my case. I was also able to limit what filter commands I supported which made things easier. I didn't do groupings for example. Mostly just the comparison operators.

There's a list of filter operators at OData.org. Split the string by "and" and "or" into individual clauses. Split each clause by a space and you should get a 3 element array with the property name in [0] the operator in [1] and the value in [2].

The clauses will be in terms of a Person but I'm assuming you'll be able to convert them into something that will pull the right results out of the db.

I ended up abandoning this approach since it won't work for POSTS. I had to write my own Linq provider but writing my own filter string parser made that easier to understand.

ReferenceURL : https://stackoverflow.com/questions/10781309/asp-net-mvc-4-webapi-manually-handle-odata-queries

반응형