Model validation, database constraints - c#

I'm trying to add some architecture to my projects and enrich my models.
I started with CQS (implementation similar to that one: CQS-Sample) and here's my first problem.
Let's say I have two classes like these below:
public class Network
{
public int Id { get; set; }
public User User { get; set; }
private IQueryFactory _queryFactory { get; set; }
public Network(IQueryFactory queryFactory)
{
_queryFactory = queryFactory;
}
public void AddUser(User user)
{
if(this.User == null && user != null)
{
userHasUniqueEmail(user);
this.User = user;
}
}
private void userHasUniqueEmail(User user)
{
bool isUnique = _queryFactory.ResolveQuery<INewUserUniqueQuery>().Execute(user.Email);
if (!isUnique)
{
throw new ArgumentException("E-mail is not unique");
}
}
}
public class User
{
public int Id { get; set; }
public string Email { get; set; }
}
Network object can have User, but I need to check first in database that given e-mail doesn't already exists or do some other checkings, so my commands will be executed successfully.
By adding user I mean adding completely new User to database.
Would it be correct way to do this?

You can do it the way you do it now and it's ok.
Another option is to make this Validation in Contoller. Then you should use Remote attribute. And Move your IsEmailUnique(string mail) method to Controller.
If you want to know how you can do it with email check - this question will help you.

Related

Create a class to store classes that use different interfaces

I am working on a project in C# which needs to store information about a user. This information is retrieved from their respective libraries which have their own implementations and interfaces. Currently users can either connect from Twitch or Discord, so they will be represented as either TwitchUser or DiscordUser objects. However, I would like to write a class User that will contain one of the 2 classes which should make it easier for me to refer to them in code.
Here is an example of how TwitchUser and DiscordUser look like:
public class TwitchUser : IChatUser
{
public TwitchUser();
public string Id { get; }
public string UserName { get; }
public string DisplayName { get; }
public string Color { get; }
//and so on...
}
public class DiscordUser : SnowflakeObject, IEquatable<DiscordUser>
{
public virtual string Email { get; internal set; }
public virtual string Username { get; internal set; }
public bool Equals(DiscordUser e);
//and so on...
}
I thought I could create a class which accepts generic types but with my implementation I would have to pass BOTH classes which means one of them would be null. This doesn't feel right to me.
public class User<T,D>
{
public TwitchUser VarA { get; set; }
public DiscordUser VarB { get; set; }
}
What is the correct way of combining 2 classes that have different implementations and don't have interfaces in common between?
I would then also write code inside my User class to return user IDs etc.
Update
For example, when I request a user ID I would perform a check inside User whether I stored a TwitchUser or DiscordUser, and based on the outcome I would return an attribute which represents the user's ID on that platform.
Update 2
A user may only be represented by one of the two classes. For example, if they used Discord as their platform to login then they will only have a DiscordUser object associated with them. Same applies to Twitch platform and it using TwitchUser object. The reason they are different is because these implementation were written by different people using 2 different libraries, which is why they don't use the same interfaces, or inherit from one common class. So what I am trying to do is retroactively add some sort of an inheritance here. This way, when I want to refer to the user in my code, I don't need to write 2 overloads for a function (where one uses TwitchUser and the other uses DiscordUser). I just want to be able to refer to User and let that class decide for me.
those 2 clases I mentioned cannot be modified [...] I want to be able to access all the necessary attributes stored in DiscordUser and TwitchUser
That sounds like a good fit for the adapter pattern. Define an interface as common denominator:
public interface IUser
{
string Id { get; }
string Username { get; }
}
Note that this interface can only contain properties that both objects share, or you're going to need null checks all over the place.
Then create an adapter for each type you want to wrap:
public class TwitchUserAdapter : IUser
{
private readonly TwitchUser _user;
public TwitchUserAdapter(TwitchUser user)
{
_user = user;
}
public string Id => _user.Id;
public string Username => _user.UserName;
}
public class DiscordUserAdapter : IUser
{
private readonly DiscordUser _user;
public TwitchUserAdapter(DiscordUser user)
{
_user = user;
}
public string Id => _user.Id;
public string Username => _user.Username;
}
Now you can treat both the same:
var users = new List<IUser>();
users.Add(new TwitchUserAdapter(new TwitchUser { Id = "Tfoo", UserName = "Tbar" }));
users.Add(new DiscordUserAdapter(new DiscordUser { Id = "Dfoo", Username = "Dbar" }));
foreach (var user in users)
{
Console.WriteLine($"Id: {user.Id}, Name: {user.Username}");
}
"What is the correct way of combining 2 classes that have different implementations and don't have interfaces in common between?"
One way to accomplish this might be to create a class that contains all the properties you care about, and then create static methods that return an instance of the class based on the properties of a TwitchUser or a DiscordUser:
public class User
{
// Add just the properties you care about
public string Id { get; private set; }
public string UserName { get; private set; }
public string DisplayName { get; private set; }
public string Color { get; private set; }
public string Email { get; private set; }
// Make the default constructor private so instances of this
// class can only be created from one of our static methods
private User() { }
public static User FromTwitch(TwitchUser twitchUser)
{
return new User
{
Id = twitchUser.Id,
Color = twitchUser.Color,
DisplayName = twitchUser.DisplayName,
UserName = twitchUser.UserName
};
}
public static User FromDiscord(DiscordUser discordUser)
{
return new User
{
Email = discordUser.Email,
UserName = discordUser.Username
};
}
}

