ASP.NET MVC automatically decoding JSON-encoded parameters from AJAX - asp.net-mvc

When my JavaScript code uses AJAX to call an ASP.NET MVC method, it passes values in JSON. For example:
var request = new XMLHttpRequest();
request.open("GET", "http://www.awesome.com/DoSomething?param1=%22some%20string%22&param2=1234", true); // parameter string created with JSON.stringify
or
var request = new XMLHttpRequest();
request.open("POST", "http://www.awesome.com/DoSomething", true);
// set some headers
request.send("param1=%22some%20string%22&param2=1234"); // parameter string created with JSON.stringify
On the ASP.NET MVC side, I have my method to handle the call:
public void DoSomething(string param1, string param2) {
What sucks is param1 is surrounded with quotation marks:
"some string"
What sucks more is param2 is the string:
1234
when I really want the value as an integer. So, the first thing I have to do is use DataContractJsonSerializer to decode both these puppies so my string doesn't have quotation marks and my second string is converted to an int. It's not too bad the first one or two times, but gets old having to do for every single AJAX action.
Ideally, it'd be awesome to have a signature like:
public void DoSomething(string param1, int param2)
where I could just jump right in and use my values without worrying about JSON decoding, just like is done for non-AJAX actions.
Is there a way to do this?

Oh, after posting I found code that does what I'm looking for. See the "ObjectFilter" class near the bottom:
http://weblogs.asp.net/omarzabir/archive/2008/10/03/create-rest-api-using-asp-net-mvc-that-speaks-both-json-and-plain-xml.aspx

I'm not sure what the advantage is of using a ModelBinder versus an ObjectFilter for this, but here's a solution I figured out that uses a custom ModelBinder.
How do I pass a Dictionary as a parameter to an ActionResult method from jQuery/Ajax?

Related

Pass List<int> from actionlink to controller method

In my controller I have this:
ViewBag.lstIWantToSend= lstApps.Select(x => x.ID).ToList(); // creates a List<int> and is being populated correctly
I want to pass that list to another controller.. so in my view I have:
#Html.ActionLink(count, "ActionName", new { lstApps = ViewBag.lstIWantToSend }, null)
Method in Controller:
public ActionResult ActionName(List<int> lstApps) // lstApps is always null
Is there a way to send a list of ints as a route value to a controller method?
its not possible directly but you can do it with Json if i have List<int>
ViewBag.lstIWantToSend= new List<int> {1, 2, 3, 4};
so my view would be something like
#Html.ActionLink(count, "ActionName", new { lstApps = Json.Encode(ViewBag.lstIWantToSend) }, null)
Json.Encode will convert List<int> to json string
and ActionName will be like this
public ActionResult ActionName (string lstApps)
{
List<int> result = System.Web.Helpers.Json.Decode<List<int>>(lstApps);
return View();
}
Json.Decode<List<int>> will convert this json string back to List<int>
MVC.net works on the convention that everything you send is a single Model. So if you want to send a list of objects (say a List of Persons) - it might be a good idea to serialize them first both from client to server, and from server to client.
On simple things, like #BryanLewis said, you can simply serialize it yourself with CSV (to string), and then split it back on the recieving Action/Client.
For more complex things you have (client side) things like AngularJS with its excelent JSON.stringify(anyObject)/JSON.parse(anyString) and you have (server side) Newton.Soft 's excelent JsonConvert.Deserialize>(myJsonString) or JsonConvert.Serialize(someObject). The nice thing about json is that it's very transparent.
Bear in mind - HTTP does not like objects. But it's great with passing strings back and forth.

ASP.NET MVC Read Raw JSON Post Data

This is driving me crazy. I'm using ASP.NET MVC. I have a controller with an HttpPost action that acts as a callback URL that is called by another server (not under my control). I want to dynamically read JSON posted to it without using WebAPI or Model Binding. The URL also has a query string parameter passed to it.
The callback URL looks something like this:
http://domain.com/callback?secret=1234
I've tried reading the posted input using:
[HttpPost]
public ActionResult Callback( String secret )
{
String jsonData = new StreamReader(this.Request.InputStream).ReadToEnd();
// ...
}
However "jsonData" is always null or empty.
I just want to get the posted input and stick it into JsonFx so I can dynamically access the contents. Any ideas on how to do this the easiest possible way?
UPDATE
I've discovered the following ...
While the above DOES NOT work (jsonData will be null or empty), the following DOES if I configure what little options I have on the calling server so as to omit the "secret" query string parameter, which is about all I can do on that end since it is not my server. In this case, jsonData will have the correct posted JSON string:
[HttpPost]
public ActionResult Callback( /* String secret */ )
{
String jsonData = new StreamReader(this.Request.InputStream).ReadToEnd();
// ...
}
This is very frustrating to work around and I don't know an easy way to accept both a query string and posted JSON data on a standard MVC controller.
I have a "callback controller" with Action methods that accept various data (via GET, via form POST, via JSON POST, via JSON POST w/ a Query String, etc.) from different third-party servers. These are merchant-type callbacks where I have no control over the formats or methods used to convey information. I just need to accept the callbacks and process the information that should be there.
All of it works fine in my Controller, except the case of "JSON POST w/ a Query String".
This appears (at least to me) to be a shortcoming in standard ASP.NET MVC controllers. ???
Can anyone suggest a solution to this that can be used in a standard ASP.NET MVC controller?
Your initial approach should work if you take into consideration the fact, that ASP.NET MVC model binding has already read the stream, so you should rewind it:
[HttpPost]
public ActionResult Callback(string secret)
{
Request.InputStream.Seek(0, SeekOrigin.Begin);
string jsonData = new StreamReader(Request.InputStream).ReadToEnd();
// ...
}
Reset the position to Zero before reading the stream.
Request.InputStream.Position = 0
For ASP.NET Core 2,this works for me.
[HttpPost]
public ActionResult RawTest() {
using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
{
string content = reader.ReadToEndAsync().Result;
//...
}
//...
}

How to access a query string in MVC

I was getting the query string back using:
public ActionResult Index(int id)
{
var queryString = Request["myQueryString"];
}
Then I looked at:
help-testing-mvc3-controller-that-accesses-querystring
Which states:
It is against MVC's design pattern to use HttpRequest directly. You can access the query string variables on your action as parameters.
I don't really understand this. Is what I've done against the design pattern? If it is why is that and how could it be done?
It breaks the concept of model binding. It also gets complicated with unit testing and trying to new up a new HttpContext for a test. If it was just a parameter, you could just pass the value.
The preferred (and easier to read) method would be:
public ActionResult Index(int id, string myQueryString)
{
...
}
Your action method should take most of the data submitted from your form. One of the strengths of MVC is the model binding it has within it. Check out this page, as it has a good example of this:
http://www.codeproject.com/Articles/159749/ASP-NET-MVC-Model-Binding-Part1
You can accept literals (string, bool, etc.) but also strongly typed objects in your action methods.

How to route legacy QueryString parameters in ASP.Net MVC 3?

I am using a third party service that does an async callback to a URL I provide to them.
So I tell them to use http://www.mysite.com/Status/Incoming.
This must obviously map to an Incoming() method on my StatusController.
However, what I don't have control over is the format of the parameters they call my URL with.
E.g. They will do a callback such as: http://www.mysite.com/Status/Incoming?param1=val1&param2=val2&param3=val3
I want to map this to the parameters of my action method: Incoming(string param1, string param2, int param3)
How do I do this?
I have found a lot of stuff about custom routing, but nothing about legacy QueryString parameters.
There is no such thing as legacy query string parameters. There are query string parameters and they are part of the HTTP specification. And assuming that the http://www.mysite.com/Status/Incoming?param1=val1&param2=val2&param3=val3 url is called you don't need any route to make it map to the following action (the default route will do just fine):
public ActionResult Incoming(string param1, string param2, string param3)
{
...
}
The default model will take care of binding those values.
Why not use a catch all?
routes.MapRoute(
"Incoming",
"Status/Incoming/{*path}", // URL with parameters
new { controller = "Status", action = "Incoming"}
);
then in your controller,
public ActionResult Incoming(string path){
// the next line would probably be better off in a model binder, but this works:
var dictionary = path
.Substring(path.IndexOf("?")+1)
.Split("&")
.Select(x =>
{
var kvArray = x.Split("=");
return new KeyValuePair<string, string>(kvArray[0], kvArray[1]);
})
.ToDictionary(x=>x.Key,x=>x.Value);
return Incoming(dictionary);
}
public ActionResult Incoming(Dictionary<string,string> dictionary){
//do stuff
}
All that being said, I think using the Request.QueryString is probably a better approach. As long as you are using MVC, it is accessible from your controller. However, if you can guarantee that the correct parameters will be passed then Darin's approach is going to be the best choice.
When I've had to deal with this before now, I just use the "legacy" call of Request.QueryString. It still works, even if it isn't very graceful.

In ASP.NET MVC, how to receive the parameter dictionary in an action?

Most of the actions in my controller have statically-defined parameter lists and so they correspond nicely with the standard tutorial examples:
public ActionResult SomeAction(string id, string arg1, string arg2)
{
// use arg1, arg2...
}
But I have one troublesome case where the view puts together a form dynamically, so the set of parameters is completely dynamic. I'd be happy with a mapping of string names to string values.
I've tried this:
public ActionResult TroublesomeAction(string id, IDictionary<string, string> args)
{
// loop through args...
}
But args is passed a null. What's the easiest way in an action to get hold of the famous "parameter dictionary" that we hear so much about in error messages these days?
And if there isn't an easy way, how would I do it the hard way?
From a controller, we have access to this:
Request.Form
Which contains exactly what I need, so no need to map to an argument on the action.

Resources