I am working on a MVC web form where user will submit the Album information in the first step, after submitting the Album information in the second step user can submit the track information data.But i am little confused how i ll do in MVC , in normal webform it is easy for me to do .I am looking for some sloution for this.
If you're not writing the Album information to some kind of permanent storage at the end of step 1, e.g. database, file etc., then you could use TempData to keep track of the information entered into the wizard between page requests.
TempData uses Session state under the hood and is only persistent across a single request, so you would need write your album/track information to TempData at the end of every controller action and read it in again at the beginning of every action. Then, once you have accumulated all the album/track information, write it to permanent storage.
You might also consider just storing the album and Track ids in the URL. There are some benefits to this, like the ability to bookmark and email the URL to friends.
When you pass a RouteValueDIctionary to the UrlHelper.Action() method, any parameters in the dictionary that are not part of the route will be added into the query. So you could do this:
return Redirect(Url.Action("myaction", "mycontroller",
new { album = selectedAlbumVariable, track = selectedTrackVariable }));
And them retrieve them in the action by adding them to the action parameters like this:
public ActionResult SomeAction(string album, string track) { ... }
You would have to check for null on album and track before using them.
You can follow what pmarflee suggested, here is a litle example, using TempData:
public ActionResult Step1()
{
var MyObject = new List<string>();
//Some Logic
//Set the TempData
TempData["data"] = MyObject;
return RedirectToAction("Step2");
}
public ActionResult Step2()
{
//Get the Data From the TempData and Cast it
var MyObject = (List<string>)TempData["data"];
//Continue working
return View();
}
Just remember that this data will be available just for 1 more action, if you want to continue passing data you must set the data again in the TempData Dictionary.
You can also use another approach and serialize the data into a hidden field, this approach is cleaner but require more work, if you just want to save a couple of fields, TempData is good to go.
Related
I have a simple MVC application that presents an IQ test to the person.
I have a controller call TestMyIQController and on this controller I have three action methods and corresponding to three views.
1) Index.cshtml
2) Questions.cshtml
3) Score.cshtml
On the first page localhost:12345/TestMyIQ/Index of the application I ask the user to input their First and Last name and click button Next to go to second page.
On the second page of the application localhost:12345/TestMyIQ/Questions I present a few multiple choice questions and I have the user select True/False for each question. Once the user complete all the question she can click button Submit to see her IQ score.
On the final score page localhost:12345/TestMyIQ/Score I show the score via a ViewBag object.
However, I want to know how to modified the final page url so that I can append the First Name of the user? For example if the person name is John Doe then I want my final score url will be like this localhost:12345/TestMyIQ/Score?firstname=John.
Note it is not necessary to append the First Name to all other url...because I only want it on the final score page.
Please help me. Thanks
Considering you received the first name in the Questions action, and added as a property of your model, you can add it to your form as a hidden field:
Questions.cshtml
using(Html.BeginForm())
{
#Html.HiddenFor(x => x.UserFirstName);
// rest of form
}
TestMyIQController
[HttpPost]
public ActionResult Question(QuestionModel model)
{
// form processing
return RedirectToAction("Score", new{ firstName = model.UserFirstName })
}
Because in the Question page you stored it as a hidden field, it will only show up in the url of the score page.
But keep in mind that while this is ok if you're learning and just want to do some cool stuff to show your friends, this isn't the best way to handle all of this.
EDIT to add more info on the problems of using this method.
The negative is that anyone can change the URL. Nothing stops me from changing ?firstName=foo to ?firstName=bar. Second, names can contain invalid characters for URLs, which will need to be encoded. Third, it's overall bad design.
There are better ways to handle this, but it depends on the what you need from it. Will the users be able to share the url? If not, you can add it to the Session. This is definitely easier to implement in your current design. If they'll do, you could store the result in a SQL table, and share the url as ?scoreId=f88f9426-04d7-4ae2-8e15-a4bbd8d6faad.
Not sure I understand your needs, but you dont have to store the name in url, you can use for example session variable, but if you insist on it being on url, why not just redirect(urlWithParameter).
For a good listing of possibilities, see
Msprogrammer
Session may be choice to store the name and retrieve it on the score page.
[HttpPost]
public ActionResult Index(UserModel model)
{
// save the name
Session["FirstName"] = model.FirstName;
return RedirectToAction("Questions")
}
On the score method, retrieve the name from session
[HttpPost]
public ActionResult Score(ScoreModel model)
{
// save the name
string firstName = (string)Session["FirstName"];
return RedirectToAction("Index")
}
Hope it helps.
I'm implementing an ASP.NET MVC post/redirect/getpattern in an Azure website. When a user creates a new entity they are redirected from the create view to the edit view with the new object id as part of the url.
The entity has quite a few fields so it's not uncommon to save multiple times and to reassure the user that their data is being saved we are showing a 'Saved successfully' message using javascript.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Branch branch, int orgs)
{
if (ModelState.IsValid)
{
// model is valid, save it and redirect to edit
_branchRepository.Save(branch);
TempData["Message"] = new NotificationViewModel(NotificationSeverity.Success,
"Saved",
"Saved successfully");
return RedirectToAction("Edit", new { id = branch.Id });
}
// model is invalid, don't save it, let them have another go
TempData["Message"] = new NotificationViewModel(NotificationSeverity.Warning,
"I'm sorry, Dave.",
"I'm afraid I can't do that.");
ModelState.Clear();
return View("Edit", branch);
}
My understanding of TempData is that any data stored in TempData will be around for the life the current request and the next request only (or until the item is removed explicitly) and is the best place to put data you want to pass another view that you will be redirecting to.
Is TempData the best place for this message?
Note: I've read that if you're load balancing your webservers that you have to have Sticky Sessions enabled. Does Azure turn on Sticky Sessions automatically or do you need to manually configure this?
Storing validation message betweeen requests when using PRG pattern in TempData is in my opinion the most popular usage of TempData. Additionally you can write some action filters that will automatically store all modelstate in tempdata if you return Redirect result and move that data from tempdata to modelstate/viewstate if you return view in Get phase.
In MVC Contrib there are two such filters:
http://mvccontrib.codeplex.com/SourceControl/latest#src/MVCContrib/Filters/ModelStateToTempDataAttribute.cs
http://mvccontrib.codeplex.com/SourceControl/latest#src/MVCContrib/Filters/TempDataToViewData.cs
Data stored in TempData is removed after end of the request in which it was read until you call TempData.Keep(key).
I really need to maintain this string called "filterParams" in my MVC application. After the user enters some search parameters he clicks submit, and the grid is rebinded with that parameter. That works great. I also save the filterParams data in a Javascript variable, so when the user pages, and the OnDataBinding event is raised, the filter is also passed through that ajax call as well. this is all well and good however there is a huge issue, because when the user updates a question, all the results dissapear because it returns to the View and it does not have any data there. The way I'm using ViewData isn't working, and I could use your help, because if I can store it in ViewData and access it, it would fix my problems. I cannot use TempData because there are a number of other Actions that can be called in between Select and Update...Long question short, how do I implement ViewData correctly to store and retrieve a string in my controller?
Here are some code snippets.
[GridAction]
public ActionResult GetAllQuestion(string filterParams)
{
var _filterParams = new List<string>();
_filterParams.Add(filterParams);
ViewData["filterParams"] = _filterParams;
return View(new GridModel(QuestionManager.Instance.GetQuestion(filterParams)));
}
[GridAction]
public ActionResult EditQuestion(int id, QuestionDTO pQuestion)
{
// var _question = QuestionManager.Instance.GetQuestion(id,false).FirstOrDefault();
// TryUpdateModel(_question);
var _filterParams = (List<string>)ViewData["filterParams"];
var filterParams = _filterParams[0];
QuestionManager.Instance.UpdateQuestion(pQuestion);
// return View(new GridModel(QuestionManager.Instance.GetQuestion(id, false)));
return View(new GridModel(QuestionManager.Instance.GetQuestion(filterParams)));
}
in my aspx page
Html.Telerik().Grid<QuestionDTO>()
.DataBinding(dataBinding => dataBinding.Ajax().Select("GetAllQuestion", "Question", new { filterParams = string.Empty }).Update("EditQuestion", "Question").Insert("CreateQuestion", "Question"))
How can I get this to work please? Help is appreciated
ViewBag/ViewData only works for sending data from an action to a view. It does not get populated by the Model Binder when a request is made to an action, and its state is not saved between requests because ASP.net MVC is entirely stateless. In other words, the ViewData dictionary is always empty at the start of a request.
Meaning this line in your EditQuestion action will not work:
var _filterParams = (List<string>)ViewData["filterParams"];
ViewData is empty, so _filterParams will be null.
You have to manually send filterParams to the EditQuestion action just as you do for the GetAllQuestions action.
Perhaps a better alternative would simply be to persist filterParams using a temp cookie on the client side.
So, just to defy all the misinformation I've read on the subject, TempData infact does persist through multiple action calls in the controller and was able to be used to implement the functionality I needed.
Why just not store the data in Session?
Here's a good explanation with examples
http://rachelappel.com/when-to-use-viewbag-viewdata-or-tempdata-in-asp.net-mvc-3-applications
I have created a mvc3 application.
Currently saving submit form value into Session as i need to do some stuff on that before
save changes to database.
Is there any other good way to store temp data in mvc like ViewState?
I'm saving form input values into Session variable each time when data is entered and and when I clicked on submit button.
After every submit i'm populating my session variable with new added values and displaying all those values into webgrid.
Once i'm done with insertion finally clicked on update button which takes all values from webgrid and pass to one stored procedure as a parameter.
Now here i want to achieve 2 things
1.need to save all inserted data as clicked on submit it gets refresh all time.
so need to save all previous data to.
2.currently using session variable which sets to webgrid to show data into webgrid and once done with insertion passing those values to stored procedure.
So need to know any other good way to save data.
Else can use javascript to do this all on client side.
You should avoid schemes that attempt to make the stateless web seem stateful for two reasons.
Firstly, Session DOES NOT avoid a round-trip, it's only nominally different than storing values in the database. Yes, a fetch of memory is faster than a fetch from SQL but this doesn't scale well -- to scale (more than 1 server) you must add components and hops that reduce the gains and dramatically increase the complexity.
Secondly, Session values are likely to make it to a database anyway so why not just start with them there in the first place.
Thirdly (yes, another one), Session is not necessarily something to trust any more than a hidden form field would be.
In 13 years I've seen session used almost exclusively for the wrong things -- developers regress to using session for convenience and later regret it (as do the developers who replace them and have to maintain their code).
In short, use a database to store this information and be smart about how you fetch and cache it.
You can use TempData (http://msdn.microsoft.com/en-us/library/system.web.mvc.controllerbase.tempdata.aspx), but know that it persists only from one request to the next.
TempData["someKey"] = "";
if you need to persist the data across posts, Session is the proper place. If you need to write the data to a database, then the model should handle the data on post. In your controller:
[HttpPost]
public ActionResult Index(YourModel model)
{
if (ModelState.IsValid)
{
model.SaveToDataBase();
return View("Success");
}
return View("Index", model);
}
Then in the model:
[Serializable]
public class YourModel
{
[Required]
public string YourData { get; set; }
public void SaveToDataBase()
{
//TODO - add code to call stored procedure with data posted to model
}
}
I'm passing structured data to my MVC page when it loads initially. After the user submits a contact form, I want to re-use the same data (I just "leave" the same page up) so I don't have to hit the database again. I declared a variable global to the controller to store the model data, but it's null at the end of the post back, so it looks like I can't re-use it there.
Seems like this would be a typical scenario. How do I handle it?
If you are wanting to reuse viewmodel or other retrieved data that is not going to be part of the postback, you can either
a) Output it in hidden fields so that it is posted back to your action (meh) or
b) Store the object(s) in Session so that it will be available to any other controllers/actions in your application. If you are worried about memory, you could delete that session variable after you reuse it if you are not going to need to use it again.
On your initial page load, check if the session variable exists, if it does, you are good - else populate it.
Oh and why the global variable thing isn't working -> a controller is new'd up for each request (assuming using the default controller factory) and as such any global variables in the controller will be reset on each request.
public ActionResult Foo()
{
var model = GetModelFromDB();
Return View(model);
}
[HttpPost]
public ActionResult Foo(Entity model)
{
Return View(model);
}
Asp.net-mvc is stateless so each HTTP request has a different context, and each time you hit the controller all it's data reset in the constructor, this why you get null.
You can get the model in the post if it's properties are within the submitted form .
If you really don't want to leave the page you are on, and don't want to post all the other data back as KMan suggests, but still want to capture the users contact information/data you could post the contact info using ajax.
If you have your view model as an argument to your method, you can just return it to the view on postback. Ex:
public ActionResult TestAction(MyViewModelType testViewModel)
{
//Do logic
return View("view",testViewModel);
}
Note that you have to have the data inside the form you are posting.