Save ASP.NET core Identity User attributes in another table - sql-server

I am developing an ASP .NET core web application. I employ Identity UI framework for the user registration and authorization in the application. I inherit Identity User to my ApplicationUser class as follows. It creates a table called as ApplicationUser and save the relevant data under the given attributes successfully: (I am using Microsoft SQL database)
ApplicationUser.cs
using Microsoft.AspNetCore.Identity;
using System;
using System.Collections.Generic;
#nullable disable
namespace WebApp.Models
{
public partial class ApplicationUser : IdentityUser<int>
{
public ApplicationUser()
{
}
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastNam { get; set; }
public DateTime? DateOfBirth { get; set; }
public string Bio { get; set; }
public virtual UserAddress UserAddress { get; set; }
}
}
Then I implemented UserAddress model class as follows. It creates another table in the database named as "UserAddress"\
UserAddress.cs
using System;
using System.Collections.Generic;
#nullable disable
namespace WebApp.Models
{
public partial class UserAddress
{
public int UserId { get; set; }
public string BuildingNo { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public virtual ApplicationUser User { get; set; }
}
}
Next in under Areas folder in Identity UI frame work, I change the Index.cshtml file as follows. i inserting new entry to enter the building number of the user, that should be saved in UserAddress table in database.
Index.cshtml
#page
#model IndexModel
#{
ViewData["Title"] = "Profile";
ViewData["ActivePage"] = ManageNavPages.Index;
}
<h4>#ViewData["Title"]</h4>
<partial name="_StatusMessage" model="Model.StatusMessage" />
<div class="row">
<div class="col-md-12">
<form id="profile-form" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="=row d-flex flex-row">
<div class="form-group col-md-6">
<label asp-for="Input.UserName"></label>
<input asp-for="Input.UserName" class="form-control" />
</div>
</div>
<div class="=row d-flex flex-row">
<div class="form-group col-md-6">
<label asp-for="Input.FirstName"></label>
<input asp-for="Input.FirstName" class="form-control" />
</div>
<div class="form-group col-md-6">
<label asp-for="Input.MiddleName"></label>
<input asp-for="Input.MiddleName" class="form-control" />
</div>
</div>
<div class="=row d-flex flex-row">
<div class="form-group col-md-6">
<label asp-for="Input.LastNam"></label>
<input asp-for="Input.LastNam" class="form-control" />
</div>
</div>
<div class="=row d-flex flex-row">
<div class="form-group col-md-6">
<label asp-for="Input.DateOfBirth"></label>
<input asp-for="Input.DateOfBirth" class="form-control" />
</div>
<div class="form-group col-md-6">
<label asp-for="Input.PhoneNumber"></label>
<input asp-for="Input.PhoneNumber" class="form-control" />
<span asp-validation-for="Input.PhoneNumber" class="text-danger"></span>
</div>
</div>
<div class="=row d-flex flex-row">
<div class="form-group col-md-6">
<label asp-for="Input.BuildingNo"></label>
<input asp-for="Input.BuildingNo" class="form-control" />
</div>
</div>
<div class="=row d-flex flex-row">
<div class="do-md-6">
<button id="update-profile-button" type="submit" class="btn btn-primary">Save</button>
</div>
</div>
</form>
</div>
</div>
#section Scripts {
<partial name="_ValidationScriptsPartial" />
}
And in the Index.cshtml.cs file, I tried to save the building number in the UserAddress table as follows but it fails to enter the data into the table.
Index.cshtml.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using WebApp.Models;
namespace WebApp.Areas.Identity.Pages.Account.Manage
{
public partial class IndexModel : PageModel
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
public IndexModel(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
public string BuildingNo { get; set; }
public string Username { get; set; }
[TempData]
public string StatusMessage { get; set; }
[BindProperty]
public InputModel Input { get; set; }
public class InputModel
{
[DataType(DataType.Text)]
[Display(Name = "User Name")]
public string UserName { get; set; }
[DataType(DataType.Text)]
[Display(Name = "First name")]
public string FirstName { get; set; }
[DataType(DataType.Text)]
[Display(Name = "Middle name")]
public string MiddleName { get; set; }
[DataType(DataType.Text)]
[Display(Name = "Last name")]
public string LastNam { get; set; }
[Display(Name = "Date of Birth")]
[DataType(DataType.Date)]
public DateTime DateOfBirth { get; set; }
[Phone]
[Display(Name = "Phone number")]
public string PhoneNumber { get; set; }
[Display(Name = "Building No:")]
[DataType(DataType.Text)]
public string BuildingNo { get; set; }
}
private async Task LoadAsync(ApplicationUser user)
{
var userName = await _userManager.GetUserNameAsync(user);
var phoneNumber = await _userManager.GetPhoneNumberAsync(user);
Username = userName;
Input = new InputModel
{
UserName = user.UserName,
FirstName = user.FirstName,
MiddleName = user.MiddleName,
LastNam = user.LastNam,
PhoneNumber = phoneNumber,
};
}
public async Task<IActionResult> OnGetAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
await LoadAsync(user);
return Page();
}
public async Task<IActionResult> OnPostAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
if (!ModelState.IsValid)
{
await LoadAsync(user);
return Page();
}
var phoneNumber = await _userManager.GetPhoneNumberAsync(user);
if (Input.PhoneNumber != phoneNumber)
{
var setPhoneResult = await _userManager.SetPhoneNumberAsync(user, Input.PhoneNumber);
if (!setPhoneResult.Succeeded)
{
StatusMessage = "Unexpected error when trying to set phone number.";
return RedirectToPage();
}
}
if(Input.FirstName != user.FirstName)
{
user.FirstName = Input.FirstName;
}
if (Input.MiddleName != user.MiddleName)
{
user.MiddleName = Input.MiddleName;
}
if (Input.LastNam != user.LastNam)
{
user.LastNam = Input.LastNam;
}
if (Input.DateOfBirth != user.DateOfBirth)
{
user.DateOfBirth = Input.DateOfBirth;
}
if (Input.UserName != user.UserName)
{
user.UserName = Input.UserName;
}
user.UserAddress.BuildingNo = Input.BuildingNo; // I tried to enter the building address to the UserAddress table by using this code
await _userManager.UpdateAsync(user);
await _signInManager.RefreshSignInAsync(user);
StatusMessage = "Your profile has been updated";
return RedirectToPage();
}
}
}
Please ignore the above lengthy Index.cshtml.cs code I have provided, I have commented near the only code that I used to insert the input building number to the UserAddress table. which is:
user.UserAddress.BuildingNo = Input.BuildingNo;
This is the part of view of the entry: The entry view
And this is the error I am getting when above code is run: The error message
For the record: all the fields in ApplicationUser table is updated. but this error occurs when I am trying to insert data into UserAddress table.
I am pretty user this is a very simple question for a person who knows ASP.NET core identity user very well.
I kindly request if somebody can please help me to save the input building number in another table named User Address?
Thanks in advance !!!

You can change your code like below:
First use code get current user include UserAddress:
var user = await _userManager.Users
.Include(x => x.UserAddress)
.SingleAsync(x => x.UserName== Input.UserName);
Then determine whether UserAddress exists and update it.
if (user.UserAddress == null)
{
user.UserAddress = new Models.UserAddress
{
BuildingNo = Input.BuildingNo
};
}
else
{
user.UserAddress.BuildingNo = Input.BuildingNo;
}
The whole code is like below:
public async Task<IActionResult> OnPostAsync()
{
//get the current user
var user = await _userManager.Users
.Include(x => x.UserAddress)
.SingleAsync(x => x.UserName== Input.UserName);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
if (!ModelState.IsValid)
{
await LoadAsync(user);
return Page();
}
var phoneNumber = await _userManager.GetPhoneNumberAsync(user);
if (Input.PhoneNumber != phoneNumber)
{
var setPhoneResult = await _userManager.SetPhoneNumberAsync(user, Input.PhoneNumber);
if (!setPhoneResult.Succeeded)
{
StatusMessage = "Unexpected error when trying to set phone number.";
return RedirectToPage();
}
}
if(Input.FirstName != user.FirstName)
{
user.FirstName = Input.FirstName;
}
if (Input.MiddleName != user.MiddleName)
{
user.MiddleName = Input.MiddleName;
}
if (Input.LastNam != user.LastNam)
{
user.LastNam = Input.LastNam;
}
if (Input.DateOfBirth != user.DateOfBirth)
{
user.DateOfBirth = Input.DateOfBirth;
}
if (Input.UserName != user.UserName)
{
user.UserName = Input.UserName;
}
//insert the BuildingNo
if (user.UserAddress == null)
{
user.UserAddress = new Models.UserAddress
{
BuildingNo = Input.BuildingNo
};
}
else
{
user.UserAddress.BuildingNo = Input.BuildingNo;
}
await _userManager.UpdateAsync(user);
await _signInManager.RefreshSignInAsync(user);
StatusMessage = "Your profile has been updated";
return RedirectToPage();
}

