MVC Redirect not working properly - c#

Hi I AM using Database first approach in my MVC project. I have an action where I am calling Stored procedure when user clicks on Accept terms.
Here as soon as i calling this stored procedure, in my table it is storing current date and making termsaccepted field from false to true. It is working fine. I have condition like only when user accepted terms they can redirect to Default page. But even after calling stored procedure and updating date it is not redirecting to Default page.
And what I observed is, if i close and open my solution, then it is taking latest value stored in database and then it is redirecting to page which i need.
So how can i redirect to page as soon as value updated in my database without restarting Visual Studio ?
My Action :
public ActionResult Termspage()
{
TermsEntities updateterms = new TermsEntities();
var ID = Session["userID"];
if (ID != null)
{
updateterms.usp_UpdateUserTerms(Convert.ToInt32(ID), true);
updateterms.SaveChanges();
}
return View();
}
My View :
<body>
<div>
#using (Html.BeginForm("DefaultPage", "Home", FormMethod.Post, new { id = "frmIndex" }))
{
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td>
<input type="submit" value="Accept Terms & Condition" />
</td>
</tr>
</table>
}
</div>
</body>
Here it's not redirecting to Defaultpage action even after details are updated in my database. But when i reopen my solution then it is redirecting to Defaultpage.
Update :
I tried to use redirecttoAction but when I use this I am getting This webpage has redirect loop error

Try PostRedirectGet method in MVC using RedirectToAction
public ActionResult Termspage()
{
TermsEntities updateterms = new TermsEntities();
var ID = Session["userID"];
if (ID != null)
{
updateterms.usp_UpdateUserTerms(Convert.ToInt32(ID), true);
updateterms.SaveChanges();
return RedirectToAction("Detail", new {id=ID})
}
}
Then
public ActionResult Detail(int id)
{
// get record
return View();
}

Related

See ASP.NET MVC Index page in C# be populated with data from model without ID in the URL

In my application I am using Entity Framework 6 and ASP.NET MVC in C#.
I have a table that has records that I plan on populating my Index page with. How do I populate the index page without having the system add the id of the record to the URL. See example below. I have already looked at routing but with adding custom route you are forced to add more text to the url when all I want is the URL to show up as example.com. I don't want and don't need example.com/MenuRecords/Details/20 for a user to see.
So example.com should load the following data from the model below in the index view of the HomeController.
index.cshtml page calling the model data shown below:
#model example.Models.tblMenuRecords
#Model.ThisWeeksBestDrink
#Model.ThisWeeksBestAppetizer
#Model.ThisWeeksBestDesert
#Model.ThisWeeksBestLunchSpecial
This is the cntroller action method:
public ActionResult Index()
{
return View();
}
How do I get that to work properly for the Index page? Since this is the home page that is calling data from a model I cannot have the URL have anything other than example.com .... but I do understand that when calling data from a model you do need some sort of ID but I just do not really understand how to do that.
I know that there is the route config that includes this default route that allows you to show only the name of the domain...But how is this done when you are trying to load data from the database.
routes.MapRoute("Default", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }
Is this the correct way to pass an instance of the tblMenuRecords to the view?
public ActionResult Index()
{
tblMenuRecords tblMenuRecords = db.tblMenuRecords();
return View(tblMenuRecords);
}
I think you have to fix the action
public ActionResult Index()
{
tblMenuRecords tblMenuRecords = db.tblMenuRecords.FirstOrDefault();
return View(tblMenuRecords);
}
I think your view is missed with model. View code should be like below
#model Models.MenuRecords
#{
ViewBag.Title = "Menu Records";
}
<h2>Details</h2>
<div>
<h4>Menus</h4>
<hr />
<table>
<tr>
<td>
#Html.DisplayFor(model => model.ThisWeeksBestDrink)
</td>
<td>
#Html.DisplayFor(model => model.ThisWeeksBestLunchSpecial)
</td>
</tr>
</table>
</div>
I hope, it will help you.

Action not being hit from another controller

