Getting null for Json data on controller side - json

I've got this html
<form action="/Cabinet/Inbox" id="frmCabinet" method="post"/>
<input type="hidden" id="hdnSearchOptions" name="searchOptions" />
<input onclick="inbox()"/>
</form>
and I have a function where I gather info from variety of DOM elements and store them in a wrapper object and then do a submit:
function inbox(){
searchOptions={};
searchOptions.SearchText=$('#txtSearch').val();
$('#hdnSearchOptions').val(JSON.stringify(searchOptions));
$('#frmCabinet').submit();
}
Here's the Inbox method on the server side:
public ActionResult(SearchOptions searchOptions){
//code goes here
}
public class SearchOptions{
public string SearchText{get;set;}
//some more properties
}
When submit takes place I get null for the searchOptions parameter. I've tried to set enctype of the form to any possible value, I've even tried appication/json as per this W3C document to no avail. When I look at the value of the hidden element just before submit I see it's like this:
<input type="hidden" id="hdnSearchOptions" name="searchOptions" value="{"SearchText":""}">
So the generated JSON string seems to be fine. What else am I missing? Or isn't this possible at all?

Ok, here's what I ended up doing. After making sure that there's no way to make form encoding "application/json" with normal form submit (contrary to what people say in many SO threads) I decided to use Request.Form to reach the json object constructed on the client side. As #Stephen Muecke stated, I had an option to provide all the input values as parameters, but there are way to many fields and I don't want to mess my action method with lot's of parameters. There's actually a better way than all the rest, which is to pass it inside a ViewModel, but the thing is, in my situation I can't do that because I can't pass a separate ViewModel to a _layout(master) page. So here's the code finally:
public ActionResult(){
var searchOptionsJson = Request.Form["searchOptions"];
if(!string.IsNullOrEmpty(searchOptionsJson))
SearchOptions searchOptions = JsonConvert.DeserializeObject<SearchOptions>(searchOptionsJson);
}

Related

Razor, two forms, same field

Form 1 is a set of filters, and the "submit" button applies those filters to a GET method. Form 2 is a set of data, and the "submit" button saves that data and also continues the filters via a POST method. The filter options are passed back and forth - the user GETs the initial page, possibly sets up some filters which GETs the same page again in terms of controller method, then the user can modify some data and save via a POST, which then returns back with a GET for the same filtered page.
Simplified (lots more that is likely to be irrelevant):
#model PagedList.IPagedList<xxx.Models.WttPlatformGridRow>
#using (Html.BeginForm("PlatformGridEdit", "Wtt", FormMethod.Get))
{
#Html.CheckBox("ExcludeThrough", (bool)ViewBag.ExcludeThrough)
<input type="submit" value="Filter" />
}
#using (Html.BeginForm("PlatformGridEdit", "Wtt", FormMethod.Post))
{
#Html.Hidden("ExcludeThrough", (bool)ViewBag.ExcludeThrough)
<input type="submit" value="Save" />
}
Simplified controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult PlatformGridEdit(List<WttPlatformGridRow> rows, bool? excludeThrough)
{ etc }
public ActionResult PlatformGridEdit(bool? excludeThrough)
{ etc }
Obviously naming two elements the same is illegal in HTML, and it doesn't work anyway (parameter is null in the C# method).
The answers I've seen so far suggest a single BeginForm with all the data. Fine. Except one is a GET (no data changes) and one is a POST (data changes). User need to be able to bookmark the filter so I can't handle it all as a POST anyway, otherwise the browser will ask the user if resubmitting form data is okay.
I'm also using an IPagedList which (as far as I know) precludes the use of a single model with a list field instead of using ViewBag.
Another option seems to be using client side scripting to copy the value from one field to another. But I don't see how to do this when the parameter name in the controller method is the same for both client side fields.
What is the best way of handling this please?
I have a solution but I can't help thinking there must be a better way.
FWIW, this is what I've done. The two fields have non-identical names (but similar). The "master" version (visible checkbox) has script that copies the value to the "slave" version (hidden field) on submit. The controller method takes both names and decides which is relevant - one or both should be null, but both shouldn't have a value, but we handle that just in case.
Finally, the controller returns the view with the combined value (using the "master" identity).
View - form 1:
bool excludeThrough = ViewBag.ExcludeThrough != null ? ViewBag.ExcludeThrough : false;
#Html.CheckBox("ExcludeThrough", excludeThrough, new
{
#class = "form-control",
onchange = "document.getElementById('ExcludeThroughFilter').value = document.getElementById('ExcludeThrough').value;"
})
View - form 2:
#Html.Hidden("ExcludeThroughFilter", excludeThrough)
Controller:
public ActionResult PlatformGridEdit(..., bool? excludeThrough, bool? excludeThroughFilter)
{
bool excThru = false;
if (excludeThrough.HasValue) excThru = excludeThrough.Value;
if (excludeThroughFilter.HasValue && excludeThroughFilter.Value) excThru = true;
...etc...
}

What is the standard method for posting variable length child deletions to an asp.net MVC application?

I have a form with a one to many relationship. Something like this, where a person can have multiple addresses.
I want to allow the user to delete an address. Without using ajax, what is the typical method for posting the appropriate model's identification to the server?
What are the drawbacks to attempting something like this?
The "delete" button is included in an editor template which displays the child model. So I am able to include the correct model's ID in the button's value and post it.
<button type="submit" name="action" value="#Model.AddressID">Delete</button>
Then, in my main edit view, I include the "Submit" button, which has the same name.
<input name="action" type="submit" value="Edit"/>
And, last, the controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(PersonViewModel person, string action)
{
if (ModelState.IsValid)
{
if(editSubmit == "Edit")
{
//update the models
}
else
{
// delete the child models whose ID == action
}
db.SaveChanges();
return RedirectToAction("Index");
}
return View(addressEdited);
}
I am doing this as a learning exercise. I realize that, for posting data with this structure, most people are using JavaScript, and probably a framework, to organize and post the data via AJAX.