Related

Asp.net core database data displayed more often than existing

I'm wondering why my ASP.NET Core MVC Project is listing my data double.
What it should be:
What it gives me:
See the difference?
My Controller (Controller Class - Index()-Method):
[HttpGet()]
public async Task<IActionResult> Index(string id)
{
IQueryable<string> werkeQuery = from m in _context.TestDbSet
orderby m.Id
select m.Id;
var test = from t in _context.TestDbSet
orderby t.Id
select t;
if (!string.IsNullOrEmpty(id))
{
test = (IOrderedQueryable<TestSet>)_context.TestDbSet.Where(x => x.Id == id);
}
var filter = new TestSet
{
Werke = new SelectList(await werkeQuery.Distinct().ToListAsync()),
Liste = await test.ToListAsync()
};
return View(filter);
}
My Model-Class (could there be the error?):
`[Table("Test", Schema = "dbo")]
public class TestSet
{
[Key]
[Display(Name = "Werk")]
[Column("Id")]
public string Id { get; set; }
[Display(Name = "Mitarbeiter ID")]
[Column("M_ID")]
public string M_Id { get; set; }
[Column("Beginn")]
[DataType(DataType.Date)]
public DateTime Beginn { get; set; }
[Column("Ende")]
[DataType(DataType.Date)]
public DateTime Ende { get; set; }
[NotMapped]
public SelectList Werke { get; set; }
[NotMapped]
public List<TestSet> Liste { get; set; }
}`
My View (relevant code: displayed list):
`#model DienstplanAnzeige.Models.TestSet
#{
ViewData["Title"] = "Startseite";
}
<form asp-controller="Home" asp-action="Index" method="get">
<div class="input-group mb-3">
<select class="custom-select" asp-for="Id" asp-items="#Model.Werke">
<option value="" disabled selected>Werk auswählen</option>
</select>
<input type="submit" value="Anzeigen" class="btn btn-outline-secondary" />
</div>
</form>
<table class="table table-hover">
<thead>
<tr>
<th>#Html.DisplayNameFor(model => model.Liste[0].Id)</th>
<th>#Html.DisplayNameFor(model => model.Liste[0].M_Id)</th>
<th>#Html.DisplayNameFor(model => model.Liste[0].Beginn)</th>
<th>#Html.DisplayNameFor(model => model.Liste[0].Ende)</th>
</tr>
</thead>
<tbody>
#foreach(var item in Model.Liste)
{
<tr>
<td>#Html.DisplayFor(modelItem => item.Id)</td>
<td>#Html.DisplayFor(modelItem => item.M_Id)</td>
<td>#Html.DisplayFor(modelItem => item.Beginn)</td>
<td>#Html.DisplayFor(modelItem => item.Ende)</td>
</tr>
}
</tbody>
</table>`
My Context-Class (named "TestContext"):
public class TestContext : DbContext
{
public TestContext(DbContextOptions<TestContext> options)
: base(options)
{
}
public DbSet<TestSet> TestDbSet { get; set; }
}
Can someone help me?
In your controller, since your id property and parameter is in string therefore instead of using == comparison operator you should use Equals(...) method of string class i.e.
if (!string.IsNullOrEmpty(id))
{
test = (IOrderedQueryable<TestSet>)_context.TestDbSet.Where(x => x.Id.Equals(id, StringComparison.InvariantCultureIgnoreCase);
}

Can't post (create) 3rd level nested model in ASP.NET Core 3.1 MVC

I'm at the end of my thoughts. It's been days. I can't figure out how to validate and then create a new database model from deep-nested models.
I have Offer and Order tables which share Company/Currency/Contact tables so I decided, instead of having Offer.Company, Order.Company, to create a table SharedInfo and have it Offer.SharedInfo.Company and Order.SharedInfo.Comapany which can be the same.
Shortened for brevity
Company.cs:
namespace memo.Models
{
public partial class Company
{
[Key]
public int CompanyId { get; set; }
[Required(ErrorMessage = "You have to fill the name of the Company")]
public string Name { get; set; }
public string City { get; set; }
}
}
SharedInfo.cs:
namespace memo.Models
{
public class SharedInfo
{
public SharedInfo()
{
Company = new Company();
}
[Key]
public int SharedInfoId { get; set; }
[Required]
public string Subject { get; set; }
[Required]
public int CompanyId { get; set; }
public virtual Company Company { get; set; }
Offer.cs:
namespace memo.Models
{
public partial class Offer
{
public Offer()
{
SharedInfo = new SharedInfo();
}
[Key]
public int OfferId { get; set; }
public int SharedInfoId { get; set; }
public virtual SharedInfo SharedInfo { get; set; }
}
}
My view model for Create.cshtml file is (again, for brevity shortened but this fills my combobox and references the Offer):
namespace memo.ViewModels
{
public class OfferViewModel
{
public Offer Offer { get; set; }
public IEnumerable<SelectListItem> CompanyList { get; set; }
}
}
Now I want to create a new offer where I select CompanyId from a combobox.
Offers/Create.cshtml:
#model memo.ViewModels.OfferViewModel
<div class="container d-flex justify-content-center">
<div class="col-lg-10 personal-info">
<form class="card" role="form" autocomplete="on" asp-action="Create" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group row">
<label asp-for="Offer.SharedInfo.Subject" class="required col-lg-3 col-form-label form-control-label control-label"></label>
<div class="col-lg-9">
<span class="has-float-label">
<input asp-for="Offer.SharedInfo.Subject" class="form-control" type="text" />
<label asp-for="Offer.SharedInfo.Subject"></label>
</span>
<span asp-validation-for="Offer.SharedInfo.Subject" class="text-danger"></span>
</div>
</div>
<div class="form-group row">
<label class="required col-lg-3 col-form-label form-control-label control-label"></label>
<div class="col-lg-4">
<select class="form-control selectpicker" asp-for="Offer.SharedInfo.Company.CompanyId" asp-items="#Model.CompanyList"></select>
<span asp-validation-for="Offer.SharedInfo.Company.CompanyId" class="text-danger"></span>
</div>
</div>
Here I select a company which gives me the CompanyId, no problem there.
But now, when I click on Create Offer button to Post the form, the validation fails...
Offers/OffersController.cs
[HttpPost]
public async Task<IActionResult> Create(Offer offer)
{
if (ModelState.IsValid)
{
offer.CreatedBy = User.GetLoggedInUserName();
offer.CreatedDate = DateTime.Now;
await _db.AddAsync(offer);
await _db.SaveChangesAsync();
}
}
Validation tells me that:
SubKey={Name}, Key="offer.SharedInfo.CompanyName", ValidationState=Invalid
What I want to achieve is to Create 2 new tables. SharedInfo which will reference the Company by ID I selected and then Offer, which will reference the new SharedInfo record.
Am I doing something horribly wrong? It's telling me I have to "it's required" specify Company.Name but when I select the company by it's ID, it should know the name...
I even tried in the controller to specify _context.Offer.SharedInfo.Company = _context.Company.Where(x => x.CompanyId == offer.SharedInfo.Company.CompanyId) but that fails in >> Validation << because, I think, the SharedInfo is not yet created? Don't know. I'm totally at the end with my thoughts.
Model validation will validate the whole model if you specify any of their property in your razor view.For you contains input named Offer.SharedInfo.Company.CompanyId and Offer.SharedInfo.Subject,model validation will validate all the properties in Company model and 'SharedInfo' model although you do not set CompanyName input.
And I think you may be confused that Offer.SharedInfo.CompanyId which is required but you also do not set input in razor view.Because it is an int type,you could see that it will receive default value 0 if you do not pass the value to backend.And 0 is a valid value for int type,that is why the validation for Offer.SharedInfo.CompanyId succeed.
For your requirement,you want to skip the validation of CompanyName,you could use ModelState.Remove(keyname) like below:
[HttpPost]
public async Task<IActionResult> Create(Offer offer)
{
ModelState.Remove("Offer.SharedInfo.CompanyName");//from your error message,it should be the key name
if (ModelState.IsValid)
{
//...
}
//...
}

Upload pdf or doc into database of ASP.NET MVC-5 application

Hi,
I have been learning ASP.NET as well as doing a small project through MVC application.
My application is based on raising a purchase request for a product by an institution. It's a basic form through which all data are stored in DB.
How to add upload PDF or DOC into this coding so that the pdf quotation can be uploaded while submitting the form.
**
My Model
**
namespace sparki02.Models{
public class PRview
{
public int Id { get; set; }
[DataType(DataType.Html)]
public string Caption { get; set; }
[Required]
[DataType(DataType.ImageUrl)]
public string ImageUrl { get; set; }
[Required]
[StringLength(100)]
[Display(Name = "Supplier Name")]
public string SupplierName { get; set; }
[Required]
[StringLength(255)]
[Display(Name = "Material Name")]
public string MATName { get; set; }
[Required]
[StringLength(100)]
public string Brand { get; set; }
public PRtype PRtype { get; set; }
[Display(Name = "PR Type")]
public byte PRtypeId { get; set; }
[Required]
[Display(Name = "Unit Price")]
public double Unitprice { get; set; }}}
**
2. Controller
**
public ActionResult NewPR()
{var prtypes = _context.PRtypes.ToList();
var viewModel = new NewPRViewModel
{PRview = new PRview(),
PRtypes = prtypes};
return View("NewPR", viewModel);
}
[HttpPost]
public ActionResult Save(PRview prview, NewPRViewModel model)
{
var validImageTypes = new string[]
{
"image/gif",
"image/jpeg",
"image/pjpeg",
"image/png"
};
if (model.ImageUpload == null || model.ImageUpload.ContentLength == 0)
{
ModelState.AddModelError("ImageUpload", "This field is required");
}
else if (validImageTypes.Contains(model.ImageUpload.ContentType))
{
ModelState.AddModelError("ImageUpload", "Please choose either a GIF, JPG or PNG image.");
}
if (!ModelState.IsValid)
{
var viewModel = new NewPRViewModel
{
PRview = prview,
PRtypes = _context.PRtypes.ToList(),
Caption = model.Caption
};
return View("NewPR", viewModel);
}
if (prview.Id == 0)
_context.PRviews.Add(prview);
else
{
var prviewInDb = _context.PRviews.Single(c => c.Id == prview.Id);
prviewInDb.PRtypeId = prview.PRtypeId;
prviewInDb.MATName = prview.MATName;
prviewInDb.SupplierName = prview.SupplierName;
prviewInDb.Brand = prview.Brand;
prviewInDb.Unitprice = prview.Unitprice;
prviewInDb.ImageUrl = prview.ImageUrl;
if (model.ImageUpload != null && model.ImageUpload.ContentLength > 0)
{
var uploadDir = "~/uploads";
var imagePath = Path.Combine(Server.MapPath(uploadDir), model.ImageUpload.FileName);
var imageUrl = Path.Combine(uploadDir, model.ImageUpload.FileName);
model.ImageUpload.SaveAs(imagePath);
prview.ImageUrl = imageUrl;
}
}
_context.SaveChanges();
return RedirectToAction("Index", "PRview");
**
My View block
** Only content related to file upload
{ #model sparki02.ViewModels.NewPRViewModel
#using (Html.BeginForm("Save", "PRview", FormMethod.Post, new { enctype = "multipart/form-data" }))
{#Html.ValidationSummary(true, "Please fix the following errors.")
<div>
#Html.LabelFor(m => m.Caption)
#Html.EditorFor(m => m.Caption)
</div>
<div>
#Html.LabelFor(m => m.ImageUpload)
#Html.TextBoxFor(m => m.ImageUpload, new { type = "file" })
</div>
<button type="submit">Create</button>
<div class="form-group">
<button type="submit" class="btn btn-primary">Save</button>
</div>
<div class="form-group"> <p> #DateTime.Now</p> </div>
}
Whereas it is non-trivial to Download or View PDFs, it is relatively trivial to upload them. I used https://learn.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-2.2 as mentioned by ADyson, but only about 5% of the code is really necessary.
In your CSHTML, you must add a Form File:
<input type="file" class="custom-control-input" tabindex="0" asp-for="FileUpload.FormFile">
<label asp-for="FileUpload.FormFile" class="custom-control-label">Upload Form</label>
Your form must include
enctype="multipart/form-data"
Your class must include:
[Required]
[BindProperty]
public BufferedSingleFileUploadDb FileUpload { get; set; }
}
public class BufferedSingleFileUploadDb
{
[Required]
[Display(Name = "File")]
public IFormFile FormFile { get; set; }
}
And in your Controller, here's some code that will work, although I commented out Microsoft's AppFile suggestion. You can save the file to a filesystem, database, etc.:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> OrderEquipmentAsync(OrderEquipmentGroup orderEquipGroup)
{
if (ModelState.IsValid)
{
// save stuff here.
using (var memoryStream = new MemoryStream())
{
await orderEquipGroup.FileUpload.FormFile.CopyToAsync(memoryStream);
// Upload the file if less than 2 MB
if (memoryStream.Length < 2097152)
{
//var file = new AppFile()
//{
// Content = memoryStream.ToArray()
//};
//_dbContext.File.Add(file);
//await _dbContext.SaveChangesAsync();
}
else
{
ModelState.AddModelError("File", "The file is too large.");
}
}
My last suggestion is that you be VERY careful when uploading files to a server. As Microsoft says in their article, here are some wise guidelines: 1. use a safe filename, 2. allow only approved file extensions, 3. limit the filesize, 4. Scan the uploaded file before saving.

I am getting 'System.Data.Entity.Infrastructure.DbUpdateConcurrencyException' .....when i tried to update a row in my table

i am trying to update a specific row in my table but i get An exception of type 'System.Data.Entity.Infrastructure.DbUpdateConcurrencyException' occurred in EntityFramework.dll but was not handled in user code
{"Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions."}
my action method is
public ActionResult createedit()
{
int id = Convert.ToInt32( Session["UserID"]);
var Certtt = (from cert in db.TBL_UserRegistration where cert.UserLoginID == id select cert).FirstOrDefault();
TBL_UserRegistration u = db.TBL_UserRegistration.Find(Certtt.UserRegistrationID);
return View(u);
}
[HttpPost]
public ActionResult createedit(TBL_UserRegistration user, HttpPostedFileBase imageup)
{
if(imageup != null)
{
user.UserImage = new byte[imageup.ContentLength];
imageup.InputStream.Read(user.UserImage, 0, imageup.ContentLength);
}
db.Entry(user).State = EntityState.Modified;
db.SaveChanges();
return View(user);
}
my view
#using (Html.BeginForm("createedit", "UserRegistration", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<form class="wiwet-checkout">
<div class="row">
<div class="col-sm-6">
<!-- <input type="text" placeholder="First Name" />-->
#*#Html.LabelFor(model => model.UserFirstName, htmlAttributes: new { #class = "text-label", #placeholder = "Password" })*#
#Html.EditorFor(model => model.UserFirstName, new { htmlAttributes = new { #class = "form-control", #placeholder = "First Name" } })
#Html.ValidationMessageFor(model => model.UserFirstName, "")
</div>
.
.
.
}
my model TBL_UserResgistration is
public partial class TBL_UserRegistration
{
public TBL_UserRegistration()
{
this.TBL_Payment = new HashSet<TBL_Payment>();
}
public int UserRegistrationID { get; set; }
public Nullable<System.DateTime> UserRegistrationDate { get; set; }
public string Username { get; set; }
public string UserPassword { get; set; }
public string UserFirstName { get; set; }
public string UserLastName { get; set; }
public string UserEmail { get; set; }
public string UserType { get; set; }
public string UserCity { get; set; }
public string UserState { get; set; }
public string UserCountry { get; set; }
public Nullable<int> UserZip { get; set; }
public string UserAddressLine1 { get; set; }
public string UserAdressLine2 { get; set; }
public Nullable<long> UserPhone1 { get; set; }
public Nullable<long> UserPhone2 { get; set; }
public byte[] UserImage { get; set; }
public Nullable<int> UserLoginID { get; set; }
public virtual TBL_Login TBL_Login { get; set; }
public virtual ICollection<TBL_Payment> TBL_Payment { get; set; }
}
You are getting this exception because entity framework can't find your user object in the database to update it READ MORE, that's because you are passing a user entity with only first name as I can see from your view, what you can do is this, pass your id as a hidden field, get user model by id from you database context, set the new user first name, update, done.
this is how you do it
in your view, pass the id as hidden
#using (Html.BeginForm("createedit", "UserRegistration", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<!-- here is the hidden field keeping your id -->
#Html.Hidden("UserRegistrationID ",Model.UserRegistrationID )
<form class="wiwet-checkout">
<div class="row">
<div class="col-sm-6">
<!-- <input type="text" placeholder="First Name" />-->
#*#Html.LabelFor(model => model.UserFirstName, htmlAttributes: new { #class = "text-label", #placeholder = "Password" })*#
#Html.EditorFor(model => model.UserFirstName, new { htmlAttributes = new { #class = "form-control", #placeholder = "First Name" } })
#Html.ValidationMessageFor(model => model.UserFirstName, "")
</div>
.
.
.
}
in your controller
// get the real entity from the database using the id passed to your controller
// as i mentioned before you should keep it in a hidden field
TBL_UserRegistration u = db.TBL_UserRegistration.Find(user.UserRegistrationID);
// update the entity user name according to the new one passed from your view
u.UserFirstName = user.UserFirstName;
// update and save
db.Entry(u).State = EntityState.Modified;
db.SaveChanges();

How to Upload 2 Image Files into MVC C# 5 database in its respective Byte[] array property?

public class Opportunity
{
[Key]
public int OpportunityId { get; set; }
[Required(ErrorMessage = "Graphics Image is required")]
public byte[] Graphics { get; set; }
[DisplayName("Faculty Picture")]
[Required(ErrorMessage = "Faculty Image is required")]
public byte[] FacultyPicture { get; set; }
}
Controller:
namespace Kaust.Views.Opportunities
{
public class OpportunitiesController : Controller
{
private KaustContext db = new KaustContext();
public ActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "OpportunityId,Graphics,FacultyPicturen")] Opportunity opportunity)
{
if (ModelState.IsValid)
{
db.Opportunities.Add(opportunity);
db.SaveChanges();
return RedirectToAction("Index");
}
}
View:
Create index:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Opportunity</h4>
<hr />
#Html.Images(m => m.Graphics, "Graphics", "id")
#Html.ValidationMessageFor(model => model.Graphics, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-horizontal">
<h4>Opportunity</h4>
<hr />
#Html.Images(m => m.FacultyPicture, "Graphics", "id")
#Html.ValidationMessageFor(model => model.FacultyPicture, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
And #Html.Images is a customhelper:
public static IHtmlString Images<TModel,TValue>(this HtmlHelper<TModel> helper,System.Linq.Expressions.Expression<Func<TModel, TValue>> expression, string name, string id){
TagBuilder tb = new TagBuilder("input");
tb.Attributes.Add("ex", expression.ToString());
tb.Attributes.Add("name", name);
tb.Attributes.Add("id", id);
tb.Attributes.Add("type", "file");
tb.Attributes.Add("accept", "Image/*");
return new MvcHtmlString(tb.ToString(TagRenderMode.SelfClosing));
}
}
It creates this output:
<input accept="Image/*" ex="m => m.Graphics" id="id" name="Graphics" type="file">
When I click the submit button:
The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters.
I have seend several methods to change the image file to Byte[] but I just don't know how to do it before the submit button or because it doesn't get into the "httppost method".
I have tried this solutions. but... I still get the error.
How to upload/display images using ASP.net MVC4 with Entity Framework
http://www.prideparrot.com/blog/archive/2012/8/uploading_and_returning_files
The question is how can I save this files into the databases in after clicking the submit button?
The properties in your model need to be HttpPostedFileBase (not byte[]) for binding to a file input in the view. Since your also wanting to store the filein the data base, you will need a separate view model and data model
// View model (Note ID property not required)
public class OpportunityVM
{
[Required(ErrorMessage = "Image is required")]
public HttpPostedFileBase Graphics { get; set; }
[DisplayName("Faculty Picture")]
public HttpPostedFileBase FacultyPicture { get; set; }
}
And in the POST method
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([OpportunityVM model)
{
if(!ModelState.IsValid)
{
return View(model);
}
// Initialize data model
Opportunity opportunity = new Opportunity();
using (var reader = new System.IO.BinaryReader(model.Graphics.InputStream))
{
opportunity.Graphics = reader.ReadBytes(model.Graphics.ContentLength);
}
if (model.FacultyPicture != null && modelFacultyPicture.ContentLength > 0)
{
// ditto for FacultyPicture
}
db.Opportunities.Add(opportunity);
db.SaveChanges();
return RedirectToAction("Index");
}
Note that you also need to include the enctype = "multipart/form-data" attribute in the form tag
#using (Html.BeginForm("Create", "Opportunities", FormMethod.Post, new { enctype = "multipart/form-data" }))
Side note: Your generating invalid html. Both file inputs in your model have id="id" (duplicate id attributes)
There is no need to pass the name and id to the helper (and in fact a minor typo passing the name means binding will fail). Instead use the ModelMetadata to generate the correct attributes. In addition, ex is not a valid attribute and its not clear what you are trying to achieve with tb.Attributes.Add("ex", expression.ToString()); but it should be removed.
public static IHtmlString Images<TModel,TValue>(this HtmlHelper<TModel> helper,System.Linq.Expressions.Expression<Func<TModel, TValue>> expression)
{
string name = ExpressionHelper.GetExpressionText(expression);
string id = HtmlHelper.GenerateIdFromName(name);
TagBuilder tb = new TagBuilder("input");
// tb.Attributes.Add("ex", expression.ToString());
tb.MergeAttribute("name", name);
tb.MergeAttribute("id", id);
tb.MergeAttribute("type", "file");
tb.MergeAttribute("accept", "Image/*");
return new MvcHtmlString(tb.ToString(TagRenderMode.SelfClosing));
}

Resources