Retaining route details on MVC Form Postback - c#

I have a basic MVC form which is accessed through a GET Action with 3 string parameters pulled from the route.
[HttpGet]
public ActionResult Application(string x, string y, string z)
{
//create model, setup form, etc...
return View(model);
}
The route to access this form is configured as follows:
routes.MapRoute("Application",
"application/{x}/{y}/{z}",
new
{
controller = "Application",
action = "Application",
x = "",
y = "",
z = ""
});
And the form is configured as follows:
Html.BeginForm("Application", "Application", FormMethod.Post)
All of this works until I click submit on the resulting form. From a routing perspective the correct POST Action is called and the Model is bound correctly. The problem is I have lost all the x/y/z route information which I still need. How can I preserve the route information?
I've tried a couple things:
Added route details to the Form in Hidden fields which are added to the form content correctly but never get returned in the Model on postback
Tried using the RouteValueDictionary overload for Html.BeginForm but can't figure out how to make it work. I may just need a proper example of how to use it and how to access the state from the Controller
Update: This adds View sample to help address comments made regarding the use of Hidden Fields
#using (Html.BeginForm("Application", "Application", FormMethod.Post, new
{
autocomplete = "on",
id = "LoanApplication",
novalidate = string.Empty,
name = "Application"
}))
{
<fieldset>
#Html.HiddenFor(m => m.x)
#Html.HiddenFor(m => m.y)
#Html.HiddenFor(m => m.z)
#Html.HiddenFor(m => m.DigiCertId)
<br />
<input id="SubmitButton" type="submit" value="#Resources.SubmitApplicationButton" title="#Resources.SubmitApplicationButtonDescription" />
</fieldset>
}

You should really put these properties in the model, then have a HiddenFor for each one, like so:
#Html.HiddenFor(m => m.x)
#Html.HiddenFor(m => m.y)
#Html.HiddenFor(m => m.z)
Then in your post method (assuming it's like this), you can pass them in the RouteValueDictionary to the Get Method, like so:
[HttpPost]
public ActionResult Application(MyModel model) //whatever type your model is
{
//do whatever your post method does before redirect
return RedirectToAction("Application", new { x = model.x, y = model.y, z = model.z});
}

in addition to the ans suggested by mattytommo. i would recommend using TempData collection in asp.net MVC. this saves the data using the session storage but does it temprorarily and the data gets deleted once you access it.
this is present specifically for these purposes
so you can save the data in TempData as TempData["Values"] = new {X=x,Y=y,Z=z};
then access the TempData["Values"] after the post

Related

ASP.NET MVC Post method : Model properties does not persit the value

I have 2 ASP.NET MVC action methods, I call the first method by passing and load some initial data, then I get some additional details from UI and call the second action method (Post action method from .cshtml). The data I received from the first call is missing in the post method. can anyone help me what am I doing wrong or missing here?
Action methods:
[Route("setprofile")]
public ActionResult SetProfile(string id)
{
ProfileData data = new ProfileData();
//do something
data.name= getData(id);
return this.View(data);
}
[Route("setprofile")]
[HttpPost]
public ActionResult SetProfile(ProfileData data)
{
// Here I'm not missing the data.name field value
}
View .cshtml file:
<div class="panel-body">
#using (Html.BeginForm("SetProfile", "Home", FormMethod.Post))
{
<div>
<h3> Name: #(this.Model.name)</h3>
</div>
<h3>
Comments:#Html.TextBoxFor(m => m.comments)
</h3>
}
I get the comments value but not getting the name field value from the model here.
Note: I need to display the value I received from the first action method as a label, not text box.
There are two things, Name is writen as text and in order to send back to server, you need to put it inside input element.
IF you dont want to show it #Html.HiddenFor(m => m.name) creates hidden input element.
Other than this, check ModelState for validation errors..
if (!ModelState.IsValid)
return BadRequest(ModelState);
.... your code here
if your model is not valid, the ProfileData returns result
You haven't added an input element for it to be sent back to the server when the form is submitted. If you don't want it to be visible, whilst still being posted back, add a hidden field for it:
#Html.HiddenFor(m => m.name)
Without that, all you're doing is rendering name to the markup but, once the form is submitted, it won't be sent back. Alternatively, you could render a textbox for the value whilst setting its readonly attribute. That would allow it to be visible, not changed, and still be sent back to the server.
#Html.TextBoxFor(m => m.name, new { #readonly = "readonly" })

Resending a Model resets values in asp.net mvc?

This is my View:
#model test2.Models.ChatModel
#{
ViewBag.Title = "Channel";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<center>
<h2>Channel: #Model.channelName</h2>
#{
foreach (string line in Model.chatLog) {
<div>#line</div>
}
}
<br />
#using (Html.BeginForm("sendMessage", "Home", FormMethod.Post)) {
#Html.TextBoxFor(model => model.message)
<button type="submit"> Send Message </button>
}
</center>
Here is my Controller:
public ActionResult sendMessage(ChatModel model) {
//send message somewhere
//this is not working
return RedirectToAction("Channel", "Home", new { channel = model.channelName });
//this is working
return RedirectToAction("Channel", "Home", new { channel = "test" });
}
The error happens in the redirectToAction method. Somehow "model.channelName" is empty, but #Model.channelName in my view is correctly displaying the channel name.
It looks like when you send a Model to a view, and "resend" this model back to a controller, the informations are lost.
Is there an easy way to solve this?
PS Step by step:
Model gets channelName
Model is send to view
View correctly displays data from model
adding message to Model
sending model to controller
model does NOT contain information from step 1
You need to include model.channelName in the form. Try adding a:
#Html.HiddenFor(model => model.channelName)
Anything not posted by the form, will be null in your model (including your chatlog)
Actually the values model properties should be rendered as input elements within the form that is posted back to controller action. The properties which are not included would loose their values.
What you can do is create a hidden field for those to post :
#using (Html.BeginForm("sendMessage", "Home", FormMethod.Post)) {
#Html.TextBoxFor(model => model.message)
#Html.HiddenFor(model => model.channelName)
<button type="submit"> Send Message </button>
}
You would need to add same way other properties too that are posting null at action and you need those for some processing.
Hope it helps.

