Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OData doesn't see QueryString when EnableQuery + AWS Lambda #1227

Closed
CrazyBaran opened this issue Jan 31, 2018 · 17 comments
Closed

OData doesn't see QueryString when EnableQuery + AWS Lambda #1227

CrazyBaran opened this issue Jan 31, 2018 · 17 comments

Comments

@CrazyBaran
Copy link

CrazyBaran commented Jan 31, 2018

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 with EnableQueryAttribute, 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.
2. Deploy to AWS Lambda.
3. 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?

@biaol-odata
Copy link
Contributor

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

@CrazyBaran
Copy link
Author

CrazyBaran commented Feb 5, 2018

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.

@robward-ms
Copy link
Contributor

@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.

@CrazyBaran
Copy link
Author

@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.

@robward-ms
Copy link
Contributor

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

@CrazyBaran
Copy link
Author

CrazyBaran commented Feb 13, 2018

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

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

@robward-ms
Copy link
Contributor

@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.

@vickityvik
Copy link

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

@vickityvik
Copy link

vickityvik commented Feb 26, 2018

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

@vickityvik
Copy link

@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.

@CrazyBaran
Copy link
Author

@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.

@vickityvik
Copy link

vickityvik commented Feb 27, 2018

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

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

@jeremymcgee73
Copy link

Thanks for this! Helped me as well! @CrazyBaran

@grascioni
Copy link

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: aws/aws-lambda-dotnet#694

@erezgreenberg
Copy link

Thanks @CrazyBaran! You are a lifesaver

@Sayan751
Copy link

Sayan751 commented Feb 5, 2021

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.

@nathanvj
Copy link

nathanvj commented Apr 1, 2023

This is still an issue, I have some custom role validation in my CustomEnableQueryAttribute and it's giving me the same response for all my OData endpoints:

{
  "message": null
}

Adding the code snippet @CrazyBaran shared, does not fix the issue either. Anyone find a different workaround?

My CustomEnableQueryAttribute looks something like this right now:

public class CustomEnableQueryAttribute : EnableQueryAttribute
{
    public CustomEnableQueryAttribute()
    {
    }

    /// <summary>
    /// See https://github.com/OData/WebApi/issues/1227
    /// </summary>
    public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
    {
        actionExecutedContext.HttpContext.Response.StatusCode = 200;
        base.OnActionExecuted(actionExecutedContext);
    }

    public override void ValidateQuery(HttpRequest request, ODataQueryOptions queryOptions)
    {
        try
        {
            if (queryOptions.SelectExpand is not null)
            {
                List<string> roles = request.HttpContext.User.GetRoles();
                queryOptions.SelectExpand.Validator = new ODataExpandValidator(roles);
            }

            base.ValidateQuery(request, queryOptions);
        }
        catch (Exception e)
        {
            throw new ODataQueryException(e.Message);
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants