mvc default model binder only binds first word of a string? - asp.net

Why does my action method only bind the first word of a string I pass into it using a query string?
For example, in jquery, I build a queryString from the results of an ajax call:
success: return(resultData){
var queryString = "?ok=true&message=" + resultData.message;
}
Then I try to load a view into a dialog by calling a controller and passing the queryString
$dialogHandle.load("/Account/RegisterStatus" + queryString, function() { ... });
At this point the queryString correctly hold an entire message. However if I break in my controller:
public ActionResult RegisterStatus(bool ok, string message)
{
//break here
}
I notice that ok binds correctly but message only contains the first word of the error message passed in.
How can I pass a sentence as one string parameter?
Is there a better way to do this, without query string?
EDIT: hmm now that I think about it does make sense since urls cant have space but then how do I accomplish this... is there a specific word delimiter in the default model binder?

It's all about URL escaping: escape("It's me!") // result: It%27s%20me%21
Do that around your resultData.Message and it should work better. For debugging purposes, use Fiddler2 or some Web Inspector to see what request is being send. This is really valuable when you are debugging AJAX...
And of course, do the reverse in C#: HttpUtility.UrDecode Method (String)

Related

Return JSON via MVC controller vs webmethod

I'm trying to convert a web forms page with a number of code-behind webmethod functions into an MVC view with a controller.
The data I get back is different. They have properly formatted JSON, but the webmethod returns JSON like this:
{"d":"{\"Success\":true,\"Data\":{\"QuoteId\":340439,\"LoginId\":40,
And the controller returns:
"{\"QuoteId\":340444,\"LoginId\":40,
Its not wrapping it in data.d like it is set up to handle in the javascript and there are no Success or Data objects. And when I try to parse it ($.parseJSON(data)) like I did with the webmethod, it gives me the old error at line 1 message.
I'm sure that if I played with it enough I could get it to work with the way the data is coming through, but I have many pages that I need to covert in the future and I'm just wondering if there is an easy way to get the controller to format it like the webmethod does.
I'm pretty sure that I know why the data is formatted differently, but it would make my life easier if I could just return the data in the same way. I've tried returning a JsonConvert.SerializeObject(obj), which is just a string, and a Return Json(obj), which I'm guessing is just a string as well, but they both return stuff the same, non-data.d way.
Okay, so I've decided to wrap the data in a "d", so that I can have a "data.d" in the Ajax result.
But for some reason the dates aren't being formatted correctly when I just send the data back via:
return Json(thewrappeddata);
they turn out weird.
So basically what I have to do is this:
public class JSONReturn {
public object d;
public static object Wrap(object data) {
return new JSONReturn() { d = data };
}
}
var thedata = new TonsofData();
return Json(
JSONReturn.Wrap(
JsonConvert.SerializeObject(thedata,
new JsonSerializerSettings {
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
}
)
)
);
It seems like I'm "jsonifying" the data twice here, once with JsonConvert.SerializeObject() and once with Json() (I THINK that serializes), but it seems to work and now I get what I need and all the JS just works as it did before. If I leave out the JsonConvert.SerializeObject(), the Json() formats the dates incorrectly and it causes all sorts of failure down the line.

Web API HttpPost body with spaces and quotes

I want to create an HttpPost controller method which takes a string which may include spaces or single quotes. The code I have now looks like:
[HttpPost]
[Route("ValidateExpression")]
public bool ValidateExpression([FromBody] string testExpression )
{
// ...
}
and I post to it via JS (Angular) like:
$http.post(myRootUrl +'ValidateExpression', "'token1' || 'token2'");
I can walk through the JS and see that the test expression is what I expect it to be, and it also looks fine in the body of the outgoing post (as seen in Fiddler & Firebug). But when I breakpoint in the first line of ValidateExpression on the server side, testExpression has been truncated to the first space, and stripped of quotes, so what I receive is token1.
How can I avoid this unwanted transformation?
I guess that I could create a model to wrap a single string, and send my string as field value in a JSON object matching the model...or I could do some escaping on the string, but the first seems ugly/unnecessary and the second seems like I'd be trying to hack around behaviour I don't really understand.
You need to pass in JSON object with key equal to that of parameter name.
// POST api/values
public string Post(string value) {
return value;
}
$.post('/api/values', { value: 'Dave' });
Alternatively, you can satisfy Web API's encoding requirement these ways:
$.post('api/values', "=" + value);
or
$.post('api/values', { '': value });
More information here: http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/
Edit:
Also, note that angualrjs http.post and jquery.post behaves differently:
The difference is in how jQuery and AngularJS serialize and transmit
the data. Fundamentally, the problem lies with your server language of
choice being unable to understand AngularJS’s transmission
natively—that’s a darn shame because AngularJS is certainly not doing
anything wrong. By default, jQuery transmits data using Content-Type:
x-www-form-urlencoded and the familiar foo=bar&baz=moe serialization.
AngularJS, however, transmits data using Content-Type:
application/json and { "foo": "bar", "baz": "moe" } JSON
serialization, which unfortunately some Web server languages—notably
PHP—do not unserialize natively.
http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/

asp.net return data in Page_Load

If a query string param exists in my page request I want to query the database on the server in the Page_Load and then return the result to the client. I can do the query string param check and query the DB but how do I return the data to the page and on the javascript side how do I access that data?
Ideally I would return JSON of an object structure and it would be returning an array of them.
Yes, returning JSON would be the best option. I'm not sure how you query your database (Do you use LINQ or ADO.NET DataTables, etc)
If you don't have custom object of type you want to send, I recommend you create one. Then you should get an array of them.
Example:
public class Person {
string Name { get; set; }
int Age { get; set; }
}
Person[] pArr = new Person[5];
Then you can use a third party library like this to create an string representaion of that array in JSON.
string json = JsonConvert.SerializeObject(product);
Then you write that json string to the Response object so its sent down to the client, by overriding the Render method of the page.
// Don't expect this code to work as it is, but take this as a guidance
Response.Clear();
Response.Write(json);
Response.Close();
on the client side use jQuery library send a request to page, and process the JSON response for you.
$.getJSON('url', function(data) {
//process data
});
Here is my suggestion if you don't want to use an AJAX request for this:
Use the objects as you would normally do in the page_load, and convert it to a JSON string as explained above.
Then use ClientScriptManager to create an JavaScript variable on the client side when it loaded.
ClientScript.RegisterClientScriptBlock(typeof(Page), "unique_key", "var myObjectList = " + json, true);
After this when the page loads you will have an variable named "myObjectList" with the list of objects without having to make a different AJAX call.
You can directly refer that variable in your javascript and do necessary processing.
Hope this helps.

how to pass an object to the GET handler with Post-Redirect-Get with Spring MVC?

I'm new to Spring MVC and trying to get a Post/Redirect/Get pattern working. We're trying to implement a survey where each page can display a variable number of questions. The way I'd like to implement this is a GET handler that prepares the next survey page and then hands that off to the view. In the same Controller, have a Post handler that processes the form's answers to the survey questions, submits that to the survey service, which returns the next page of questions, and then redirects that next surveyPage to the getNextPage GET handler.
Most of it is working, except the problem is that I don't know how to hand that 'next survey page' object from the POST handler to the getNextPage GET handler in the redirect. The redirect is working; it goes from the POST method to the GET method, but the surveyPage ModelAttribute is a new object in the GET method, and not the one that was set at the end of the POST method. As you can see, I've tried using ModelAttribute, but it doesn't work. I also tried using #SessionAttributes above the class, but then got a HttpSessionRequiredException.
We didn't know how to handle the dynamic form containing a variable # of questions with Spring MVC Forms, so we just did straight JSTL. It's funky but it works. That funkiness is what resulted in using the #RequestBody and SurveyPageBean coming back with the Post. Honestly, I don't know how the SurveyPageBean is populated. It looks like some Spring MVC magic, but it's working so I'm leaving it alone for now (another developer did this and then I picked it up, and we're both new to Spring MVC). Please don't get distracted by the unusual form handling, unless that is part of the problem with the empty surveyPage ModelAttribute not being redirected.
Here's the Controller snippet:
#Controller
#RequestMapping("/surveyPage")
public class SurveyPageController{
#RequestMapping(method=RequestMethod.GET)
public String getNextPage(#ModelAttribute("surveyPage") SurveyPage surveyPage, Model model) {
if(surveyPage.getPageId() == null) {
// call to surveyService (defined elsewhere) to start Survey and get first page
surveyPage = surveyService.startSurvey("New Survey");
}
model.addAttribute("surveyPage", surveyPage);
return "surveyPage";
}
#RequestMapping(method=RequestMethod.POST)
public String processSubmit(#RequestBody String body, SurveyPageBean submitQuestionBean, Model model, #ModelAttribute("surveyPage") SurveyPage surveyPage) {
// process form results, package them up and send to service, which
// returns the next page, if any
surveyPage = surveyService.submitPage(SurveyPageWithAnswers);
if (results.getPageId() == null) {
// The survey is done
surveyPage = surveyService.quitSurvey(surveyId);
return "redirect:done";
}
model.addAttribute("surveyPage ", surveyPage );
return "redirect:surveyPage";
}
Use Flash Attributes as shown in Warlock's Thoughts.
#RequestMapping(method = RequestMethod.POST)
public String handleFormSubmission(..., final RedirectAttributes redirectAttrs) {
...
redirectAttrs.addFlashAttribute("AttributeName", value);
return "redirect:to_some_url_handled_by_BController";
}
Your GET takes the surveyPage as a model attribute, which means it is reading it from the URL. In the POST, rather than adding the surveyPage to the model (which is lost because you are telling the client to redirect, which creates a new request and therefore a new model) you should add the surveyPage as a query parameter in your "redirect:surveyPage" You'll have to look at how the surveyPage is constructed from the query params in order to know what to put on the query string.
If, for instance, the surveyPage is constructed from a user, page number, and question count or something, I believe you could do something like "redirect:surveyPage?userId=1234&pageNumber=5678&questionCount=12 in order to pass that model attribute along.

In MVC, how to determine if partial view response was valid (on the client side)?

I am new to MVC, so hopefully my question will be straight forward. I am thinking of a scenario where the user submits a form (that is a partial view) and it undergoes server validation. I am wondering how I will know the result of the validation on the client side (javascript) after the form is submitted. For example, if validation fails I will obviously want to return the partial view again with validation messages set, but if it passes validation I may not necessarily want to return the partial view. I may want to return a json object with a message or hide a div or something. I want to be able to determine the validation result on the client. Is something like that possible? Or can I approach this a different way?
The tricky part with AJAX is that the client and server both have to agree on what's supposed to come back from the server in any circumstance. You have a few options:
Your server will always return HTML, and jQuery will always replace the editor content with the HTML that comes back. If the model is invalid, you return a PartialView result. If the model is valid, you return a <script> tag that tells the page what it needs to do (e.g. close a dialog, redirect to a different page, whatever). jQuery will automatically run any script it finds in the results when it tries to insert them into the DOM.
Your server will always return a JSON object representing what happened. In this scenario, your client-side javascript code has to be complex enough to take the results and modify your page to match. Under normal circumstances, this will mean that you don't get to take advantage of MVC's validation features.
Same as 2, except that you use a custom utility method to render the partial view you want into a string, and you make that entire string part of the JSON that comes back. The javascript code then just has to be smart enough to check whether the JSON shows a valid or invalid result, and if the result is valid, replace the contents of your editor area with the partialview HTML that is returned as part of the JSON object you got back.
Same as 3, except you develop an event-based architecture where all your AJAX requests will always expect to get back a JSON object with one or more "events" in it. The AJAX code can then be consolidated into one method that hands the events off to an Event Bus. The event bus then passes the event information into callbacks that have "subscribed" to these events. That way, depending on what kind of events you return from the server, you can have different actions occur on the client side. This strategy requires a lot more up-front work to put in place, but once it's done you can have a lot more flexibility, and the client-side code becomes vastly more maintainable.
Partial views would not have a Layout page. You may use this code to check if the view is rendered as partial view.
#if (String.IsNullOrWhiteSpace(Layout))
{
// Do somthing if it is partial view
}
else
{
// Do somthing if it is full page view
}
If you are using the MVC Data Annotations for validating your Model, then the controller will have a property called ModelState (typeof(ModelStateDictionary) which as a property of IsValid to determine if your Model passed into the Controller/Action is valid.
With IsValid you can return a Json object that can tell your Javascript what to do next.
Update
Here is a really basic example (USES jQuery):
[SomeController.cs]
public class SomeController : Controller
{
public ActionResult ShowForm()
{
return View();
}
public ActionResult ValidateForm(MyFormModel FormModel)
{
FormValidationResults result = new FormValidationResults();
result.IsValid = ModelState.IsValid;
if (result.IsValid)
{
result.RedirectToUrl = "/Controller/Action";
}
this.Json(result);
}
}
[FormValidationResult.cs]
public class FormValidationResults
{
public bool IsValid { get; set; }
public string RedirectToUrl { get; set; }
}
[View.js]
$(document).ready(function()
{
$("#button").click(function()
{
var form = $("#myForm");
$.ajax(
{
url: '/Some/ValidateForm',
type: 'POST',
data: form.serialize(),
success: function(jsonResult)
{
if (jsonResult.IsValid)
{
window.location = jsonResult.RedirectToUrl;
}
}
});
});
});

Resources