I am asking a simple login page to get the user to enter a pin on a mobile responsive app its in house not online.
When the page is posted the user clicks the submit button the SaveUsers is the function that is called first this is on the Login Controller.
[HttpPost]
[ActionName("Index")]
public ActionResult SaveUsers(Users model)
{
BrianScott_SOMEntities usr = new BrianScott_SOMEntities();
var s = usr.GetUsers(model.Pin);
var item = s.FirstOrDefault();
if (item == "Success")
{
var sageDetails = usr.Users.Where(w => w.Pin ==model.Pin).FirstOrDefault();
HttpCookie cookie = new HttpCookie("BScotSalesOrderManagerLogin");
cookie.Values.Add("SageUserName", sageDetails.SageUserName.ToString());
cookie.Values.Add("SagePassword", sageDetails.SagePassWord.ToString());
cookie.Expires = DateTime.Now.AddDays(30);
Response.Cookies.Add(cookie);
return View("~/Views/Home/Index.cshtml");
}
else if (item == "User Does not Exists")
{
ViewBag.NotValidUser = item;
}
else
{
ViewBag.Failedcount = item;
}
return View("Index.cshtml");
}
The below form is the form that is represented with the above controller which prompts the user for their pin number.
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
#model Web.SOM.Models.Users
#using (Html.BeginForm())
{
<div class="bs-example" style="border:2px solid gray;">
<label>#ViewBag.SageUserName</label>
<div class="form-group centerlook">
<h1> Login </h1>
</div>
<div class="form-group centerlook">
<label>Pin: </label>
#Html.EditorFor(model => model.Pin )*
#Html.ValidationMessageFor(model => model.Pin)
</div>
<div class="form-group error">
#if (#ViewBag.Failedcount != null)
{
<label> Failed Attempt count is: #ViewBag.Failedcount</label>
}
#if (#ViewBag.NotValidUser != null)
{
<label> #ViewBag.NotValidUser</label>
}
</div>
<div class="loginbtn">
<input type="submit" value="Login" class="btn btn-primary" />
</div>
</div>
}
The home controller is what the controller in the first piece of codes redirects to it is the index action to which I want to hit.
public ActionResult Index()
{
if (Request.Cookies["BScotSalesOrderManagerLogin"] != null)
{
ViewBag.SageUserName = Request.Cookies["BScotSalesOrderManagerLogin"].Values["SageUserName"];
ViewBag.SagePassword = Request.Cookies["BScotSalesOrderManagerLogin"].Values["SagePassword"];
}
return View();
}
But the method is not getting hit unless I do a hard reload is there another way of moving to the other view and making sure that the index method is being hit ?.
Because when I look at the viewbag the items are null when they should contain a username and a password of the related row when I debug on the first page the values are their but then lost on the other page.
On my page i am wanting to display the information I am just doing
<label>Sage Username : #ViewBag.SageUserName </label>
But the value is blank? I am coming from a web forms background so please excuse me better late than never jumping ship
Your sequence of events is...
User POSTs to SaveUsers on Login (aliased as the action Index)
You return a view
User POSTs from that view to Index, still on Login
When you do this:
return View("~/Views/Home/Index.cshtml");
You're essentially overriding the framework's standard behavior. You're returning a specific file to be used as the view, but not telling the framework to switch any context or change the URL in any way. So from the browser's perspective, even though you returned a view from your server-side Home folder, the page is still /Login/Index and any form actions, links, etc. will be from there.
In general you should prefer redirects to manually specifying views. So a sensible sequence of events might be:
User POSTs to SaveUsers on Login (aliased as the action Index)
Server-side code performs its logic, redirects the user to Index on Home
User GETs Index on Home
Server returns the view
User POSTs to Index on Home
So your SaveUsers action method, when successful, can do something like:
return RedirectToAction("Index", "Home");
This will then cause the user to make a GET request to Index on Home, which can just return View() and that will default to the view you're manually returning now. Now from the browser's perspective it's on /Home/Index and all form actions, links, etc. will be from that context.
Additionally, if you always want a given form, link, etc. to point to a specific controller action regardless of where it was loaded from, you can specify that. For example, when you do this:
using (Html.BeginForm())
You are telling the framework that this form will "POST to the current URL, whatever that URL is". But when you do this:
using (Html.BeginForm("Index", "Home"))
This tells the framework that the form will always post to the Index action on the Home controller, regardless of the current URL.
can you try using
#using (Html.BeginForm(yourActionName, yourControllerName))
{
}
And use RedirectToAction to return to your Home Index..