Asp.NET MVC Value of DynamicForm posted but not passed to controller

So what I have is a HTML-Form enabling the user to register for sportsevents. The user can register different profiles (e.g. his children) and every event can potentially have so called "Additional Attributes" like textboxes for T-Shirt-size etc.
#model Models.EventRegistrationModel
#{
Layout = null;
var playerCount = Model.PlayersToRegister.Count;
}
#using (Html.BeginForm("RegisterForEvent", "Event", FormMethod.Post)){
#Html.AntiForgeryToken()
<div class="form-group">
#for (int i = 0; i < playerCount; i++)
{
<div>
<p>#Model.PlayersToRegister[i].User.FullName</p>
</div>
<div
#Html.CheckBoxFor(model => Model.PlayersToRegister[i].PlayerShallGetRegistered)
</div>
//this is the "Additional Attributes"-section for each user-profile
#Html.Raw(Model.PlayersToRegister[i].Form.RenderHtml())
}
</div>
<input type="submit" value="Confirm Registration"/>
}
Since I do not create those events, I cannot know, what these "Additional Attributes" look like, which is why they are rendered dynamically using DynamicForm.
My problem is that I cannot access the user-input for those attributes in the controller. When I check the browser's console, I see the input being posted, but checking the dynamic form's value, it always says "null".
Here's my controller:
[HttpPost, ValidateAntiForgeryToken]
public ActionResult RegisterForEvent(EventRegistrationModel model)
{
for (int i = 0; i < playerList.Count; i++)
{
var form = Session["Form" + i] as Form;
model.PlayersToRegister[i].Form = form;
//var test = form
//var testtest = test.GetResponses(false);
}
return RedirectToAction("EventOverview");
}
As you can see, I tried to use the Form's "GetResponses"-Method, but it returned null.
public List<Response> GetResponses(bool completedOnly)
{
return InputFields.OrderBy(inputField => inputField.DisplayOrder).Select(field => new Response
{
Title = field.Title, Value = field.Response
}).Where(response => !completedOnly || !String.IsNullOrEmpty(response.Value)).ToList();
}
At the moment I am trying to get the values via Session, as this worked in an older version, where you were only able to register one profile at a time. The Session-variable gets assigned in the ActionResult returning the above View.
I've been trying various solutions from various threads over the past days (e.g. ModelState.Clear), but unfortunately nothing has been successful.
If you need more information, code or whatever, please let me know.
Since your form is dynamic you may want to use a dynamic model in the post method. Try something like this:
[HttpPost, ValidateAntiForgeryToken]
public ActionResult RegisterForEvent(FormCollection collection)
{
// stuff....
}
You'll have to do a bit of work parsing out the collection that comes in but it should have everything that was posted from the form. In general I don't recommend this as it can really spiral out of control. Having a well defined view model (as you did in the original posting) is much better in general. However, sometimes you really need something dynamic and this gets the job done.

