I have a collection of of key-value pairs, where the value part can be of any of the types (C#) string, DatetimeOffset, long, float, boolean. The key-value pair is an alternate key of a class named Component:
public class Component {
public long Id { get; set;}
public string Key { get; set; }
// another properties here ...
public object Value { get; set;}
}
The user enters the value part in an input bound with knockoutjs to an observable, and I expect to find the corresponding component instance given the key and that value with this controller action method (MVC4):
public JsonResult GetComponent(string compKey, object compValue)
{
var comp = Database.FindComponentValue(compKey, compValue);
return this.Json(comp, JsonRequestBehavior.AllowGet);
}
which I invoke in a function of the knockout view model in this way:
self.findComponent = function (component) {
// component is ko.observable() generated on-the-fly with ko.mapping.fromJS()
//var compdata = ko.mapping.toJS(component);
$.get("MyController/GetComponent", {
compClasskey: component.FullCode(),
compValue: component.Value()
},
self.validateComponent
);
};
validateComponent is a function that shows an icon OK if the component is found.
Now, if component.Value() has a string value, MyController.GetComponent receives an array of string with the value in the first position (compValue[0]). But declaring compValue parameter as string works:
public JsonResult GetProductComponent(string compClassKey, string compValue) { ... }
But it leads to me to declare the method like this in order to be able to accept the other types:
public JsonResult GetProductComponent(string compClassKey, string compValueString, DatetimeOffset compValueDateTimeOffset, bool? compValueBoolean, long compValueLong) {
...
}
Another approach is to be compValue of type string and its corresponding type in another parameter also of type string.
Is this the solution or is it possible to have only one parameter of type object and I am making a mistake I am not seeing?
Your basic issue is that you are pushing the data payload as items on the querystring, not as a JSON payload. In this scenario the QueryString value provider will be responsible for populating the method's parameters.
All querystring key values are treated as an array by the provider. If you specify a data type and the key's value has 1 entry then the provider will flatten the array to a single value.
In your case you specify an object
datatype, so the provider gives you the array of 1 entry.
To fix this you need to switch from $.get to $.ajax, supply a few extra parameters and force the data payload to be a JSON string.
$.ajax({
url: "MyController/GetComponent",
type: 'POST',
contentType: 'application/json',
dataType: 'JSON'
data: JSON.stringify(
{
compClasskey: component.FullCode(),
compValue: component.Value()
})
});
The MVC application should now use the JSON value provider ( as the contentType is now changed to application/json
) instead of the QueryString provider and the compValue parameter will now set as you expect.
As an aside: IMHO you should NEVER request a JSON document via a GET request, it is still an attack vector, unless you can 100% guarantee IE10+, Chrome 27+ or Firefox 21+.