Unwanted caching in MVC application - asp.net-mvc

I have an issue with caching and have tried every solution I can find!
I have a simple create screen where one row is inserted in a table (although I also get the same issue when editing existing rows).
When the row is created, the user is returned to the previous screen, which still shows the old data. (same issue with edit)
Refreshing the page makes no difference. Difference browsers have the same problem. The data is successfully added in the database. Only by restating the application does it refresh the data on screen.
Things I have tried:
1:
DataContext.Refresh(RefreshMode.OverwriteCurrentValues)
2:
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
3:
ModelState.Clear()
None of which made any difference. I've not had this problem before with edits or creates, so I must be missing something. Any help much appreciated!
The following is the relevant parts of the controller:
ISISDataContext db = new ISISDataContext(StudentISIS.Properties.Settings.Default.ISISConn.ToString());
public ActionResult Index()
{
var student = (ISIS2Models.Student)Session["CurrentUser"];
return View(student);
}
public ActionResult STGCreate(int id)
{
var enrolment = db.Enrolments.Single(e => e.EnrolmentID == id);
return View(enrolment);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult STGCreate([Bind(Exclude = "Id")] StudentGrade STGToCreate, FormCollection collection)
{
var STG = new StudentGrade();
STG.Grade = collection["StudentTG"];
STG.EnrolmentID = int.Parse(collection["Enrolment"]);
STG.DateChanged = DateTime.Now;
db.StudentGrades.InsertOnSubmit(STG);
db.SubmitChanges();
return RedirectToAction("Index");
}
Edit:
Here is the code from the index view which loops through enrolments to show the grade:
<%foreach (var en in Model.Enrolments) {%>
//Some table stuff
<td>
<%try
{ %>
<%= Html.ActionLink(en.StudentGrades.Grade,"STGEdit",new {controller = "Progress", id = en.StudentGrades.StudentGradeID})%>
<%}
catch (NullReferenceException) {%><%= Html.ActionLink("Set","STGCreate",new {controller = "Progress", id = en.EnrolmentID})%><% } %>
</td>
//Some more table stuff
<%}%

Where do the rows come from? is it your ISIS2Models.Student class? I can only assume it is because you have so little code in your Index method.
If it is, and you are storing that in the session, then you are not updating that value, so when you retrieve it from within Index it will still have the same old values.
What you need to do is get the updated model from the database each time you make a call to Index. Some method like this:
public ActionResult Index()
{
var currentUser = (ISIS2Models.Student)Session["CurrentUser"];
var student = GetStudentById(currentUser.ID);//this will get the up-to-date student record from the DB
return View(student);
}

Related

Reference DropDownList selected value from enclosing Form

I'm just getting started with MVC5 (from WebForms), and dropdownlist bindings are giving me some fits.
I'd like to get this working using a GET request back to the page, with a selected value parameter. I'm hopeful that I can specify the route arguments in the form itself, so I'd like to reference the DDL's SelectedValue.
<p>
#using (Html.BeginForm("Index", "Profile", FormMethod.Get, new { id = WHATDOIPUTHERE} )) {
#Html.AntiForgeryToken()
#Html.DropDownList("ApplicationID", new SelectList(ViewBag.ApplicationList, "ApplicationID", "ApplicationName", ViewBag.SelectedApplicationId), new {onchange = "this.form.submit();"})
}
</p>
I can make it work with a POST form, but that requires a second controller method so I end up with
public ActionResult Index(long? id) {
ConfigManager config = new ConfigManager();
//handle application. default to the first application returned if none is supplied.
ViewBag.ApplicationList = config.GetApplications().ToList();
if (id != null) {
ViewBag.SelectedApplicationId = (long)id;
}
else {
ViewBag.SelectedApplicationId = ViewBag.ApplicationList[0].ApplicationID; //just a safe default, if no param provided.
}
//handle profile list.
List<ProfileViewModel> ps = new List<ProfileViewModel>();
ps = (from p in config.GetProfilesByApp((long)ViewBag.SelectedApplicationId) select new ProfileViewModel(p)).ToList();
return View(ps);
}
//POST: Profile
//read the form post result, and recall Index, passing in the ID.
[HttpPost]
public ActionResult index(FormCollection collection) {
return RedirectToAction("Index", "Profile", new {id = collection["ApplicationId"]});
}
It would be really nice to get rid of the POST method, since this View only ever lists child entities.
What do you think?
You can update your GET action method parameter name to be same as your dropdown name.
I also made some small changes to avoid possible null reference exceptions.
public ActionResult Index(long? ApplicationID) {
var config = new ConfigManager();
var applicationList = config.GetApplications().ToList();
ViewBag.ApplicationList = applicationList ;
if (ApplicationID!= null) {
ViewBag.SelectedApplicationId = ApplicationID.Value;
}
else
{
if(applicationList.Any())
{
ViewBag.SelectedApplicationId = applicationList[0].ApplicationID;
}
}
var ps = new List<ProfileViewModel>();
ps = (from p in config.GetProfilesByApp((long)ViewBag.SelectedApplicationId)
select new ProfileViewModel(p)).ToList();
return View(ps);
}

