ASP.NET MVC 4 - Create a ViewModel from a base class (Model) - asp.net

There is a class (Model) User.cs:
namespace BookStore
{
using System;
using System.Collections.Generic;
public class User
{
public int user_id { get; set; }
public string user_login_name { get; set; }
public string user_first_name { get; set; }
public string user_last_name { get; set; }
}
}
I want to create a ViewModel to then use it in Views. How should I do it? I create ViewModels folder in the project, create a class UserViewModel.cs in it, then what? I just copy and paste the original User.cs content and put limitations? Like this:
namespace BookStore.Models
{
public class UserViewModel
{
[Editable(false)]
public int user_id { get; private set; }
public string user_login_name { get; set; }
public string user_first_name { get; set; }
public string user_last_name { get; set; }
}
}
I did so and now my UserController says it can't implicitly convert type BookStore.User to BookStore.UserViewModel:
public class UserController : Controller
{
private DBEntities db = new DBEntities();
public ActionResult UserDetails()
{
UserViewModel user = db.Users.FirstOrDefault(u => u.user_login_name==User.Identity.Name);
if (user == null)
return RedirectToAction("Create");
else
return View(user);
}
I know it is important in MVC to separate concerns, domain models and view models should be used for different purposes, but why is there no any detailed info on how to create ViewModels correctly?

Related

How to organize the Model class in Asp.net web api core 6?

I am to make re use the variables, without creating new variables and class everytime.
For example,
I have UserAuthentication Api controller
public class AuthController : ControllerBase
{
[HttpPost("register")]
public async Task<ActionResult<UserAuth>> Register(UserRegister registerRequest)
{
//....
}
[HttpPost("Login")]
public async Task<ActionResult<string>> Login(UserLogin loginRequest)
{
//....
}
}
I created Model class like be below
namespace DemoAsp.Models.User
{
public class UserLogin
{
public string Username { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
}
public class UserRegister : UserLogin
{
// I will use the Variable Username and Password from base class "UserLogin"
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public string ConfirmPassword { get; set; } = string.Empty;
}
public class UserData : UserRegister
{
// I will use the all the Variables from both class "UserLogin" and "UserRegister", In case I need it.
}
}
I don't think this is the way to organize the MODEL Class and their fields. If I define the variable separately for UserRegister and UserLogin, then the variable name will be repeat
Could someone suggest me the way to handle/organize the Model class.
So that it will be helpful to create and maintain any other models

My dbContext return null, when I want get list of user, which are from identity

My dbContext return null, when I want get list of user in Index View. This list are from my database AspNetUsers table, which has been generate by identity. I can get other my database table list.
There is my ApplicationDbContext
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<ProductCategory> ProductCategories { get; set; }
public DbSet<ProductBrand> ProductBrands { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<ApplicationUser> ApplicationUsers { get; set; }
public DbSet<Address> Address { get; set; }
public DbSet<Recipe> Recipes { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<Order_detail> Order_Details { get; set; }
}
There is my UserController
[Area("Admin")]
public class UserController : Controller
{
UserManager<IdentityUser> _userManager;
private ApplicationDbContext _db;
public UserController(UserManager<IdentityUser> userManager, ApplicationDbContext db)
{
_userManager = userManager;
_db = db;
}
public IActionResult Index()
{
return View(_db.ApplicationUsers.ToList());
}
}
There is my ApplicationUser.Model, which inherit IdendityUser
public class ApplicationUser : IdentityUser
{
public string Name { get; set; }
public string Surname { get; set; }
public ICollection<Recipe> Products { get; set; }
public ICollection<Order> Orders { get; set; }
}
I don't know how you register ApplicationDbContext and Identity framework on your ASP.NET Core MVC application because you didn't show them on the question.
There are couple problems in your code.
First, if you have a custom IdentityUser, like the ApplicationUser you have, you would have to use the generic version of IdentityDbContext:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
...
}
You would need to use the matching generic version of IdentityDbContext if you have any of following:
Custom IdentityUser
Custom IdentityRole
Custom primary key
All 7 classes, user and role, plus IdentityUserRole, IdentityUserClaim, IdentityRoleClaim, IdentityUserLogin, and IdentityUserToken
After you register your custom class with IdentityDbContext, you don't need to put the class as one of the DbSet<> there:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
...
public DbSet<ProductCategory> ProductCategories { get; set; }
public DbSet<ProductBrand> ProductBrands { get; set; }
public DbSet<Product> Products { get; set; }
// public DbSet<ApplicationUser> ApplicationUsers { get; set; }
public DbSet<Address> Address { get; set; }
public DbSet<Recipe> Recipes { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<Order_detail> Order_Details { get; set; }
}
You would also need to use the generic version of AddIdentity<TUser>, AddDefaultIdentity<TUser>, or AddIdentityCore<TUser> in your Startup.cs, depending on what you need:
AddDefaultIdentity = AddIdentity + AddDefaultTokens + AddDefaultUI
You didn't specify what version of ASP.NET Core Identity you're using so I don't exactly know which one you use, but the following is how I registered it:
services.AddIdentity<ApplicationUser, ApplicationRole>(options =>
{
options.User.RequireUniqueEmail = ...;
...
})
.AddEntityFrameworkStores<ApplicationDbContext>();
I have all 7 classes customized as well as change the primary key from string to Guid.
Lastly, to use the dependency injected UserManager and SignInManager, you would need to correct generic version of them as well:
[Area("Admin")]
public class UserController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
public UserController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
public IActionResult Index()
{
// Get the user list
var users = _userManager.Users.ToList();
// Build your view model to define what your UI only needs, not just passing
// everything to it
var vm = new UserManagementListViewModel
{
Users = users.Select(x => new UserViewModel
{
UserId = x.Id,
UserSurname = x.Surname,
ProductCount = x.Products.Count(),
OrderCount = x.Orders.Count()
})
};
return View(vm);
}
}

Getting computed column filled in EF Core on every call to entity

I am using code first with Entity Framework in my ASP.NET Core application. I am using a generic repository for crud operations.
I have a base audit class which is inherited by all entities in my dbcontext.
public class Audit_base
{
public int AddedUserId { get; set; }
public int ModifiedUserId { get; set; }
// I'd like to have it filled every time I query
[NotMapped]
public String AddedUsername { get; set; }
[NotMapped]
public String EditedUserName { get; set; }
}
And I have a User class in the dbcontext
public class UserMaster
{
public int Id { get; set; }
public int FullName { get; set; }
}
All my tables (about 70) inherit from the Audit_base class.
public class Book : Audit_base
{
public int Id { get; set; }
public String BookName { get; set; }
public virtual UserMaster CreatedByUser { get; set; }
public virtual UserMaster ModifiedByUser { get; set; }
}
And this is the part of generic repository class where I query these tables
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
protected readonly ApplicationContext _context;
public GenericRepository(ApplicationContext context)
{
_context = context;
}
public IEnumerable<T> Find(Expression<Func<T, bool>> expression)
{
return _context.Set<T>().Where(expression);
}
public IEnumerable<T> GetAll()
{
return _context.Set<T>().ToList();
}
public T GetById(int id)
{
return _context.Set<T>().Find(id);
}
}
Is there a way that I can get the user name corresponding to the created and modified userid when I query it, like a computed column?