How to track identity changes in EF Core?

I have a service in my application which creates a User, and saves it to the database. Here's a method of my service:
public async Task<UserDTO> CreateUserAsync(User newUser)
{
var result = (UserDTO)await _userRepository.CreateUserAsync(newUser);
if (result != null)
{
await _userRepository.SaveChangesAsync();
}
return result;
}
And a method from a UserRepository:
public async Task<User> CreateUserAsync(User newUser) => (await _dbContext.AddAsync(newUser)).Entity;
Here's a User class:
public class User
{
public int UserId { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}
The problem is when the user is being added via service, UserId is not known yet. It has default value 0, then ef core saves it to a database, finding a proper UserId. But value returned by my methods has no UserId updated - it is still 0, and i would like to return updated value. How to achieve that in a proper way?
newUser WILL have an Id read from the database.
Your code is casting from User to UserDTO, which is unlikely to work.

Ignore object attribute when using signalR

i have a problem with ignoring an attribute so it doesn't get sent down to the client. I have this object
public class UserEntry : IComparable<UserEntry>
{
[JsonIgnore]
public string UserId { get; set; }
public string AnonymousUserId { get; set; }
}
And i am having a problem for when for example i send a message to my signalR application the UserId is still in the data but i only want the AnonymousUserId to get sent down because the UserId is only used in the backend and shouldn't ever be in client.
so when i get here
public Task TopUserBroadcast(TopUsersBroadcastNotificationModel model)
{
SignalRClient.SendAsync(SignalRAppMethods.Broadcast, Constants.GetInfoGroup(model.InfoId), ResponseMessageIDs.TopUsers,model.Entries);
return Task.CompletedTask;
}
The userId is still in the model.Entries. Anyway i can make it ignore that attribute?
and the TopUsersBroadcastNotificationModel looks like this
public class TopUsersBroadcastNotificationModel
{
public List<UserEntry> Entries { get; set; }
public long InfoId { get; set; }
public TopUsersBroadcastNotificationModel(List<UserEntry> entries, long InfoId)
{
Entries = entries;
InfoId = infoId;
}
}
So what i really want and hoped the [JsonIgnore] would solve is that when its sent down to the client the UserId should be ignored so if i log the entries i get down to client there should be no UserId there.
you need to add a function as following in your entity :
public bool ShouldSerializeXXXX() { return false; }
change the XXXX to your attribute name .
in your case UserId:
public bool ShouldSerializeUserId() { return false; }
If you need to make it dynamic you can input a static boolean value in the return field and change it when you need
EDIT
about your comment , this is what working in my case :
i have a person class with fingerprint as a string field , and i didn't want to send it to by a SignalR hub or even a webservices , but by using an specific action to get the fingerprint , so what considere a entity person with attributs fingerprint as following
public string fingerprint { get; set; }
i added this method :
public bool ShouldSerializefingerprint() { return ShouldSerializefingerprintTest; }
the ShouldSerializefingerprintTest field is a static boolean attributs who can be edited to true or false
by default is false so the fingerprint will not be showen on any webservice/signalR
and when i need to get the fingerprint ShouldSerializefingerprintTest to true
but public bool ShouldSerializefingerprint() { return false; } can do what you need.
you can find more on microsoft doc.

Disallow user to perform an update on a field or member of a class and return 405 Method Not Allowed : HTTP

I am working on an api which serves creating,updating,deleting of user settings for an application. My users are of two types
admin user
common user
I have a field public bool ReadOnly { get; set; } which says whether a common user is allowed to change the setting or not.
Now the question is in which layer i need to validate this and throw the 405 response to the client. Please suggest.
private readonly SettingsRepository _SettingsRepository;
[HttpPut("{userid}/settings/{settingName}")]
public IActionResult Put(string userid, [FromBody]Setting setting)
{
var result = _SettingsRepository.Update(userid, setting);
if (result == true)
{
return Ok(201);
}
else
{
return BadRequest();
}
}
//Updates the existing setting for a user having userid
public bool Update(string userid, Setting setting)
{
bool flag = false;
if (userid == null || setting == null)
{
return flag;
}
var existing = Profiles.profiles.Where(p => p.UserID.ToLower() == userid.ToLower() && p.Settings.Any(s => s.Name.ToLower() == setting.Name.ToLower())).SelectMany(res => res.Settings).ToList();
if (existing.Count() > 0)
{
existing.ForEach(e =>
{
e.Name = setting.Name;
e.Value = setting.Value;
e.Type = setting.Type;
e.Valid = setting.Valid;
e.ReadOnly = setting.ReadOnly;
e.ModifiedOn = DateTime.UtcNow;
e.Encrypted = setting.Encrypted;
e.Enabled = setting.Enabled;
e.CreatedOn = setting.CreatedOn;
e.Description = setting.Description;
});
FileSerDe.SerializeSettings<IList<Profile>>(Profiles.profiles, System.IO.Directory.GetCurrentDirectory() + "\\" + "seed.txt");
flag = true;
}
return flag;
}
//Profile Entity
public class Profile
{
public string UserID { get; set; }
public string UserName { get; set; }
public List<Setting> Settings { get; set; }
}
//Setting Entity
public class Setting
{
public string Name { get; set; }
public object Value { get; set; }
public string Type { get; set; }
public bool Encrypted { get; set; }
public bool ReadOnly { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime ModifiedOn { get; set; }
public bool Valid { get; set; }
public bool Enabled { get; set; }
public string Description { get; set; }
}
It looks business logic is in repository. so you can put security measure in repository. do that first thing in repository & throw exception on failed.
this will centralize your business logic to single place.
405 Method not allowed would be used when the HTTP method (e.g. GET or PUT) is specifically not allowed to be used with a given URL, and would apply to all users. For something which is permissions-within your application and related to a specific user it would be more accurate to a send a 403 Forbidden response.
As for the layers, clearly the API Action method is the only one which can return the actual HTTP error code, but since the information that tells you whether the user has permission is held in the database, you could arrange it so that the data layer tells the API layer what the appropriate response should be, perhaps by throwing an exception or by setting a flag on an output parameter to the database method. This would require you to pass information about the current user to the database layer, though, some people think that's unnecessary overhead, unless it's required anyway to record audit data etc.
The alternative is that you could get the API layer to retrieve the relevant data from the database before attempting to run the Update, and make a decision based on that retrieved data, entirely within the API action method. It's really a design decision that is up to you and what suits your application structure. Either way is possible, and, arguably, valid.

C# Lazy loading & Ajax

I have a class where some properties are going back to the database, ONLY when they are called. So, let consider the following example:
class User
{
public int UserID { get; internal set; }
public string UserName { get; set; }
public Role[] Roles
{
get
{
if (this.UserID > 0)
return RoleRepository.GetByUserID(this.UserID).ToEntityArray();
else
return RoleRepository.GetByUserName(this.UserName).ToEntityArray();
}
}
}
There is also a Role class, but that's probably not important. The 'Roles' property in the 'User' class is kind of like lazy loading. It is only retrieving the info when that property is accessed. The question is how can I use JQuery to ensure that the lazy loading occurs or is that even possible? Any articles on this concept would also be helpful.
Thanks
I don't see what jQuery has to do with this at all.
Touching that Property will trigger the lazy-load.
If you use JQuery to call some HttpHandler/WebMethod/ActionMethod/etc, as soon as you try to iterate through or access that Property it is going to load that data
Also, rather than having that biz logic in your domain object you could try a delegate approach to keep "how" data is bound to that Property in its proper place
class User
{
public int UserID { get; internal set; }
public string UserName { get; set; }
public delegate Role[] GetRolesDelegate(int userId, string username);
public GetRolesDelegate GetRoles { get; set; }
Role[] _roles;
public Role[] Roles
{
get
{
if (_roles == null)
{
_roles = GetRoles == null
? new Role { }
: GetRoles(UserID, UserName).ToEntityArray();
}
return _roles;
}
}
}
Then you could bind that like so:
User user = new User();
user.GetRoles = RoleRepository.GetRoles;
Like hunter I'm not sure what jQuery has to do with this. To make the Roles property lazy load add a private backing property that stores the value the first time it is accessed from the repository. Then, for subsequent accesses, you can just return that private backing variable, rather than going through the RoleRepository. Something like:
class User
{
public int UserID { get; internal set; }
public string UserName { get; set; }
private Role[] _roles;
public Role[] Roles
{
get
{
if (_roles == null)
{
if (this.UserID > 0)
_roles = RoleRepository.GetByUserID(this.UserID).ToEntityArray();
else
_roles = RoleRepository.GetByUserName(this.UserName).ToEntityArray();
}
return _roles;
}
}
}

Categories

Resources