mvc4 ef5 return points to folder not controller - entity-framework

I have 3 sequential date fields: Start, End, Certify. When the user indicates he wants to update a date in a given row, I actionlink to the controller for that table, Task, where I have added code to determine which field is null and then direct to a view customized to that field. My concept was that the return would go to the scaffold generated edit where the data would be saved. So 3 views with a common return.
I'm getting a 404 error. Since I know the name is present, it must be unavailable.
The scaffold generated post code:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Task task)
{
if (ModelState.IsValid)
{
db.Entry(task).State = EntityState.Modified;
db.SaveChanges();
}
And my selection code:
public ActionResult EditBegin(int? id)
{
Task ViewModel = db.Tasks.Find(id);
{
if (ViewModel.SStart == null)
{
ViewModel.TaskID = id.Value;
ViewModel.SStart = DateTime.Now;
return View("EditStart", ViewModel);
}
else if (ViewModel.SEnd == null)
{
ViewModel.TaskID = id.Value;
ViewModel.SEnd = DateTime.Now;
return View("EditEnd", ViewModel);
}
else if (ViewModel.SCert == null)
{
ViewModel.TaskID = id.Value;
ViewModel.SCert = DateTime.Now;
return View("EditCert", ViewModel);
}
return View("EditCert", ViewModel); //solves not all paths have return error
}
}
And in the EditEnd view the EditorFor and Actionlink.
#Html.EditorFor(model => model.SEnd) // preloaded with NOW
#Html.ActionLink("Save End Date", "Edit", "Task" ) //is the TaskID passed back as part of this?
So in the EditEnd view, press the "Save end date" button and I get the 404 error. I've tested the Task edit function to confirm "the resource is available" and it works fine.
I've discovered the path is to a folder .../task/edit not the controller.
How do I get it to reference the controller. Removing the quotes doesn't help.
Thanks
My entire view is:
#model MVCBSV.Models.Task
#{
ViewBag.Title = "Scanedit";
}
<h2>Add Start Date</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
Html.BeginForm("Edit", "Task", FormMethod.Post);
<fieldset>
<legend>Task</legend>
#Html.HiddenFor(model => model.TaskID)
<div class="editor-label">
Step Name
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.StepName);
</div>
<div class="editor-label">
#Html.LabelFor(model => model.SStart)
</div>
<div class="editor-field">
#Html.EditorFor( model => model.SStart)
#Html.ValidationMessageFor(model => model)
</div>
#* <p>
<input type="submit" value="Save" />
</p>*#
</fieldset>
}
<div>
#Html.ActionLink("Save Start Date", "Edit", "Task" )
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}

You edit method is decorated as an HTTP Post method. An anchor tag will provide a link which your browser uses to make an HTTP GET request. You can change from attribute to HttpGet and this will work.
However, it's better practice to actually POST a form to your save method.

Related

RedirectToAction on [HttpPost] returning "resource not found" error

