I have multiple models that get update in my database. Each model, like tasks, vendors, and invoicing is tied to a single job. When I create and edit one of these models (using the corresponding CRUD page), I want it to open up a create/edit page for all available models. For example, if I create a new job site, I also want the option to add in vendors, tasks, etc. If I edit a job site, I also want the option to edit all of the other models. As it stands, getting the details of these models to display as one page was simple. Getting the create function to work in the same way is more difficult. Is it possible to use one of my controller's create method to serve as a create method for another controller/model? Is it possible to do the same thing for the Edit and Delete functions? Here is what my controller looks like for the Create method.
// GET: Towers/Create
public IActionResult Create()
{
return View();
}
// POST: Towers/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,SiteId,SiteName,TowerHeight,TowerType,TaskOrder,Street,City,State,Zip,CrossStreet,Latitude,Longitude,Notes,StartDate,EndDate,ParsonsPm,ParsonsRe,DecomCrewNum,ActualStartDate,ActualEndDate")] Tower tower)
{
if (ModelState.IsValid)
{
_context.Add(tower);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(tower);
}
And the CREATE method for the Vendor controller (I haven't edited it from what dotnet scaffolds)
// GET: Vendors/Create
public IActionResult Create()
{
ViewData["TowerId"] = new SelectList(_context.Tower, "Id", "Id");
return View();
}
// POST: Vendors/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("VendorId,CraneVendor,CranePhone,PortableToiletVendor,PortableToiletPhone,ForkliftVendor,ForkliftPhone,SkidSteerVendor,SkidSteerPhone,ExcavatorVendor,ExcavatorPhone,LoaderVendor,LoaderPhone,SteelDumpstersVendor,SteelDumpstersPhone,ConcreteDumpstersVendor,ConcreteDumpstersPhone,CraneCallOffNum,CraneOnRent,CraneOffRent,PortableToiletOnRent,PortableToiletOffRent,ForkliftOnRent,ForkliftOffRent,SkidSteerOnRent,SkidSteerOffRent,ExcavatorOnRent,ExcavatorOffRent,LoaderOnRent,LoaderOffRent,SteelDumpstersOnRent,SteelDumpstersOffRent,ConcreteDumpstersOnRent,ConcreteDumpstersOffRent,ForkliftCallOffNum,SkidSteerCallOffNum,ExcavatorCallOffNum,LoaderCallOffNum,SteelDumpsterCallOffNum,ConcreteDumpsterCallOffNum,TowerId")] Vendor vendor)
{
if (ModelState.IsValid)
{
_context.Add(vendor);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
ViewData["TowerId"] = new SelectList(_context.Tower, "Id", "Id", vendor.TowerId);
return View(vendor);
}
For reference, this my DETAILS method in my TowerController
// GET: Towers/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var tower = await _context.Tower
.Include(v => v.Vendor)
.FirstOrDefaultAsync(m => m.Id == id);
if (tower == null)
{
return NotFound();
}
return View(tower);
}
You can see that it also includes the details of the relevant vendors for the particular site.
I'm having a real problem trying to articulate this seemly simple problem.
I have a single view that contains a FORM with a few search fields at the top of the view and the results of that search get shown on the same view after submitting the form.
I have a single HTTPGET controller method that takes the form fields as parameters and IF it was submitted by a user it will pass the model back to the view with the results to be shown and pre-populate the search form with what they filled out.
How can I tell if the page was loaded with default parameters vs. someone actually submitted the form.
What's the best way to accomplish this?
If I am understanding your question correctly then I think you need to consider the HttpGet attribute:
https://msdn.microsoft.com/en-us/library/system.web.mvc.httpgetattribute(v=vs.118).aspx
and the HttpPost attribute:
https://msdn.microsoft.com/en-us/library/system.web.mvc.httppostattribute(v=vs.118).aspx
Lets say you have a create method. The Http method would look like this:
[HttpGet]
public ActionResult Create()
{
}
and the post method would look like this:
[HttpPost]
public ActionResult Create(Person p)
{
//Logic to insert p into database. Could call an application service/repository to do this
}
RedirectToAction solve the problem.
you can go back to the get method after submited data and populate the view with default values
[HttpGet]
public ActionResult Create()
{
// fill model to default data
return view(model);
}
[HttpPost]
public ActionResult Create(Person p)
{
//do your stuff save data
return RedirectToAction("Create");
}
or
[HttpPost]
public ActionResult Create(Person p)
{
if(...)
{
//do your stuff any logic
return RedirectToAction("Create");
}
//do your stuff
return view(...);
}
After reading this very helpful answer I modified a pair of methods to allow them both to accept the same view model:
[ActionName("AddressCorrection"), HttpGet]
public IActionResult AddressCorrectionGet(AddressCorrectionViewModel model)
{
return View(model); // was return View();
}
[ActionName("AddressCorrection"), HttpPost]
[ValidateAntiForgeryToken]
public IActionResult AddressCorrectionPost(AddressCorrectionViewModel model)
{
if (ModelState.IsValid)
{
return View("Index", new ApplicationViewModel { SuccessMessage = "That worked." });
}
model.ErrorMessage = "Something went wrong";
return View(model);
}
Problem is, calling return View(model); in AddressCorrectionGet now treats the invocation as a POST of sorts. Specifically, the validators on AddressCorrection.cshtml run. Instead of seeing a blank form ready for input, I see a form with a bunch of “required fields missing” messages.
How do I prevent the View from running the validators in this case? Or in the more general case, how does the View know that it should vs. should not run validators (I was thinking this was simply based on whether the Request method was GET vs POST. Clearly wrong.), and how can I explicitly tell the view to run or not run the validators?
Use ModelState.Clear(); before return View(model);
When I load the default page (http://localhost/MVCP/Home/index) it loads correctly, whereas when I load another view (http://localhost/MVCP/Home/Create) it doesn't load. How can I fix this?
My Create action in HomeController:
[HttpGet] [ActionName("Create")] public void Create() { }
Q: Do you have an action in your HomeController called Create?
A: Yes, [HttpGet] [ActionName("Create")] public void Create() { }
Your action return value is void and probably you even didn't write anything in response. change the signature of action to have an ActionResult as return a View.
public ActionResult Create()
{
return View();
}
To learn more:
Adding a View
in Getting Started with ASP.NET MVC 5 Series.
May be there is no view you have created so far and it seems your controller are inside area folder so have u checked your routeing too.
I think your Action should return ActionResult or ViewResult but certainly not "void" as you have written currently.
and also you should write
return view();
in Create action
I am attempting to make a simple test website to allow me to list, create, edit and delete customer objects using MVC4.
Inside my controller I have 2 create methods, a Get for when the form loads with the controls, and a Post that actually saves the data.
//
// GET: /Customer/Create
[HttpGet]
public ActionResult Create()
{
return View();
}
//
// POST: /Customer/Create
[HttpPost]
public ActionResult Create(Customer cust)
{
if (ModelState.IsValid)
{
_repository.Add(cust);
return RedirectToAction("GetAllCustomers");
}
return View(cust);
}
However when I run the project and attempt to access the create action I get an error that:
The current request for action 'Create' on controller type 'CustomerController' is ambiguous between the following action methods:
System.Web.Mvc.ActionResult Create() on type [Project].Controllers.CustomerController
System.Web.Mvc.ActionResult Create([Project].Models.Customer) on type [Project].Controllers.CustomerController
My I understand that it can't see the difference between my Get and Post methods, but I have added the attribues. What could be the cause of this and how can I make it work again?
MVC does not authorize you to have 2 action methods with the same name.
BUT you can have 2 action methods with the same URI when the http verb differs (GET, POST). Use the ActionName attribute to set the action name. Don't use the same methods names. You can use any name. A convention is to add the http verb as the method suffix.
[HttpPost]
[ActionName("Create")]
public ActionResult CreatePost(Customer cust)
{
if (ModelState.IsValid)
{
_repository.Add(cust);
return RedirectToAction("GetAllCustomers");
}
return View(cust);
}