Best way to handle a validations before a delete? - asp.net-mvc-3

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.

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"});

Retaining failed validation data

I've got a requirement to keep and display an incorrect entry on the view. It isn't possible to go to the next page without passing all validation.
For example, the use has to enter a date in text field in a certain format. Currently if the model binding fails it doesn't keep the invalid date text entry. I'd like to keep t and display it back to user with a vanadium failed message.
I'd like to know if this is achievable without creating a data holder type which temporarily hold the entered game and parsed value.
Yes, it is possible. Because you haven't posted any code, I'll just give you an example of how this can be achieved using server side validation.
Here is the [HttpGet] action method that serves up the form allowing the user to enter data.
[HttpGet]
public ActionResult Create()
{
// The CreateViewModel holds the properties and data annotations for the form
CreateViewModel model = new CreateViewModel();
return View(model);
}
Here is the [HttpPost] action method that receives and validates the form.
[HttpPost]
public ActionResult Create(CreateViewModel model)
{
if (!ModelState.IsValid)
{
return Create(); // This will return the form with the invalid data
}
// Data is valid, process the form and redirect to whichever action method you want
return RedirectToAction("Index");
}
You can also use return View(model); in the [HttpPost] action method instead of return Create();.

Show validation messages on GET

We have a possibility that data loaded from a GET operation could be invalid for posting, and would like to be able to display the validation messages when the data is first loaded. The validation all takes place on server side using ValidationAttributes.
How can I force the validation summary to be displayed when the data is first loaded? I am guessing that I need to force errors into ModelState somehow, but I first need to get them out of the model class.
I ended up adding a validation method for the model class which adds errors to the ModelState. Then I created and added a custom ModelValidator and AssociatedValidatorProvider
for calling it during the normal validation that takes place during form binding. That way the controller actions that don't bind to the Model class directly can still have a call to the model's .Validate(ModelState) method to fake a validation. This approach works well for server-side-only validation.
UserInfo Model class:
private IEnumerable<RuleViolation> GetRuleViolations()
{
List<RuleViolation> violationList = new List<RuleViolation>();
if (String.IsNullOrWhiteSpace(FirstName))
violationList.Add(new RuleViolation("First Name is required.", FirstName"));
return violationList;
}
public void Validate(System.Web.Mvc.ModelStateDictionary ModelState)
{
foreach (RuleViolation violation in GetRuleViolations())
{
ModelState.AddModelError(violation.PropertyName, violation.ErrorMessage);
}
}
This is how it can be used directly from a controller action. In this action the Model class object is returned as part of the UserSearch model.
public ActionResult Search(UserSearch model)
{
if (this.ModelState.IsValid)
{
model.Search();
if (model.UserInfo != null )
{
model.UserInfo.Validate(ModelState);
}
}...
That is all I had to do for the particular use case I was working on. But I went ahead and completed the work to do "normal" validation on a postback: created a simple ModelValidator, with the Validate override looking like this. If you followed the above pattern in all of your Model classes you could probably reusue this for them, too.
public override IEnumerable<ModelValidationResult> Validate(object container)
{
var results = new List<ModelValidationResult>();
if (Metadata.Model != null)
{
UserInfoViewModel uinfo = Metadata.Model as UserInfoViewModel;
foreach (var violation in uinfo.GetRuleViolations())
{
results.Add(new ModelValidationResult
{
MemberName = violation.PropertyName,
Message = violation.ErrorMessage
});
}
}
return results;
}
Finally, extend AssociatedValidationProvider to return this ModelValidator and add it to the ModelValidationProviders collection in Application_Start. There is a writeup of this at http://dotnetslackers.com/articles/aspnet/Customizing-ASP-NET-MVC-2-Metadata-and-Validation.aspx#s2-validation
I don't know if understand what you need, but here is it...
run validation to display the validation summary when the form is loaded, using jquery
$(document).ready(function() {
$('#FormId').valid();
});

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);
}

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

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.

Resources