I'm very new in MVC 5 and EF6 and need help please.
I have two classes and one single View, I can get the values of class Person but class Address is always null.
I tried use constructor and Bind in PersonController/Create
My classes:
public partial class Person
{
[Key]
public int PersonID { get; set; }
[Required]
[StringLength(40)]
public string Name { get; set; }
[StringLength(40)]
public string Email { get; set; }
public virtual Address AddressDI { get; set; }
}
public class Address
{
[Key]
public int AddressID { get; set; }
[Required]
public string City { get; set; }
[Required]
public string Street { get; set; }
[Required]
public virtual Person PersonDI { get; set; }
}
Controller
public class ContatoController : Controller
{
private readonly Address _address;
public PersonController()
{
_address = new Address();
}
HttpPost]
ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = #"Name,Email,AddressID,City,")] Person person, Address address)
{
if (ModelState.IsValid)
{
db.Person.Add(person);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(person);
}
/* Other Actions and stuffs */
}
This is my 3 days pain :(
I don't know what exactly you're trying to achieve here. If you want to post a person class then just post the person:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Person person)
{
if (ModelState.IsValid)
{
db.Person.Add(person);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(person);
}
and in the view, something like:
#model Partner
#Html.BeginForm("Create","Contato", FormMethod.Post){
#Html.TextboxFor(p => Model.AddressDI.City)
}
Also it is a common practice to send data across controller actions in wrapper classes referred to as viewModels. ViewModels usually contain everything that needs to be posted or displayed at a given moment in the view, as well as potential parameters for the view.
something like:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ContatoViewModel viewModel)
{
var person = new Person();
person.Name = viewModel.Name;
person.Email = viewModel.Email;
person.AddressDI = viewModel.AddressDI
if (ModelState.IsValid)
{
db.Person.Add(person);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel);
}
Being honest I can't say more without seeing what you're doing in the view.
More on MVVM pattern: https://msdn.microsoft.com/en-us/library/hh848246.aspx
There are tools available such as Jimmy Bogard's AutoMapper which help with copying the values between the view models and the classes.
Related
I have a situation where I need to map a single property as a combination of multiple source properties based on some conditions.
Destination :
public class Email
{
public Email() {
EmailRecipient = new List<EmailRecipient>();
}
public string Subject{get; set;}
public string Body {get; set;}
public virtual ICollection<EmailRecipient> EmailRecipient { get; set; }
}
public class EmailRecipient
{
public int EmaiId { get; set; }
public string RecipientEmailAddress { get; set; }
public int RecipientEmailTypeId { get; set; }
public virtual Email Email { get; set; }
}
Source:
public class EmailViewModel
{
public List<EmailRecipientViewModel> To { get; set; }
public List<EmailRecipientViewModel> Cc { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
}
public class EmailRecipientViewModel
{
public string RecipientEmailAddress { get; set; }
}
I want Mapper.Map<EmailViewModel,Email>()
Here I would like to map my Email.EmailRecipient as a combination of EmailViewModel.To and EmailViewModel.Cc.
However the condition is, Email.EmailRecipient.RecipientEmailTypeId will be 1 for To and 2 for Cc
Hope my question is clear.
One possible way to achieve this is to create a map that uses a specific method for this conversion. The map creation would be:
Mapper.CreateMap<EmailViewModel, Email>()
.ForMember(e => e.EmailRecipient, opt => opt.MapFrom(v => JoinRecipients(v)));
Where the JoinRecipients method would perform the conversion itself. A simple implementation could be something like:
private ICollection<EmailRecipient> JoinRecipients(EmailViewModel viewModel) {
List<EmailRecipient> result = new List<EmailRecipient>();
foreach (var toRecipient in viewModel.To) {
result.Add(new EmailRecipient {
RecipientEmailTypeId = 1,
RecipientEmailAddress = toRecipient.RecipientEmailAddress
});
}
foreach (var ccRecipient in viewModel.Cc) {
result.Add(new EmailRecipient {
RecipientEmailTypeId = 2,
RecipientEmailAddress = ccRecipient.RecipientEmailAddress
});
}
return result;
}
I'm a huge opponent of converters, mostly because for other people in your project, things will just happen 'like magic' after the mapping call.
An easier way of handling this would be to implement the property as a method that converts other properties on the viewmodel to the required formatting. Example:
public class EmailViewModel
{
public ICollection<EmailRecipient> EmailRecipient {
get {
return To.Union(Cc);
}
}
public List<EmailRecipientViewModel> To { get; set; }
public List<EmailRecipientViewModel> Cc { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
}
Now automapper automatically maps from EmailRecipient property to EmailRecipient property, and if someone is trying to figure out how it happens, they just need to look on the viewmodel.
Editing this some years later: Just as a warning, doing things this way means that every time you call EmailRecipient, you incur the o(n) task of unioning the To and Cc fields. This is fine if you're only dealing with one email, but if you're reusing the viewmodel and someone sticks it in a loop with say, every other email in the system, it might be a huge performance issue. In that case I'd go with the accepted answer so that you dodge this potential performance pitfall.
So, I'm building a system for managing contacts. My contact domain model has quite a few string properties, as well as booleans. In the spirit of keeping behavior inside of the domain models, I've gone down the path of creating "update methods." I'm starting to feel like it's getting a bit burdensome. In the past, CRUD apps would just have a single update method and it would set all of the properties in one shot.
Am I on the right path? I'm concerned about having 10 - 15 update methods on my domain service and domain entities.
FYI, the example given is a bit contrived, so imagine a model with lots of string and boolean properties.
// Application Layer Stuff
public class UpdateContactCommand
{
public UpdateNamePredicate UpdateName { get; set; }
public UpdatePhonePredicate UpdatePhone { get; set; }
public int ContactId { get; set; }
}
public class UpdateNamePredicate
{
public string NewFirstName { get; set; }
public string NewLastName { get; set; }
}
public class UpdatePhonePredicate
{
public string NewPHone { get; set; }
}
public class UpdateContactResponse
{
public bool Success { get; set; }
public string Message { get; set; }
}
public interface IWcfService
{
UpdateContactResponse UpdateContact(UpdateContactCommand updateContactCommand);
}
public class WcfService : IWcfService
{
private readonly IContactService _contactService;
public WcfService(IContactService contactService)
{
_contactService = contactService;
}
public UpdateContactResponse UpdateContact(UpdateContactCommand updateContactCommand)
{
if (updateContactCommand.UpdateName != null)
{
_contactService.UpdateName(updateContactCommand.ContactId, updateContactCommand.UpdateName.NewFirstName,
updateContactCommand.UpdateName.NewLastName);
}
if (updateContactCommand.UpdatePhone != null)
{
_contactService.UpdatePhone(updateContactCommand.ContactId, updateContactCommand.UpdatePhone.NewPHone);
}
return new UpdateContactResponse();
}
}
// Domain Layer
public interface IContactService
{
// There are lots more of these
void UpdateName(int contactId, string newFirstName, string newLastName);
void UpdatePhone(int contactId, string newPhone);
}
public class ContactService : IContactService
{
private readonly IContactRepository _contactRepository;
public ContactService(IContactRepository contactRepository)
{
_contactRepository = contactRepository;
}
public void UpdateName(int contactId, string newFirstName, string newLastName)
{
var contact = _contactRepository.GetById(contactId);
contact.SetName(newFirstName, newLastName);
_contactRepository.Commit();
}
public void UpdatePhone(int contactId, string newPhone)
{
var contact = _contactRepository.GetById(contactId);
contact.SetPhone(newPhone);
_contactRepository.Commit();
}
}
public interface IContact
{
int Id { get; set; }
// There are lots more of these
void SetName(string newFirstName, string newLastName);
void SetPhone(string newPhone);
}
public class Contact : IContact
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Phone { get; set; }
public void SetName(string newFirstName, string newLastName)
{
FirstName = newFirstName;
LastName = newLastName;
}
public void SetPhone(string newPhone)
{
Phone = newPhone;
}
}
public interface IContactRepository
{
IContact GetById(int id);
void Commit();
}
public class ContactRepository : IContactRepository
{
public IContact GetById(int id)
{
// Not important
throw new NotImplementedException();
}
public void Commit()
{
// Not important
throw new NotImplementedException();
}
}
First of all, not all applications lend themselves well to a DDD approach. If you say your application could pretty much have been implemented in a CRUDish way before, chances are it's still CRUD now. Don't try to apply DDD on any app because it's the shiny new thing.
That being said, you don't just write "update methods" for the fun of it. They have to reflect the domain tasks your user wants to perform. Why does the user want to update a Contact ? Has the contact moved or just changed phone number ? Changed marital status and name ? Has the point of contact in a company been taken over by another employee ?
Usually, you won't have tons of update methods for a given entity. There's always a way to group changes in operations that are meaningful for the domain. Good ways to force yourself to do it are :
Think about the maximum number of form fields you can reasonably display to the user. Couldn't you split that complex UI into smaller, more meaningful screens ? From there you have to start reasoning (preferably with the help of a domain expert) about the tasks these should reflect.
Make your entity fields immutable from the outside. Thus you'll have to think harder about their true nature -- what should be in the constructor ? what should some other manipulation methods be ?
I am having a problem merging these 2 contexts.
I deleted this line of code from IdentityModels.cs:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
}
I implemented this inside my DataContext.cs
public class DataContext : DbContext
{
public DataContext()
: base("name=DefaultConnection")
{
}
// Account tables
public DbSet ApplicationUsers { get; set; }
public DbSet Roles { get; set; }
public DbSet Tokens { get; set; }
public DbSet UserClaims { get; set; }
public DbSet UserLogins { get; set; }
public DbSet UserManagements { get; set; }
public DbSet UserRoles { get; set; }
public DbSet UserSecrets { get; set; }
// App Models
public DbSet<Course> Courses { get; set; }
public DbSet<Student> Students { get; set; }
}
Problem:
When I "update-database" it only created the Courses and Students tables.
Question
If I successfully implement this method will I lose all of the nice methods that IdentityDbContext interface offers for example:
var rm = new RoleManager<IdentityRole>(
new RoleStore<IdentityRole>(new ApplicationDbContext()));
return rm.RoleExists(name);
Ok here is the solution that I found posted by Olav Nybo in this topic How can one put application users in the same context as the rest of the objects?.
Go to his sample project on github: https://github.com/onybo/Asp.Net-Identity-sample-app/tree/master/CustomUser/CustomUser
Download the configurations folder from the Models folder and place the folder inside your models folder.
Inside your DataContext file you will put this snippet of code which will call these configuration files to build out your database.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
if (modelBuilder == null)
throw new ArgumentNullException("modelBuilder");
modelBuilder.Configurations.AddFromAssembly(typeof(Generic_Repo_Template.Models.Configurations.ApplicationUserConfiguration).Assembly);
}
Now that your database is created you still do not have access to these tables through the datacontext object. In order to be able to access these tables through your datacontext is to include these lines of code:
public virtual IDbSet<ApplicationUser> Users { get; set; }
public virtual IDbSet<IdentityRole> Roles { get; set; }
public virtual IDbSet<IdentityUserClaim> Claims { get; set; }
So the full DataContext file will look something like this:
public class DataContext : DbContext
{
public DataContext()
: base("name=DefaultConnection")
{
}
// Account tables
public virtual IDbSet<ApplicationUser> Users { get; set; }
public virtual IDbSet<IdentityRole> Roles { get; set; }
public virtual IDbSet<IdentityUserClaim> Claims { get; set; }
// App Models
public DbSet<Course> Courses { get; set; }
public DbSet<Student> Students { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
if (modelBuilder == null)
throw new ArgumentNullException("modelBuilder");
modelBuilder.Configurations.AddFromAssembly(typeof(AspNetRoleBasedSecurity.Models.Configurations.ApplicationUserConfiguration).Assembly);
}
}
You have to use:
DbSet<Model> Name {get;set;}
Instead of
DbSet Model {get;set;}
As the answer to your question. The RoleStore needs a DbContext (IdentityDbContext inherits from DbContext). So you should be able to still use the roleManager and more...
public class PageRoleService
{
public void SetRoles(Page page, User activeUser)
{
var rb = page.Project.ProjectType.GetRoleFor(activeUser.UserType);
page.RolesForPage.Add(activeUser, rb);
var managers = GetAllManagersOf(activeUser);
foreach (var m in managers)
{
page.RolesForPage.Add(m, rb);
}
}
}
public class Project : Entity
{
public ProjectType ProjectType { get; set; }
public IList<Page> Pages { get; set; }
}
public class Page : Entity
{
public string Name { get; set; }
public Project Project { get; set; }
public IDictionary<User, RoleBehaviour> RolesForPage { get; set; }
}
public class ProjectType : Entity
{
public IQueryProcessor QueryProcessor { get; set; }
public IList<RoleBehaviour> RoleBehaviours { get; set; }
public RoleBehaviour GetRoleFor(USerType userType)
{
var behaviour = return QueryProcessor.Execute(new GetRolesByUserAndProjectTypeQuery() {
ProjectType = this,
UserType = userType
});
// Filter behaviour attributes for project type properties, business rules, etc...
// FilterBehaviour(behaviour);
return behaviour;
}
}
public class GetRolesByUserAndProjectTypeQuery
{
public UserType UserType { get; set; }
public ProjectType ProjectType { get; set; }
}
public class GetRolesByUserAndProjectTypeQueryHandler
{
public Db Db { get; set; }
public RoleBehaviour Execute(GetRolesByUserAndProjectTypeQuery query)
{
return Db.FirstOrDefault(r => r.UserType == query.UserType && r.ProjectType == query.projectType);
}
}
public class RoleBehaviour : Entity
{
public Role ROleForArea1 { get; set; }
public Role ROleForArea2 { get; set; }
public UserType UserType { get; set; }
public ProjectType ProjectType { get; set; }
public IDictionary<string, string> Attributes { get; set; }
}
public enum UserType
{
A,
B,
C,
D
}
public class Role : Entity
{
public IList<string> Permissions { get; set; }
}
I don't use repository, no need data abstraction, I use CQRS for crud operations. (CreateProjectCommand, GetRolesByUserAndProjectTypeQuery, etc..)
Users related a lot of project and page. Users have more than role for each Page Entity and is dynamically created when user (client) request to fetch All projects page or single page item.
My Page Role Service determinates page roles for active user and its managers. My MVC Controller use PageRoleService.
PageRoleService is Application Service or Domain Service or .....?
QueryProcessor in Entity (ProjectType) is invalid approach? How can handle this/their problems without lazy or eager loading?
RoleBehaviour is Entity or Value Object?
PageRoleService is a service or business logic in domain?
I know that I'm some years later, but:
I would put away the base class Entity, because it looks that this are just Dtos returned by the queryhandler (infact GetRolesByUserAndProjectTypeQueryHandler.Execute returns a RoleBehaviour).
Given this, I think that:
PageRoleService is a simple service that completes a Dto, hence it looks a kind of factory
Given that ProjectType here has two different roles (a Dto and Entity, and this is against CQRS), if:
it's a Dto, then use a service/factory/ORM to load extra data on it
it's an Entity, try to load all the data that's needed by it. This because there're great changes that you'll need it on the way to execute your command (great explanation about DDD and entities).
The object has it's own identity? Has it an Id that, even if things will change, remains the same? Looking at it, it looks just a Dto, with nothing really interesting (at business level).
see 1.
I have a flat domain class like this:
public class ProductDomain
{
public int ID { get; set; }
public string Manufacturer { get; set; }
public string Model { get; set; }
public string Description { get; set; }
public string Price { get; set; }
}
I have two DTO classes like this:
public class ProductInfoDTO
{
public int ID { get; set; }
public string Manufacturer { get; set; }
public string Model{ get; set; }
}
public class ProductDTO : ProductInfoDTO
{
public string Description { get; set; }
public string Price { get; set; }
}
Now the problem is:
Scenario #1:
Mapper.CreateMap<ProductDomain, ProductInfoDTO>() // this mapping works fine
Scenario #2:
Mapper.CreateMap<ProductDomain, ProductDTO>() // this mapping is not working and throws System.TypeInitializationException
So my question is how to create mapping between ProductDomain and ProductDTO (which inherits ProductInfoDTO) without breaking the definition of both source and destination classes. Also I dont want to introduce any new inheritance for the domain class ProductDomain.
Thanks
You can build your own custom TypeConverter like this
public class ProductDomainToProductDTOConverter : ITypeConverter<ProductDomain, ProductDTO>
{
public ProductDTO Convert(ProductDomain source)
{
ProductDTO product = new ProductDTO();
product.Price = source.Price;
...
return product;
}
}
And then create a map with your custom TypeConverter like this
Mapper.CreateMap<ProductDomain, ProductDTO>().ConvertUsing<ProductDomainToProductDTOConverter>();