ASP .NET MVC 3 - Handle errors that occur in ActionResult DeleteConfirmed - asp.net-mvc-3

In a controller a error with Create/Edit ActionResult can be handled with a try-catch block with the error being displayed on the view (via ModelState.AddModelError).
Now I am trying something similar with the DeleteConfirmed ActionResult but there is no error appearing on the view page. The table I am trying to delete from should be complaining about deleting a foreign-key field value.
Should I RedirectToAction differently or add something else?
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
try
{
StatusList statuslist = db.Status.Find(id);
db.Status.Remove(statuslist);
db.SaveChanges();
}
catch (DataException dex)
{
ModelState.AddModelError("", dex.Message);
return RedirectToAction("Delete");
}
return RedirectToAction("Index");
}

If you do a redirect, you lost the ModelState.
So you can do two things imo.
Setting the error message in TempData["myerrorkey"] = dex.Message, so the message will "survive" for one redirect
Change your method and, in case of error, return a View so that the model state is not wiped out during the redirect
Personally I will choose the first. so you can think also to implement TempData in case of a delete telling the user, in the index page, that everything went smooth.

Related

Redirect in MVC controller to another controller not working

Hi Everyone , I am new to MVC but have programmed before. I have setup an error controller
which can be called when an error occurs in the main controller. My aim is to have one error view , which I can pass in the relevant error messages.
In the code below I am calling the error controller to displays the index view when there no record is returned from the product list
Here is my main controller
public ActionResult Details(int ProductID)
{
var model = db.Get(ProductID);
if (model == null)
{
//return RedirectToAction("Index", "ErrorController");
return errorController.Index("Record not Found", "The Product you are looking for is no longer available");
}
return View(model);
}
And this is my Error Controller that it calls successfully
public ActionResult Index(string errorTitle, string errorMessage)
{
ViewBag.ErrorTitle = errorTitle;
ViewBag.ErrorMessage = errorMessage;
return View();
}
At the moment the Index Action Result is called and the view returned but the details view from the original controller is also called, which causes an error as there is no records .
So my Error view is not being displayed .
How can I stop the original details view from being called ?
Any help would be great
Thanks
Try this-
return RedirectToAction("Index", "Error", new {
ErrorTitle = "Record not Found",
ErrorMessage = "The Product you are looking for is no longer available"
});
You basically need to redirect to the error controller and pass in the params as part of the route. RedirectToAction takes a parameter of RouteValues
Also you do not need "ErrorController", you can just use "Error"
Okay so generally in .net you don't want to pass along errors with redirects like that, instead you should use a library like Vereyon.Web FlashMessageCore which will help you with redirecting errors to the user in an easy and concise way.
However, if you want to do it that way (totally fine) you still need to pass the error title and error message like so in the redirect to action call:
return RedirectToAction("Index", "Error", new {errorTitle="error", errorMessage="message"});

Best way to handle a validations before a delete?

I need to be to perform validations during the Delete Action in my controller. Does ASP.net MVC3 have anything to assist with this type of validation? I know you can use the Attributes to handle edit validations but what about deletion?
For example i need to check the state of the entity object and if a certain condition is met they are not allowed to delete. What's the best way to check and display an error
You can have your delete action to be like the following, you can check for your condition by making a call like in the example below the method CanThiBeDeleted() does, if not then you can add an error to the Model State and send it back to the view, where this error message will be displayed.
public ActionResult Delete(string id)
{
if(!_service.CanThisBeDeleted(id))
{
ModelState.AddModelError("", "Sorry this cannot be deleted !");
return View();
}
bool isItemDeleted = false;
isItemDeleted = _service.DeleteItem(id);
if(isItemDeleted)
{
// if deleted send where you want user to go.
return RedirectToAction("Index");
}
else
{
ModelState.AddModelError("", "Delete operation failed.");
return View();
}
}
your view can have use #Html.ValidationSummary to display the errors/warnings you want to display.

How to update the textbox value #Html.TextBoxFor(m => m.MvcGridModel.Rows[j].Id)

I have problem, that the text box value doesn't get updated with the new value in the model.
#Html.TextBoxFor(m => m.MvcGridModel.Rows[j].Id)
First the collection MvcGridModel.Rows get populated with some data, then when press button and submit the form it get new data successfully, but it doesn't update the textbox's value.
Do you have any ideas?
Thank u in advance
That's because HTML helpers such as TextBoxFor first look in the ModelState when binding their values and only after that in the model. So if in your POST action you attempt to modify some value that was part of the initial POST request you will have to remove it from the ModelState as well if you want those changes to take effect in the view.
For example:
[HttpPost]
public ActionResult Foo(MyViewModel model)
{
// we change the value that was initially posted
model.MvcGridModel.Rows[0].Id = 56;
// we must also remove it from the ModelState if
// we want this change to be reflected in the view
ModelState.Remove("MvcGridModel.Rows[0].Id");
return View(model);
}
This behavior is intentional and it is by design. This is what allows for example to have the following POST action:
[HttpPost]
public ActionResult Foo(MyViewModel model)
{
// Notice how we are not passing any model at all to the view
return View();
}
and yet inside the view you get the values that the user initially entered in the input fields.
There's also the ModelState.Clear(); method that you could use to remove all keys from the modelstate but be careful because this also removes any associated modelstate errors, so it is recommended to remove only values from the ModelState that you intend to modify inside your POST controller action.
All this being said, in a properly designed application you should not need this. Because you should use the PRG pattern:
[HttpPost]
public ActionResult Index(MyViewModel model)
{
if (!ModelState.IsValid)
{
// there was some error => redisplay the view without any modifications
// so that the user can fix his errors
return View(model);
}
// at this stage we know that the model is valid.
// We could now pass it to the DAL layer for processing.
...
// after the processing completes successfully we redirect to the GET action
// which in turn will fetch the modifications from the DAL layer and render
// the corresponding view with the updated values.
return RedirectToAction("Index");
}

