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?
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:
My _Layout uses the BaseViewModel to render the user's name in the navbar which i want to keep consistent through the application. My HomeController has an action on it called Login that passes a UserViewModel to the Dashboard view upon successful login. UserViewModel derives form BaseViewModel and is only used in the Dashboard view right now.
My question is how do I make this BaseViewModel which will be used by the _Layout page be available throughout the views of the application. Do I have to keep making a call to my service (Database) to fetch this data each time a page loads? because the data that the BaseViewModel needs is only fetched in the Login action of the HomeController so the page breaks if i navigate to another view, and I get this error below
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[InventoryManager.Web.Models.ProductViewModel]', but this dictionary requires a model item of type 'InventoryManager.Web.Models.BaseViewModel'.
BaseViewModel.cs
public class BaseViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
UserViewModel
public class UserViewModel : BaseViewModel
{
public Guid UserId { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
BaseController
public class BaseController : Controller
{
//
// GET: /Base/
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
var model = filterContext.Controller.ViewData.Model as BaseViewModel;
}
}
HomeController
public ActionResult Login(LoginViewModel model)
{
if (!ModelState.IsValid)
{
return ReturnLoginViewOnError(CustomErrorMessages.LOGIN_CREDENTIALS_NOT_PROVIDED);
}
var userService = new UserServiceClient();
var user = userService.GetUser(model.Username, model.Password);
if (null == user)
{
return ReturnLoginViewOnError(CustomErrorMessages.INVALID_USER);
}
var userViewModel = Mapper.Map<UserContract, UserViewModel>(user);
return RedirectToAction("Index", "Dashboard", userViewModel);
}
You can keep your UserViewModel and BaseViewModel and use composition to send a compatible type to your View and avoid the error as show below. This approach uses what is referred to as Object Composition
See below, Create AppViewModel class
public class AppViewModel
{
public UserViewModel UserViewModel { get; set; }
public List<ProductViewModel> ProductViewModel { get; set; }
}
// Login Action Method or any action method
Populate AppViewModel to send to the view
public class HomeController {
//Action method
public ActionResult Login(LoginViewModel model)
{
//Do stuff and populate AppViewModel
UserViewModel userViewModel = new UserViewModel {Username = "username", Password ="secret", FirstName = "John", LastName = "Doe"};
AppViewModelmodel model = new AppViewModel{UserViewModel = userViewModel };
return RedirectToAction("Index", "Dashboard", model);
}
}
// ProductController
public class ProductController
{
public ActionResult Products()
{
ProductViewModel productViewModel = new ProductViewModel { /*Initialize properties here*/};
AppViewModel model = AppViewModel { ProductViewModel = new List<ProductViewModel>{ new ProductViewModel = productViewModel }};
return View(model);
}
}
// Dashboard View
// Do include your model namespace
#model AppViewModel
<div>
<p> FirstName : #Model.UserViewModel.FirstName</p>
</div>
// Products View
// Do include your model namespace
#model AppViewModel
<div>
//You get the idea
<p> Product Name: #Model.ProductViewModel.Select( x => x.ProductName). </p>
</div>
What I usally do, is that I create an LayoutController. With this controller, I render all the persistent information which is used on the layout pages.
public class LayoutController : Controller
{
private readonly IProvideData _provider;
public LayoutController(IProvideData provider)
{
_provider = provider;
}
[ChildActionOnly]
public ActionResult AccountInformation()
{
var model = _provider.GetUserStuff();
return PartialView("_AccountInformation", model);
}
}
The ChildActionOnly attribute ensures that an action method can be called only as a child method from within a view. On my _Layout.cshtml I can render this action with:
#{ Html.RenderAction("AccountInformation", "Layout"); }
Which renders the _AccountInformation partial view which can look like:
#model MyApplication.ViewModels.UserInformation
Username: #Model.UserName
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.
Let's say that I have a Action method like this:
public ActionResult Page(int? id)
{
}
The question is, how can I read 'id' parameter in View?
Your code won't build successfully, until you return a view like this
public ActionResult Page(int? id)
{
return View();
}
and because you want to return id to your view you can do
Simple object
public ActionResult Page(int? id)
{
return View(id);
}
Just remember to accept the new value in your view, by dong the following at the top (very first line)
#model int?
ViewModel approach
public class MyViewModel
{
public int? Id { get; set; }
//Other properties here
}
public ActionResult Page(int? id)
{
var myViewModel = new MyViewModel()
{
Id = id
};
return View(myViewModel);
}
and then in your view
#model MyViewModel
You can access parameters from Request in view as below
Request.Params["id"]
Have created a model and with required fields and used to create a form like so:
Model:
public class formModel {
[Required]
public string name {get;set;}
[Required]
public string Add1 {get;set;}
etc....
}
View:
#model myProj.Models.formModel
#using (BeginForm("Action", "Controller", FormMethod.Post))
{
#Html.TextBoxFor(f => f.name)
#Html.TextBoxFor(f => f.Add1)
etc...
#Html.ValidationSummary()
<button type="submit" value="submit">Submit</button>
}
Controller:
[HttpPost]
public ActionResult Action(formModel f)
{
if (ModelState.IsValid)
{
// Do Stuff here
return RedirectToAction("Result");
}
return RedirectToAction("Form", new { id = "showForm" });
}
Problem is the validation summary is being displayed if the model is in valid. Have used same approach on lots of other forms and has been fine.
Any ideas?
When the model is invalid, do not use
return RedirectToAction("Form");
But
return View(f); // or return View("ViewName", f);