Home > database >  ASP.NET Core, query string to object programmatically
ASP.NET Core, query string to object programmatically

Time:11-26

I know that in ASP.NET Core it is possible to automatically convert some query string to an object using special model binding attributes - [FromRoute], [FromQuery] and so on.

Is it possible to perform such a conversion manually? Something like:

var queryString = Request.QueryString;
var obj = SomeMagic.QueryStringToObject<MyClass>(queryString);

CodePudding user response:

You can use QueryHelpers.ParseQuery(String) to parse a query string into a dictionary.

If you want the actual same behavior as provided by the [FromQuery] attribute I'd look at the QueryParameterValueSupplier.RenderParametersFromQueryString method, which does most of the heavy-lifting. I'm not sure if this is meant to be used outside of the existing ASP.NET Core framework infrastructure.

Note that a query string is just a collection of string-based name-value pairs. There's no standard that dictates how this should be mapped to something more complex like a Java or C# class. So frameworks like ASP.NET Core build their own convention on top of that, in order to make their complex binding mechanisms work. (e.g. foo.bar[2]=123). ASP.NET Core actually has two ways of binding query strings to a model (the "MVC" way and the "jQuery" way), see JQueryKeyValuePairNormalizer.

    // This is a helper method for Model Binding over a JQuery syntax.
    // Normalize from JQuery to MVC keys. The model binding infrastructure uses MVC keys.
    // x[] --> x
    // [] --> ""
    // x[12] --> x[12]
    // x[field]  --> x.field, where field is not a number
    private static string NormalizeJQueryToMvc(StringBuilder builder, string key)

Finally on a personal note I tend to avoid the query string for anything more complex than simple name-value pairs. When you start to pull in more complex data structures you also run into many limitations. For instance: differentiating between null and empty strings; awkward syntax for handling collections; etc. If I really must use the query string for passing along complex data structures, I fallback to a single Base64 encoded JSON-string and handle that manually within my code.

CodePudding user response:

Finally I found more generic solution than just parsing a query string. Here I get an instance of IModelBinder (actually an instance of ComplexObjectModelBinder) and use that as a service.

// DTO
//
public class PersonName
{
    public string FirstName { get;set; }
    public string LastName { get;set; }
}



// Action handler
// Here I want to convert HTTP request to an instance of PersonName manually
// Example: /SearchByName?LastName=Doe&FirstName=John
//
[AcceptVerbs("GET")]
public async Task<IActionResult> SearchByName(
  [FromServices] IModelMetadataProvider modelMetadataProvider,
  [FromServices] IModelBinderFactory modelBinderFactory)
{
    var valueProvider = await CompositeValueProvider.CreateAsync(ControllerContext);
    var modelMetadata = modelMetadataProvider.GetMetadataForType(typeof(PersonName));
    var modelBinderFactoryContext = new ModelBinderFactoryContext
    {
        Metadata = modelMetadata,
        CacheToken = modelMetadata
    };
    var modelBinder = modelBinderFactory.CreateBinder(modelBinderFactoryContext);
    var modelBindingContext= DefaultModelBindingContext.CreateBindingContext(ControllerContext, valueProvider, modelMetadata, new BindingInfo(), string.Empty);
    await modelBinder.BindModelAsync(modelBindingContext);
    var personName = modelBindingContext.Model as PersonName;
    // ...
    return Ok(personName);
}
  • Related