So, I have this variable that I push into the controller via POST from a form in my view.
I then push the variable into viewdata so it's available to the next view which is fine. But that view has no need of a form so I'm unable to push that same variable into the next controller. In short, it's cumbersome to push pieces of information back and forth from controller to view and reverse, so I'm looking for a way to keep a global variable alive inside a controller so that it's accessible by all action results... The general breakdown of my program is this...
-User types a "name"
-I send "name" to controller.
-I push 'name' into viewstate (query entity framework to get a list of stuff 'name'
has access to) and return that list into the view.
-In that view I can access the 'name' since it was in view state.
-Clicking on a link inside the page takes me to another controller where I need
to get access to 'name' WITHOUT passing view Routing or POST.
Obviously the easiest way would be to declare 'name' globally and then it's always available but for the life of me I can't figure out how.
Have you considered storing it in the Session?
This will allow you to easily access it, either from your controller or views, and avoids the need for global variables.
Storing:
[HttpPost]
public ActionResult YourPostMethod(string name)
{
Session["Name"] = "yourName";
}
Access: *
Make Sure to check that it exists prior to grabbing it:
var whatsMyName = (Session["Name"] != null) ? Session["Name"] : "";
Scalability Consideration
It's worth mentioning that MVC applications are designed to mimic the web and are stateless. Introducing Session variables changes this, so be aware that it can introduce issues regarding scalability, etc.
Each user that stores data within the Session will take up resources at the server level. Depending on the number of users and what you are storing within the Session, you could potentially run out of memory if those values become too large.
Why not use the session object, which is an associative array which lives while the client is connected?
$_SESSION['name'] = "zzzz"; // store session data
name = $_SESSION['name']; //retrieve data
You can use this for each user till their session is active.. hope this helps
Related
I am still learning asp.net core and need to know if I'm going about this problem the correct way. Within my app I have a page that is acting as a wizard to create a complex object. I am using a view model to control the inputs. A brief overview of the viewmodel is:
Master Object
-2 Child Objects (that contain 3 child objects each)
-Second Child Object (that contains 1 child object)
I have gotten to the point where I can create the Master Object and all children without any issues. The next step is to add a search option for the 2 child objects.
Currently I have a link to a search page for the child object, I am using TempData to pass the ID of the selected object back (since TempData doesn't support complex objects). On my originating controller I am checking the TempData for the key, and if it exists I am querying the database (via _context) for the selected object.
Child Controller:
TempData["ChildObjectId"] = SelectedID;
return Redirect(MasterObjectControllerCreationURL);
Master Object Controller:
if (TempData.ContainsKey("ChildObjectId"))
{
ViewData["ChildObject"] = _context.ChildObject.Include(x => x.SubObject).Where(x => x.ChildObjectId == Convert.ToInt32(TempData["ChildObjectId"])).FirstOrDefault();
TempData.Remove("ChildObjectId");
}
Master Object Create Page:
if (ViewData.ContainsKey("ChildObject"))
{
Set field variables for the fields we want.
}
Ultimately this is resulting in 2 database calls, one for the search, and then one for the next retrieval. Is this the most efficient way to handle the problem, or is there a better solution? It seems like there should be a more efficient way to handle this. I know I could just set TempData for all of the fields in question, but that would result in 40 possible fields being stored in TempData. Maybe this isn't a problem and is the correct way, I just don't know enough about ASP.Net Core and MVC to know.
I am working on ASP.NET MVC 4 Project of our Company. It is revenue based application and It has some Filters at every Controller and Action of the application.They are Year and Quarter like some filters. for these filter changes I used Create Base Model, (It contains these filter values) and every other Models inherit from this Base Model.Base Model is use at #layout view.
Every change of filter should update the view.
Base Model in layout view something like this
public class BaseModel
{
public string YearSelected{ get; set;}
public string QuarterSelected{ get; set;}
}
and other Models are inherit from this BaseModel
public class RevenueModel:BaseModel
{
// other stuff
}
For all these things I am sending through the parameters.Seems like now Parameters are increase requirements are changes to add more parameters
1.I want to know the method that handle is correct and If method is insufficient Suggest me best
way to handle this parameter changes.
2.In the UI(View),
When user change the view by checking radio button and click on apply filter button I am using jquery for handle this,
window.href='Url Action with new Parameters';
window.href='#Url.Action("SomeAction","Controller",new{ // those all parameters } ';
When button click window.href will automatically call and update the view I want to knowIs this method Robust? Suggest me best way to handle this scenario.
"Simply I need a answer for if i use jquery to call an action and use high numbers of parameters for the call controller action"
What you're doing is doable, but as #ps2goat points out, you can run into issues if you have too many GET parameters in the URL.
But the right answer depends on how the filters will be used. Will the user often change the filters or will he rarely change them? If the user is expected to browse through your app and only rarely change the filters, I would suggest you to use another approach than including the parameters as GET parameters in the URL because:
You could run into problems if the total length of your URL becomes too long, as #ps2goat points out.
You could run into user experience problems. If a user bookmarks a page, and then later changes his filters, and uses the bookmark to return to the earlier page, his filters would be reverted, which is probably not what he would have expected.
It wouldn't look very pretty. All your urls on your site would look like /controller/action/?YearSelected=2014&QuarterSelected=1&Parameter3=2&Parameter4=8, which could also create SEO issues you would need to take care of.
In that case, I would recommend you to consider using a cookie or saving the user's filters on the server instead. (But preferably not in a Session, as that can create scalability problems for your application). If you used a cookie, the user's filters would be available to your Controller Action on each request automatically, as the cookie would be sent along with every request. (This is of course also something to have in mind when considering which strategy to use. If you have alot of cookie data, this will slow down the perceived responsiveness of your application, as the cookie data has to be sent along with every request to your server. So keep your cookie data as small as possible)
On the other hand, if you expect the user to change the filters often and maybe even several times on the same page, you could consider using jQuery to do an asynchronous POST to your MVC controller, retrieve the neccessary data using JSON, and update the view. This is actually not as difficult as it might sound.
What you would need to do to implement it, is to create a Javascript function on your page that submits your parameters to your controller action. You can send the data as JSON to the controller action also. Something like this could work: (Untested code)
<script>
function submitFilters() {
var parameters = {
parameter1: $('#parameter1').val(),
parameter2: $('#parameter2').val(),
...
};
$.ajax('#Url.Action("SomeController", "SomeAction")', {
contentType: 'application/json',
data: JSON.stringify(parameters),
success: function(data) {
alert('Received data back from server. Ready to update the view.');
}
};
}
</script>
Then you would hook up the filters (Radio buttons, drop downs etc) to call the method submitFilters.
MVC automatically converts the JSON data it receives from the client into your C# ViewModel as long as the property names match. Then you can do whatever querying and filtering you need to on the server, and then send the data back as the result of the action. (Pseudo code)
public ActionResult SomeAction(MyViewModel vm)
{
var data = SomeRepository.GetData(vm.Parameter1, vm.Parameter2, ...);
return Json(data);
}
Then you just need to update the view when the data is received. You would preferably use a template engine for that, but it's not required of course.
This is just a crude example of how you could do it. Normally I would create a Knockout View Model to encapsulate it all. But this should get you started.
I have an application.
I am stuck at a point from where i want to pass a model from a Post method to a Get method.
// Code in get method
FoundAccounts fa=new FoundAccounts();
fa.register = model;
return RedirectToAction("FoundAccounts", fa);
//Post Method
public ActionResult FoundAccounts(FoundAccounts fa)
{
//Use that values here
}
Can i do it like this?
I am unable to find a way.
Please help me with the same.
Thanks
Can i do it like this?
No, you can't. You can only pass simple, scalar properties to the route values of a RedirectToAction call. It doesn't make sense to pass complex objects, because when you perform a redirect, only the simple properties will be included in the GET request as query string parameters.
So you have different possibilities:
Persist the entity in your backend and then pass only the id to the GET action (this is the solution I recommend):
int id = repository.Save(fa);
return RedirectToAction("FoundAccounts", new { id = id });
and then your GET action will take the id as action parameter and use this id to retrieve the entity from wherever you persisted it initially:
public ActionResult FoundAccounts(int id)
{
FoundAccounts model = repository.Get(id);
...
}
Pass all properties and leave the model binder dehydrate the entity in the GET action:
return RedirectToAction("FoundAccounts", new
{
prop1 = fa.prop1,
prop2 = fa.prop2,
...
});
Obviously here if you have some complex properties you will need to pass them as well. Remember that the properties you include will be the properties you will be able to retrieve in your GET action. Everything else will be lost:
return RedirectToAction("FoundAccounts", new RouteValueDictionary
{
{ "prop1.SubComplexProp1", fa.prop1.SubComplexProp1 },
{ "prop1.SubComplexProp2", fa.prop1.SubComplexProp2 },
{ "prop2", fa.prop2 },
});
The drawback of this solution is that if you have lots of properties this could quickly become cumbersome. And you could even hit on a roadblock because there's a limitation to the size of a GET request. This limitation will vary between browsers, but I wouldn't pass anything more than 2048 characters in a GET request.
Use Session or TempData (not recommended as it introduces state into your application);
TempData["fa"] = fa;
return RedirectToAction("FoundAccounts");
and then inside the GET action retrieve the model from the Session or TempData:
public ActionResult FoundAccounts()
{
FoundAccounts model = TempData["fa"] as FoundAccounts;
...
}
The difference between Session and TempData is that TempData will survive only for a single redirect and will then be automatically evicted by the framework. Under the covers it uses Session, it's just that it is automatically cleared once you read the value in the GET action. The problem with this of course is that if the user hits F5 to refresh the page in his browser, you will no longer find the value in TempData because it was evicted. Even worse if the user decides to bookmark the GET action, he will have the same problem if later he decides to come back and navigate to this bookmark. So people tend to use Sessions for those kind of things. Sessions of course do not solve the problem with bookmarks (because the user could have closed his browser in-between and the Session will be lost). Also Sessions introduce other problems in web farm scenarios. For example if the session is stored in-memory (which is the default), this means that you could store the value on one node of the farm but when you perform the redirect you could hit another node of the farm and then this node no longer has any knowledge of the session. So people start to use an out-of-process sessions - either stored in a State Service machine or SQL service. But what's the point? I mean take a look at my first and recommended solution. It's exactly what you will end up a fortiori if you want to have scalable solution working in a web farm environments.
I am having some trouble saving the state of my current view.
Currenly I have several selectlist calling their own Action method on the controller that returns the Index view with the filtered model based on the values of the selectlist.
I have also written a little FileResult action that creates a csv file based on the current model. But I am only covering one selectlist right now as I only save the value of selectList1 into the session and access it with Session["SelectListValue1"]
What are the best practices in this situation?
Should I redo the entire (each action for each SelectList) part?
Should I save each SelectLists value into the session and check if it's null?
Or should I just save the Lambda Expression into the session and modify it during every call?
Well, generally in MVC we don't directly save to Session, it's not considered a best practice b/c of impact to your app's performance. Generally, it's a best practice to make each request as stateless as possible.
Each form should follow the POST-Request-GET pattern where possible, so you're not going to do what you did in WebForms as a rule (where you keep posting back to the same form/action).
So you should consider what the state is that you're trying to capture represents. THe list of possible values is one thing, drawn possibly from a database and stored as a list or enumerable in the cache perhaps (in some scenarios; could look it up every time in others). The value that's selected probably represents a property on osme other object, though, so you should use that as your means of getting out the selected value.
If it's something that's not a part of a persistent object, then you can either just read the post values each time and set the viewstate again (probably the best practice) or, if you need to persist that value across a redirect, then use the TempData bag (which works much like session; in fact uses session under the hood) but values get garbage collected after one the next request, so you don't have to worry as much about the memory bloat.
It doesn't sounds like you need to be using the session at all. Can't you pass the values of your select lists via the query string or in a form?
I am currently using a number of query string parameters to pass some data from one page to a second page (the parameters hold confirmation/error messages to display in the second page), that due to a third party product can no longer work correctly in the production environment. The user completes an action on the first page, and is then transferred to the second page. What are the possible alternatives to use instead of a query string and GET - session variables, POST data, or something completely different?
Thanks, MagicAndi.
You could create public properties in a source page and access the property values in the target page when using a server transfer. You could also get control information in the target page from controls in the source page by referencing the Page.PreviousPage property.
Both of these methods are oulined here: http://msdn.microsoft.com/en-us/library/6c3yckfw.aspx
Both POST data and session variables would work just fine. POST data has the drawback that it can be changed by the client and session variables take up memory, so you can choose based on that. I personally don't think that you should pass such messages to the client for the reason stated above but I guess you are already doing that, so...
you can use this if you use window.open("openTheotherPage",...etc)
so form the opened page you can do something like this
var valuefromCallerPage = window.opener.document.FormNmae.textbox.value
or button or anything on the caller page