Perform CRUD in controller with ViewModel in ASP.NET MVC - c#

From my two models Student and InventoryRecord. I created a ViewModel named TestViewModel. I'm confused as to how do I write my controller?
public class TestViewModel
{
//from Student model
[Key]
public string UserID { get; set; }
public string PhoneNumber{ get; set; }
public string Address{ get; set; }
//other properties
//from Inventory model
public string FathersName { get; set; }
public string FathersAddress { get; set; }
//other properties
}
When I'm using only my main model Student. This is how I write my controller:
// GET: Students/CreateEdit
public ActionResult InventoryRecord()
{
var currentUserId = User.Identity.GetUserId();
var newid = db.Students.FirstOrDefault(d => d.UserID == currentUserId);
if (newid == null)
{
newid = db.Students.Create();
newid.UserID = currentUserId;
db.Students.Add(newid);
}
Student student = db.Students.Find(newid.UserID);
if (student == null)
{
return HttpNotFound();
}
return View(student);
}
// POST: Students/CreateEdit
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult InventoryRecord(Student student)
{
var currentUserId = User.Identity.GetUserId();
var userName = User.Identity.GetUserName();
var u = db.Students.FirstOrDefault(d => d.UserID == currentUserId);
if (u == null)
{
u = db.Students.Create();
u.UserID = currentUserId;
db.Students.Add(u);
}
if (ModelState.IsValid)
{
u.PhoneNumber = student.PhoneNumber;
u.Address = student.Address;
//other properties
db.SaveChanges();
TempData["Message"] = "User: " + userName + ", details successfully updated!";
}
return View(student);
}
Now, I'm really confused how to proceed here. How should I write my controller if I'm using my TestViewModel? Someone please point me in the right direction. Thank you.

Well personally I would move the code out of the controller.
However for example you just need to create an instance of your TestViewModel and pass that to your view. You may also need to update your View if you specific the model in the cshtml.
public ActionResult InventoryRecord()
{
var currentUserId = User.Identity.GetUserId();
var newid = db.Students.FirstOrDefault(d => d.UserID == currentUserId);
if (newid == null)
{
newid = db.Students.Create();
newid.UserID = currentUserId;
db.Students.Add(newid);
}
Student student = db.Students.Find(newid.UserID);
if (student == null)
{
return HttpNotFound();
}
TestViewModel model = new TestViewModel
{
UserID = student.UserId,
PhoneNumber = student.PhoneNumber,
//add the rest.
};
return View(model);
}

Rather than returning Student , return TestViewModel
Student student = db.Students.Find(newid.UserID);
if (student == null)
{
return HttpNotFound();
}
TestViewModel tvm = new TestViewModel()
{
UserID =student.Id,
PhoneNumber = student.PhoneNumber,
Address= student.Address
};
return View(tvm);
}
and second method will be
public ActionResult InventoryRecord(TestViewModel tvm)

Related

How do i confirm the action delete(POST) in my controller?

