My problem: I have a list A selected from database of a controller A, controller A will display list A. In view, each record of list A has a link call controller B (#html.ActionLink("text","actionB","controllerB", new {id=listA.ID})) and i want to send list A to controller B as well. I've searched about how can send data between 2 controller, there are 2 ways are:
Using tempdata
Using session
But all of those above is not really suitable on this case, can anyone tell me other ways to solve my problems. Thanks
A better alternative would be to retrieve the list again in your second controller. This is generally pretty cheap and fast.
This is what I do. For things like lists I may re-use in several places I utilise the Initialize method in each controller then check the Action name to determine which lists of objects I need to load.
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
//if this is the insert or edit form - get the lists for the d.down form inputs
var actionName = requestContext.RouteData.Values["action"].ToString().ToLower();
if (actionName == "insert" || actionName == "edit")
{
var _uow = new UnitOfWork();
var lstMyList = _uow.MyRepository.Get().OrderBy(n => n.title).ToList();
_uow.Dispose();
ViewBag.MyList = lstMyList;
}
}
Obviously the code to retrieve the list may differ depending on how you access your DB but you get the idea. This way, you only call in one place within each controller's code and yes, it may result in more database calls but for me, I like the neatness of not having calls littered all through my actions. MyList is available in the ViewBag to populate form controls or output where needed or for in-view logic if you're that way inclined.
As the application grows there will be many requests you will need to make requests to the db, do not worry about such calls to the db.
However to answer your question...
You can store it in session/tempdata and then retrieve it. This will increase your server memory usage, what if the user didnt have to look at the detail. It's just a waste.
You store it in the page it self as json and then post it to the server and pass it to the second controller, but the data can be manipulated on client and also increases the bandwidth, making the page slower to download and upload.
Becomes difficult to maintain.
In short retrieve it from db from the second controller.
Related
I need to pass objects between ActionMethods and Views in an ASP.net MVC 5 app.
I'm using it for a multi page signup - and for a multi page payment.
Is this bad practice? I haven't seen a good way to pass objects between different controllers.
Code:
public ActionResult Join1()
{
//
return View("Join2", MyObject);
}
[HttpPost]
public ActionResult Join2(MyObject MyObj)
{
//manipulate object
//return
}
It seems to be an effective way to do it - though I haven't seen many people do it this way. I haven't seen objects being passed between action methods much at all.
Is there a flaw in this approach, a better way of passing models between Views - or should each ActionMethod stick to passing simple data with, say, TempData instead of objects?
Why haven't I seen any sample projects doing things like this?
I've seen return RedirectToAction("act"); plenty - but that is Get and passing an object in a URI is limiting - and I don't want users to be able to manipulate or see the data being passed.
thx.
Unless I have misunderstood the description, your code is not doing what you think it's doing. That first return View("Join2", MyObject); statement is not executing the second ActionMethod, it is only passing your data into the View that happens to have the same name as the second method. Therefore the code implied by //manipulate object will not run before that View is rendered and sent back to the user.
Assuming the View file Join2.cshtml exists, and it contains the default #using (Html.BeginForm()), then users submitting the form will cause the Join2 Action to be executed and the same view rendered with the manipulated data - unless, of course, you add another return View() statement that names a different View.
The reason you haven't seen this done much is that the MVC convention is to have a View named the same as the ActionMethod, this makes the code slightly simpler and also much easier for other ASP.NET developers to understand because it is what they are expecting to see.
If you want the form rendered by each View to then execute a different ActionMethod when it is posted back, the place to do that is in the View code, where Html.BeginForm() has several overloads that allow you to do just that, e.g. in Join.cshtml you could write:
#using (Html.BeginForm("Join2", "JoinController"))
{
// form fields and stuff
}
// Produces the following form element
// <form action="/JoinController/Join2" action="post">
To address the final part of your question, "I don't want users to be able to manipulate or see the data being passed", sorry to say it but your proposed code doesn't prevent that: users can see the data in the web form, before it is ever posted back to the Join2 method; they can manipulate the data by sending an HTTP POST containing any data they want back to the Join2 method.
If you absolutely, positively need to actually execute Join2() from within Join(), before anything is passed back to the user, then you can call it just like any other C# method:
var myResult = Join2(MyObject);
Then you have an ActionResult object that you can manipulate or return straight to the browser. But why you would want to do this, is beyond me.
I have 3 partialviews with 3 viewmodels on page:
List of accounts
Modal popup (you can modify multiple accounts here)
Search panel
I want to refresh 1. after doing POST on 2. This is straightforward, but what if I want to keep results I got after using Search Panel?
I can do this in 2 ways but both seems bad (correct me if I am wrong).
First (the one I chose and works) is to store viewmodel used in 3. in TempData. I do Search (POST) and save passed viewmodel in TempData. Then whenever I do POST on different partialview I can refresh 1. using data(search parametrs) from TempData.
private const string SearchDataKey = "SearchData";
[HttpGet]
public PartialViewResult RefreshData()
{
if (TempData[SearchDataKey] != null)
return PartialView("AccountListView", PrepareAccountListViewModelForSearchData(TempData[SearchDataKey] as AccountSearchViewModel));
else
return PartialView("AccountListView", PrepareAccountListViewModel());
}
and saving ViewModel:
public PartialViewResult Search(AccountSearchViewModel searchParameters)
{
...
TempData[SearchDataKey] = searchParameters;
return PartialView("AccountListView", databaseAccountListViewModel);}
Second approach is to always POST "big" viewmodel with all 3 viewmodels. This way I will have data from Search's viewmodel but I will send many not needed information instead just Modal Popup's viewmodel which I need to call procedure.
I asked few MVC folks with better experience and they said they never had to store viewmodel in TempData but it still seems more reasonable than having 1 Big form and passing everything in every POST.
Do you know any better ways to handle this or which one is correct?
PS. Topic had "Best Practice" but was removed cause of warning message. I hope asking about opinion is still allowed on SO.
PS2. Most of my POSTs & GETs after initial load are through Ajax.
I do Search (POST)
This seems semantically incorrect to me. Searching is an action that shouldn't modify any state on the server. So using GET seems more appropriate. And when you use GET you have the benefit that all parameters are already present in the query string and thus preserved upon successive POST actions (like modifying an account in your case). So your RefreshData action could take the AccountSearchViewModel as parameter and the model binder will take care of the rest.
I want to pass a class object from one controller action to different controller's action.
Sender Action
public class CourseController : Controller
{
[HttpPost]
public ActionResult CreateNewCourse(CourseViewModelBase courseViewModel)
{
if (ModelState.IsValid)
{
// Do some stuff
return RedirectToAction("CreateNewProject", "Project",
new { courseVM = courseViewModel});
}
// Bad happened
return View("CreateNewCourse", courseViewModel);
}
Receiver Action
public class ProjectController : Controller
{
[HttpGet]
public ActionResult CreateNewProject(CourseViewModelBase courseVM)
{
// Use CourseVM data and do other stuff
return View("Create", projectCreateViewModel);
}
}
I am getting data properly in Sender Action and Receiver Action is called properly from the redirect to action call. However courseVM in Receiver Action is null.
I know this is a very old question and had been asked repetitively. But I found that most of the answers suggested to use TempData and were answered in 2008/2009. I believe there would be someway to pass data using RedirectToAction without using TempData. If there is not then I would go with TempData only.
Finding
If I pass some simple data e.g. new {id = courseViewModel.CourseDuration} and change the argument in Receiver action to id then id is properly received.
Similar Questions
Question 1
Question 2
Question 3
Question 4
Question 5
Question 6, tried to use this one but did not workout
Question 7
Question 8
Question 9
Question 10
Most of the answers in above questions are dated back in 2008/09 and uses tempdata.
This question itself is now about a year old, but I came across it so I thought I would help out others who come across it in the future. The accepted answer doesn't work - the complex object still arrives at the receiving action null.
I found that this answer from 2012 is still valid. You just can't pass complex objects in an HttpGet request (by nature this is what a RedirectToAction is - again, not something you can change). You can only pass scalar values: int, string, etc.
Make sure you've ruled out the below two options:
Avoid sending a complex object altogether, and send only scalar values. Obviously this is only an option sometimes - but I mention it as a reminder to consider it.
Skip the receiving Get action altogether - perform its logic & return the View directly from your Post action. Ie; return View("ReceivingViewName", viewmodel) Again, will only work for some situations, more than likely you'll need the other action and thus will need the Redirect, but worth remembering as a possiblity.
If you can't get around the problem, and have eliminated the two above options, your options are:
Persist the data to Database, possibly using a temp table if you know the data won't be used later. Send the primary key to the receiving action, and once there, query the database. This is the "cleanest" option.
[Edited Option] Store the object in TempData (data lasts only thru the next request in which it is used - if it's not used, it will hang around for the life of session) or Session (data lasts for life of session). Neither are really great options. TempData is probably the better of the two, as its lifespan is potentially shorter... but you'll still have to consider what happens when a page reload occurs or a subsequent request is made to the method (WebGrid paging, for example - which was my scenario). For these specific scenarios, I originally recommended getting the data out of TempData, and then putting it back in so it's available for a subsequent request to that action. Since TempData actually hangs around until it's used once, that makes this option even less desirable, since it won't go away if the user navigates elsewhere. More info on this in the answers here. Bottom line is don't put anything in TempData unless you intend to use it right away. If you don't need the data for a specific scenario like paging, and you put it in TempData and immediately consume it in the receiving method, without putting it back in, this option is okay. The first option is still better.
use this
return RedirectToAction("ActionName", "ControllerName", modelObj);
in your case
return RedirectToAction("CreateNewProject", "Course", courseViewModel);
You can also use
TempData
I have a value which I want to be vaild during a single request. I am not using Session, as this would make the value global for the entire navigation session.
So I have put thie value in a static field of a class. Great, but then I discovered that such fields are even more global, that is, they stay set for the entire application! This means that there could be random interaction among navigation sessions.
So the question is: is there a safe place I can put a global variable, which will be
global throughout the request
reset after the request is completed
not affected by any other request, either of the same user or by other users
Thanks
Palantir
EDIT
I'll elaborate. I have a piece of code in my master page, which I need to hide on certain conditions, of which I am aware in the controller only. I thought about setting a static variable in the controller, which then would be queried by the master page, but now I see there could be a better way...
Use HttpContext.Items - a per-request cache store. Check out this article on 4guysfromrolla for more details.
It should work fine in ASP.NET MVC. You may wish to derive your master page from a base class (either via code-behind or using the Inherits directive) and have a protected method on the base class that inspects HttpContext.Items and returns, e.g. true/false depending whether you want to display the conditional code.
TempData lasts until the next request as already noted.
But there are also two other dictionaries scoped to the single request.
{Controller,ViewPage}.ViewData
Context.Items
To communicate from controller to (master) page ViewData is probably the better choice.
Two approaches come to mind:
Create a base controller where you set this variable, and then have all your controllers inherit from that.
Use TempData - the problem here being that it sticks around for the next request. But maybe knowing that, you can work around it by using a GUID key to determine that you are, in fact, getting a new value when you need it.
I would probably go with 1).
The common way to access data in a MasterPage that is set in Controller (Action) is via ViewData["TheDataKey"] = "SomeValue".
This is relatively easy and there are a couple of ways that you can do it - depending on how your site works.
I'm interpreting your request as that you want a property or variable that exists for the duration of the request and is visible to the controller, model and master.
A static property is visible to the current application in ASP this means a load of users connecting at once, but not necessarily all of them. IIS will spawn new ASP applications as it needs to.
So the ways you can do this:
You can have a custom base class for your master page or a code-behind page (as all the WebForms stuff still works)
You can have a custom base class for your controllers.
You can get to one from the other, so:
void Page_Init( object sender, EventArgs e )
{
var ctrl = this.ViewContext.Controller as MyBaseController;
if ( ctrl != null )
{
MyLocalProp = ctrl.PropOnMyController;
}
}
This will then be available in the controller and the master page on a per Request basis.
Did you look into the tempData that is attached to the controller class? it is a simple dictionary that preserves it's value through one single request.That would meant that your data can only be accessed in the controller but that should not be a problem.
public class MyController : Controller
{
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult MyAction(string id)
{
this.TempData["Message"] = "YourData";
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult MyAction(string Id)
{
var myData = this.TempData["Message"];
}
}
This works for me. I use it only to display warning messages and stuff like that.
I’m building an application that monitors other systems. Now I want to implement partial view, a User Control called “status”. This control shall display status information about the application.Like:
user logged in,
How many systems online,
Latest activity.
This partial view shall be rendered in nearly all other views. How shall I pass this information to the view?
I don’t want to write
Wiewdata[“SystemsOnline”] = Helpers.CountSystemsOnline()
Wiewdata[“SystemLatestActivity”] = ………………
in all my actions.
Can I write something like Html.RenderPartial(../Shared/Status) that fist go to an action that adds the viewdata?
Or shall i access the information directly in the view trough the hepler?
I noticed that the defult LogOnUserControl view use Page.User.Identity.Name to directly access that data.
When is it ok to not pass data throug viewdata in the controller?
You have to use the ViewData class for that purpose. I do not recommend to invent tricks instead.
But you do not need to manually pass the same data from every action. Just do it in your base controller:
protected override void OnActionExecuted(ActionExecutedContext context) {
base.OnActionExecuted(context);
if (context.Result is ViewResult) {
// Pass the systems online to all views
ViewData[“SystemsOnline”] = Helpers.CountSystemsOnline();
}
}
Only a couple of lines of code and you make it available everywhere.