Using the Trim function in ASP.net MVC 3 - asp.net-mvc-3

Hi everyone new to MVC and I need to trim some %20's off of my data so it will display correctly. At the moment my CRUD displays the index correctly and it is able to edit user created records but when I try to edit a record that was from the legacy database it doesn't work and throws an error that the resource cannot be found. I looked closer at the URL for the legacy database records and saw that following most of the database records was %20%20%20%20%20. This told me that the database records were being followed by extra white space since that is what %20 meaning is. I did some research and found that the Trim function could get rid of the extraneous characters for me. I just don't understand how to use the trim function in my specific situation.
I think that I need to use the function in my Controller under my Edit ActionResult but when I tried it in a few different spots I had no luck. I thought that I understood how this function works but with no change in result for the better I am stuck. I hope that this explains the problem well enough, below I have posted the code for my controller with my CRUD methods in it but if you need me to post any other classes let me know.
You may notice that I have left a trim method in my edit method, this was my attempt at solving the problem and can easily be removed if I am completely wrong, and since it didn't work I believe I am! Thanks for your help if you need my edit class just ask I will be checking back often! And for anyone reading this to help them solve the same problem I will be sure and post the solution once it has been solved!
PaController
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using DBFirstMVC.Models;
using System.Data;
namespace DBFirstMVC.Controllers
{
public class PaController : Controller
{
PaEntities db = new PaEntities();
//
// GET: /Pa/
public ActionResult Index()
{
using (var db = new PaEntities())
{
return View(db.iamp_mapping.ToList());
}
}
//
// GET: /Pa/Details/5
public ActionResult Details(int id)
{
return View();
}
//
// GET: /Pa/Create
public ActionResult Create()
{
return View();
}
//
// POST: /Pa/Create
[HttpPost]
public ActionResult Create(iamp_mapping IAMP)
{
try
{
using (var db = new PaEntities())
{
db.iamp_mapping.Add(IAMP);
db.SaveChanges();
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
//
// GET: /Pa/Edit/5
public ActionResult Edit(string id)
{
using (var db = new PaEntities())
{
string trimmedID = id.Trim();
return View(db.iamp_mapping.Find(trimmedID));
}
}
//
// POST: /Pa/Edit/5
[HttpPost]
public ActionResult Edit(string id, iamp_mapping IAMP)
{
try
{
using (var db = new PaEntities())
{
db.Entry(IAMP).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("");
}
}
catch
{
return View();
}
}
//
// GET: /Pa/Delete/5
public ActionResult Delete(string id)
{
using (var db = new PaEntities())
{
return View(db.iamp_mapping.Find(id));
}
}
//
// POST: /Pa/Delete/5
[HttpPost]
public ActionResult Delete(string id, iamp_mapping IAMP)
{
try
{
using (var db = new PaEntities())
{
db.Entry(IAMP).State = EntityState.Deleted;
db.SaveChanges();
return RedirectToAction("");
}
}
catch
{
return View();
}
}
}
}

You're using the trim function correctly so it seems your problem is elsewhere. That said, I would advise you do the trimming before you display the index page, otherwise you will have to trim the id in any actions which take the id as a parameter (edit, delete, etc).

Sounds like you want HttpUtility.HtmlDecode:
http://msdn.microsoft.com/en-us/library/7c5fyk1k.aspx

Related

MVC3 - Validating inputs - Difference between create() and edit()

I'm again struggling at validating inputs.
Let's say I edit a customer and the field "name" is required via
[Required(ErrorMessage = Constants.ErrorMsgNameMissing)]
public string NAME { get; set; }
inside the model.
The edit method does
[HttpPost]
edit(ViewModel vm)
{
// some code here
try
{
UpdateModel(vm);
// some code there
}
catch (Exception e)
{
return View(vm);
}
}
While doing UpdateModel(vm), an exception is thrown if the name is empty. Then my view shows the Html.ValidationSummary(). So far, so good.
Now, if I create a customer via
[HttpPost]
create(ViewModel vm)
{
if (ModelState.IsValid) { ... }
}
I don't have the method UpdateModel() since there's nothing to update. And ModelState.IsValid seems to return true every time. Even if the ViewModel is null. So I run into trouble then.
How do I validate this? And what do I return in case of errors?
Update: I think it was too late yesterday. In fact, it DOES work. But I was hoping for an exception and forgot the else { ... }...
Try this:
[HttpPost, ValidateInput(true)]
create(ViewModel vm)
{
if (ModelState.IsValid) { ... }
}

MVC3 binding nested model using Entity Framework with GUID keys

I have been fighting with this all day and still I am failing.
I can simplify the problem as follows:
I have reports and reports have forms. I have entity models of each. They have Guid id's as shown below.
I am trying to get a single view where I can create a report and a form. As an end goal I would like to be able to add multiple forms, but just one would be great. My controller is as follows:
// GET: /AllInOne/Create
public ActionResult Create()
{
ViewBag.PossibleReportBases = reportBaseRepository.All;
ViewBag.PossibleCategories = categoryRepository.All;
var model = new Report {FromDate = DateTime.Now};
model.Forms.Add(new Form());
return View(model);
}
// POST: /AllInOne/Create
[HttpPost]
public ActionResult Create(Report report)
{
if (ModelState.IsValid) {
reportRepository.InsertOrUpdate(report);
reportRepository.Save();
return RedirectToAction("Index");
}
else
{
ViewBag.PossibleReportBases = reportBaseRepository.All;
ViewBag.PossibleCategories = categoryRepository.All;
return View();
}
}
The repository code looks like this:
public void InsertOrUpdate(Report report)
{
if (report.Id == default(System.Guid)) {
// New entity
report.Id = Guid.NewGuid();
context.Reports.AddObject(report);
} else {
// Existing entity
context.Reports.Attach(report);
context.ObjectStateManager.ChangeObjectState(report, EntityState.Modified);
}
}
At one stage the binding was giving me this error:
The EntityCollection has already been initialized. The InitializeRelatedCollection method should only be called to initialize a new EntityCollection during deserialization of an object graph.
I have tried many things for the views, but none of them have worked.
Please help.
i dont' think you need to bother with the attaching. if you've selected the report from your context, it is already being tracked. you can simplify your repository like so
public void InsertOrUpdate(Report report)
{
// i prefer Guid.Empty but no big deal
if (report.Id == default(System.Guid)) {
// New entity
report.Id = Guid.NewGuid();
context.Reports.AddObject(report);
}
context.SaveChanges();
}

Is this the correct way to save form values in MVC3?

Here's my code:
[HttpGet]
public ActionResult Register()
{
RegisterViewModel model = new RegisterViewModel();
using (CityRepository city = new CityRepository())
{
model.SelectCityList = new SelectList(city.FindAllCities().ToList(), "CityID", "CityName");
}
using (CountryRepository country = new CountryRepository())
{
model.SelectCountryList = new SelectList(country.FindAllCountries().ToList(), "CountryID", "CountryName");
}
return View(model);
}
[HttpPost]
public ActionResult Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
//Actually register the user here.
RedirectToAction("Index", "Home");
}
//Something went wrong, redisplay the form for correction.
return View(model);
}
Is this the best approach or is there another better tested way? Keep in mind that my database tables/field names are nothing like what I declared in my models. I have to scrape the values from the ViewModel and put them into an entity framework generated class to persist the information.
Anything here that screams out at you as wrong?
I use that pattern and another pattern which looks like this (important part is the AutoMapper part):
[HttpPost]
public ActionResult Register(RegisterViewModel model)
{
if (!ModelState.IsValid)
{
// repopulate any input or other items set in GET
// prefer to do at top due to ^^^ is easy to overlook
return View(model);
}
// if it's an edit, pull to new instance
// from the database and use automapper to
// map over the submitted values from model to instance
// then update instance in database
//
// VALUE: useful if form only shows
// some of the properties/fields of model
// (otherwise, those not shown would be null/default)
// if it's new, insert
RedirectToAction("Index", "Home");
}
That's the pattern I generally use.
I prefer this pattern:
Controller:
[HttpGet]
public ActionResult Index()
{
var cities= (from m in db.cities select m);
ViewBag.Cities= cities;
var states = (from m in db.States select m);
ViewBag.States = states;
return View();
}
[HttpPost]
public ActionResult Index(RegisterViewModel model)
{
if (ModelState.IsValid)
{
// Saving the data
return View("ActionName", model);
}
return View();
}
View:
#Html.DropDownList("DDLCities",new SelectList(ViewBag.Cities, "CityId" , "CityName" ), new { #class = "className" })
#Html.DropDownList("DDLStates",new SelectList(ViewBag.States, "StateId" , "StateName" ), new { #class = "className" })
Advised changes to [HttpGet]:
[HttpGet]
public ActionResult Register()
{
// Get
var cities = new List<City>();
var countries = new List<Country>();
using (CityRepository city = new CityRepository())
{
cities = city.FindAllCities().ToList();
}
using (CountryRepository country = new CountryRepository())
{
counties = country.FindAllCountries().ToList();
}
// Map.
var aggregatedObjects = new SomePOCO(cities, countries);
var model = Mapper.Map<SomePOCO,RegisterViewModel>(aggregatedObjects );
// Return
return View(model);
}
Summary of changes:
Layout your logic in such a way the controller's job makes sense. Get - Map - Return. Exactly the tasks (in order) for which a Controller is designed for.
Use AutoMapper to do the heavy lifting of ViewModel creation for you.
Advised changes to your [HttpPost]:
[HttpPost]
public ActionResult Register(RegisterViewModel model)
{
if (!ModelState.IsValid)
return View(model);
try
{
var dbObj = Mapper.Map<RegisterViewModel,SomeDomainObj>(model);
_repository.Save(dbObj);
return RedirectToAction("Index");
}
catch (Exception exc)
{
if (exc is BusinessError)
ModelState.AddModelError("SomeKey", ((BusinessError)exc).FriendlyError);
else
ModelState.AddModelError("SomeKey", Resources.Global.GenericErrorMessage);
}
return View(model);
}
Summary of changes:
Try/catch. Always need to capture exceptions, whether they are domain exceptions or lower-level (database ones)
Check ModelState validity first. As #Cymen says - do it first so you don't forget later
Add exceptions to ModelState. Use custom exception classes for business errors with descriptive, resource-based messages. If the error is too low-level for the user (foreign key constraint, etc), show a generic message

RedirectToAction after validation errors

If I have the usual Edit actions, one for GET to retrieve an object by it's ID and to display it in an edit form. The next for POST to take the values in the ViewModel and update the object in the database.
public virtual ActionResult Edit(int id)
[HttpPost]
public ActionResult Edit(VehicleVariantEditSaveViewModel viewModel)
If an error occurs during model binding in the POST action, I understand I can RedirectToAction back to the GET action and preserve the ModelState validation errors by copying it to TempData and retrieving it after the redirect in the GET action.
if (TempData["ViewData"] != null)
{
ViewData = (ViewDataDictionary)TempData["ViewData"];
}
How do I then convert that ViewData, which includes the previous invalid ModelState, into a new model to send to the view so the user sees their invalid input with validation warnings? Oddly enough if I pass in a new instance of my ViewModel retrieved from the database (with the original valid data) to the View() this is ignored and the (invalid) data in the ViewData is displayed!
Thanks
I had a similar problem and decided to use the following pattern:
public ActionResult PersonalRecord(Guid id)
{
if (TempData["Model"] == null)
{
var personalRecord = _context.PersonalRecords.Single(p => p.UserId == id);
var model = personalRecord.ToPersonalRecordModel();
return View(model);
}
else
{
ViewData = (ViewDataDictionary) TempData["ViewData"];
return View(TempData["Model"]);
}
}
[HttpPost]
public ActionResult PersonalRecord(PersonalRecordModel model)
{
try
{
if (ModelState.IsValid)
{
var personalRecord = _context.PersonalRecords.Single(u => u.UserId == model.UserId);
personalRecord.Email = model.Email;
personalRecord.DOB = model.DOB;
personalRecord.PrimaryPhone = model.PrimaryPhone;
_context.Update(personalRecord);
_context.SaveChanges();
return RedirectToAction("PersonalRecord");
}
}
catch (DbEntityValidationException ex)
{
var errors = ex.EntityValidationErrors.First();
foreach (var propertyError in errors.ValidationErrors)
{
ModelState.AddModelError(propertyError.PropertyName, propertyError.ErrorMessage);
}
}
TempData["Model"] = model;
TempData["ViewData"] = ViewData;
return RedirectToAction("PersonalRecord", new { id = model.UserId });
}
Hope this helps.
I noticed that the Model is included in ViewData so you don't need to pass it in addition to the ViewData, what I don't understand is how you get at it to then return it to the view.
public ViewResult Edit(int id)
{
// Check if we have ViewData in the session from a previous attempt which failed validation
if (TempData["ViewData"] != null)
{
ViewData = (ViewDataDictionary)TempData["ViewData"];
}
VehicleVariantEditViewModel viewModel = new VehicleVariantControllerViewModelBuilder()
.BuildForEdit(id);
return View(viewModel);
}
The above works but obviously it's making an unnecessary call to the database to build a new Model (which gets automagically overwritten with the invalid values from the Model in the passed ViewData)
Confusing.

MVC Delete record but how to code this in Controller

I'm a beginner of MVC3 with ASP.Net (C#) but I don't get the next situation to delete a record.
I have a View that ask the user to confirm delete a item (record). As code I have this to initialize the view:
public ActionResult KeywordsDelete(Guid id)
{
_db = new BlaContext();
return _db.SearchTerms.Where(x => x.id.Equals(id)).First();
}
But when confirmed, then I have the next code.
[HttpPost]
public ActionResult KeywordsDelete(Guid id)
{
_db = new BlaContext();
var term = _db.SearchTerms.Where(x => x.id == id).First();
_db.SearchTerms.Remove(term);
_db.SaveChanges();
return View("Keywords", _db.SearchTerms.ToList());
}
Building is not possible because the signature of this method is already exists (same parameters and method name).
So I don't get how to delete a record in this situation. The view is created with a default Scaffold template (delete).
I found an alternative solution to this problem while reading up on MVC. Check out: Improving the Details and Delete Methods
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id = 0)
{
// Delete stuff...
}
This will route the action Delete to the method DeleteConfirmed.
You can give your post function another additional parameter
[HttpPost]
public ActionResult KeywordsDelete(Guid id, FormCollection collection)
{
_db = new BlaContext();
var term = _db.SearchTerms.Where(x => x.id == id).First();
_db.SearchTerms.Remove(term);
_db.SaveChanges();
return View("Keywords", _db.SearchTerms.ToList());
}
But your GET Action should also return a View not a data object, I think.
public ActionResult KeywordsDelete(Guid id)
{
_db = new BlaContext();
return View(_db.SearchTerms.Where(x => x.id.Equals(id)).First());
}

Resources