Reputation: 3523
We are having this problem with a controller right now; the controller looks like this:
public class AccountsController:Controller {
public ActionResult List(int? page, int? pageSize, string keywords) {...}
}
We are posting to this page via jquery:
$.post("/myapp/Accounts/List",
{"page":0,"pageSize":10,"keywords":"asdf"},
updategrid,
"json");
...
function updategrid(result) {...}
Inside the action: Request.Form["keywords"] == "asdf", but keywords=="" and here I am at a loss. Why doesn't keywords have the value we want?
Upvotes: 1
Views: 1774
Reputation: 3523
quoting answer provided as comment from Mark Worth...
How is your controller being instantiated? I had this problem and I found that it was my SpringControllerFactory creating my controllers as singletons (and hence was always using the values from the first request). – Mark Worth May 19 at 8:19
That's it! My controller was registered as a singleton into my Windsor container so my WindsorControllerFactory returned a singleton. – Bill Barry May 19 at 18:14
Upvotes: 1
Reputation: 461
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class JsonParametersFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string contentType = filterContext.HttpContext.Request.ContentType;
if (string.IsNullOrEmpty(contentType))
return;
if (!contentType.Contains("application/json"))
return;
string paramValue;
using (var reader = new StreamReader(filterContext.HttpContext.Request.InputStream))
paramValue = reader.ReadToEnd();
var serializer = new JavaScriptSerializer();
var rawResult = (IDictionary<string, object>)serializer.DeserializeObject(paramValue);
var keys = new List<string>(filterContext.ActionParameters.Keys);
foreach (var key in keys)
{
object value = null;
if (rawResult.TryGetValue(key, out value))
{
filterContext.ActionParameters[key] = value;
}
}
}
}
This will attempt to populate all parameters values from inputstream.
Upvotes: 0
Reputation: 1234
That is very odd, because the code on my machine works. What happens when you request the URL directly from a browser (without the jQuery .post() call) like so:
/myapp/Accounts/List?page=0&pageSize=10&keywords=asdf
That generates a GET request (instead of the POST request generated by the jQuery .post() method -- but the action method parameters should be populated nonetheless).
For the purposes of debugging, you might want to change your action method to something like:
public ActionResult List(int? page, int? pageSize, string keywords)
{
return Content(String.Format("page = {0}, pageSize = {1}, keywords = {2}",
page, pageSize, keywords));
}
If that works, the next step would be to test your jQuery call with something like (changing the returned data format from JSON to text):
$.post('/myapp/Accounts/List',
{ 'page' : 0, 'pageSize' : 10, 'keywords' : 'asdf' },
function(result) {
alert(result);
},
'text');
Everything above worked correctly for me, so unless I'm missing something... I'm puzzled why it didn't work for you? Where did I go wrong?
Upvotes: 0
Reputation: 87
Since the attribute specified above works, have you checked to compare the contents of the HttpContext.Request.Form collection against the MVC-Binder-Bound FormCollection object.? Seems like there's a difference between the two sets. Also, try other ways of accessing the FormCollection - Get(), GetValue() ... check AllKeys for the key you're interested in???
Also, with regards to the route-registering idea ...
If you don't have the route myApp/Accounts/List/{page}/{pageSize} registered and the pagesize is still coming through, it stands to reason that there isn't a need to register a myApp/Accounts/List/{page}/{pageSize}/{keywords} route either.
Upvotes: 0
Reputation: 3523
Using this attribute:
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
public class StringParamFilterAttribute:ActionFilterAttribute {
public string Param { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext) {
filterContext.ActionParameters[Param] = filterContext.HttpContext.Request[Param];
}
}
I was able to put an attribute on the action in order to give this parameter to the method:
[StringParamFilter(Param="keywords")]
public ActionResult List(int? page, int? pageSize, string keywords) {...}
and now keywords has the desired value
Upvotes: 0
Reputation: 5156
If you are posting the values, you could just use a FormCollection..
public class AccountsController:Controller {
public ActionResult List(int? page, FormCollection collection) {
string keywords=collection["keywords"];
....
}
}
Also, for the post, you could append the id to the url and put the other params in json. I also do not think it is necessary to put your property names in quotes in json..
$.post("/myapp/Accounts/List/"+page,
{pageSize:10,keywords:"asdf"},
updategrid,
"json");
... function updategrid(result) {...}
... or as others suggested, you could create a route that has all the possible parameters ..
Upvotes: 0
Reputation: 7512
Dont you want to pass the values on the URL and let the routing of MVC take care of passing the values? Not pass as actual variables?
Upvotes: 0