I have a ViewModel and I would like to make a fonctionnal delete(GET) and deleteConfirmed(POST) so i can delete what ever data is stored in my DB
I don’t know and would like to know what step to take to complete the deleteConfirmed. There is normally auto-generated code but it’s not what I need.
here is my ViewModel
using System;
using ExploFormsDB.Models;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace ExploFormsDB.ViewModels
{
public class WorkShiftDetailViewModel
{
[Key]
public int WorkShiftId { get; set; }
public int? HoleId { get; set; }
public string HoleName { get; set; }
public int SurveyLocationId { get; set; }
public int SupplierId { get; set; }
public int ZoneId { get; set; }
public string SurveyLocation1 { get; set; }
public string SupplierName { get; set; }
public string ZoneName { get; set; }
public DateTime StartDay { get; set; }
public DateTime EndDay { get; set; }
public ICollection<WorkerViewModel> WorkShiftEmployees { get; set; }
}
}
Here is my Controller, i have included the Create to help have a better understanding. GET: Delete seems to be working correctly, i am having trouble with the Post. any help what so ever will do. if the question as been answered already please send me a link. I'm pretty new to c# and core and completly new to ViewModels
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(WorkShiftDetailViewModel workShiftDetailViewModel)
{
if (!ModelState.IsValid)
{
WorkShift ws = new WorkShift();
ws.StartDay = workShiftDetailViewModel.StartDay;
ws.EndDay = workShiftDetailViewModel.EndDay;
ws.SupplierId = workShiftDetailViewModel.SupplierId;
ws.SurveyLocationId = 1;
ws.ZoneId = workShiftDetailViewModel.ZoneId;
ws.HoleId = workShiftDetailViewModel.HoleId;
_context.Add(ws);
await _context.SaveChangesAsync();
foreach (WorkerViewModel member in workShiftDetailViewModel.WorkShiftEmployees)
{
if (member.isDeleted == false) {
WorkShiftTeam emp = new WorkShiftTeam();
emp.EmployeeId = member.EmployeeId;
emp.RoleId = member.RoleId;
emp.WorkShiftId = ws.WorkShiftId;
_context.Add(emp);
}
}
HttpContext.Session.SetInt32("wsId", ws.WorkShiftId);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(CreateSharedView));
}
return View(workShiftDetailViewModel);
}
public IActionResult Delete(int? id)
{
if (id == null)
{
return NotFound();
}
List<WorkerViewModel> Workers = new List<WorkerViewModel>();
WorkShift ws = _context.WorkShift.Include(w => w.WorkShiftTeam).SingleOrDefault(x => x.WorkShiftId == id);
WorkShiftDetailViewModel detail = new WorkShiftDetailViewModel();
detail.HoleName = ws.HoleId == null ? "N/A" : _context.Hole.Find(ws.HoleId).HoleName;
detail.StartDay = ws.StartDay;
detail.EndDay = ws.EndDay;
detail.ZoneName = _context.Zone.Find(ws.ZoneId).ZoneName;
detail.SurveyLocation1 = _context.SurveyLocation.Find(ws.SurveyLocationId).SurveyLocation1;
detail.SupplierName = _context.Supplier.Find(ws.SupplierId).SupplierName;
detail.WorkShiftId = ws.WorkShiftId;
int order = 0;
var rolelist = new SelectList(_context.Role, "RoleId", "Role1");
var empsWithFullName = from e in _context.Employee.Where(a => a.IsActive)
select new
{
ID = e.EmployeeId,
FullName = e.LastName + ", " + e.FirstName
};
var empList = new SelectList(empsWithFullName, "ID", "FullName");
foreach (WorkShiftTeam member in ws.WorkShiftTeam.OrderBy(a => a.EmployeeId))
{
Workers.Add(new WorkerViewModel() { EmployeeId = member.EmployeeId, RoleId = member.RoleId, Index = order, Roles = rolelist, Employees = empList });
order++;
}
detail.WorkShiftEmployees = Workers;
return View(detail);
}
// POST: WorkShiftDetailViewModels/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
//??
} ```
Why you created an extra method for delete action as HttpGet? (that occurred conflict)
change it to:
[HttpGet]
public IActionResult GetById(int? id) { ... }
and just one delete method with this definition
[HttpPost]
public async Task<IActionResult> Delete(int? id) { ... }

EF Core: Updating One-to-Many Relationship dependent entity id

I am new in ASP.NET core and EF core. Please check my code and let me know what I am doing wrong.
** Foreign key constraint violation for AuthorId.
** BookCategory entity can not be tracked because another instance with same ID is being tracked
Book Model
public class Book
{
public int BookId { get; set; }
public string Title { get; set; }
public double Price { get; set; }
public int? Discount { get; set; }
public string ImagePath { get; set; }
public int? Stock { get; set; }
public Author Author { get; set; }
public int AuthorId { get; set; }
public BookCategory Category { get; set; }
public int? CategoryId { get; set; }
public ICollection<JoinBookTag> BookTags { get; set; }
}
BookCategory Model
public class BookCategory
{
public int Id { get; set; }
[Display(Name = "Category Name")]
public string CategoryName { get; set; }
public ICollection<Book> Books { get; set; }
}
Author Model
public class Author
{
public int AuthorId { get; set; }
public string Name { get; set; }
public ICollection<Book> Books { get; set; }
}
BookController
private readonly ApplicationDbContext _db;
private readonly HostingEnvironment _hostingEnvironment;
[BindProperty]
public BookViewModel ViewModel { get; set; }
public BookController(ApplicationDbContext db, HostingEnvironment host)
{
_db = db;
_hostingEnvironment = host;
ViewModel = new BookViewModel()
{
Book = new Models.Book(),
Authors = _db.Authors.ToList(),
BookCategories = _db.BookCategories.ToList(),
Tags = _db.Tags.ToList()
};
}
...............
[HttpGet]
public IActionResult Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var book = _db.Books.Include(b => b.Category)
.Include(b => b.Author)
.SingleOrDefault(b => b.BookId == id);
if (book == null)
{
return NotFound();
}
ViewModel.Book = book;
return View(ViewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(BookViewModel model, int? id)
{
if (id == null)
{
return NotFound();
}
if (id != model.Book.BookId)
{
return NotFound();
}
if (!ModelState.IsValid)
{
/*ViewModel.Book = model.Book;
return View(ViewModel);*/
var errors = ModelState.Select(x => x.Value.Errors)
.Where(y => y.Count > 0)
.ToList();
return Json(new { errors });
}
var dbModel = _db.Books.Include(b => b.Category).Where(b => b.BookId == id).FirstOrDefault();
var file = HttpContext.Request.Form.Files;
if (file.Count > 0)
{
var RootDirectory = _hostingEnvironment.WebRootPath;
var extension = Path.GetExtension(file[0].FileName);
var filePath = Path.Combine(DataContext.ImageDirectory, model.Book.BookId + extension);
using (var fileStream = new FileStream(Path.Combine(RootDirectory, filePath), FileMode.Create))
{
file[0].CopyTo(fileStream);
}
dbModel.ImagePath = #"/" + filePath;
}
dbModel.AuthorId = model.Book.AuthorId;
dbModel.CategoryId = model.Book.CategoryId;
dbModel.Discount = model.Book.Discount;
dbModel.Price = model.Book.Price;
dbModel.Stock = model.Book.Stock;
dbModel.Title = model.Book.Title;
await _db.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
You need to add the key attribute on your id properties inside your models.
The next thing you need to update is tell _db to update your entity first then and only then save changes.
Why are you using async and await? Are these controller actions slowing down the UI?
Also can you post your book view model?
You action methods are wrong in certain places. Let me know if you want some more detailed advice.
[HttpGet]
public IActionResult Edit(int? id)
{
//Give this a name other than view model for example BookViewModel
ViewModel model = new ViewModel();
if (id == null)
{
return NotFound();
}
var book = _db.Books.Include(b => b.Category)
.Include(b => b.Author)
.SingleOrDefault(b => b.BookId == id);
if (book == null)
{
return NotFound();
}
model.Book = book;
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(BookViewModel model, int? id)
{
if (id == null || id != model.Book.BookId)
{
return NotFound();
}
if (ModelState.IsValid)
{
var dbModel = _db.Books.Include(b => b.Category).Where(b => b.BookId == id).FirstOrDefault();
var files = HttpContext.Request.Form.Files;
if (files.Any())
{
var RootDirectory = _hostingEnvironment.WebRootPath;
var extension = Path.GetExtension(files[0].FileName);
var filePath = Path.Combine(DataContext.ImageDirectory, model.Book.BookId + extension);
using (var fileStream = new FileStream(Path.Combine(RootDirectory, filePath), FileMode.Create))
{
file[0].CopyTo(fileStream);
}
dbModel.ImagePath = #"/" + filePath;
}
dbModel.AuthorId = model.Book.AuthorId;
dbModel.CategoryId = model.Book.CategoryId;
dbModel.Discount = model.Book.Discount;
dbModel.Price = model.Book.Price;
dbModel.Stock = model.Book.Stock;
dbModel.Title = model.Book.Title;
await _db.Books.UpdateAsync(dbModel);
await _db.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(model);
}

LINQ Select one field based on query from a different column

I am trying to retrieve a field from my database based on the user.identity.name. I have tried the following but I can't seem to get a result for either UserName or CustomerId, but I do get "jmcgee" for User.Identity.Name. So dealerId ends up beging null, when I want it to return CustomerId (01d1).
What am I doing wrong? It looks like I have everything set up the same as other questions/examples here, msdn, etc.
UserProfile Table: UserName = jmcgee; CustomerId= 01d1
var dealerId = db.UserProfiles
.Where(d=>d.UserName.Equals(User.Identity.Name))
.Select (d=>d.CustomerId);
or
var dealerId = from d in db.UserProfiles
where d.UserName == User.Identity.Name
select d.CustomerId;
or
var dealerId = (from d in db.UserProfiles
where d.UserName == User.Identity.Name
select d.CustomerId).SingleOrDefault();
I've also tried FirstOrDefault to no avail, but that might be my lack of understanding how to set it up. I've even tried replacing User.Identity.Name with "jmcgee" just to see if that would work.
Here's more of the code (let me know if something else needed is missing and I'll add it):
Controller
TintagliaContext db = new TintagliaContext();
public ActionResult OpenQuotes(string searchString, string excludeString, string modelFilter, int? page)
{ // var dealerId = "01D1628";
var dealerId = (from d in db.UserProfiles
where d.UserName == User.Identity.Name
select d.CustomerId).SingleOrDefault();
string context = _customerRepository.GetContext(dealerId);
Tintaglia.Models.Filter filter;
if (context == "coverpools")
{
filter = new Tintaglia.Models.Filter { IsSubmitted = false, Order = quote => quote.Date_Created, SearchString = searchString, ExcludeString = excludeString };
}
else
{ filter = new Tintaglia.Models.Filter { IsSubmitted = false, DealerId = dealerId, Order = quote => quote.Date_Created, SearchString = searchString, ExcludeString = excludeString };
}
var quotes = _configurationRepository.GetQuotes(filter);
var model = new List<ConfigurationViewModel>();
foreach (var quote in quotes)
{
var viewModel = new ConfigurationViewModel();
viewModel = viewModel.MapModelToViewModel(quote);
model.Add(viewModel);
}
ViewData.Model = model.ToPagedList(page ?? 1, 20); ;
return View();
}
ICustomerRepository
namespace Infotech.Coverpools.Portal.Tintaglia.Repositories.Interfaces
{
public interface ICustomerRepository
{
string GetContext(string dealerId);
//bool Login(string userName, string password);
}
}
_customerRepository
namespace Infotech.Coverpools.Portal.Tintaglia.Repositories
{
public class CustomerRepository : ICustomerRepository
{
//public string GetContext(string dealerId)
public string GetContext(string dealerId)
{
using (var db = new TintagliaContext())
{
var customer = db.Customers.FirstOrDefault(x => x.No_ == dealerId);
return customer.Internal_Login == 1 ? "coverpools" : "default";
}
}
}
}
TintagliaContext
namespace Infotech.Coverpools.Portal.Tintaglia.CodeFirst.Models
{
public partial class TintagliaContext : DbContext
{
static TintagliaContext()
{
Database.SetInitializer<TintagliaContext>(null);
}
public TintagliaContext()
: base("TintagliaContext")
{
}
public DbSet<Configuration> Configurations { get; set; }
public DbSet<Customer> Customers { get; set; }
//New for Account Module
public DbSet<UserProfile> UserProfiles { get; set; }
public DbSet<Role> Roles { get; set; }
public DbSet<webpages_UsersInRoles> webpages_UsersInRole { get; set; }
// public DbSet<Customer> Customers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ConfigurationMap());
modelBuilder.Configurations.Add(new CustomerMap());
}
}
}

Calculated attributes in model results in The requested attribute does not exist

Having trouble update users in AD
My Model:
public class UserModel
{
....
[ScaffoldColumn(false)]
[DisplayName("Fødselsdag")]
[DataType(DataType.Date)]
[NotMapped]
public DateTime extensionAttribute1_date
{
get
{
try
{
return DateTime.Parse(extensionAttribute1);
}
catch (Exception e)
{
return new DateTime();
}
}
set { }
}
}
My Controller:
[HttpPost]
public ActionResult Edit(string sAMAccountName, FormCollection collection, UserModel data)
{
if (ModelState.IsValid)
{
var config = new LdapConfiguration();
config.ConfigureFactory("domain.local").AuthenticateAs(new NetworkCredential("xxxx", "xxxxx"));
using (var context = new DirectoryContext(config))
{
var user = context.Query(new UserModel(), "OU=users,OU=xxx,DC=xxx,DC=dk", "User").FirstOrDefault(d => d.sAMAccountName == sAMAccountName);
if (user == null) return RedirectToAction("Index");
user.title = data.title;
user.mobile = data.mobile;
user.homePhone = data.homePhone;
user.streetAddress = data.streetAddress;
user.postalCode = data.postalCode;
user.l = data.l;
user.department = data.department;
user.physicalDeliveryOfficeName = data.physicalDeliveryOfficeName;
user.extensionAttribute1 = data.extensionAttribute1_date.ToLongDateString();
context.Update(user);
}
return RedirectToAction("Index");
}
return View();
}
When i submit to Edit Action i results in an error:
The requested attribute does not exist.
If i remove extensionAttribute1_date from the model i updates fine.
How do i exclude my calculated attributes from the update?
I have other attributes in the model such as Age which is calculated! Is this the wrong procedure for this?
/Michael

Retrieving Data Depending on the Username

I am doing Authentication depending on the username.So an unauthorized person can't see any methods which is working fine.
The problem is all of the users are able to each others data.
Person A shouldn't see the records of person B so that he/she can't edit another person's records.Does anyone know how I can write a lambda expression for that?
I have my Edit method pasted below:
// GET: /IcerikDB_/Edit/5
[Authorize(Roles = "Administrator")]
public ActionResult Edit(int id)
{
icerik icerik = db.icerik.Find(id);
ViewBag.Kategorid = new SelectList(db.Kategoriler, "Id", "Adi", icerik.Kategorid);
ViewBag.Userid = new SelectList(db.Users, "UserId", "UserName", icerik.Userid);
return View(icerik);
}
[HttpPost]
public ActionResult Edit(icerik icerik)
{
if (ModelState.IsValid)
{
if (User != null && User.Identity != null && User.Identity.IsAuthenticated)
{
string userName = User.Identity.Name;
var user = db.Users.First(u => u.UserName == userName);
icerik.Userid = user.UserId;
db.Entry(icerik).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
}
ViewBag.Kategorid = new SelectList(db.Kategoriler, "Id", "Adi", icerik.Kategorid);
ViewBag.Userid = new SelectList(db.Users, "UserId", "UserName", icerik.Userid);
return View(icerik);
}
Here is the code for icerik.cs
namespace KategoriEditor.Icerik_DB
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
public partial class icerik
{
public int Id { get; set; }
public Nullable<int> Kategorid { get; set; }
public Nullable<System.Guid> Userid { get; set; }
[DataType(DataType.Date)]
public Nullable<System.DateTime> Baslangic { get; set; }
[DataType(DataType.Date)]
public Nullable<System.DateTime> Bitis { get; set; }
public string tamicerik { get; set; }
public string kisaicerik { get; set; }
public string resimlink { get; set; }
public virtual Kategoriler Kategoriler { get; set; }
public virtual Users Users { get; set; }
}
}
Try this:
public ActionResult Edit(int id)
{
// Get the currently logged in user.
string userName = User.Identity.Name;
var user = db.Users.First(u => u.UserName == userName);
// Determine whether the requested id is the same id as the currently logged in user.
icerik icerik = db.icerik.Find(id);
if (icerik.Userid.HasValue && icerik.Userid.Value == user.UserId)
{
ViewBag.Kategorid = new SelectList(db.Kategoriler, "Id", "Adi", icerik.Kategorid);
// You should not need this SelectList anymore.
//ViewBag.Userid = new SelectList(db.Users, "UserId", "UserName", icerik.Userid);
return View(icerik);
}
// This redirect the unauthorized user to the homepage. This can be any other page of course.
return RedirectToAction("Index", "Home");
}

Categories