Update specific fields using EF in asp.net MVC - c#

I have an application that needs to be able to update data. There is a table called "HomePage" with multiple fields. For ease of use, I want the user to update just 2 fields in this table(Description1 and Description2). While trying to achieve this, it does update these 2 fields but the rest of the data in the other fields in the table are deleted. Please check below code
Controller.cs
// GET: HomePages/Edit/5
public ActionResult EditDescription(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
HomePage homePage = db.HomePages.Find(id);
if (homePage == null)
{
return HttpNotFound();
}
return View(homePage);
}
// POST: HomePages/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditDescription([Bind(Include = "ID,Description1,Description2,TestName1,TestName2,TestName3,TestComp1,TestComp2,TestComp3,TestDesc1,TestDesc2,TestDesc3,FooterAddress,FooterEmail,FooterTel,FooterFax")] HomePage homePage)
{
if (ModelState.IsValid)
{
db.Entry(homePage).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(homePage);
}
cshtml
#using (Html.BeginForm()) { #Html.AntiForgeryToken()
<div class="form-horizontal">
<hr /> #Html.ValidationSummary(true, "", new { #class = "text-danger" }) #Html.HiddenFor(model => model.ID)
<div class="form-group">
#Html.LabelFor(model => model.Description1, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextAreaFor(model => model.Description1, 5, 100, null) #Html.ValidationMessageFor(model => model.Description1, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Description2, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextAreaFor(model => model.Description2 , 8, 100, null) #Html.ValidationMessageFor(model => model.Description2, "", 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" style="color:white;background-color:#ad301c" />
</div>
</div>
</div>
}

You should use the #Html.HiddenFor tag helper for the fields that you do not want to edit. This way the view will send the field data back to the POST method in your controller. For example: <input type="hidden" asp-for="TestName1" /> or #Html.HiddenFor(x => x.TestName1) will pass the TestName1 field to the post method in your controller.

You are binding all model and gets only 2 elements.
[Bind(Include = "ID,Description1,Description2,TestName1,TestName2,TestName3,TestComp1,TestComp2,TestComp3,TestDesc1,TestDesc2,TestDesc3,FooterAddress,FooterEmail,FooterTel,FooterFax")]
So try to do this without Bind option.

Related

Upload Images while creating new Model

