I've been a software developer for a long time, but I'm always looking to learn "different ways of doing things". I am currently working on a new project and decided to base the architecture on proposals suggested by the community using a combination of DDD, Entity Framework Code First and other "little things". However, in practice and due to some particularities of my business rules, I feel a little difficult to apply some concepts. I would appreciate it if you could help me with these issues.
This is the summary structure of my solution. All projects presented here are of Class Library type:
- Core - Contains basic system-wide functionality such as resource management, globalization, etc.
References . - Domain - Contains the definition of entities and validations.
References: (...) - Repository - Responsible for communicating with the database and mapping entities through the Fluent API.
Core Entity Framework 6
Entity Framework 6 - Security - Applies the features of the above projects to provide security features such as authentications and encryptions.
Entity Framework 6
Entity Framework 6
(...)
The Domain project contains a class called User defined by the following code (summarized):
namespace Domain.Entities
{
public class User : EntityBase
{
private string _userCode;
private string _userPassword;
//outras variáveis....
private int _customerId;
[MaxLength(255), Required(AllowEmptyStrings = false)] //Estou utilizando Data Annotations para facilitar os testes de integridade e definir restrições básicas ao modelo.
public string UserCode
{
get { return _userCode; }
set
{
ValidateValue(GetType(), nameof(UserCode), value); //O método ValidadeValue está definido na classe base EntityBase e tem o propósito de validar o valor a ser atribuído à propriedade.
_userCode = value;
}
}
[MaxLength(255)]
public string UserPassword
{
get { return _userPassword; }
set
{
ValidateValue(GetType(), nameof(UserPassword), value);
_userPassword = value;
}
}
//outras propriedades...
public int CustomerId
{
get { return _customerId; }
set
{
ValidateValue(GetType(), nameof(CustomerId), value);
_customerId = value;
}
}
//Propriedades de navegação para outras entidades relacionadas
public virtual Customer Customer { get; set; }
public virtual ICollection<Membership> Memberships { get; set; }
//Construtores
public User() { }
public User(string userCode, string userName, string email, Address address = null, bool isAdministrator = false)
{
UserCode = userCode;
UserPassword = "";
//demais inicializações...
CustomerId = 0;
}
//outros métodos...
///<summary>
///Retorna as regras da política de senha vigentes ao usuário por meio de seus papéis.
///</summary>
public PasswordRules GetPasswordRules()
{
var rules = (from r in Memberships.Select(x => x.Role)
where r.RulesPrecedence > 0
orderby r.RulesPrecedence
select r.PasswordRules).FirstOrDefault();
return rules;
}
}
}
I'll write another class here:
namespace Domain.Entities
{
public class Membership : EntityBase
{
public int UserId { get; set; }
public int RoleId { get; set; }
public virtual User User { get; set; }
public virtual Role Role { get; set; }
public Membership() { }
}
}
The questions I need to address are:
The User
class exposes the UserPassword
property that, despite having its content encrypted, I would not like to expose it to the final developers, so that it was an internal property. But how do you do this if in the Repository project you need to have access to this property so you can map it to its column in the database table?
As you can see, the User
class has a navigation property for the Membership
entity, in a one-to-many relationship. A Membership
, in turn, has two navigation properties (one for User
and another for Role
), so Membership
makes a many-to-many relationship between User
and Role
. Through these relationships and properties, a user can know their password policy rules (defined in Role), as shown by the User.GetPasswordRules()
method. So far so good. The problem is that a certain user will not necessarily be able to access the Roles, in the same way that someone who has access to the role register does not necessarily have access to the users. Therefore, Membership
should not expose its browsing properties. But if I remove the User
and Role
navigation properties from Membership
, how can I get the functionality of the User.GetPasswordRules()
method since the Domain project does not access the database?
There are a few other issues, but I think these two are the main ones. I hope I have been clear. Thanks for any help.