Data does not refresh in browser but does in database

I have a working submit button, so when I make changes to my form and click submit the form updates to the changes...
HOWEVER. In the database it shows the new data. But when I RedirectToAction to the last page it doesn't show the updated data.
This is my code (Controller):
[HttpPost]
public ActionResult Save(M2Portal.Areas.Admin.Models.Users.Roles roleForm)
{
try
{
if (ModelState.IsValid)
{
var role = Srvctx.Roles.FirstOrDefault(w => w.RoleID == roleForm.RoleId);
role.RoleDescription = roleForm.RoleDescription;
Srvctx.SubmitChanges();
return RedirectToAction("RoleManagement");
}
return RedirectToAction("RoleManagement");
}
catch
{
return RedirectToAction("RoleManagement");
}
}
so when it hits:
return RedirectToAction("RoleManagement");
it just goes to the page but doesnt refresh the data. but when i look at my database its been changed there.
Am new to ASP.NET MVC and have no idea where to start looking...
Any ideas?
role mangagement:
public ActionResult RoleManagement(string userName)
{
return View("RoleManagement", new UserForm(userName));
}
Rolemangement cshtml:
#foreach (M2DAL.M2Service.Role r in Model.AllRoleIDs)
{
<tr>
<td>#r.RoleName</td> //This is not refreshing, on debug shows the number, but browser shows old number)
<td>#r.RoleID</td>
<td>#Html.ActionLink("Edit Roles", "EditRole", "Users", new { roleId = r.RoleID }, new { #class = "action" }) </td>
</tr>
}
You didn't post the code for RoleManagement action. I don't know where are you storing your model, but are you sure, that this action is reading the DB again ?
There should be something like (just an example)
[HttpGet]
public ActionResult RoleManagement()
{
var roles = Srvctx.Roles.Take(1000);
return roles;
}

Edit & Delete object with ViewModel

I've successfully implemented a viewmodel so I can create and return items from my database using two tables. My issue is editing and deleting individual items.
I was able to edit/delete when I was using just one table, but with two, i've run into a snag.
My view uses a viewmodel now. I am not able to figure out how to pass the specific object id when Passing an id and TransactionViewModel Viewmodel into my Edit method Parameters.
Here is my old Edit and Edit post.
public ActionResult Edit(int id = 0)
{
Transactions transactions = _db.Transactions.Find(id);
if (transactions == null)
{
return HttpNotFound();
}
return View(transactions);
}
[HttpPost]
//[ValidateAntiForgeryToken]
public ActionResult Edit(TransactionViewModel viewModel)
{
var transactionType = viewModel.Transaction.TransactionType;
if (ModelState.IsValid)
{
//If the transaction category is an Expense, set it to a negative so we can calculate later.
if (transactionType == Classes.Constants.Expense || (transactionType == Classes.Constants.Payment && viewModel.Transaction.Amount < 0))
{
viewModel.Transaction.Amount *= -1;
}
var transaction = new Transactions()
{
ClientId = viewModel.Transaction.ClientId,
Amount = viewModel.Transaction.Amount,
Date = viewModel.Transaction.Date,
Category = viewModel.Transaction.Category,
Description = viewModel.Transaction.Description,
TransactionType = viewModel.Transaction.TransactionType
};
_db.Entry(transaction).State = EntityState.Modified;
_db.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel);
}
I've tried this for my get Edit, but it returns the same thing each time and not the one specified on my view. Ex. If click edit for Client D, it will pull up the edit screen for Client A and I cannot save it. I have an edit and delete button in my viewable table next to each transaction using an #Html.ActionLink().
public ActionResult Edit(TransactionViewModel viewModel)
{
if (ModelState.IsValid)
{
var transactions = from t in _db.Transactions
join c in _db.Clients
on t.ClientId equals c.ClientId
select new TransactionViewModel() { Clients = c, Transaction = t };
return View(transactions.FirstOrDefault());
}
return RedirectToAction("Index");
}
Any help would be appreciated. Thanks!
I bet that view is being cached. There are many different ways to influence caching in the controller. If you want to simply remove cacheing, in your case for editing, then decorate that action with the following:
[OutputCache(NoStore = true, Duration = 0)]
public ActionResult Edit(TransactionViewModel viewModel)
[OutputCache(NoStore = true, Duration = 0)]
public ActionResult Edit(int id = 0)
Note: You will have to clear cache to get the new view with the no cache set above.
Your Get Edit method should still accept an int ID to select the correct record form the database and it should return the view model.
something like this:
public ActionResult Edit(int id = 0)
{
var transactions = from t in _db.Transactions
join c in _db.Clients
on t.ClientId equals c.ClientId
where t.id == id
select new TransactionViewModel() { Clients = c, Transaction = t };
return View(transactions.FirstOrDefault());
}

