0

I have succeded in creating simple objects as follows.

The json on the client side js is as follows.

{"Page":1, "Take":10, "SortOrder":"Asc", "PropName":"Id"}

On the webapi side, I have the following class

public class PaginatedRequestCommand
{

    public int Page { get; set; } 

    public int Take { get; set; } 

    public string PropName { get; set; } 

    public string SortOrder { get; set; } 
}

And the WebApiConfig class is as follows

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

    // skiped many other lines as they are not relevant

        config.ParameterBindingRules.Insert(0, typeof(PaginatedRequestCommand),
            x => x.BindWithAttribute(new FromUriAttribute()));

    }
}

And so in Wep Api controller I have the following action method.

    [HttpPost]
    [HttpGet]
    public PaginatedList<PatientCategory> PatCat(PaginatedRequestCommand cmd)
    {
    //......
}

So here I have PaginatedRequestCommand object correctly constructed and the properties Page, Take etc are correctly available. The Angularjs ajax call on the browser is

$http({
            method: 'GET',
            url: this.callParams.uri, // The URI
            params: this.callParams.paginationOptions, // This is where the JSON that showed earlier goes.
            headers: { 'Content-Type': 'application/Json' }
})

Every thing so far so good.

Now I want to pass in some more parameters. I want to include an array in the JSON as follows.

{"Page":1,"Take":10,"SortOrder":"Asc","PropName":"Id",
    "wherePredicateParams":
[{"propName":"Name","val":"s"},
 {"propName":"Description","val":"h"}
]
}

So you see that the "wherePredicateParams" is the additional object that I want to pass. Its an array. What modifications do I have to do on the WebApi side?

I have tried adding the one more property to the PaginatedRequestCommand class, public string[] wherePredicateParams { get; set; } so the full class is as follows.

public class PaginatedRequestCommand
{

    public int Page { get; set; } 

    public int Take { get; set; } 

    public string PropName { get; set; } 

    public string SortOrder { get; set; } 

    public string[] wherePredicateParams { get; set; }
}

This is actually working, in the sense that the property wherePredicateParams of PaginatedRequestCommand object created by the api inside the action method of the above controller is providing me with {"propName":"Name","val":"s"} and {"propName":"Description","val":"h"}. But the problem is I have to parse it my self and use. Is there a better way.

Then I have tried changing string[] to whereParam[] and defined a class

public class whereParam 
{
    public string propName { get; set; }
    public string val { get; set; }
}

enter image description here So you see the propName and val are null? What am I missing?

VivekDev
  • 20,868
  • 27
  • 132
  • 202

2 Answers2

2

After quite a struggle, I found the answer. The problem is not on the webApi side. Its on the client side. I am using AngularJS for the ajax call. So thats where the problem is. Here I describe it.

Please note I have changed the class names during the coarse of the investigation, so the class name PaginatedRequestCommand would now be PaginatedRequest. Similarly there would be some other changes. I shall post all the details here again, to avoid any confusion.

Earlier it was

$http({
            method: 'GET',
            url: this.callParams.uri,
            params: this.callParams.paginationOptions,
            headers: { 'Content-Type': 'application/Json' }
})

You see the this.callParams.paginationOptions. That javascript object would look something like this.

{"Page":1,"Take":10,"SortOrder":"Asc","PropName":"Id","whereParams": 
[{"FilterPropName":"Name","FilterPropValue":"jk"}]}

And this.callParams.uri would be something like this.

'/api/PatientCategoryApi/PatCat'

Here PatientCategoryApi is the WebApi controller, and PatCat is the action method on the WebApi side. The action method with the following signature would be needed.

    [HttpPost]
    [HttpGet]
    public PaginatedList<PatientCategory> PatCat(PaginatedRequest rqst)

The PaginatedRequest class is as follows.

public class PaginatedRequest
{
    public int Page { get; set; } // Page Index
    public int Take { get; set; } // Page Size
    public string PropName { get; set; } // Property Name for sorting.
    public string SortOrder { get; set; }  // Sort Direction Asc or Desc
    public List<WhereParam> whereParams { get; set; }
}

And WhereParam class is as follows

public class WhereParam
{
    public string FilterPropName { get; set; }
    public string FilterPropValue { get; set; }
}

Configure parameter binding rules in webApiConfig as follows.

config.ParameterBindingRules.Insert(0, typeof(PaginatedRequest),
    x => x.BindWithAttribute(new FromUriAttribute()));

This is all to it. Had I used JQuery, this would work. But with AngularJS, the serialization is different. So the trick is to add

paramSerializer: '$httpParamSerializerJQLike',

to the ajax call. I found in this so question AngularJS GET ajax call with Array parameters. So the entire call would now look like the following.

$http({
            method: 'GET',
            url: this.callParams.uri,
            paramSerializer: '$httpParamSerializerJQLike',
            params: this.callParams.paginationOptions,
            headers: { 'Content-Type': 'application/Json' }
})

This now ensures the serialization would be the way WebApi understands. And the binding on the WebApi side happens correctly.

If you wish, you can also the change the action method signature as follows to separate List property into a param. In this case the binding is no longer a complex object, but one simple object and an array(or list).

[HttpPost]
[HttpGet]
public PaginatedList<PatientCategory> PatCat(PaginatedRequest rqst, 
List<WhereParam> whereParams){...}

In such a case PaginatedRequest would not have the WhereParam list as a property.

public class PaginatedRequest
{
    public int Page { get; set; } // Page Index
    public int Take { get; set; } // Page Size
    public string PropName { get; set; } // Property Name for sorting.
    public string SortOrder { get; set; }  // Sort Direction Asc or Desc
    // You dont want this here in this approach.
    //public List<WhereParam> whereParams { get; set; }
}

And in the webApiConfig class you need to add the following additionally.

        config.ParameterBindingRules.Insert(0, typeof(List<WhereParam>),
            x => x.BindWithAttribute(new FromUriAttribute()));

And there is no other change needed on the client side. This should work. Overall, in any case, the key is as I mentioned,

paramSerializer: '$httpParamSerializerJQLike',

Community
  • 1
  • 1
VivekDev
  • 20,868
  • 27
  • 132
  • 202
1

The property wherePredicateParams is a string[] not a whereParam[] so this make that the serializer dont serialize this properties, but I suggest you to use Json.NET you can get it here http://www.newtonsoft.com/json, this lib allows that you use Attributes on your properties that map your json schema to a class/type.

You can do something like the example:

public class WhereParam 
{
    [JsonProperty("propName")]
    public string PropName { get; set; }
    [JsonProperty("val")]
    public string Val { get; set; }
}
Joel R Michaliszen
  • 4,164
  • 1
  • 21
  • 28