简体   繁体   中英

How to pass "System.Object" type to the Controller through a FromQuery parameter

I have this method in my controller that needs to receive a List of filtering expressions, so I can filter a DynamoDB table but the Value to filter can be string, numeric, boolean, etc... so I used a "System.Object" typed property. But it seems the controller can't bind a FromQuery Parameter to a Type "System.Object" object.

        [HttpGet]
        public IActionResult Get(
            [FromRoute]string name,
            [FromQuery]FilterExpression[] filters
            )
        {
            return Ok(m_attributeService.GetByAttributeName(name, filters));
        }

The FilterExpression class

    public class FilterExpression
    {
        public FilterExpression(){}
        public FilterExpression(
            string field, 
            string comparisonOperator, 
            dynamic values
            )
        {
            Field = field;
            ComparisonOperator = comparisonOperator;
            Values = values;
        }

        public string Field { get;set; }
        public string ComparisonOperator { get;set; }
        public object Values { get;set; }
    }

But every time I do any request the Values Property is always null . I want to know a workaround solution to receive different data types on my method.

I think custom data binder can help you. See more in the MSDN documentation

You can bind to whatever you like. However, the modelbinder must inspect the type to determine what properties it can bind to and then bind the data from the request accordingly. Object has no properties, and thus, the modelbinder will bind nothing to it. I'd imagine you're attempting to polymorphically bind, but that's not how model-binding works. Even though actions are technically methods, they do not function like a regular method would because they are dynamically invoked. When you as a developer are upcasting some object by passing into a method, you still have the full object, and can therefore always downcast it back to its type later. In the request pipeline, the modelbinder just has a collection string key-value pairs that it's trying to interpret as some type. It must know what type to create from the action param, so if you use a base type, all you get is the base type. All extraneous data will be discarded.

You can use the trick used by Json Serializers as a solution.

Controller, Action & Model

[ApiController]
[Route("api/test")]
public class TestController : Controller
{
    [HttpGet]
    public bool Get([FromQuery] Filter filter)
    {
        filter = Request.Query.ExtractFilter();
        return true;
    }
}

public class Filter
{
    public object Equal { get; set; }
}

The Extension Method

public static class QueryCollectionExtensions
{
    public static Filter ExtractFilter(
        this IEnumerable<KeyValuePair<string, StringValues>> queryCollection)
    {
        Filter result = new();

        if (!queryCollection.TryGetByKey("filter", out StringValues filter))
        {
            return result;
        }

        if (!filter.Any())
        {
            return result;
        }

        result = JsonConvert.DeserializeObject<Filter>(filter);

        return result;
    }

    public static bool TryGetByKey(
        this IEnumerable<KeyValuePair<string, StringValues>> queryCollection,
        string key, out StringValues values)
    {
        values = string.Empty;

        KeyValuePair<string, StringValues> keyValuePair = queryCollection
            .FirstOrDefault((KeyValuePair<string, StringValues> x) => x.Key == key);

        if (keyValuePair.Equals(default(KeyValuePair<string, StringValues>)))
        {
            return false;
        }

        values = keyValuePair.Value;

        return true;
    }
}

Request URLs

https://localhost:7134/api/test?filter={"Equal":50}
https://localhost:7134/api/test?filter={"Equal":"abc"}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM