Use single post action method for multiple views - asp.net-mvc

I have an sms sms application, which has different templates that users can use to send their SMSs, I used different view to represent different templates, however I want to use one action method to send an SMS, i might be different templates but at the end of the day user will send an sms which has two parameters, message itself and cell number to which this sms is to be send to,
Here is my 3 templates for now
[HttpGet]
public ActionResult BookingServiceReminder()
{
return View();
}
[HttpGet]
public ActionResult ServiceReminder()
{
return View();
}
[HttpGet]
public ActionResult DetailedReminder()
{
return View();
}
[HttpPost]
public ActionResult SendSMS(string message, string cellNumber)
{
if (_dbManager.SendSMS(cellNumber, message, User.Identity.Name))
{
TempData["Success"] = "Message was successfully sent";
}
else
{
TempData["Error"] = "An error occured while sending the message";
}
return RedirectToAction("BookingServiceReminder");
}
My question is, is there a way of using one method for all this views, I dont want to have multiple post methods which will almost have same code except the redirectToAction on which I want to return then current view(current template).

Yes, you can.
You would need to keep track someway that at which action user should be redirected after sending the sms.
One way for it is you can pass the flag back to view and post it as hidden field to determine that which action should be redirected to :
[HttpGet]
public ActionResult BookingServiceReminder()
{
ViewBag.RedirectTo = "BookingServiceReminder";
return View();
}
[HttpGet]
public ActionResult ServiceReminder()
{
ViewBag.RedirectTo = "ServiceReminder";
return View();
}
[HttpGet]
public ActionResult DetailedReminder()
{
ViewBag.RedirectTo = "DetailedReminder";
return View();
}
and in View you can have a hidden field which would post to action :
<input type="hidden" value="#ViewBag.RedirectTo" name="RedirectTo">
and in action add a new paramter:
[HttpPost]
public ActionResult SendSMS(string message, string cellNumber,string RedirectTo)
{
if (_dbManager.SendSMS(cellNumber, message, User.Identity.Name))
{
TempData["Success"] = "Message was successfully sent";
}
else
{
TempData["Error"] = "An error occured while sending the message";
}
return RedirectToAction(RedirectTo);
}

Related

show status after post and keep entered model as is on MVC view

I have this mvc controller that add a customer to the database called CustomerController. This Controller has one ActionResult called Add. It works as it is but I want to display a status message after the user hit submit, and I want all information added to the model be kept on the page as is. How can I keep the all the entered text in the form fields and also show a status message after the form has been posted?
public ActionResult Add()
{
// This is the empty view the user see when he is about to add new form data
return View(new CreateSupplierViewModel());
}
public ActionResult AddNew(CreateSupplierViewModel model)
{
// I post to this and need to display the status of this on the view with the entered text fields as is
return RedirectToAction("Add", "Supplier");
}
You need to refactor your code as below :
The CustomerController :
public ActionResult Add()
{
return View(new CreateSupplierViewModel());
}
public ActionResult Add(CreateSupplierViewModel model)
{
return View(model);
}
public ActionResult AddNew(CreateSupplierViewModel model)
{
return RedirectToAction("Add", "Supplier", model);
}
Your SupplierController
public ActionResult Add(CreateSupplierViewModel model)
{
//save the entity
Viewbag.Message ="submit result";
return RedirectToAction("Add", "Customer", model);
}
The Customer/Add.cshtml (show the submit result in view)
#if( Viewbag.Message != null)
{
<p> #Viewbag.Message </p>
}

How to go to some controllers method from another?

I have this controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public PartialViewResult SearchData(DataClass dc)
{
//Some logic
return PartialView(data);
}
public ActionResult Search(DataClass dc)
{
//Some logic
return View(dc);
}
[HttpGet]
public ActionResult Info(string edrpou)
{
//Some logic
return View(dc);
}
[HttpPost]
public ActionResult Info(DataClass dc)
{
// ???
return View("Search", dc);
}
}
In view Search.cshtml I have some forms like
#Html.TextBoxFor(x => x.Param, new { #class = "form-control", #id = "textBox" })
to create query string and <input type="submit" /> to confirm. Then I show some info from db and create link
#Html.ActionLink((string)Model.Rows[i]["NAME"], "Info", "Home", new { edrpou = (string)Model.Rows[i]["EDRPOU"] }, null)
after pressing it redirected to view Info.cshtml. In result I get /Home/ResultInfo?edrpou=41057472 page with some info and forms like in Search
After pressing confirm button in Info reference still /Home/ResultInfo?edrpou=41057472 but I expect to use logic from Search after pressing that button.
P.S. PartialViewResult triggered in Search and it exactly what I need by pressing confirm button in Info
Thank you for help!
Looks like you need RedirectToAction:
[HttpPost]
public ActionResult Info(DataClass dc)
{
// some specific logic, if any
return RedirectToAction("Search");
}
And because you need to move around the DataClass object, you could also use TempData:
[HttpPost]
public ActionResult Info(DataClass dc)
{
// some specific logic, if any
TempData['data'] = dc; //of course 'data' is not a good name, use something more specific
return RedirectToAction("Search");
}
public ActionResult Search(DataClass dc)
{
if (dc == null && TempData.ContainsKey('data'))
dc = (DataClass)TempData['data'];
//Some logic
return View(dc);
}
Alternatively you could just call Search directly, but that's not as nice, because it won't redirect user to the correct route: it will appear as though user is still on "info" page while in reality they are already on "search".

Reusing Controller Action based on ViewModel

I will have a registration form on my website which will firstly show the boardrules / legal. Once accepted it will then show the main registration form. Using a ViewModel as below:
public class MyViewModel
{
public int Readrules { get; set; }
public int Coppa { get; set; }
}
public ActionResult Register(MyViewModel model)
{
... at this stage model.Readrules and model.Coppa will contain the values passed
as query string parameters tat you could use here
}
The idea is if I go to /register it will show the rules and then /register?readrules=1 it will then show the registration form. This is how it was done in PHP but now I am migrating to ASP.NET..
What is the best way of doing this? Can I redirect to the same action and just parse the value of model.ReadRules or must I use more than one action? I would prefer to keep this in one action and just check if model.ReadRules == 1 and either display the boardrules or registration form.
Thanks
Instead of re-using the Register action, you could have different controller actions for displaying the rules, registering and processing the registration, like so:
Controller Actions:
public ActionResult BoardRules()
{
return View();
}
public ActionResult Register(MyViewModel model)
{
if (model.ReadRules != 1)
return RedirectToAction("BoardRules");
return View();
}
public ActionResult Registration(MyViewModel model)
{
if (model.ReadRules != 1)
return RedirectToAction("BoardRules");
//Process the registration
return View();
}
Views:
BoardRules.cshtml:
#* HTML Displaying Rules *#
Accept Rules
Register.cshtml:
#using (Html.BeginForm("Registration", "[Controller Name]", new { ReadRules = 1 }))
{
#* Form Fields *#
<input type="submit" value="Process Registration" />
}
Registration.cshtml
<h2>Congratz on Registering!</h2>
public ActionResult Register()
{
return View("boardrules"); //Default
}
public ActionResult Register(MyViewModel model)
{
if (model.ReadRules == 1)
{
model.ReadRules++; //Next time it won't be 1 but step 2
return View("registration",model);
}
else
{
//Do IF or Case for other step
}
return View("boardrules"); //Default
}

ASP.net MVC4 Clear Model Values

So I have a simple action in my controller. The project is a MVC Mobile Application.
public ActionResult Index()
{
return View();
}
this gives an form to enter data. I then handle the data in the post back.
[HttpPost]
public ActionResult Index(ScanViewModel model)
{
if (ModelState.IsValid)
{
Scan ns = new Scan();
ns.Location = model.Location;
ns.Quantity = model.Quantity;
ns.ScanCode = model.ScanCode;
ns.Scanner = User.Identity.Name;
ns.ScanTime = DateTime.Now;
_db.Scans.Add(ns);
_db.SaveChanges();
}
return View(model);
}
I want to clear the fields in the form and allow users to enter data again. However I get the exact same values back into my inputs. How can I clear them in the controller.
Just call this.ModelState.Clear()
You should follow the PRG pattern.
Just redirect to the Action method which is meant for the Create Screen. You can use the RedirectToAction method to do so.
RedirectToAction returns an HTTP 302 response to the browser, which causes the browser to make a GET request to the specified action.
[HttpPost]
public ActionResult Index(ScanViewModel model)
{
if(ModelState.IsValid)
{
//Code for save here
//..............
_db.SaveChanges();
return RedirectToAction("Index","User");
}
return View(model);
}
public ActionResult Index()
{
return View();
}
Assuming your controller name is UserController.

Passing a variable from [HttpPost] method to [HttpGet] method

I am redirecting the view from [HttpPost] method to [HttpGet] method. I have gotten it to work, but want to know if this is the best way to do this.
Here is my code:
[HttpPost]
public ActionResult SubmitStudent()
{
StudentViewModel model = TempData["model"] as StudentResponseViewModel;
TempData["id"] = model.Id;
TempData["name"] = model.Name;
return RedirectToAction("DisplayStudent");
}
[HttpGet]
public ActionResult DisplayStudent()
{
ViewData["id"] = TempData["id"];
ViewData["name"] = TempData["name"];
return View();
}
View:
<%# Page
Language="C#"
Inherits="System.Web.Mvc.ViewPage"
%>
<html>
<head runat="server">
<title>DisplayStudent</title>
</head>
<body>
<div>
<%= ViewData["id"]%> <br />
<%= ViewData["name"]%>
</div>
</body>
</html>
There are basically 3 techniques in ASP.NET MVC to implement the PRG pattern.
TempData
Using TempData is indeed one way of passing information for a single redirect. The drawback I see with this approach is that if the user hits F5 on the final redirected page he will no longer be able to fetch the data as it will be removed from TempData for subsequent requests:
[HttpPost]
public ActionResult SubmitStudent(StudentResponseViewModel model)
{
if (!ModelState.IsValid)
{
// The user did some mistakes when filling the form => redisplay it
return View(model);
}
// TODO: the model is valid => do some processing on it
TempData["model"] = model;
return RedirectToAction("DisplayStudent");
}
[HttpGet]
public ActionResult DisplayStudent()
{
var model = TempData["model"] as StudentResponseViewModel;
return View(model);
}
Query string parameters
Another approach if you don't have many data to send is to send them as query string parameters, like this:
[HttpPost]
public ActionResult SubmitStudent(StudentResponseViewModel model)
{
if (!ModelState.IsValid)
{
// The user did some mistakes when filling the form => redisplay it
return View(model);
}
// TODO: the model is valid => do some processing on it
// redirect by passing the properties of the model as query string parameters
return RedirectToAction("DisplayStudent", new
{
Id = model.Id,
Name = model.Name
});
}
[HttpGet]
public ActionResult DisplayStudent(StudentResponseViewModel model)
{
return View(model);
}
Persistence
Yet another approach and IMHO the best consists into persisting this model into some data store (like a database or something and then when you want to redirect to the GET action send only an id allowing for it to fetch the model from wherever you persisted it). Here's the pattern:
[HttpPost]
public ActionResult SubmitStudent(StudentResponseViewModel model)
{
if (!ModelState.IsValid)
{
// The user did some mistakes when filling the form => redisplay it
return View(model);
}
// TODO: the model is valid => do some processing on it
// persist the model
int id = PersistTheModel(model);
// redirect by passing the properties of the model as query string parameters
return RedirectToAction("DisplayStudent", new { Id = id });
}
[HttpGet]
public ActionResult DisplayStudent(int id)
{
StudentResponseViewModel model = FetchTheModelFromSomewhere(id);
return View(model);
}
Each method has its pros and cons. Up to you to choose which one suits best to your scenario.
If you are inserting this data into a database then you should redirect them to a controller action that has this data in the route:
/Students/View/1
You can then write code in the controller to retrieve the data back from the database for display:
public ActionResult View(int id) {
// retrieve from the database
// create your view model
return View(model);
}
One of the overrides of RedirectToAction() looks like that:
RedirectToAction(string actionName, object routeValues)
You can use this one as:
[HttpPost]
public ActionResult SubmitStudent()
{
StudentViewModel model = TempData["model"] as StudentResponseViewModel;
return RedirectToAction("DisplayStudent", new {id = model.ID, name = model.Name});
}
[HttpGet]
public ActionResult DisplayStudent(string id, string name)
{
ViewData["id"] = TempData["id"];
ViewData["name"] = TempData["name"];
return View();
}
Hope that works.
This is the classic Post-Redirect-Get pattern (PRG) and it looks fine but I would add one bit of code. In the DisplayStudent method check if your TempData variables are not null otherwise do a redirect to some default Index action. This is in case a user presses F5 to refresh the page.
public ActionResult DisplayStudent()
{
if(TempData["model"] == null)
{
return RedirectToAction("Index");
}
var model = (StudentResponseViewModel)TempData["model"];
return View(model);
}
public ViewResult Index()
{
IEnumerable<StudentResponseViewModel> students = GetAllStudents();
return View(students);
}

Resources