ASP.NET MVC Architecture : ViewModel by composition, inheritance or duplication? - c#

I'm using ASP.NET MVC 3 and Entity Framework 4.1 Code First.
Let's say I have a User entity :
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
When editing it in my UserController I want to add a PasswordConfirmation field and verify that PasswordConfirmation == Password
1. By composition
My first try was :
public class EditUserModel
{
[Required]
public User User { get; set; }
[Compare("User.Password", ErrorMessage = "Passwords don't match.")]
public string PasswordConfirmation { get; set; }
}
In this case the client side validation works but (Edit: client side validation working was a coincidence.) doesn't work and the server side validation fails with the following message : Could not find a property named User.Password
Edit: I think the best solution, in this case, would be to create a custom CompareAttribute
Implementing IValidatableObject
public class EditUserModel : IValidatableObject
{
[Required]
public User User { get; set; }
public string PasswordConfirmation { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if(this.PasswordConfirmation != this.User.Password)
return new[] { new ValidationResult("Passwords don't match", new[] { "PasswordConfirmation " }) };
return new ValidationResult[0];
}
}
In this case the server side validation works but the client side validation doesn't work anymore. Implementing IClientValidatable seems a bit too complicated and I prefer not having client side validation in this case.
2. By inheritance
public class EditUserModel : User
{
[Compare("Password", ErrorMessage = "Passwords don't match.")]
public string PasswordConfirmation { get; set; }
}
When trying to directly save EditUserModel using EF it doesn't work, I get some some error message about the EditUserModel metadata so I'm using AutoMapper to convert from User to EditUserModel and backwards.
This solution works but it more complex because I have to convert from the model to the view model and backwards.
3. By duplication
(Suggested by Malte Clasen)
The view model would have all the properties of the model plus additional ones. AutoMapper can be used to convert from one to another.
public class EditUserModel {
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
[Compare("Password", ErrorMessage = "Passwords don't match.")]
public string ConfirmPassword { get; set; }
}
This is the solution I like the least because of code duplication (DRY)
Questions
What are the pros and cons of inheritance, composition and duplication in this case ?
Is there a simple way to have both client side and server side validation without having to convert the model to the view model and backwards ?

