DropDownList SelectedValue in Controller is Zero in MVC - asp.net-mvc

I am binding my DDL with tempdata which is basically all username and userid as shown below.
<div class="form-group">
#Html.LabelFor(model => model.AssignedTo, "Assigned To : ", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("UserID", TempData["UserList"] as SelectList, htmlAttributes: new { #class = "control-label col-md-2" })
#Html.ValidationMessageFor(model => model.AssignedTo, "", new { #class = "text-danger" })
</div>
</div>
In controller I am trying to fetch value like below.
public ActionResult Create(WMTProjects prj)
{
prj.AssignedTo
where I am getting value as 0, and I was supposed to get corresponding user's userid.
I was all working fine till i changed from
#using (Html.BeginForm("Create", "CreateProjects", FormMethod.Post, new { id = "FormId" }))
to
#using (Html.BeginForm())
and changed my button attributes to
<input type="submit" value="Create" formaction="Create" formmethod="post" class="btn btn-default" />
Not sure what's wrong in this approach.

You are generating a dropdownlist for a property named UserID, not AssignedTo (and changing the #Html.BeginForm() had nothing to do with it)
When you submit the form, there is no name/value pair for AssignedTo, therefore it is set to the default (0 for an int property)
Change your code to generate the dropdownlist to
#Html.DropDownListFor(m => m.AssignedTo, TempData["UserList"] as SelectList, new { #class = "control-label col-md-2" })

Related

How to fix submit form call http method get with query params

I have an asp net core mvc application. An action that create article. The problem is that when I submit the form , my application always calls the get method. How to fix this ?
Create.cshtml
#model MyBlog.Models.Article
#{
Layout = "~/Views/Shared/_AdminLayout.cshtml";
ViewBag.Title = "Create article";
}
<h2>Create article</h2>
#using (Html.BeginForm("Create", "Article", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Title, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Title, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Title, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Content, htmlAttributes: new { #class = "control-label col-md-2" })
<div ass="col-md-10">
#Html.TextAreaFor(model => model.Content,new { #id = "Content", #class = "form-control", #rows = "200" })
#Html.ValidationMessageFor(model => model.Content, "", new { #class = "text-danger" })
<script>
CKEDITOR.replace("Content");
</script>
</div>
</div>
<div class="col-md-offset-2 col-md-10">
<input id="Submit" type="submit" value="submit" />
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Article controller:
// POST: Article
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind("Title,Content")] Article article)
{
try
{
return RedirectToAction("Index");
}
catch (DataException /* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
}
return View();
}
// GET: Article/Create
[HttpGet]
public ActionResult Create()
{
return View();
}
When I submit form. I see a url like this appears:
xxx//localhost:7158/article/create?Title=a&Content=b__RequestVerificationToken=CfDJ8JLgrvFS_U1JlinCQaKFM9rmomKaF5pDFJjX5Mbp7_OCoQq2hNZ6ygB05XZd-Qy8osia_h_1i1nzXuk5lZWQRBSTsId3hu-lbcapc3xDViukVhv6xeMv_ekiCyW6HdFkFh8iBzjXhJ9bRnZyrnP651U
Debug on VS studio
I have found this bug. If I change Layout shared to null. It working. So I have modified my shared layout. Tks for your help !

Unable to Call a method if i mentioned its attribute as HttpPost

I have a signin page which users can use to signin,i defined its method in controller as HttpPost,when i try to access it from browser,it shows no file found,if i remove the HttpPost attribute it hits the controller and return the view.Eventhough it pass the values in the form to controller if i didnt mentioned its type as HttpPost .Here my code of Login/SignIn.cshtml:
#model BOL.Player_Access
#using (Html.BeginForm("SignIn","Login",FormMethod.Post)){
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Sign In</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.PlayerEmail, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PlayerEmail, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.PlayerEmail, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Password, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Password, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Password, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="SignIn" class="btn btn-default" />
</div>
</div>
</div>
And my LoginController Code is here
[AllowAnonymous] //This filter removes authorize filter for this controller alone and allow anonyomous request
public class LoginController : Controller
{
// GET: Login
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult SignIn(Player_Access plyr_obj)
{
return View();
}
}
You need code for both GET and POST.
You need a GET action to show the form that will be POST'ed
public ActionResult SignIn()
{
return View();
}
This will show the SignIn view.
Then you need a POST action to take the values from the form and send them to the controller.
[HttpPost]
public ActionResult SignIn(Player_Access plyr_obj)
{
//do some work to authenticate the user
return View();
}

Use same partial to add form to Create and Edit actions

When you create a new scaffolded item on VS it creates the views for Create and Edit actions that are almost identical, with the exception of the Edit view having an #Html.HiddenFor for your primary key.
Example of Edit view:
#model MyApp.Models.Destaque
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(m => m.IdDestaque)
<div class="form-group">
#Html.LabelFor(model => model.Mensagem, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Mensagem, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Mensagem, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.CaminhoImagem, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.CaminhoImagem, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.CaminhoImagem, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.UrlLink, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.UrlLink, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.UrlLink, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Salvar" class="btn btn-primary" />
</div>
</div>
</div>
}
If I place all content from the BeginForm (including the #using (...) and keep the #Html.HiddenFor(m => m.IdDestaque) in a _Form partial, it doesn't allow me to create new rows.
If I remove the #Html.HiddenFor from the _Form partial, the Edit action does not work (ModelState is invalid).
So what is the right way to do this and keep the DRY principles? Removing the PK from the ModelState validation in my Edit action seems an "uggly" workaround.
You should render the id of your model inside the view and use another overload for Html.BeginForm as follows:
#using (Html.BeginForm("Edit", "Controller", FormMethod.Post, new{attr1 = value1, attr2 = value2}))
{
#Html.HiddenFor(x => x.Id)
...
}
You always make a post to the EditAction. In you controller you will then only need one POST action for Edit and two get actions one Create and other Edit.
public ActionResult Create()
{
return View("Edit"); //return the edit view
}
public ActionResult Edit(int id)
{
var entity = manager.FetchById(id);
if (entity == null)
return HttpNotFound();
//convert your entity to model (optional, but recommended)
var model = Mapper.Map<ViewModel>(entity);
//return your edit view with your model
return View(model);
}
[HttpPost]
public ActionResult Edit(ViewModel model)
{
if (ModelState.IsValid)
{
//work with your model
return RedirectToAction("Index", "Controller");
}
//at this point there is an error, so your must return your view
return View(model);
}
Hope this helps!

Upload a HttpPostedFileBase for image but always null

I am new to MVC and web programming.
My uploading image is working fine, but when I use almost the exact same code to allow user to modify its upload, it HttpPostedFileBase is always null. Driving me crazy...
here is the model
public class ModifyGenreViewModel
{
public int Id { get; set; }
[Display(Name = "Nom du style")]
public string Name { get; set; }
[Display(Name = "Image")]
public HttpPostedFileBase Image { get; set; }
}
and the view
#using (Html.BeginForm("ModifyGenre", "Upload", null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>#Resource.StyleCreationHeader</h4>
<hr />
#Html.ValidationMessageFor(model=>Model)
<div class="form-group" style="display:none">
#Html.LabelFor(model => model.Id, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-5">
#Html.EditorFor(model => model.Id, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-5">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Image, new { #class = "control-label col-md-2" })
<div class="col-md-10">
<input type="file" data-val="true" id="ModifyGenreViewModel_Image" name="ModifyGenreViewModel.Image" />
#Html.ValidationMessageFor(model => model.Image, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="#Resource.Modify" class="btn btn-primary" />
</div>
</div>
</div>
}
When I set the breakpoint in my controller, I see the Id and the name, but Image is always null.
Thank's for your help!
The name property value of your file input should match with the view model property name for model binding to work properly.
Change the input field name to "Image"
<input type="file" data-val="true" id="ModifyGenreViewModel_Image" name="Image" />
Assuming your HttpPost action method accepts the ModifyGenreViewModel object as parameter.
[HttpPost]
public ActionResult ModifyGenre(ModifyGenreViewModel model)
{
// to do : return something
}
In model class change it to public String Image { get; set; }
In .cshtml page change it to #Html.TextBoxFor(m => m.Image, new {
type = "file", name="Image" })
In Controller you should use the name what you have decleared in html helper HttpPostedFileBase Image

Does the name of parameter have to be model?

Hit a strange issue where my model is not binding and shows up on the controller as null.
I have a form doing a httppost. My breakpoint in the controller is hit and the parameter I expect to be my model is null.
Looking at some example code on another page that works, I copied and pasted it and the only difference was the name of the parameter was 'model' instead of message.
View
#model Site.Models.ContactMessage
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>ContactMessage</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Message, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Message, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Message, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.To, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.To, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.To, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Controller
public ActionResult Contact()
{
return View();
}
[HttpPost]
public ActionResult Contact(ContactMessage message)
{
var m = message;
return View();
}
and it worked. I thought I must have entirely missed something about naming convention. Found you can use Bind, from reading a heap of other posts, to change the prefix like;
public ActionResult Contact([Bind(Prefix = "model")] ContactMessage message)
but that didn't work, still null. Going to rename it to model so it works and I can move on but would like to know why it's not binding if not called model.
public ActionResult Contact(ContactMessage message)
Changed back to this as above but still returns a null.
Interestingly, if I open up another MVC app, that one has whatever parameter names I want and works fine. It's using an older version of MVC 5 (not updated it yet but I will do that and see if anything happens. I don't expect it will.)
Your problem is that you model contains a property named Message and you also have a parameter named message The DefaultModelBinder reads the form values which will include message = "someTextValue" and searches for model properties that have the name message. It finds the one in you model and sets it value (all OK so far) but then it finds another one (your parameter) and tries to set the value of a complex object string value (in effect ContactMessage message = "someTextValue";) which fails so the model becomes null

Resources