Best way to handle add/view/delete on one page

What I want to do
I am very new to MVC.
I'm trying to create a page that allows users to perform the following actions on the same page:
View the list (table)
Add a new item (Filling the form and clicking the Add button should update the table)
Delete an item from the list (Clicking the Delete button in a row should update the table)
A simple example looks like this but I actually have two lists on one page (Fees and Costs):
Question
What would be the best way to achieve this?
Should I go with Dylan Beattie's method posted here which would look something like this?
public ActionResult MyAction(string submitButton, MyViewModel form)
{
switch (submitButton)
{
case "AddFee":
return (AddFee(form));
case "AddCost":
return (AddCost(form));
case "RemoveFee":
return (RemoveFee(form));
case "RemoveCost":
return (RemoveCost(form));
}
}
public ActionResult AddFee(MyViewModel form)
{
Fee newFee = ....; // Get entered data from `form`
_repository.InsertFee(newFee);
return View("Create"); //Back to the original page
}
Or is there any other recommended methods to handle this such as using JavaScript?
You could create the table as a partial view and re render this via ajax.
Wrap the partial view in a div and Wrap the form in #using (Ajax.BeginForm(.... and target the wrapper div. Your controller action that is targeted by the ajax request will need to return a partial view.
Here is a simple example
public class HomeController : Controller
{
public ActionResult Index()
{
MYvm vm = new MYvm() { id = 1, name = "This is my View Model" };
return View(vm);
}
public ActionResult DA(MYvm vm)
{
vm.name = "CHANGED";
return PartialView("Part", vm);
}
View:
#model MvcApplication1.Controllers.HomeController.MYvm
#{
ViewBag.Title = "Home Page";
}
#using (Ajax.BeginForm("DA", "Home", new AjaxOptions() { UpdateTargetId = "cont", HttpMethod = "Get" }))
{
<div>
Id: #Html.EditorFor(model => model.id)
</div>
<div>
Name: #Html.EditorFor(model => model.name)
</div>
<input type="submit" value="SubmitForm" />
}
<div id="cont">
#{Html.RenderPartial("part", Model);}
</div>
Partial View
#model MvcApplication1.Controllers.HomeController.MYvm
#{
ViewBag.Title = "part";
}
<h2>part</h2>
#Model.name
Should I go with [previous SO answer]
No. That answer was for a different scenario where the question had a form with two submit buttons that wanted to do two different actions (and wasn't even the accepted answer to that question).
Your sample screenshot indicates that some javascript/jquery and ajax would solve the issue cleanly.
As you're new to MVC, try to keep it relatively simple. Break up the page into separate parts:
the containing page
the edit form
the list with remove
the edit/list work independently and should be written in a way that they could be put on any other page - the page is just there to contain them and doesn't do much else (obviously your real page will contain more, but add those parts as separate components as well).
1 Create actions for your list and edit forms that return partialviews - just the parts that are needed for that view (self-contained)
controller:
[HttpGet]
public ActionResult AddCost()
{
var model = new Cost();
return PartialView(model);
}
[HttpPost]
public void AddCost(Cost model)
{
if (ModelState.IsValid) {
db.SaveCost(model);...
}
}
form Views/Home/AddCost.cshtml:
#using (Ajax.BeginForm(...
{
<div class='editor-label'>#Html.LabelFor(model=>model.Description)</div>
...etc...
}
I'll leave you to set the Ajax.BeginForm properties. But make sure the on-success calls reloadCostList() (see below)
controller
public ActionResult CostList()
{
var model = db.loadCosts(); ...
return PartialView(model);
}
list, Views/Home/CostList.cshtml
#model IEnumerable<ViewModels.Cost>
<table>
<thead>
<tr>
<th>Cost Description</th>
...
<tbody>
#foreach (var cost in Model.Costs)
{
<tr data-id='#cost.Id'>
<td>#Html.DisplayFor(x=>cost.Description)</td>
...
<td><a href='#' class='remove-button'>Remove</a></td>
}
...
2 Create an action + view for the main page with placeholder for the form and calls the list partial-action, eg:
<div id="body">
<div id="formWrapper">
#Html.Action("AddCost")
</div>
<div id="listWrapper">
#Html.Action("ListView")
</div>
</div>
if you already load the data for the page, you can pass it directly to the partial, but there's no need:
#Html.Partial("ListView", Model.Costs)
this allows you to refresh the list via an ajax call, something like:
function reloadCostList() {
$(".listWrapper").load("Home/CostList");
}
(ideally, $.ajax and add some fancy UI to indicate loading)
3 Add a remove action to your controller
[HttpPost]
public void RemoveCost(int id)
{
}
4 Wire up the Remove link
$(function() {
$(".remove-button").click(function() {
var id = $(this).closest("tr").attr("id");
$.post("/Home/RemoveCost/" + id, null, function() {
$(".listWrapper").load("Home/CostList");
// or reloadCostList(); from above
// or:
//$(".listWrapper tr[id=" + id + "]").hide();
});
});
}
rather than re-load the entire list, you could just remove the row (add some fancy UI like fade-out...)

EPiServer MVC currentPage issues

I'm currently having some problems with the following codesnippets which seems almost identical to me, but behaves differently.
These snippets are from two different projects I've been working on, and they are built the same way but only one of them works correctly.
These are the Forms where I enter the controllers:
Form 1, inside a twitter bootstrap dropdown menu, located in the _Layout file:
#using (Html.BeginForm("EditProfile", "ProfilePage", FormMethod.Post))
{
<li>
<button type="submit" class="dropdownButton">Redigera Profil</button>
</li>
}
Form 2, tried different locations but right now it's in a table in a Block view:
<td>
#using (Html.BeginForm("EditProfile", "ProfilePage", FormMethod.Post))
{
<button type="submit">Redigera profil</button>
}
</td>
Both seems pretty identical, right?
Now here are the controllers
Controller 1:
public ActionResult EditProfile(ProfilePage currentPage)
{
var model = new ProfilePageViewModel(currentPage);
model.CurrentUser = ConnectionHelper.GetUserInformationByEmail(User.Identity.Name);
return View("EditProfile", model);
}
Controller 2:
public ActionResult EditProfile(ProfilePage currentPage)
{
ProfilePageViewModel model = new ProfilePageViewModel(currentPage);
model.currentUser = ConnectionHelper.GetCurrentUserByEmail(User.Identity.Name);
return View("EditProfile", model);
}
Also pretty much identical.
I've added the same routing in both projects:
protected override void RegisterRoutes(RouteCollection routes)
{
base.RegisterRoutes(routes);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" });
}
Now here's the problem:
Form 1 and controller 1 works perfectly and recieves the ProfilePage currentPage without any problems, but form 2 and controller 2 doesn't work and gets null value.
As I stated earlier Form 1 is posted on the _Layout page and Form 2 is posted from a Block which is rendered within an mvc #section. I don't think this is the problem because I've tried to access the controller from different parts of the page, but it's not working anywhere - but in the other project it's working everywhere, which is driving me insane.
Does anyone have any idea why it is like this? I've stepped through both of them while debugging but the only difference is that one works and the other doesn't.
Thanks in advance
deSex
EDIT :
Here I render a section called "content", where almost everything will be rendered.
<div id="content">
#RenderBody()
#RenderSection("content", false)
</div>
My startpage has a ContentArea for blocks, rendered within this section:
#model Intranet.Models.ViewModels.StartPageViewModel
#section content{
#if (User.Identity.IsAuthenticated)
{
<div class="contentArea">
#Html.PropertyFor(x => x.MainContentArea)
</div>
}
}
And here is the controller that inherits from BlockController:
public class ProfileBlockController : BlockController<ProfileBlock>
{
public override ActionResult Index(ProfileBlock currentBlock)
{
ProfileBlockViewModel model;
if (currentBlock != null)
{
model = new ProfileBlockViewModel(currentBlock);
}
else
{
model = (ProfileBlockViewModel)Session["model"];
}
model.CurrentUser = ConnectionHelper.GetCurrentUserByEmail(User.Identity.Name);
var availableStatuses = ConnectionHelper.GetAllOfficeStatuses();
availableStatuses.Remove(model.CurrentUser.OfficeStatus);
model.AvailableStatusChanges = availableStatuses;
Session["model"] = model;
return PartialView(model);
}
}
The "currentPage" route value (i.e. parameter) will only be set by EPiServer's page route. It will always be null in a block controller.
However, you can get the page of the current request in a block controller with:
PageRouteHelper.Page
If the block is being rendered as part of a request for a profile page, you'll be able to get that profile page through PageRouteHelper.

MVC3 - Multiple Ajax forms in a partial view are all filled with the same data on refresh

I'm learning MVC3 and building a little "to-do" website as a learning exercise, so I'm open to the idea that I'm just completely going down the wrong path!
Anyway, I have a page working perfectly with regular postbacks. I'm trying to Ajax it up with jQuery and UnobtrusiveAjax and everything still technically works correctly (the data is passed to the controller and saved in my database). The problem is that in the element I replace, each form's fields are all filled with the values that I just passed in on the one form.
Index.cshtml
#model WebUI.Models.HomeViewModel
#{
ViewBag.Title = "Index";
<script src="#Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
}
<h2>My Goals</h2>
...snip...
<div id="goal_div">
#foreach (var goal in Model.Goals)
{
Html.RenderPartial("GoalDetail", goal);
}
</div>
GoalDetail.cshtml
#model Domain.Entities.Goal
<div class="goal" id='goal_id#(Model.ID)'>
<h4>#Model.Name</h4>
<p>#DateTime.Now.ToString()</p>
<p class="goal_description">#Model.Progress % complete</p>
<ul>
#foreach (var task in Model.Tasks)
{
using (Ajax.BeginForm("UpdateTask", "Home", new AjaxOptions { UpdateTargetId = "goal_id" + Model.ID }))
{
#Html.HiddenFor(g => g.ID)
#Html.Hidden("TaskID", task.ID)
<li class="task">
#Html.CheckBox("IsComplete", task.IsComplete)
#Html.TextBox("TaskName", task.Name)
#task.Name
<input class="actionButtons" type="submit" value="Update task" />
</li>
}
}
<li>
#using (Html.BeginForm("AddTask", "Home"))
{
#Html.HiddenFor(g => g.ID)
#Html.Editor("TaskName")
<input class="actionButtons" type="submit" value="Add task" />
}
</li>
</ul>
</div>
HomeController.cs
public class HomeController : Controller
{
private IGoalRepository Repository;
public HomeController(IGoalRepository repo)
{
Repository = repo;
}
public ViewResult Index()
{
HomeViewModel viewModel = new HomeViewModel();
viewModel.Goals = Repository.Goals;
return View(viewModel);
}
public ActionResult AddTask(int ID, string TaskName)
{
bool success = Repository.SaveTask(ID, 0, TaskName, DateTime.Today, false);
return RedirectToAction("Index");
}
public ActionResult UpdateTask(int ID, int TaskID, bool IsComplete, string TaskName)
{
bool success = Repository.SaveTask(ID, TaskID, TaskName, DateTime.Today, IsComplete);
Goal updatedGoal = Repository.Goals.FirstOrDefault(g => g.ID == ID);
return PartialView("GoalDetail", updatedGoal);
}
public ActionResult AddGoal(string Name, DateTime Enddate)
{
bool success = Repository.SaveGoal(0, Name, DateTime.Today, Enddate);
return RedirectToAction("Index");
}
public ActionResult UpdateGoal(int GoalID, string Name, DateTime Enddate)
{
bool success = Repository.SaveGoal(GoalID, Name, DateTime.Today, Enddate);
return RedirectToAction("Index");
}
}
I have the time there just to make sure that the AJAX refresh has actually happened, and you'll see why I have the task name there twice.
This is what I see when I first load the page:
Then I check the checkbox of the the 2nd task of the 1st goal, rename it "Updated Task #2", and click the update button. That's when this happens:
Seeing how the task names NOT part of the form are all correct (ignoring the re-ordering for now), and the progress value has been updated correctly (it just takes the completed tasks and divides by the total number of tasks), I have no idea why all the form values have been replaced. Even the AddTask form has been filled in, even though I haven't changed that one to use Ajax yet. I've been searching for reasons for this for 2 days now, and have come up empty.
After even more searching, I finally discovered the issue. Basically, it has to do with the way ModelState works in MVC. Reading this help thread and this article really helped me understand what was happening with my page. I ended up calling ModelState.Clear() in my controller right before returning the partial view, but this SO question and answer
suggests another method.

Categories

Resources