I'm going to create profile for my users in ASP.Net MVC application. Users creation controller is something like this:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(UserProfileViewModel userViewModel)
{
if (ModelState.IsValid)
{
....
}
return View(userViewModel);
}
Besides, each user model got several properties including one photo. Everything goes well till I want to add an input field to accept photo.
#Html.TextBoxFor(model => model.ImageUrl, new { type = "file" })
And I add below field to UserProfileViewModel:
[Display(Name = "Profile Photo")]
public HttpPostedFileBase ImageUrl { get; set; }
Among snippets to upload a photo and answers to my previous question, it seems uploading photo was considered as a separate task. i.e. I need an individual form and controller to upload a photo (like first part of this answer).
I want to know are there any methods that I can create whole user profile in one form and pass its photo to the same controller (which included photo in UserProfileViewModel)?
I need to note I don't know to use jQuery or AJAX and I want to use standard HTML helpers for this task.
Update: My View Looks like this:
#model ProjectManager.Models.UserProfileViewModel
#{
ViewBag.Title = "Create";
}
<h2>#ViewBag.Title</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>User Profile</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.Description, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Description)
#Html.ValidationMessageFor(model => model.Description)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Name, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Age, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Age)
#Html.ValidationMessageFor(model => model.Age)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ImageUrl, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.ImageUrl, new { type = "file" })
#Html.ValidationMessageFor(model => model.ImageUrl)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="ثبت" class="btn btn-default" />
</div>
</div>
</div>
}
<div class="rtl text-right">
#Html.ActionLink("Back To List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
File inputs are not sent in the request unless your form element contains the enctype = "multipart/form-data" attribute. Change the view code to
#using (Html.BeginForm("Create", "User", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
....
}
All i have got, your question is I want to know are there any methods that I can create whole user profile in one form and pass its photo to the same controller (which included photo in UserProfileViewModel)?
Yes. It is possible. If you overwrite the form as Stephen Muecke said, you should get the photo with viewmodel. If you get null in viewmodel, you can retrieve the file(photo) from the request also.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(UserProfileViewModel userViewModel)
{
if (ModelState.IsValid)
{
HttpPostedFileBase fileUploadObj= Request.Files[0];
//for collection
HttpFileCollectionBase fileUploadObj= Request.Files;
....
}
return View(userViewModel);
}
Hope this helps :)
You need to use an BeginForm() that allows you to add htmlAttributes, and because you need to add
new {enctype = "multipart/form-data" }
#using (Html.BeginForm("UserProfileViewModel ", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
Controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult UserProfileViewModel(UserProfileViewModel userViewModel)
{
if (ModelState.IsValid)
{
HttpPostedFileBase fileUpload= Request.Files[0];
//for collection
HttpFileCollectionBase fileUpload= Request.Files;
....
}

remove items to a bound list model in ASP MVC.NET

I followed an online tutorial to dynamically add items to a bound list model using ajax, which works perfectly. (http://www.mattlunn.me.uk/blog/2014/08/how-to-dynamically-via-ajax-add-new-items-to-a-bound-list-model-in-asp-mvc-net/comment-page-2/#comment-68909)
My question is, how would I correctly remove items from the list?
Right now what I have done is add a delete link which when clicked removes the item from the view. However, when I submit the form I noticed that the modelState is no longer valid and it has null entries for the item that was removed from the view. So I guess the model is not being updated.
Test.cshtml
#model TesterManager.Models.Test
<div class="form-group">
#Html.LabelFor(model => model.Software, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div class="form-group">
<div class="col-md-5">
#Html.DropDownListFor(m => m.Software, TesterManager.Models.Helper.GetTestSoftwares(), "Choose a USB Card", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Software, "", new { #class = "text-danger" })
</div>
<div class="col-md-5">
#Html.EditorFor(model => model.Version, new { htmlAttributes = new { #class = "form-control", #title = "Enter a USB FW Version", #placeholder = "Enter a USB FW Version" } })
#Html.ValidationMessageFor(model => model.Version, "", new { #class = "text-danger" })
</div>
<div class="col-md-2">
Delete
</div>
</div>
</div>
</div>
AdminTesterConfigurations.cshtml (snippet):
#model TesterManager.Models.AdminTesterConfigurations
<div class="form-group">
<div class="col-md-6">
....
</div>
</div>
<hr />
<div class="form-group">
<div class="col-md-12">
<h3>Test Software</h3>
<div id="test-list">
#Html.EditorForMany(x => x.Tests, x => x.Index)
</div>
<input type="button" id="add-test" value="Add" />
</div>
</div>
RequestEditViewModel.cshtml:
#model TesterManager.Models.RequestEditViewModel
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.EditorFor(model => model.ShippingLocation)
#Html.EditorFor(model => model.RequesterTesterConfigurations)
#Html.EditorFor(model => model.AdminTesterConfigurations)
<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>
Edit.cshtml:
#model TesterManager.Models.RequestEditViewModel
#Styles.Render("~/Content/Edit")
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#section Scripts
{
<script>
jQuery(document).ready(function ($) {
$('#add-test').on('click', function () {
jQuery.get('/TesterManager/Request/AddTest').done(function (html) {
$('#test-list').append(html);
});
});
});
</script>
}
#using (Html.BeginForm())
{
<h2>Edit</h2>
#Html.AntiForgeryToken()
#Html.EditorFor(x => x);
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
RequestController.cs
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(RequestEditViewModel request)
{
if (ModelState.IsValid)
{
Request domainRequest = new Request(request);
requests.Add(domainRequest);
return RedirectToAction("Index");
}
return View(request);
}
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public ActionResult AddTest()
{
var request = new RequestEditViewModel();
request.AdminTesterConfigurations.Tests.Add(new Test());
return View(request);
}
I realized that the problem was that when I would remove the item from the list in the view, I was not removing the hidden input for the collection indexer as well. I updated the code to remove the hidden input and it works fine now.

HttpPostedFileBase is null

I'm trying to upload a file, but it does not work as expected. I have the following view:
#using (Ajax.BeginForm("RegisterBand", "NewProfile", new AjaxOptions() { HttpMethod = "Post",
InsertionMode = InsertionMode.Replace,
}, new { enctype = "multipart/form-data"}))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-horizontal">
<div class="form-group">
<div class="col-md-10">
Bandname
</div>
<div class="col-md-10">
#Html.EditorFor(x => x.BandProfile.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(x => x.BandProfile.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-10">
Genres
</div>
<div class="col-md-10">
#Html.DropDownListFor(x => x.BandProfile.Genres, Enumerable.Empty<SelectListItem>(), new { #class="", multiple = "multiple", style ="width: 100%;"} )
#Html.ValidationMessageFor(x => x.BandProfile.Genres, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-10">
Coverpicture
</div>
<div class="col-md-10">
<input type="file" name="file" id="CoverPicture" />
#Html.ValidationMessageFor(x => x.BandProfile.CoverPicture, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-10">
Description
</div>
<div class="col-md-10">
#Html.EditorFor(x => x.BandProfile.Description, new { htmlAttributes = new { #class = "form-control"} })
#Html.ValidationMessageFor(x => x.BandProfile.Description, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Spara" class="btn btn-success" />
</div>
</div>
</div>
}
Here is my controller:
[HttpPost]
public ActionResult RegisterBand(ProfileViewModel model, HttpPostedFileBase file)
{
if (ModelState.IsValid == false)
{
return Json(JsonRequestBehavior.AllowGet);
}
var bandProfile = _profileService.CreateBandProfile(model.BandProfile, file, UserId);
if (bandProfile != null)
{
userManager.AddToRole(UserId, "Band");
return RedirectToAction("Index", "Welcome");
}
return View("Index");
}
The problem I have is that file always results in null. I can't understand why. How can I find the problem?
The issue here is that you are using the Ajax.BeginForm() helper to create and post your form. However, files cannot be uploaded using AJAX.
You may want to consider using a jQuery-based plug-in to accomplish this, which relies on the use of an <iframe> to handle your uploading operations behind the scenes and posting them to the proper location.
Otherwise, you could consider trying a normal form using Html.BeginForm(), which should work in your scenario (if you don't explicitly need any of the AJAX functionality).
Update
Another issue here is that the constructor that you are using for your Ajax.BeginForm() call is accepting an AjaxOptions and htmlAttributes parameter, which falls in like with this constructor
However, your current use is missing the third RouteValues parameter. You could try adding null in there to see if that makes any difference :
#using(Ajax.BeginForm("RegisterBand",
"NewProfile",
null,
new AjaxOptions() {
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace
},
new { enctype = "multipart/form-data"})){
<!-- Content -->
}

Form post failing to bind to strongly-typed model MVC4 [duplicate]

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

Render view with modified Model

I´m new in MVC, and I´m working in a simple FORM, but,I have a problem,
for some reason I want to change the bound model in the controller operation and
render the view, but this not happen.
For example:
public class Product{
int id {get; set;}
string description {get; set;}
}
and the controller method:
[POST]
public ActionResult Edite(Product p){
p.description = "HELLOOOOOO!!!"
return View(P);
}
the view:
#model WebSite.Models.Product
#{
ViewBag.Title = "Modificar (Product)";
}
<h2>Modificar (Product)</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4></h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.Id)
<div class="form-group">
#Html.LabelFor(model => model.description, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.description, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.description, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Guardar" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Volver a la Lista", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
but in the rendered view, the description of the product is not "HELLOOOOO!!!!".
Why MVC render the view with the user entered values and not with the new model I want?
maybe isn't the best way to resolve the problem, but this post solved my problem:
Asp.net MVC ModelState.Clear

Categories