I am currently building an ASP.NET MVC application that allows admin users to add, edit and delete users. For the application, I have 3 different database tables called AdminUsers, Users and AuditChanges. Every time a user is added, edited or deleted, I would like it to update the Users table as necessary, which isn't a problem. On top of this, I would also like the application write an entry into the AuditChanges table which states which admin it was that processed the function, which user was updated and also what type of function was processed e.g. an edit or delete. What I am currently struggling with is updating more than one database and was wondering if this was possible?
For Example:
If I was to access my Create User page and add a user I would like my User table to look like this:
UserID BranchNumber
U123456 1234
But then I would also like my AuditChanges table to look like this:
AdminID UserID BranchNumber Type
U654321 U123456 1234 Add
U235874 U192395 4321 Edit
U827734 U283849 9999 Delete
This is so I am able to keep track of who has been updating the Users table and what they have been updating it with.
Controller
public ActionResult Edit(int id)
{
Users user = db.Users.Find(id);
return View(user);
}
[HttpPost]
public ActionResult Edit(Users user)
{
if (ModelState.IsValid)
{
db.Entry(user).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(user);
}
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(Users user, AuditChanges changes)
{
if (ModelState.IsValid)
{
db.Users.Add(user);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(user);
}
public ActionResult Delete(int id)
{
Users user = db.Users.Find(id);
return View(user);
}
//
// POST: /Errors/Delete/5
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
Users user = db.Users.Find(id);
db.Users.Remove(user);
db.SaveChanges();
return RedirectToAction("Index");
}
Models
[Table("CTP_Users")]
public class Users
{
[Key]
public int Id { get; set; }
public string LogonId { get; set; }
public string BranchNumber { get; set; }
}
[Table("CTP_Users")]
public class Users
{
[Key]
public int Id { get; set; }
public string LogonId { get; set; }
public string BranchNumber { get; set; }
}
If you require anymore information then let me know.
Thanks in advance.
Related
I'm building a CRUD that is accessible only to logged in users and i'm trying to add extra information (userid) to the crud records. How do I go about fetching the userId and saving it with the record?
Here is my controller
public ActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "CompanyName,Telephone")]Company company)
{
try
{
if (ModelState.IsValid)
{
db.Companies.Add(company);
db.SaveChanges();
return RedirectToAction("Index");
}
}
catch (DataException /* dex */)
{
ModelState.AddModelError("", "Unable to save changes.");
}
return View(company);
}
Here is my model
namespace ProjectX.Models
{
public class Company
{
//public int Id { get; set; }
public int CompanyID { get; set; }
public string CompanyName { get; set; }
public string Telephone { get; set; }
}
}
Thank you for your help!
You can access it in different ways depending where you are in the code but since you are in the controller you should have an extension method like this User.Identity.GetUserId(); It will be string in this case but you can parse it, but be sure your table AspNetUsers has the id as int datatype. Assuming this is true you can say:
[HttpPost, Authorize]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "CompanyName,Telephone")]Company company)
{
try
{
if (ModelState.IsValid)
{
company.Id = int.Parse(User.Identity.GetUserId());
db.Companies.Add(company);
db.SaveChanges();
return RedirectToAction("Index");
}
}
catch (DataException /* dex */)
{
ModelState.AddModelError("", "Unable to save changes.");
}
return View(company);
}
Do not forget to apply [Authorize] attribute.
In case you want to save more data from a user to a Company then you need to get the user from database and then extract user`s data needed from it and then save them in company object like below:
var user = UserManager.FindById(int.Parse(User.Identity.GetUserId()));
company.Username = user.Username;
//and so on...
Here you have more details for this:
I am creating an employee scheduling site in ASP.net MVC 6. I have an employee table, shift table and a shiftEmployee table to handle the many to many relationship.
It's configured so that each employee logs into the site using their employee ID number and a password. Then they can see each future shift they are scheduled to. They must acknowledge each assigned shift in a process known as "pulling their pin".
So far everything is working as expected. My goal and my question is this:
When an employee pulls their pin for each shift, I would like them to have to confirm this action by entering their password again, keeping in mind the user is already signed into the site. What is the easiest/correct/most secure way to accomplish this?
The Pull GET/POST methods are basically the same as a standard MVC edit action, simply renamed Pull.
// GET: PullPin/Pull/5
public IActionResult Pull(int? id)
{
if (id == null)
{
return HttpNotFound();
}
var shiftEmp = _context.ShiftEmployees.Single(m => m.ShiftEmployeeID == id);
if (shiftEmployee == null)
{
return HttpNotFound();
}
}
// POST: PullPin/Pull/5
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Pull(ShiftEmployee shiftEmployee)
{
var user = GetCurrentUserAsync();
pullPin.PinStatusID = 3; // Status ID #3 = Pulled
if (ModelState.IsValid)
{
_context.Update(shiftEmployee);
_context.SaveChanges();
return RedirectToAction("Index");
}
return View(shiftEmployee);
}
And here is my ShiftEmployee class
public class ShiftEmployee
{
public int ShiftEmployeeID { get; set; }
public int ShiftID { get; set; }
public int EmployeeID { get; set; }
public int PinStatusID { get; set; }
public virtual Shift Shift { get; set; }
[JsonIgnore]
public virtual Employee Employee { get; set; }
public virtual PinStatus PinStatus { get; set; }
}
In the standard MVC6 template, it uses ASP.NET Core Identity for the login functionality. Part of that package is the UserManager object (you also get a SignInManager among other things.)
The UserManager object has a method specifically for checking passwords called CheckPasswordAsync and is used like this:
_userManager.CheckPasswordAsync(user, password)
keep getting this error when i try to edit single column in ASP NET MVC 5
Cannot insert the value NULL into column 'naam', table
this is my post code
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index([Bind(Include = "id,email")] user user)
{
var username = HttpContext.User.Identity.Name;
if (ModelState.IsValid)
{
db.Entry(user).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(user);
}
And this is the model
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace LiemersApp.Models.EntityModels
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
public partial class profiel
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public profiel()
{
this.meldingens = new HashSet<meldingen>();
}
public int id { get; set; }
[DisplayName("Email:")]
public string email { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<meldingen> meldingens { get; set; }
}
}
so im wondering why it doesnt work as i just want to save changes to the Email column any ideas why this is happening cause i cant figure it out
Greetings
In your example you don't change only name property in your model, you map all fields that came and bind in controller. If you don't bind some properties the are null like your field in error.
You can change controller like this:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index([Bind(Include = "id,email")] user user)
{
var username = HttpContext.User.Identity.Name;
if (ModelState.IsValid)
{
var userChange = db.profiels.Single(x => x.id == user.id);
userChange.email = user.Email;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(user);
}
For simplicity and testing, i'm doing this from a new project and then apply it to my actual project once i understand the problem.
I made a model, named Person, which contains a List property, named ServiceNeeded. Users in the front end may encode as much string of services as they wish, so the input field for ServiceNeeded is dynamically created. In the POST method, those string input binds as expected. I save the Person object into the database, and works as expected. When I try to retrieve the people objects from the database, all but ServicesNeeded are present.
Here are my codes
Model (Person.cs):
public class Person
{
public Guid Id { get; set; }
public String Name { get; set; }
public List<String> ServiceNeeded { get; set; }
public Person()
{
this.ServiceNeeded = new List<String>();
}
}
Controller(Index and [POST]Create methods):
public ActionResult Index()
{
var x = db.People.ToList();
return View(db.People.ToList());
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Id,Name,ServiceNeeded")] Person person)
{
if (ModelState.IsValid)
{
person.Id = Guid.NewGuid();
db.People.Add(person);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(person);
}
As I said the input fields for ServicesNeeded are dynamically create but properly bind to the model.
Here are some screenshots during runtime:
After user do some input:
The I added a variable before Index returns the View to check in runtime:
As seen, the same Person is present and everything but ServicesNeeded. I am fairly new with ASP.NET MVC and web development in general. I do handle other collections in my project, although are collection of objects. Only this particular case I do not understand. Where could my error be?
You need to tell the dbcontext to load the references if lazy loading is not enabled.
First change ServiceNeeded to a virtual property
public virtual List<String> ServiceNeeded { get; set; }
then load the property when you pull down the person by using Include
var x = db.People.Include("ServiceNeeded").ToList();
return View(x);
Article on loading related entities https://msdn.microsoft.com/en-us/data/jj574232.aspx
Look in the database; are the records there? I think the issue is that the ServicesNeeded collection is not persisted to the database; try adding:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Id,Name,ServiceNeeded")] Person person)
{
if (ModelState.IsValid)
{
person.Id = Guid.NewGuid();
db.People.Add(person);
foreach (var service in person.ServicesNeeded)
db.ServicesNeeded.Add(service);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(person);
}
I'm don't believe the relationships attached to the Person object auto-persist on SaveChanges(), and are probably not making it to the database.
I think the best idea that suits Entity Frame work is to create another Model for your 'ServiceNeeded', add it to your 'DbContext', save any services in the corresponding DbSet and retrieve them using .Include in LINQ. After this lengthy introduction look at the following codes:
In your Models:
public class MyService{
public Guid Id {get;set;}
public string ServiceName {get;set;}
public Guid PersonId {get;set;}
}
public class Person
{
public Guid Id { get; set; }
public String Name { get; set; }
public virtual IList<MyService> ServiceNeeded { get; set; }
}
In your ApplicationDbContext:
public System.Data.Entity.DbSet<MyService> MyServices { get; set; }
public System.Data.Entity.DbSet<Person> People { get; set; }
In your POST ActionResult:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Id,Name,ServiceNeeded")] Person person, List<String> ServiceNeeded)
{
if (ModelState.IsValid)
{
db.People.Add(person);
db.SaveChanges();
db.Entry(person).GetDatabaseValues();
foreach (string service in ServiceNeeded){
db.MyServices.Add( new MyService {ServiceName = service,
PersonId = person.Id})
}
db.SaveChanges();
return RedirectToAction("Index");
}
return View(person);
}
Please note that I removed person.Id = Guid.NewGuid(); so that the Id
be generated by Database Identity and then I re-get the person.Id so that I create the MyService record.
and finally as #JamieD77 suggested, in your GET ActionResult:
public ActionResult Index()
{
var x = db.People.Include("ServiceNeeded").ToList();
return View(x);
}
I'd like to have a user in my model. By user I mean something that holds username. Email and the rest of the stuff would also be nice.
I tried like that:
Model:
public class MyModel
{
public virtual MembershipUser Finder { get; set; }
...
}
Controller:
[HttpPost]
public ActionResult Create(MyModel mymodel)
{
if (ModelState.IsValid)
{
//mymodel.FinderId = Membership.GetUser(User.Identity.Name).ProviderUserKey;
mymodel.Finder = Membership.GetUser(User.Identity.Name);
_repo.Save(mymodel);
return RedirectToAction("Index");
}
return View(mymodel);
}
And than in a view:
#Html.DisplayFor(modelItem => item.Finder.UserName)
While in the controller the poperty UserName was set to "admin" in the view it was null.
On the other hand email was set in both controller and view.
What am I doing wrong?