Created and Modified date issue

I was practicing User.Identity and timestamps functions in ASP.NET MVC 5,
So I created a student class filled some properties, I just wanted to test if it is capturing timestamps and userId, so user id is getting captured and datetime too, problem is whenever I'm editing a record and save it, its created date becomes Null and modified date is updated, please review the code and help.
Thanks in advance.
Below is the Code
{
public class BaseEntity
{
public DateTime? DateCreated { get; set; }
public string UserCreated { get; set; }
public DateTime? DateModified { get; set; }
public string UserModified { get; set; }
}
public class Student : BaseEntity
{
public int Id { get; set; }
public string Name { get; set; }
public string Subject { get; set; }
public string Class { get; set; }
public Section Section { get; set; }
public byte SectionId { get; set; }
}
then I used Codefirst approach and created an application Database and added this code in Identity Model
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public DbSet<Student> Students { get; set; }
public override int SaveChanges()
{
AddTimestamps();
return base.SaveChanges();
}
//public override async Task<int> SaveChangesAsync()
//{
// AddTimestamps();
// return await base.SaveChangesAsync();
//}
private void AddTimestamps()
{
var entities = ChangeTracker.Entries().Where(x => x.Entity is BaseEntity && (x.State == EntityState.Added || x.State == EntityState.Modified));
var currentUsername = !string.IsNullOrEmpty(System.Web.HttpContext.Current?.User?.Identity?.Name)
? HttpContext.Current.User.Identity.Name
: "Anonymous";
foreach (var entity in entities)
{
if (entity.State == EntityState.Added)
{
((BaseEntity)entity.Entity).DateCreated = DateTime.UtcNow;
((BaseEntity)entity.Entity).UserCreated = currentUsername;
}
else
((BaseEntity)entity.Entity).DateModified = DateTime.UtcNow;
((BaseEntity)entity.Entity).UserModified = currentUsername;
}
}
public DbSet<Section> Sections { get; set; }
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
I have created a simple controller with create,edit and dispay actions.
The code you posted doesn't show DateCreated being set to null as far as I can see. I think the issue is when you save an existing record you do not have the DateCreated or UserCreated fields in your view. So when you post the form the MVC model binder doesn't see them and thus sets them to null (I'm assuming your are binding to the Student model in your controller action).
In your edit view add the following hidden fields:
#Html.HiddenFor(model => model.DateCreated)
#Html.HiddenFor(model => model.UserCreated)
Now when you post the form the MVC model binder will bind these values to your model and save them to the database.

Using ComplexType with ToList causes InvalidOperationException

I have this model
namespace ProjectTimer.Models
{
public class TimerContext : DbContext
{
public TimerContext()
: base("DefaultConnection")
{
}
public DbSet<Project> Projects { get; set; }
public DbSet<ProjectTimeSpan> TimeSpans { get; set; }
}
public class DomainBase
{
[Key]
public int Id { get; set; }
}
public class Project : DomainBase
{
public UserProfile User { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public IList<ProjectTimeSpan> TimeSpans { get; set; }
}
[ComplexType]
public class ProjectTimeSpan
{
public DateTime TimeStart { get; set; }
public DateTime TimeEnd { get; set; }
public bool Active { get; set; }
}
}
When I try to use this action I get the exception The type 'ProjectTimer.Models.ProjectTimeSpan' has already been configured as an entity type. It cannot be reconfigured as a complex type.
public ActionResult Index()
{
using (var db = new TimerContext())
{
return View(db.Projects.ToList);
}
}
The view is using the model #model IList<ProjectTimer.Models.Project>
Can any one shine some light as to why this would be happening?
Your IList<ProjectTimeSpan> property is not supported by EF. A complex type must always be part of another entity type, you cannot use a complex type by itself. If you absolutely need to have ProjectTimeSpan as a complex type, you will need to create a dummy entity type that only contains a key and a ProjectTimeSpan, and change the type of Project.TimeSpans to a list of that new type.

Resources