I have a fairly simple project with is using ninject with asp mvc 4 and entity framework.
I have added an edit and create ActionResult based on the view with no problems. However the delete ActionResult is not working.
The view is a IEnumrable based on the entity, with a simple ActionLink
#Html.ActionLink("Delete", "Delete_Client", new { item.ClientId })
The controller is also very simple.
[HttpPost]
public ActionResult Delete_Client(int id)
{
Client deleteClient = repository.DeleteClient(id);
if (deleteClient != null)
{
TempData["message"] = string.Format("{0} was deleted.", deleteClient.Name);
}
return RedirectToAction("Admin_Client_List");
}
This interacts with the model through the Iinterface
Client DeleteClient(int id);
and in the Entity framework
public Client DeleteClient(int id)
{
Client dbEntry = context.Clients.Find(id);
if (dbEntry != null)
{
context.Clients.Remove(dbEntry);
context.SaveChanges();
}
return dbEntry;
}
The error is
The resource cannot be found.
This is very confusing because i feel like i am not understanding a very fundamental principle of the framework. As i understand it, that means that there is no corresponding ActionResult for the client controller. But there is. The tutorial is am working through suggested that a delete action should be idempotent and therefore only contain a [HttpPost] .
The Uri looks like this
/Client/Delete_Client?ClientId=12
I thought that maybe it would need to look like this
/Client/Delete_Client/12
However that does not work.
Updated request for Admin_Client_List.cshtml
#model IEnumerable<Project.Domain.Entities.Client>
#{
ViewBag.Title = "Client List";
ViewBag.Icon = "entypo-layout";
ViewBag.ClientActive = "active";
Layout = "~/Views/Shared/_AdminLayout.cshtml";
}
Create a new Client
<div class="row">
#foreach (var item in Model)
{
<div class="col-sm-3">
<div class="tile-progress tile-blue">
<div class="tile-header">
<a href="#Url.Action("Client_Details", "Client", new { id =item.ClientId})">
<h3>#item.Name <i class="entypo-right-open-big"></i> <span class="badge badge-secondary pull-right">7</span></h3>
</a>
</div>
<div class="tile-progressbar">
<span data-fill="78%" style="width: 78%;"></span>
</div>
<div class="tile-footer">
<h4>
<span class="pct-counter">78</span>% increase
</h4>
<span>#item.Description</span>
</div>
<div class="tile-header">
<a href="#Url.Action("Edit_Client", "Client", new { id = item.ClientId})" type="button" class="btn btn-blue btn-icon icon-left">
<i class="entypo-pencil"></i> Edit
</a>
#*Show Me*#
#Html.ActionLink("Delete", "Delete_Client", new { id = item.ClientId })
#*Delete <i class="entypo-cancel"></i>*#
</div>
</div>
</div>
}
</div>
try with
#Html.ActionLink("Delete", "Delete_Client", null, new { id = item.ClientId })
and you must delete the [HttpPost], this is a GET request
Use the following code:
#Html.ActionLink("Delete", "Delete_Client", new { id = item.ClientId })
[HttpPost]
public ActionResult Delete_Client(int id)
{
Client deleteClient = repository.DeleteClient(id);
if (deleteClient != null)
{
TempData["message"] = string.Format("{0} was deleted.", deleteClient.Name);
}
return RedirectToAction("Admin_Client_List");
}
Change your code
#Html.ActionLink("Delete", "Delete_Client", new { item.ClientId })
to
#Html.ActionLink("Delete", "Delete_Client", new { id = item.ClientId })

Set selected Kendo menu item with HtmlAttributes to hiddem form field

i have a kendo menu that is bound to my form by the onclick event like this
#(Html.Kendo().Menu()
.Name("MenuCreate")
.Items(items =>
{
items.Add().Text("<<").Action("Index", "BSfune");
items.Add().Text("New").HtmlAttributes(new{onclick = "getElementById('FormCreate').submit()", #id = "New"});
items.Add().Text("Edit").HtmlAttributes(new { onclick = "getElementById('FormCreate').submit()", #id = "Edit" });
})
.Events(e => e.Select("select"))
)
and in my form i have a hiden field called FormmMode
#using (Html.BeginForm("Create", "BSfune", FormMethod.Post, new { id = "FormCreate" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div class="form">
<fieldset>
<legend>#ViewBag.Title</legend>
<div>
<div>
(My form code)
</div>
#Html.HiddenFor(model => model.FormMode, new { #id = "FormMode"})
<br />
<br />
<br />
</div>
</fieldset>
</div>
}
i want to set my field form (FormMode) with the selected menuitem text "New" or "Edit".
I noticed that the onclick overrides the selected event. So.. It would be something like this
<script type="text/javascript">
$(function () {
$('#New').on('click', function () {
$("#FormMode").val($(this).text());
});
});
function select(e) {
}
But this does not work..
On the controler side i have
public ActionResult Create(CrBSfune p_BSfune)
{
(...)
if (p_BSfune.FormMode == "New")
return RedirectToAction("Create");
else
return RedirectToAction("Index");
}
But my p_BSfune.FormMode is null.
Can you help?
Thanks.:)
Got it!!! Catching the click event was the solution, the way to pass the value.. that was more trickie.. but after several attempts got it.:) did this and it works fine.:)
$('#New').click(function (e) {
e.preventDefault();
$('#FormCreate')[0].FormMode.value = e.target.innerText;
$('#FormCreate').submit();});
Don't know if it is the best approach.. but it works.:)

