Webapi: OData doesn't see QueryString when EnableQuery + AWS Lambda

Created on 31 Jan 2018  路  16Comments  路  Source: OData/WebApi

I have problem with get working OData Query on AWS Lambda. When I try locally everything works fine, but when deploy into AWS something goes wrong. It is only wrong withEnableQueryAttribute, when I change it into ODataQueryOptions and care about ApplyTo myself it works fine.

Assemblies affected

Microsoft.AspNetCore.OData 7.0.0-beta1
Microsft.AspNetCore.All
Amazon.Lambda.AspNetCoreServer

Reproduce steps

1.Made Get method with [EnableQuery] and allow filtering.

  1. Deploy to AWS Lambda.
  2. Try to request with ?$filter=startswith(Name,'K').

Expected result

Should return a filtered query.

Actual result

Return full list with odata metadata, like it will any QueryString.

Additional detail

Walkaround for it is to use ODataQueryOptions as parameter in Get method.
I made additional investigation and there is QueryString in Request. Maybe something wrong with pipeline?

P4 featurnetcore in-progress

Most helpful comment

@vickityvik As I write in previous post, I made custom Enable Query Attribute and set StatusCode explicitly.

 public class CustomEnableQueryAttribute : EnableQueryAttribute
    {
        public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
        {
            actionExecutedContext.HttpContext.Response.StatusCode = 200;
            base.OnActionExecuted(actionExecutedContext);
        }
    }

This is little ugly, but it work. I think the problem is with AWS implementation not with OData.

All 16 comments

@CrazyBaran Can you provide details of the additional investigation from your side, so that we can have more context? Thanks.

I made additional investigation and made CustomEnableQuery where I try to log a condition from EnableQueryAttribute.cs as:

 public class CustomEnableQueryAttribute : EnableQueryAttribute
    {
        public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
        {
            HttpResponse response = actionExecutedContext.HttpContext.Response;
            LambdaLogger.Log("Test "+ response.StatusCode+ " "+ (response != null).ToString() +" " + 
                response.IsSuccessStatusCode().ToString()+ " " + (actionExecutedContext.Result != null).ToString());

            base.OnActionExecuted(actionExecutedContext);
        }
    }

and result is: Test 0 True False True. very weird. I return in this method Ok().

Edit 1: I remake it to return IQueryable and the same StatusCode 0.

Edit 2: I set StatusCode to 200 in this CustomEnableQuery and it start working so additional workaround.
I dont know is it issue of OData or Amazon.Lambda.AspNetCoreServer

Edit3: I move into Microsoft.AspNetCore.OData -Version 7.0.0-Nightly201802051329 and nothing change, still StatusCode 0.

@CrazyBaran - Is there a difference between your development config and AWS config. i.e. a different web server?

Can you try the following experiment? In you OnActionExecuted:

1.) get a Uri from the HttpRequest using Microsoft.AspNetCore.Http.Extensions.UriHelper.GetEncodedUrl()
2.) See what's in the Query property of that Uri.
3.) See that's in the Query of the HttpRequest itself.

The HttpRequest is available via actionExecutedContext.HttpContext.Request.

The HttpRequest object itself, supplied by the server implementation, is a bit odd in that it only provides the parts of the Uri, not the Uri itself. The HttpRequest has a Query and QueryString property. The code path which applies the query uses an abstracted version of the request and checks the Query property of a Uri obtained from GetEncodedUrl(). See here and here.

@robward-ms I wrongly investigate a problem in first time, in my opinion there is no problem with queryString, it pass correctly. Problem is with WebServer I think, when EnableQueryAttribute is executed there is no Http Code yet. As i write in previous post when i set Http Code manually odata start work.

There was some differences between local web server and AWS implementation.

@CrazyBaran - Can you post the controller Get method that is decorated with [EnableQuery]?

@robward-ms If you want to, there is nothing fancy :)

        [EnableQuery(AllowedQueryOptions = AllowedQueryOptions.Filter, AllowedFunctions = AllowedFunctions.StartsWith)]
        public IQueryable<ProductDto> Get()
        {
            return _productService.GetByQuery();
        }

@CrazyBaran - You could try an OKObjectResult() as a return type, which would explicitly set the status code as part of your response. Otherwise, an action filter is handling this for you and it guess it's possible that the order of action filters is causing an issue.

@CrazyBaran - I am seeing the same thing. Did you find any workaround for this?

@robward-ms - I tried your suggestion, but I am still getting the whole object back.

@robward-ms - FYI I added the following to my controller to see if the query parameters were making their way from API Gateway -> Lambda -> Controller:

            foreach (var query in HttpContext.Request.Query)
            {
                _logger.Warning(new LoggingEvent
                {
                    EventId = 5000,
                    Message = "KEY:" + query.Key + " VALUE:" + query.Value
                });
            }

In the logs, I am able to see the parameter and its value:

[WARNING] 06cba715-1b7a-11e8-a692-c520719655d9 KEY:$select VALUE:code...

I also noticed this in the logs:

[INFORMATION] 0HLBTJM7TS8H9 Request starting GET https://someapi/api/AddressTypes('MAIL')?%24select=code SourceContext:Microsoft.AspNetCore.Hosting.Internal.WebHost RequestPath:/api/AddressTypes('MAIL') ActionName: ActionId: [{Protocol=null, Method="GET", ContentType=null, ContentLength=null, Scheme="https", Host="someapi", PathBase="", Path="/api/AddressTypes('MAIL')", QueryString="?%24select=code", EventId={Id=1}}] 

Noticed that the "QueryString" is encoded.

@vickityvik As I write in previous post, I made custom Enable Query Attribute and set StatusCode explicitly.

 public class CustomEnableQueryAttribute : EnableQueryAttribute
    {
        public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
        {
            actionExecutedContext.HttpContext.Response.StatusCode = 200;
            base.OnActionExecuted(actionExecutedContext);
        }
    }

This is little ugly, but it work. I think the problem is with AWS implementation not with OData.

@CrazyBaran - I did see your comment, after I posted mine. :)

I did give it a go, and it worked! Thanks!

Thanks for this! Helped me as well! @CrazyBaran

Thanks for this! Helped me as well! @CrazyBaran

I have no idea why but CustomEnableQueryAttribute did work for me as well. BTW, opened a related issue in the aws-lambda-dotnet repo: https://github.com/aws/aws-lambda-dotnet/issues/694

Thanks @CrazyBaran! You are a lifesaver

This issue should be reopened, as the suggested patch always sets the status code to 200, which always results in HTTP OK even if there is any internal error. For example, in my case, there is a null in one of column in the database, but on model-side that property is non-nullable. Naturally the conversion failed, but due to the application of the patch I still get HTTP 200 from the calling side.

Was this page helpful?
0 / 5 - 0 ratings