Bonjour à tous,

Je suis en train de coder un générateur de menu hebdomadaire, le principe est simple: générer un menu sur 5 ou 7 jours à partir d'une base de donnée de recettes.
Je développe ce générateur en C# .NET Core 6 avec MongoDB.
Pour l'instant je n'ai pas fait grand chose à part une DAL pour la partie utilisateur (j'ai utilisé cet article que j'ai adapté), un singleton et Un UserRepository.

Le but de ce projet est, en plus de me facilité la vie, de pouvoir m'exercer et d'implémenter des concepts que je veux maîtriser.

Voici mon UserDTO:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using System.Diagnostics.CodeAnalysis;
 
namespace Common
{
    public class UserDTO : DTOBase
  {
    [BsonId]
    public Guid? Id { get; set; }
 
    [BsonElement("user_id")]
    [DisallowNull]
    public string UserId { get; set; }
 
    [BsonElement("created_date")]
    [BsonRepresentation(BsonType.DateTime)]
    public DateTime CreatedDate { get; set; }
 
    [BsonElement("updated_date")]
    [BsonRepresentation(BsonType.DateTime)]
    public DateTime UpdatedDate { get; set; }
 
    [BsonElement("name")]
    [DisallowNull]
    public string Name { get; set; }
 
    [BsonElement("email")]
    [DisallowNull]
    public string Email { get; set; }
 
    [BsonElement("birthdate")]
    [BsonRepresentation(BsonType.DateTime)]
    public DateTime Birthdate { get; set; }
 