MVC3: PRG Pattern with Search Filters on Action Method

I have a controller with an Index method that has several optional parameters for filtering results that are returned to the view.
public ActionResult Index(string searchString, string location, string status) {
...
product = repository.GetProducts(string searchString, string location, string status);
return View(product);
}
I would like to implement the PRG Pattern like below but I'm not sure how to go about it.
[HttpPost]
public ActionResult Index(ViewModel model) {
...
if (ModelState.IsValid) {
product = repository.GetProducts(model);
return RedirectToAction(); // Not sure how to handle the redirect
}
return View(model);
}
My understanding is that you should not use this pattern if:
You do not need to use this pattern unless you have actually stored some data (I'm not)
You would not use this pattern to avoid the "Are you sure you want to resubmit" message from IE when refreshing the page (guilty)
Should I be trying to use this pattern? If so, how would I go about this?
Thanks!
PRG Stands for Post-Redirect-Get. that means when you post some data to the server back, you should redirect to a GET Action.
Why do we need to do this ?
Imagine you have Form where you enter the customer registration information and clicking on submit where it posts to an HttpPost action method. You are reading the data from the Form and Saving it to a database and you are not doing the redirect. Instead you are staying on the same page. Now if you refresh your browser ( just press F5 button) The browser will again do a similar form posting and your HttpPost Action method will again do the same thing. ie; It will save the same form data again. This is a problem. To avoid this problem, We use PRG pattern.
In PRG, You click on submit and The HttpPost Action method will save your data (or whatever it has to do) and Then do a Redirect to a Get Request. So the browser will send a Get Request to that Action
RedirectToAction method returns an HTTP 302 response to the browser, which causes the browser to make a GET request to the specified action.
[HttpPost]
public ActionResult SaveCustemer(string name,string age)
{
//Save the customer here
return RedirectToAction("CustomerList");
}
The above code will save data and the redirect to the Customer List action method. So your browser url will be now http://yourdomain/yourcontroller/CustomerList. Now if you refresh the browser. IT will not save the duplicate data. it will simply load the CustomerList page.
In your search Action method, You dont need to do a Redirect to a Get Action. You have the search results in the products variable. Just Pass that to the required view to show the results. You dont need to worry about duplicate form posting . So you are good with that.
[HttpPost]
public ActionResult Index(ViewModel model) {
if (ModelState.IsValid) {
var products = repository.GetProducts(model);
return View(products)
}
return View(model);
}
A redirect is just an ActionResult that is another action. So if you had an action called SearchResults you would simply say
return RedirectToAction("SearchResults");
If the action is in another controller...
return RedirectToAction("SearchResults", "ControllerName");
With parameter...
return RedirectToAction("SearchResults", "ControllerName", new { parameterName = model.PropertyName });
Update
It occurred to me that you might also want the option to send a complex object to the next action, in which case you have limited options, TempData is the preferred method
Using your method
[HttpPost]
public ActionResult Index(ViewModel model) {
...
if (ModelState.IsValid) {
product = repository.GetProducts(model);
TempData["Product"] = product;
return RedirectToAction("NextAction");
}
return View(model);
}
public ActionResult NextAction() {
var model = new Product();
if(TempData["Product"] != null)
model = (Product)TempData["Product"];
Return View(model);
}

Using modelstate.isvalid to validate data from inside the controller in MVC3

I am pretty new to ASP.NET MVC3 but i have about 4 years of experience with PHP frameworks.
I am trying to build an MVC3 web app, but i am having issues with validationg my model.
Here is a test controller to show you what i am trying without success to do.
I am trying to pass a value to my model inside the controller, but it doesnt take it into account the parameter.
I tried using modelstate.setmodelvalue, for junk.sentence, but it keeps the value from the POST request which is invalid an that i want to change by default (for test purposes) in the controller.
Can anyone help?
Thanks in advance.
Michael
[HttpPost]
public ActionResult Create(Junk junk)
{
//ModelState.Clear();
junk.sentence = "coucou";
ModelState.SetModelValue("sentence", new ValueProviderResult(junk.sentence, junk.number, null));
//ModelState
if (ModelState.IsValid)
{
db.Junks.Add(junk);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(junk);
}
//
// GET: /Junk/Edit/5
public ActionResult Edit(int id)
{
Junk junk = db.Junks.Find(id);
return View(junk);
}
Try removing it from modelstate:
[HttpPost]
public ActionResult Create(Junk junk)
{
junk.sentence = "coucou";
//ModelState
if (ModelState.IsValid)
{
db.Junks.Add(junk);
db.SaveChanges();
return RedirectToAction("Index");
}
ModelState.Remove("sentence");
return View(junk);
}
This assumes that in your view you have a corresponding input field that was generated using some of the Html helpers such as EditorFor for example:
#Html.EditorFor(x => x.sentence)
or:
#Html.TextBoxFor(x => x.sentence)
ModelState.IsValid returns false when there are model errors added to the model state. MVC validates the properties on your model and creates a list of errors for you in the ModelState. You must remove the errors from the model state that you wish to be ignored from inside your controller action. You can then update the actual values on the model. (Darin Dimitrov shows you an example of doing this)

Resources