FormMethod.Post in MVC4 has unexpected behavior

I have following View:
#model DocuLive.ViewModels.InstallationRequestViewModel
#{
ViewBag.Title = "AttachDB";
Layout = "~/Views/Shared/_AdminPage.cshtml";
}
<h2>AttachDB</h2>
#using (Html.BeginForm("AttachDB","AppStart", FormMethod.Post)) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<p>Database DocuLive already exists on the server where you attempted installation. Do wish to attach existing DB to this installation of DocuLive? Details below will be used for this attempt.</p>
<fieldset>
<p>
<input type="submit" name="command" value="Attach" />
<input type="submit" name="command" value="Start over" />
</p>
<legend>DB server credentials</legend>
<div class="display-label">
#Html.DisplayNameFor(model => model.Server)
</div>
<div class="display-field">
#Html.DisplayFor(model => model.Server)
</div>
<div class="display-label">
#Html.DisplayNameFor(model => model.UserName)
</div>
<div class="display-field">
#Html.DisplayFor(model => model.UserName)
</div>
<div class="display-label">
#Html.DisplayNameFor(model => model.Password)
</div>
<div class="display-field">
#Html.DisplayFor(model => model.Password)
</div>
</fieldset>
}
I have follownt two methods in controller:
public ActionResult AttachDB(InstallationRequestViewModel requestVM)
{
if (requestVM != null)
return View("AttachDB", requestVM);
else
{
TempData["Fail"] = "DocuLive database exist, but inicalization request has null value and cannot be used to attach DB";
return RedirectToAction("Index");
}
}
[HttpPost]
private async Task<ActionResult> AttachDB(InstallationRequestViewModel requestVM, string command)
{
try
{
switch (command)
{
case "Attach":
// do something complex and return RedirectToAction
case "Start over":
return RedirectToAction("Index");
default:
return RedirectToAction("Index");
}
}
catch (Exception ex)
{
TempData["Fail"] = ex.Message;
return RedirectToAction("Index");
}
}
For some reason when i submit the form with either button, it hits the first method with no regard to fact that I explicitly specified FormMethod.Post for the form to make sure that submitting the form will take user to the second method that actually contains some business logic.
It is very strange because I am using similar approach all over the app and so far I had no issues with this.
Can anyone advise, why submitting the form with either button is considered Get instead of POST?
Thanks in advance...
Found it. I made the second method private by accident. Pretty stupid mistake...

ASP MVC 3 RAZOR dynamic form generation post