MVC, How to read rendered HTML in a controller?

Maybe it´s a strange question, but imagine this:
//We all know that View is a method...
public ActionResult Something()
{
return View("index");
}
But what if I step before this method to perform some stats
public ActionResult Something()
{
return PerformStats(View("index"));
}
I will have a private method like this:
private ActionResult PerformStats(ViewResult viewResult)
{
//THIS IS WHAT I WANT TO ACCHIEVE:
//*********************************
var contentSent = viewResult.InnerHtml.Lengh; <<-- I wish!
return viewResult;
}
And latter, what i want to do, is to save that ammount of content sent to the client.
It doesn´t matter if it is the exactly quantity of html, even if I get the .count() of a json it will do the trick.
Is any way to know the rendered content on the controller?
Thanks!
OnActionExecuting: Called before action method executes. You can put stats related logic in there.
http://msdn.microsoft.com/en-us/library/system.web.mvc.iactionfilter.onactionexecuting(v=vs.98).aspx
OnActionExecuted: Called after action method executed.
http://msdn.microsoft.com/en-us/library/system.web.mvc.iactionfilter.onactionexecuted(v=vs.98).aspx
Within these methods you can access ActionExecuting and ActionExecutedContext
If you want to get a size of rendered HTML (partial or complete view), then you probably need to:
Find the view that you want to render
Store it in the string builder
Get its length
There is a question that explains how to render view as a string within the action method: In MVC3 Razor, how do I get the html of a rendered view inside an action?

A plain HTML Submit button passes to the controller only after the second click

I have many submit buttons in my plain HTML . The one not working is as below:- the other are as same as below
< form:submit cssClass="action-button" name="excelBTNX" value="Excel" id="excelBTNX" />
The function of the above button in the controller is to create a excel sheet and put in session(I can download it from cookies ) and returns back .
The defination of the corrosponding method in Controller is as same as for other buttons which are working fine .
The problem with this is ,it works only at even count hit .When I click for the first time the page gets refreshed . When I click for the second time , control passes to the controller and my excel comes up as cookies.
I tried to track whether the submit is working or not with javaScript code as
$(‘form’).submit(function(){
alert("event getting fired");
});
and it gives the alert for both the cases.
I have done the validation part from the controller(manually), so local inbuilt validators are not used . So I believe they are not the case.
How do I fix it ?
Controller codes:-
#RequestMapping(value = "execute.action", method = RequestMethod.POST, params = "excelBTNX")
public String excelOut(HttpServletRequest request, HttpServletResponse response,
#ModelAttribute("mymodel") myModel model, BindingResult bindingResult, ModelMap modelmap) {
scr14(request).initializeSomeCalculation(model);// some innercalss called to manupulate model
HttpSession session = request.getSession(false);
if(1=1){//CRUD condition here true in READ mode.
model= new myModel ();
}
byte[] excel = createExcelS14(model,request);
String fileName = getExcelName() + ".xls";
String filepath = myFrameWorkUtils.createTempFile(excel, fileName);
if (session != null) {
session.setAttribute(fileDownload, filepath);
}
scr14(request).initializeSomeCalculation(model);
model.setDate(somedate);
return "myPanel";}
Here are some steps:
Check whether this issue is related to your Excel processing or whether it is something with your Controller. I assume you have something like
#RequestMapping(..., params = "excelBTNX")
public ModelAndView next(...)
{ <EXCEL FUNCTIONALITY> }
Just comment out the in the Controller and verify that the method is called every time. Please test this a let us know whether this is working.
What happens that makes you think the Controller is only called at the second click? Maybe the signs that you are looking at don't really mean that the controller is only called every second click. Please explain.
Fix if (1=1) code. = in Java is the assignment operator, == is the comparison operator. I assume you want to do a comparison. It also seems like you simplified this part of the code, but it may actually be the problem. Please post the actual code here.
I don't see anything about cookies here. It looks to me like you are creating a temporary Excel file, and setting the name of the file in the session.
session.setAttribute(fileDownload, filepath) cannot work, since the key of the session attribute map is of type String. It should probably be session.setAttribute("fileDownload", filepath).
Can you see whether there is a new temp Excel file generated with each click? You should be able to tell by the timestamp.
This may still not point to the problem, but it will certainly get us closer.

Receiving data from a FormPanel in GWT

I have a FormPanel in GWT that should send a TextBox input to a new page (newPage.html). Below is my code. How do I receive this input in newPage.html, so that I can work with it from the associate newPage.java class? Thanks
final FormPanel form = new FormPanel();
form.setEncoding(FormPanel.ENCODING_MULTIPART);
form.setMethod(FormPanel.METHOD_POST);
TextBox userid = new TextBox();
userid.setName("userid");
form.add(userid);
form.add(new Button("Submit", new ClickListener()
{
public void onClick(Widget sender)
{
form.submit();
}
}));
form.setAction("newPage.html");
RootPanel.get("demo").add(form);
If what you are trying to do is POST variables from one gwt-page using a formpanel to another gwt-page to process these POST results you can not, simply because gwt-pages are coded with java but in the end they are translated into javascript and javascript alone can not access POST variables.
You need to define a backend that can process your form in your form.setAction() method that should execute on the server-side and produce a valid html/text response. To get these results produced by your backend you need to add a FormHandler to your FormPanel. There is an example showing how to do that on javadocs. Then evaluating these results you can redirect accordingly.
If you want to handle what you send with a java class meaning you have a java backend, why not use GWT-RPC?