What is difference between these two paths?
http://www.mydomain.com/testmvc3
http://www.mydomain.com/testmvc3/
I put the code in HomeController:
// GET: /Home/
public ActionResult Index()
{
if (Request.IsAuthenticated)
{
return RedirectToAction("Index", "Member");
}
else
{
return View();
}
}
But only the second link works fine, but the first one still show the Home page.(even it is authenticated) How to make them have the same react?
I found the problem, it was caused by the page cache. To avoid the problem, I modify the code to:
[OutputCache(Duration = 30, VaryByCustom = "Request.IsAuthenticated")]
public ActionResult Index()
{
if (Request.IsAuthenticated)
{
return RedirectToAction("Index", "Member");
}
else
{
return View();
}
}
Now it works.
You will want to leave the trailing slash off of a normal route, otherwise it indicates that there may be url parameters coming into the action.
To enforce this you might want to check out the cleanurl filter that is in MvcCms. Source Code
private bool IsTrailingSlashDirty(ref string path)
{
//we only want a trailing slash on the homepage
if (path.EndsWith("/") && !path.Equals("/"))
{
path = path.TrimEnd(new char[] { '/', '/' });
return true;
}
return false;
}
Related
I am using .Net Core 5 and uploading images for my Trademark. I use Repository for my work and got error CS706: There is no argument given that corresponds to the required formal parameter 'photo' of 'Interface.Create(Trademark, IFormFile)' in Controller
_trademarkRepo.CreateNewTrademark(trademark);
Controller
public IActionResult CreateTrademark(Trademark trademark)
{
if(ModelState.IsValid)
{
_trademarkRepo.CreateNewTrademark(trademark);
}
_logger.LogInformation("...");
return RedirectToAction("Index");
}
Repo
public bool CreateNewTrademark(Trademark trademark, IFormFile photo)
{
var path = Path.Combine(this._webHostEnvironment.WebRootPath, "trademarks", photo.FileName);
var stream = new FileStream(path, FileMode.Create);
photo.CopyToAsync(stream);
if(CheckExist(trademark.TrademarkName))
{
return false;
}
var newTrademark = new Trademark
{
TrademarkName = trademark.TrademarkName,
Description = trademark.Description,
Image = photo.FileName
};
_dbContext.Trademarks.Add(newTrademark);
_dbContext.SaveChanges();
return true;
}
From error it is evident that what error is.
Method at repo level required two argument. One is trademark and another is photo.
When you have called that from controller , you have only passed one. (Trademark only and photo is missing). This is the error.
Basically your controller should look like following.
public IActionResult CreateTrademark(Trademark trademark,IFromFile photo)
{
if(ModelState.IsValid)
{
_trademarkRepo.CreateNewTrademark(trademark,photo);
}
_logger.LogInformation("...");
return RedirectToAction("Index");
}
Note: There are many other dependencies like how you post file from UI etc. That is not scope of this question and so answer. You have to look for those detail.
I have a simple form with a textbox (and a model editor I want to render in specific cases)
#using (Html.BeginForm("Import", "Flow"))
{
#Html.TextBoxFor(model => model.IsConfirmed)
#if (Model.IsConfirmed)
{
#Html.EditorFor(m => m.Preview)
}
}
The model used in this view is the following
public class ImportViewModel
{
public Boolean IsConfirmed { get; set; }
public PreviewViewModel Preview { get; set; }
public ImportViewModel()
{
this.IsConfirmed = false;
}
}
The form posts on the following controller
public class FlowController
{
[HttpPost]
public ActionResult Import(ImportViewModel model)
{
try
{
if (ModelState.IsValid)
{
if (model.IsConfirmed)
{
// do something else
}
else
{
model.Preview = Preview(model.strCA, model.SelectedAccount);
model.IsConfirmed = true;
return View(model);
}
}
}
catch (Exception ex)
{
throw new Exception("arf", ex);
}
return RedirectToAction("Index", "Home");
}
}
On first load, the textbox contains "false"
When posted, the property IsConfirmed of the model is set to "true" and this model is passed to the same view.
I expect the textbox to be "true" but it is still "false"... moreover the Preview property is correctly rendered, so it means Model.IsConfirmed is indeed true...
Am I missing something ?
Thanks
Make sure you remove the value from the ModelState if you intend to modify it:
ModelState.Remove("IsConfirmed");
model.IsConfirmed = true;
The reason you need to do that is because, by design, all Html helpers (such as TextBoxFor) will first look for a value in the ModelState when binding and only not found they will use the value on your model. And since there's a value with the same name in the ModelState (coming from the POST request), that's what's being used.
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
I have a partial view in which there is a form. I POST this form using the PRG pattern. I am using the AjaxHelper to create my form. I also need this form to work without javascript. The problem is that when model validation fails, it always changes the url to my partial view.
public ActionResult PostForm(PostFormModel postFormModel)
{
if (ModelState.IsValid)
{
return RedirectToAction("SomewhereElse");
}
else
{
if (Request.IsAjaxRequest())
{
return PartialView("_PostForm")
}
else
{
// What do I do here?
}
}
}
Here's what I have tried:
return PartialView("_PostForm", postFormModel);
This just renders the partial view and doesn't contain any of the parent stuff.
return View("Index", new ParentModel() { PostFormModel = postFormModel });
This actually produces the correct result. It displays the parent view, but the URL is that of the partial http://localhost:22485/Controller/PostForm! I feel like this is really close to the solution. What now?
If you want to change url, you should redirect to another action (using PRG pattern). Insert next code instead of '// What do I do here?':
postModelService.Save(postFormModel); //to Session or to DB
return RedirectToAction("Parent");
New action should look like this:
public ActionResult Parent()
{
var postFormModel = postModelService.Load();
return View("Index", new ParentModel() { PostFormModel = postFormModel });
}
Hope it helps.
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