Having struggled with this question before, I have in various instances gone with all three. In general, most of the opinions I've seen favor duplication in an MVC project, with a ViewModel constructed specifically for each view. In this manner the convention you'd use is something like UserDetailsViewModel and UserCreateViewModel. As you said, at that point AutoMapper or some other auto mapping tool would be used to convert from your domain objects to these flat ViewModels.
While I, too, don't like repeating code, I also don't like polluting my domain objects with validation or other view-specific attributes. Another advantage, though admittedly one almost nobody would ever have to contend with (regardless of what all the pros say), is that you can manipulate your domain objects in some ways without necessarily manipulating your ViewModels. I mention that because it's commonly cited, not because it carries much weight for me.
Lastly, using a truly flat ViewModel makes for cleaner markup. When I've used composition, I've often made errors creating HTML elements with names that are something like User.Address.Street. A flat ViewModel reduces at least my likelihood of doing that (I know, I could always use HtmlHelper routines to create elements, but that's not always feasible).
My recent projects have also pretty much required separate ViewModels these days anyway. They've all been NHibernate-based, and the use of proxies on NHibernate objects makes it not possible to use them directly for views.
Update - here's a good article I've referred to in the past: http://geekswithblogs.net/michelotti/archive/2009/10/25/asp.net-mvc-view-model-patterns.aspx

You could also consider independent classes for domain and view models, in this case for example
public class EditUserModel {
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string ConfirmPassword { get; set; }
}
if the Id is stored in the url. If you want to avoid the manual copy between the instances of User and EditorUserModel, AutoMapper can help you. This way you can easily decouple the password string in your view model from the password hash in your domain model.

I have trying to work this out and I found a solution that does not involve duplicating code. It's kind of workaround but, in my opinion, it's better than the other proposed solutions.
You have the User Model with all the validation:
public class UserModel
{
[Required]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
You compose the previous model with a new model
public class EditUserModel
{
public UserModel User { get; set; }
[Required]
public string PasswordConfirmation { get; set; }
}
The trick is in the action, you could receive more than one model:
[HtttPost]
public ActionResult UpdateInformation(UserModel user, EditUserModel editUserModel) {
if (ModelState.IsValid) {
// copy the inner model to the outer model, workaround here:
editUserModel.User = user
// do whatever you want with editUserModel, it has all the needed information
}
}
In this way the validation works as expected.
Hope this helps.

I don't use Entity Models too much, I prefer LINQ - SQL models so this may be incorrect:
Why not use a meta-data class which is applied to the Entity?
With LINQ - SQL the metadata assigned is taken into consideration for both client-side as well as server-side validation.
From what I understand application of a [MetaDataType] attribute is similar to inheritance only it works without implementing a new class (model) for alterations to the basic entity.
Also, another option you might want to try is creating a custom attribute - I did this once for a similar purpose. Essentially a flag which indicated the persistence of a member.
So i would have an entity defined as follows:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
[DoNotPersist]
public string ConfirmPassword {get; set;}
}
Also, I don't know what you are doing to store data but I had hooked an override into the OnInserting , OnEditing, OnDeleting functions for my DataContext which basically removed any members having my custom attribute.
I like this method simple because we use a lot of temporary, rather algorithmic data for each model (building good UI's for Business Intelligence) which is not saved in the database but is used everywhere inside model functions, controllers, etc - so we use dependency injection in all model repositories and controllers and so we have all these extra data points for each table to play with.
Hope that helps!
PS:- Composition vs Inheritance - it really depends on the target user of the application. If it is for an intranet app where security is less of an issue and the user / browser environment is controlled then just use client side validation, ie: composition.

I would favour composition over inheritance.
In case of your user password it looks like you're actually storing the password in Users table in clear text, which is VERY, VERY BAD.
You should store only a salted hash, and your EditUserModel should have two string properties for password and password confirmation, which are NOT the fields in your table.

Related

Is it possible in EF Core to make a one-way navigation property required?

I am working on a basic group chat system, for which I created these classes:
public class Role
{
public Guid Id { get; set; };
public string Username { get; set; }
}
public class Message
{
public Guid Id { get; set; };
public Role Author { get; set; }
public Conversation Conversation { get; set; }
public DateTime Date { get; set; }
public string Text { get; set; }
}
public class Conversation
{
public Guid Id { get; set; };
public IList<ConversationParticipant> ConversationParticipants { get; set; };
public IList<Message> Messages { get; set; };
}
public class ConversationParticipant
{
public Conversation Conversation { get; set; }
public Role Role { get; set; }
}
We are using EF Core 3.1 Code-First with migrations.
I am looking for a way to make Message.Author a required property, which should lead to a column in table Message that is created as AuthorId NOT NULL.
I tried:
public static void Map(this EntityTypeBuilder<Message> builder)
{
builder.HasOne(m => m.Author);
}
As this is applied using Add-Migration and Update-Database, the database column AuthorId is created, but with NULLs allowed.
There does not seem to be a method IsRequired() that I can add after HasOne().
I also tried:
public static void Map(this EntityTypeBuilder<Message> builder)
{
builder.Property(m => m.Author).IsRequired();
}
but that fails saying
The property 'Message.Author' is of type 'Role' which is not supported by current database provider. Either change the property CLR type or ignore the property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
Doing .HasOne(...) followed by .Property(...).IsRequired() also does not work:
'Author' cannot be used as a property on entity type 'Message' because it is configured as a navigation.
I managed to make Message.Conversation required through this:
public static void Map(this EntityTypeBuilder<Conversation> builder)
{
builder.HasMany(c => c.Messages) // A conversation can have many messages
.WithOne(e => e.Conversation) // Each message belongs to at most 1 conversation
.IsRequired(); // A message always has a conversation
}
However I'd rather not make Role aware of Messages, as I will never want to retrieve Messages directly from a Role (this will happen through Conversations and Participants).
My ultimate question is: Is there a way to make Message.Author required (NOT NULL), without linking Message and Role together in a full 1-to-many relationship with a Messages property in Role?
What about adding Role's foreign key to Message and then requiring that property to not be null? Something like:
// MessageConfiguration.cs
builder.Property(b => b.RoleId).IsRequired()
While the answer by #Ben Sampica was helpful and got me where I needed to be, the comments by #Ivan Stoev provided details and clarity that made me think that a more comprehensive answer would be useful.
There are multiple ways to make a foreign key column required (NOT NULL) in the generated table.
The simplest is to put [Required] on the navigation property:
public class Message
{
// ...
[Required] public Role Author { get; set; }
// ...
}
This will cause EF to create a shadow property AuthorId of type Guid because Message.Author is a Role and Role.Id is of type Guid. This leads to UNIQUEIDENTIFIER NOT NULL in case of SQL Server.
If you omit [Required] then EF will use Guid?, which leads to UNIQUEIDENTIFIER NULL, unless you apply one of the other options.
You can use an explicit Id property with a type that can't be null:
public class Message
{
// ...
public Guid AuthorId { get; set; }
public Role Author { get; set; }
// ...
}
Note (i) - This only works if you follow EF Core shadow property naming rules, which in this case means you must name the Id property nameof(Author) + nameof(Role.Id) == AuthorId.
Note (ii) - This will break if one day you decide to rename Author or Role.Id but forget to rename AuthorId accordingly.
If you can't or don't want to change the Model class, then you can tell EF Core that it needs to treat the shadow property as required:
builder.Property("AuthorId").IsRequired();
The same Notes apply as listed at 2, with the addition that you could now use nameof() to reduce the effort and the risks.
In the end I decided to use the [Required] approach, because
It is simple and descriptive,
No effort needed to think of which shadow property name to use,
No risk of breaking the shadow property name later on.
This may apply sometimes, not always:
Input forms may use the Model class attribute to check if a property is required. However it may be a better approach to build your forms around DTO classes, and then an attribute on an EF Model class may provide no worth for your forms.

Allowed Values of field in ASP.NET

Is there any data annotation for the allowed values in ASP.NET MVC Core? Since there is no enum in SQL server I am not able to migrate my class with enum field in it to the database. I want to give possible/allowed values to the field in the class. Is there any way to do this?
public class Employee
{
[Key]
public int ID { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Status { get; set; }
}
I want to provide Active and Inactive as the only possible values to the Status field.
you can also do this using a regular expression as below:
[Required]
[RegularExpression("Active|Inactive", ErrorMessage = "Invalid Status")]
public string Status { get; set; }
More details can by found here
As #ps2goat mentioned, you could use a check constraint on your database. However, for the model coming into the API you probably still want to provide validation there. Ideally you will do what you can, within reason, to prevent bad data from ever getting to the data layer. You don't mention whether you're using an n-tier architecture, or if your controller is directly referencing the data model. Either way, I believe this custom attribute can be used either at the API layer or on the entity model.
This is a good answer that explains how to create a custom validation attribute. It's an old answer, but it still applies to .Net Core. And here is an answer for a custom validation attribute in .Net Core. It basically looks like this:
public class EmployeeStatusAttribute : ValidationAttribute
{
private string[] _allowedValues;
public EmployeeStatusAttribute(string[] allowedValues)
{
_allowedValues = allowedValues;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var employee = value as Employee;
if (_allowedValues.Contains(employee.Status))
{
return ValidationResult.Success;
}
return new ValidationResult(`{employee.Status} is not a valid status`);
}
}
Then in your model:
public class Employee
{
...
[EmployeeStatus("Active", "Inactive")]
public string Status { get; set; }
...
}

Model or ViewModel when representing a subset of data in MVVM?

If I have a complex model representing a large amount of data, and I only wish to display a cut-down version of that model (e.g. Name, Description), what is the best approach in MVVM?
Most solutions I can find seem to assume that the data is already present in memory and recommend using a new ViewModel that exposes only the fields required.
However rather than select out all of the data from the database, it would be preferable to select just what is necessary. Do I then create a new model to hold that data? Selecting directly into the ViewModel is possible but feels like the wrong thing to do. Likewise using a new model to represent a different version of the same data also feels off somehow.
What is the accepted method of doing this?
As a simple example (Simple enough class that I wouldn't ordinarily do this):
public class User {
public int UserID {get;set;}
public string FirstName
public string LastName
public int AccessLevelID
public List<Groups> UserGroups
}
but I only really need:
public class PreviewUser {
int UserID
string FirstName
}
You can create another type with is a subset of the business type.
usually this is known as a
DTO - Data transfer Object which encapsulates only what you need. so the database needs to query only the subset of the entity.
public class UserDto
{
public int ID { get;set;}
public string Name{ get;set;}
}
Secondly if you need to add some ui logic to the display it is common to wrap the specific DTO in a more specific UI model.
public class UserUI
{
UserDTO _userDto;
UserUI(UserDTO userDto)
{
_userDto = userDto;
}
public string Name
{
get{return IsAfter_21_hours ? "The user as gone home" : _userDto.Name;}
}
}
the UserViewModel will reference an instance of UserUI.
You can either remove properties you don't need from the model (to slightly improve performance) or you can create a viewmodel that will provide only properties that you want to show.
Here is an example:
public class UserViewModel
{
private readonly User _user;
public UserViewModel(User user)
{
_user = user;
}
public int UserID
{
get { return _user.UserID; }
}
public string FirstName
{
get { return _user.FirstName; }
}
}
...
var viewModels = userRepository.GetUsers().Select(user => new UserViewModel(user));
UPDATED:
If performance is really important for you, you can use inheritance. Base class will be smaller version of the data and derived class will contain complete data. You can use the base class when you need to get only some fields from DB and save bandwidth.
public class BaseUser
{
public int UserID { get; set; }
public string FirstName { get; set; }
}
public class User : BaseUser
{
public string LastName { get; set; }
public int AccessLevelID { get; set; }
public List<Groups> UserGroups { get; set; }
}
There are number of approaches you may use:
use "full version" of source model. Since you're building UI, the user will see only what you want to display;
use view model, and wrap source model into this view model. The implementation is trivial, and amount of data is limited before UI;
use view model, and copy data from source model into this view model. The implementation is more complex (either mapping from existing model, or loading only required data from database), but view model and model are totally decoupled.
Actually, it depends on what is more suitable for you.
Note, that often the difference between "view model" and "model" is blurred. If the model looks like this:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
...and view model - like this:
public class PersonViewModel
{
public int Id { get; set; }
public string Name { get; set; }
}
then throw this view model away. While there's no difference, you don't need to create extra classes.
I think you don't have to create new model class to hold user data for view . Instead create a view model class and map the model properties to VM. See the example below
public class UserViewModel
{
Public UserViewModel(User user)
{
//initialize required viewmodel properties here
}
int UserID {get;set;}
string FirstName{get;set;}
}

How to map a class properties in dynamodb without using attribute in .net

I am very new in dynamodb. I am following http://www.rkconsulting.com/blog/persistence-model-framework-with-aws-dynamodb
step by step tutorial for connecting and CRUD operation in dynamodb and it`s works fine.
In that tutorial they using attribute mapping for map class properties
[DynamoDBTable("Dinosaur")]
public class Dinosaur
{
[DynamoDBHashKey]
public string Id { get; set; }
[DynamoDBProperty(AttributeName = "Name")]
public string Name { get; set; }
[DynamoDBProperty(AttributeName = "HeightMetres")]
public double HeightMetres { get; set; }
[DynamoDBProperty(AttributeName = "WeightKG")]
public double WeightKg { get; set; }
[DynamoDBProperty(AttributeName = "Age")]
public int Age { get; set; }
[DynamoDBProperty(AttributeName = "Characteristics")]
public List<string> Characteristics { get; set; }
[DynamoDBProperty(AttributeName = "Photo", Converter = typeof(ImageConverter))]
public Image Photo { get; set; }
[DynamoDBIgnore]
public int IgnoreMe { get; set; }
}
My question is there any way to map class properties without using attribute ?
like as mongoDb
public class Employee
{
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
}
we can write this in this way in a separate class
BsonClassMap.RegisterClassMap<Employee>(cm => {
cm.AutoMap();
cm.IdMemberMap.SetRepresentation(BsonType.ObjectId);
});
Is it possible in dynamodb ?
In the latest version of the .NET SDK you don't have to put in the attribute tags, it will see all read/write properties and upload the attributes as the same name. You would only have to use the [DynamoDBProperty(...)] if you want the attribute name in DynamoDB to be something other than the .NET object name.
So in your case you could simply remove that attribute for all properties except photo (which needs the converter, you could remove the AttributeName part of it) and WeightKg (because the capitalization is different) and you would get the same result.
I see this is a little bit older question now, so it may not have been that way in older versions (not sure) but I'm using 3.3.0.0 of the SDK and it does work that way. You have probably moved on but answering for others that may come upon this thread as I did...
There is no way, the default "strongly typed" client relies on attributes.
If you have time to do the plumbing yourself - there is nothing stopping your from doing your own implementation of the POC to Dynamo mapping though. Amazon client api (AWSSDK.DynamoDBv2) exposes the raw class AmazonDynamoDBClient which handles all the API calls and the DynamoDBConext is just implementation of IDynamoDBContext interface - which exposes all the "strongly typed" operations. So you can make your own implementation and take different mapping approach in it.
Also you can make a feature request for this:
https://github.com/aws/aws-sdk-net/issues

EF Code First 4.1: "Multiple Inheritence" (Is A) Question

I am trying to model a sort of "multiple inheritence" relationship with EF 4.1 Code First. Here is an example what I am trying to do.
Let's say I am attempting to model the way a user interacts with my application using a "User" object. This, being the base class, is used to describe the current user when they aren't doing anything in particular (such as visiting the homepage). It may look like this:
public class User
{
public Guid ID { get; set; } // Just use the forms authentication user ID
public string FirstName { get; set; }
public string LastName { get; set; }
}
Now, if I want to create a representation of that same user but in a different portion of the site, say, as a shopper, it may look like this:
public class Shopper : User
{
public virtual ICollection<Orders> Orders { get; set; }
}
And so on, and so forth. When I go to insert a Shopper that has a pre-existing User entry, it throws an exception because the PK is already taken in the User table.
Is there any way to model this (IsA) relationship with EF Code First? Or am I going to be stuck with something like this?
public class Shopper
{
public Guid UserID { get; set; }
public virtual User User { get; set; }
public virtual ICollection<Order> Orders { get; set; }
public string FirstName
{
get { return User.FirstName; }
set { User.FirstName = value; }
}
// yada, yada, yada...
}
I would like to stick with Code First and model the relationships right in my DbContext, but I can't figure out quite how to do something like this. Thanks!
EDIT:
So, I am trying to do something like this:
public void SomeMethod ()
{
var UserID = Guid.NewGuid ();
var MyUser = new User () { ID = UserID };
SaveUserToDatabase (MyUser);
var ShopperRepresentation = GetUserAsShopper (UserID);
// Do stuff.
}
Basically like using object-oriented roles, I guess. I want to use the same PK for every represenation of that user, but store all of their basic information in a base class called User. I know this is possible if I write my own SQL, of course, but I want to see if EF Code First can do it, too.
Yes, you can do it the way you describe in your first two code examples.
I think you just need to define a mapping, which you'll want to do in your OnModelCreating function of your DataContext in addition to having your classes set up right. How you do it depends on what mapping scheme you're using. I went for Table-Per-Type (TPT) in my most recent project, so I had something like this:
modelBuilder.Entity<User>().ToTable("Users");
modelBuilder.Entity<Shopper>().ToTable("Shoppers");
modelBuilder.Entity<OtherUser>().ToTable("OtherUsers");
Let me know if that doesn't work for you and I'll see what I can do.
Edit:
Having seen your clarification below, I can't think of a way to do that. You'd have to keep each objects stored separately (having EF treat a Shopper as just a Shopper, not a Shopper and a User), even though they share common data. That could lead to data mismatches (if, say, Shopper got its LastName updated but User didn't). I think you might be better off going with something like:
public class User
{
public virtual Guid ID { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual ShopperInfo { get; set; }
}
public class ShopperInfo
{
public virtual ICollection<Order> Orders { get; set; }
}
and then when you need to treat User as a Shopper, you just access the ShopperInfo (and if its not there, you create it). EF will be able to properly set that up for you no problem.
Though if you're going to have a lot of types of users, that might get cumbersome. Just a suggestion though - I think its a bit cleaner.

Categories