I'm trying to create asp mvc 3 page with a form with text fields that are dynamically generated based on the number of object in a list that is in the model I passed into page controller. The problem I'm running into is that whenever I post to the controller the list maintains the values but not the names of the objects in the list. Here is an example:
The Model:
public class SomeModel
{
List<Field> fieldList;
public SomeeModel()
{
fieldList = new List<Field>();
}
public string Name { get; set; }
public List<Field> FieldList
{
get
{
return fieldList;
}
}
}
The controller:
public ActionResult Preview()
{
SomeModel model = new SomeModel();
model.FieldList.Add( new Field { name = "test 1"});
model.FieldList.Add( new Field { name = "test 2"});
model.FieldList.Add( new Field { name = "test 3"});
return View(model);
}
The View:
#using (Html.BeginForm()) {
<div>
<fieldset>
<legend>Input Field List</legend>
#for (var i = 0; i < Model.FieldList.Count(); i++)
{
<div class="editor-label">
#Html.Label(Model.FieldList[i].name)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => Model.FieldList[i].value)
</div>
}
<p>
<input type="submit" value="Generate PDF" />
</p>
</fieldset>
</div>
I saw a similar post here .NET MVC Razor Dynamic Form Generation but answer runs into the same issues as I got. Hope I'm being clear! If not I'll post more info. Thanks!
You could include those names as hidden fields. This way their values will be posted to the controller action:
#for (var i = 0; i < Model.FieldList.Count(); i++)
{
#Html.HiddenFor(model => Model.FieldList[i].name)
...
}
Also instead of writing those loops I would recommend you using editor templates:
#model SomeModel
#using (Html.BeginForm())
{
<div>
<fieldset>
<legend>Input Field List</legend>
#Html.EditorFor(x => x.FieldList)
<p>
<input type="submit" value="Generate PDF" />
</p>
</fieldset>
</div>
}
and the corresponding editor template (~/Views/Shared/EditorTemplates/Field.cshtml) which will be rendered for each element of the FieldList collection:
#model Field
#Html.HiddenFor(model => model.name)
<div class="editor-label">
#Html.LabelFor(model => model.value, Model.name)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.value)
</div>
Another possibility instead of using hidden fields would be to externalize those names into some data store and then have a repository which would return them. So in your two actions you would simply query this repository for the names. Because they cannot be changed it is not necessary to include them in the HTML.

Getting data from view to create controller in asp.net MVC

Getting data from view to create controller in asp.net MVC
I know this is very simple but I am just learning ASP.net MVC.
I have a Create controller and a create view (used the generator)
I can hard code data into the controller and that does get saved but I want to know how to get the data the user put on the form back into the controller.
My controller is like this.
public ActionResult Create(Seller newSeller)
{
if (ModelState.IsValid)
{
try
{
newSeller.SellerID = 34324442;
newSeller.State = "NA";
newSeller.UserType = "Seller";
newSeller.FirstName = "sdfasd";
newSeller.LastName = "dasdfadsf";
newSeller.Phone = "33333";
newSeller.Email = "dfasdfasdf";
// write to database
listingsDB.Sellers.AddObject(newSeller);
listingsDB.SaveChanges();
return RedirectToAction("Details", newSeller.SellerID);
}
catch(Exception ex)
{
}
}
return View(newSeller);
}
My view looks like this
<% using (Html.BeginForm()) {%>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Fields</legend>
<div class="editor-label">
<%: Html.LabelFor(model => model.SellerID) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.SellerID) %>
<%: Html.ValidationMessageFor(model => model.SellerID) %>
</div>
... Lots of propterties and then
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
<% } %>
<div>
<%: Html.ActionLink("Back to List", "Index") %>
</div>
I am using ASP.net MVC 2 if it matters.
You usually have two actions on the controller: one for rendering the form and one for processing the posted form values. Typically it looks like this:
public class SellerController: Controller
{
// used to render the form allowing to create a new seller
public ActionResult Create()
{
var seller = new Seller();
return View(seller);
}
// used to handle the submission of the form
// the seller object passed as argument will be
// automatically populated by the default model binder
// from the POSTed form request parameters
[HttpPost]
public ActionResult Create(Seller seller)
{
if (ModelState.IsValid)
{
listingsDB.Sellers.AddObject(seller);
listingsDB.SaveChanges();
return RedirectToAction("Details", new { id = seller.SellerID });
}
return View(seller);
}
}
then your view looks as you have shown, it contains a form and input fields allowing the user to fill each property of the model. When it submits the form, the second action will be invoked and the default model binder will automatically fill the action parameter with the values entered by the user in the form.