    [BsonElement("foodrule")]
    public string? FoodRule { get; set; }
 
 
    // Constructeur par défaut
    public UserDTO()
    {
      Id = Guid_NullValue;
      UserId = String_NullValue;
      CreatedDate = DateTime_NullValue;
      UpdatedDate = DateTime_NullValue;
      Name = String_NullValue;
      Email = String_NullValue;
      Birthdate = DateTime_NullValue;
      FoodRule = String_NullValue;
      IsNew = true;
 
    }
  }
}
Voici mon UserDB (là où j'implémente mon CRUD) :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
using Common;
using System.Globalization;
using System.Text.RegularExpressions;
 
namespace DAL
{
    public class UserDB : DALBase
  {
    public static string Collection { get { return "users"; } }
 
    public UserDTO GetUserById(string userId)
    {
      Tuple<string, string, string>[] filters = { Tuple.Create("=", "userId", userId) };
 
      return GetSingleDTO<UserDTO>(Collection, filters);
    }
 
    public UserDTO GetUserByEmail(string email)
    {
      Tuple<string, string, string>[] filters = { Tuple.Create("=", "email", email) };
 
      return GetSingleDTO<UserDTO>(Collection, filters);
    }
 
    public List<UserDTO> GetAll()
    {
      Tuple<string, string, string>[] filters = { Tuple.Create("", "", "") };
 
      return GetListDTO<UserDTO>(Collection, filters);
    }
 
    public void SaveUser(ref UserDTO user)
    {
      bool isNewRecord = false;
      if (user.Id.Equals(CommonBase.String_NullValue)) { isNewRecord = true; }
 
      var userDoc = new UserDTO
      {
        UserId = user.UserId,
        CreatedDate = user.CreatedDate,
        UpdatedDate = user.UpdatedDate,
        Name = user.Name,
        Email = user.Email,
        Birthdate = user.Birthdate.ToLocalTime(),
        FoodRule = user.FoodRule
 
      };
 
      //Validation
      if (IsValidDateTime(userDoc.CreatedDate.ToString()) || IsValidDateTime(userDoc.UpdatedDate.ToString()))
      {
        throw new Exception("Date invalide.");
      }
 
      if (IsValidDate(userDoc.Birthdate.ToString()))
      {
        throw new Exception("La date de naissance est invalide.");
      }
 
      if (IsValidString(userDoc.UserId) || IsValidString(userDoc.Name) || IsValidString(userDoc.Email))
      {
        throw new Exception("Ces champs ne peuvent pas être vides.");
      }
 
      if (IsValidEmail(userDoc.Email) || IsDuplicateEmail(userDoc.Email))
      {
        throw new Exception("L'adresse e-mail est invalide ou elle existe déjà.");
      }  
 
      if (isNewRecord) { userDoc.Id = Guid.NewGuid(); }
 
 
      //Insertion dans MongoDB
      var client = GetMongoDBConnection();
      var collection = client.GetDatabase(Database).GetCollection<UserDTO>(Collection);
      collection.InsertOne(userDoc);
 
    }
 
    private bool IsValidDateTime(string date)
    {
      DateTime dDate;
      return DateTime.TryParseExact(date, "YYYY-mm-ddTHH:MM:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out dDate);
    }
 
    private bool IsValidDate(string date)
    {
      DateTime dDate;
      return DateTime.TryParseExact(date, "YYYY-mm-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out dDate);
    }
 
    private bool IsValidEmail(string value)
    {
      if (string.IsNullOrWhiteSpace(value))
        return false;
 
      try
      {
        // Normaliser le domaine
        value = Regex.Replace(value, @"(@)(.+)$", DomainMapper, RegexOptions.None, TimeSpan.FromMilliseconds(200));
 
        // Examine la partie domaine de l'email et le normalise.
        string DomainMapper(Match match)
        {
          // Utilise la classe IdnMapping pour convertir les caractères Unicode du nom de domaine
          var idn = new IdnMapping();
 
          // Extraire et traiter le nom de domaine (Lève un ArgumentException si invalide)
          string domainName = idn.GetAscii(match.Groups[2].Value);
 
          return match.Groups[1].Value + domainName;
        }
      }
      catch (RegexMatchTimeoutException)
      {
        return false;
      }
      catch (ArgumentException)
      {
        return false;
      }
 
      try
      {
        return Regex.IsMatch(value, @"^[^@\s]+@[^@\s]+\.[^@\s]+$", RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250));
      }
      catch (RegexMatchTimeoutException)
      {
        return false;
      }
 
    }
 
    private bool IsDuplicateEmail(string value)
    {
      UserDTO user = GetUserByEmail(value);
      if (user.Email == value)
      {
        return true;
      }
      else return false;
    }
 
  }
}
Mon interface IUserRepository :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
using Common;
 
namespace DAL
{
    public interface IUserRepository
    {
        UserDTO GetUserById(string userId);
        UserDTO GetUserByEmail(string email);
        List<UserDTO> GetAll();
        void SaveUser(ref UserDTO user);
 
    }
 
}
Et enfin ma classe UserRepository:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using System;
using Common;
using MongoDB.Driver;
 
namespace DAL
{
    public class UserRepository : IUserRepository
    {
        private readonly UserDB _userCollection;
 
        public UserRepository()
        {
            _userCollection = new UserDB();
        }
 
        public UserRepository(UserDB userCollection)
        {
            _userCollection = userCollection;
        }
 
        public List<UserDTO> GetAll()
        {
            return _userCollection.GetAll();
        }
 
        public UserDTO GetUserByEmail(string email)
        {
            return _userCollection.GetUserByEmail(email);
        }
 
        public UserDTO GetUserById(string userId)
        {
            return _userCollection.GetUserById(userId);
        }
 
        public void SaveUser(ref UserDTO user)
        {
            _userCollection.SaveUser(ref user);
        }
 
    }
}
Si j'ai bien compris mon DTO est l'objet qui va représenter mes données qui sont en DB, La DAL est ce qui va me permettre d'accèder à ces données, le Singleton est ce qui va permettre d'avoir une seule instance de connection à ma DB et enfin mon Repository qui est une couche d'abstraction pour l'accès à mes données (Sur ce point j'ai un doute sur ma compréhension).

Question 1 : Je ne sais pas si ce que j'ai fait est correct. Si quelqu'un pouvait m'éclairer svp ?
Question 2 : Je n'arrive pas à comprendre comment faire intéragir la DAL avec le Repository et le Singleton. De ma compréhension, le Repository doit appeler le Singleton quand il en as besoin et ensuite mon Repository doit intéragir avec ma DAL, via mon UserDB, qui elle-même utilise le DTO pour représenter les données qui sont en DB.

Voilà. Merci d'avance à ceux qui prendront le temps de m'aider.