Foreach does not work while using json in asp.net mvc

,Hi all,
I am trying to use json.İf ı return to partial view ,i can not use foreach for my customer session.My Customer Session has customers.I can not list them.
Where i miss ?
CONTROLLER:
public ActionResult ShowResult(MyModel model)
{
Session["CustomerList"] = context.Customer.Where(s => s.CustomerSituation== true).ToList(); // Customers List To Session
var stringView = RenderRazorViewToString("_ShowResultPartial", model);
return Json(stringView, JsonRequestBehavior.AllowGet);
}
.
My _ShowResultPartial View:
#foreach (var item in (List<Q502351.Models.Customer>)Session["CustomerList"])
{
Ajax.ActionLink(item.CustomerName, "ShowResult", new { CustomerId = item.CustomerId}, new AjaxOptions { HttpMethod = "POST" });
}
From what you have posted, it's not clear why you want to store the customer list in session; data for the view should generally be stored on the view model. Even if you have a compelling reason to use session, it's a better practice to retrieve the session variables in the controller and store them in the view model. Then you should be able to loop through the list on the model from the view. In this situation it doesn't look like session is necessary at all (unless you intend to reuse the stored data later and for some reason cannot pass it along via models).
Also, unless there is a good reason to return json, your ShowResult controller method should just return a PartialView.
Something like this should work...
Controller:
public ActionResult ShowResult(MyModel model)
{
model.Customers = context.Customer.Where(s => s.CustomerSituation == true).ToList();
return PartialView("_ShowResultPartial"), model);
}
Partial view:
#model MyModel
#foreach (var item in Model.Customers)
{
Ajax.ActionLink(item.CustomerName, "ShowResult", new { CustomerId = item.CustomerId}, new AjaxOptions { HttpMethod = "POST" });
}

ASP.NET MVC: Server Validation & Keeping URL paramters when returning the view

I currently have the following code for the POST to edit a customer note.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditNote(Note note)
{
if (ValidateNote(note))
{
_customerRepository.Save(note);
return RedirectToAction("Notes", "Customers", new { id = note.CustomerID.ToString() });
}
else
{
var _customer = _customerRepository.GetCustomer(new Customer() { CustomerID = Convert.ToInt32(note.CustomerID) });
var _notePriorities = _customerRepository.GetNotePriorities(new Paging(), new NotePriority() { NotePriorityActive = true });
IEnumerable<SelectListItem> _selectNotePriorities = from c in _notePriorities
select new SelectListItem
{
Text = c.NotePriorityName,
Value = c.NotePriorityID.ToString()
};
var viewState = new GenericViewState
{
Customer = _customer,
SelectNotePriorities = _selectNotePriorities
};
return View(viewState);
}
}
If Validation fails, I want it to render the EditNote view again but preserve the url parameters (NoteID and CustomerID) for something like this: "http://localhost:63137/Customers/EditNote/?NoteID=7&CustomerID=28"
Any ideas on how to accomplish this?
Thanks!
This action is hit by using a post. Wouldn't you want the params to come through as part of the form rather than in the url?
If you do want it, I suppose you could do a RedirectToAction to the edit GET action which contains the noteId and customerId. This would effectively make your action look like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditNote(Note note)
{
if (ValidateNote(note))
{
_customerRepository.Save(note);
return RedirectToAction("Notes", "Customers", new { id = note.CustomerID.ToString() });
}
//It's failed, so do a redirect to action. The EditNote action here would point to the original edit note url.
return RedirectToAction("EditNote", "Customers", new { id = note.CustomerID.ToString() });
}
The benefit of this is that you've removed the need to duplicate your code that gets the customer, notes and wotnot. The downside (although I can't see where it does it here) is that you're not returning validation failures.

Resources