How to pass parameter to sitecore controller rendering method

I have this on my cshtml page
<div class="liveMatch-timer">
#Html.Sitecore().Controller("Blog", "LiveBlogHeader")
</div>
And this is my controller
public PartialViewResult LiveBlogHeader()
{
var matchHeader = GetMatchDayHeader();
return PartialView(BlogConstant.LiveBlogHeaderPath, matchHeader);
}
I have one hidden field with the name "liveMatchItemId" on my cshtml page. I would like to pass its value to controller so that I can access it inside controller. I am expecting to change controller definition something like this
public PartialViewResult LiveBlogHeader(string liveMatchItemId)
Anyone can help me understand on how can I do this? I am new to sitecore and MVC.
EDIT: I am able to achieve this using below code
#Html.Action("LiveBlogHeader", "Blog", new { liveMatchItemId = "12" })
But how can I set hidden field value instead of static field "12"?
Probably you could use something like:
#Html.Action("LiveBlogHeader", "Blog", new { liveMatchItemId = Model.LiveMatchItemId })
Where Model.LiveMatchItemId is the property that you want to pass to the controller.

How to retain parameters for xtraReport with a dataset as the datasource

I have a devExpress xtraReport that is being supplied by a strongly typed dataset. As long as I'm hard coding two parameters into the Actions, it loads the data into the dataset and displays in the report. Once I try to make it pass the values from the main page down through the partial, it fails. My first attempt was to pass the parameters through the ViewBag, wasn't working, so switched to a model, still not working right.
main page controller
public ActionResult SubsequentVisitReport(int noteType = 1, int noteId = 9)
{
ViewBag.noteType = noteType;
ViewBag.noteId = noteId;
ReportParameters reportParamters = new ReportParameters();
reportParamters.noteType = noteType;
reportParamters.noteId = noteId;
return View(reportParamters);
}
main page cshtml - added in the EditorFor to make sure the model makes it there (it does). Have tried calling the Partial both with and without putting 'Model'
#model ReportParameters
#Html.EditorFor(m => m.noteId)
#Html.EditorFor(m => m.noteType)
#Html.HiddenFor(m => m.id)
#Html.HiddenFor(m => m.noteType)
#Html.HiddenFor(m => m.noteId)
#Html.Partial("_SubsequentVisitReport", Model)
controller for the partial - this does not receive the data from the model and I don't understand why. The model is NOT null, all the values are 0 (zero).
[HttpPost]
public ActionResult _SubsequentVisitReport(ReportParameters model)
{
int noteType = model.noteType;
int noteId = model.noteId;
rptSubsequentVisit report = new rptSubsequentVisit();
try { report.DataSource = getSubsequentVisitData(model.noteType, model.noteId).Tables[0]; }
catch { return RedirectToAction("Not_Authorized"); }
ViewData["Report"] = report;
return PartialView("_SubsequentVisitReport");
}
The view for the partial
#model ReportParameters
#Html.HiddenFor(m => m.id)
#Html.HiddenFor(m => m.noteType)
#Html.HiddenFor(m => m.noteId)
#Html.DevExpress().DocumentViewer(settings =>
{
// The following settings are required for a Report Viewer.
settings.Name = "reportViewer1";
settings.Report = (rptSubsequentVisit)ViewData["Report"];
// Callback and export route values specify corresponding controllers and their actions.
// These settings are required as well.
settings.CallbackRouteValues = new { Controller = "Reports", Action = "_SubsequentVisitReport"};
settings.ExportRouteValues = new { Controller = "Reports", Action = "_SubsequentVisitReportExport" };
}).GetHtml()
The data needs to persist through the partial both to load the note for viewing, but also for the export function.
What am I doing wrong, or is there another better way to do this?
Thanks,
Dave K.
The settings.CallbackRouteValues object tells the DocumentViewer where to request the actual report, and it can take parameters. Unfortunately it will be a separate request, so you can't send your model, only simple values that can be passed as strings. In this example, they are using a custom model for the report, but the model has to be re-created from raw values in each action.
If you convert your partial action to take integer parameters:
public ActionResult _SubsequentVisitReport(int noteType, int noteId)
you should be able to tack those arguments on the end of the CallbackRouteValues:
settings.CallbackRouteValues = new { Controller = "Reports",
Action = "_SubsequentVisitReport",
noteType = model.noteType,
noteId = model.noteId};

Categories

Resources