helper,
ModelStateDictionary dictionary, string property, string className)
{
+ if (helper == null)
+ {
+ throw new ArgumentNullException(nameof(helper));
+ }
+
+ if (dictionary == null)
+ {
+ throw new ArgumentNullException(nameof(dictionary));
+ }
+
+ if (string.IsNullOrEmpty(property))
+ {
+ throw new ArgumentNullException(nameof(property));
+ }
+
+ if (className == null)
+ {
+ throw new ArgumentNullException(nameof(className));
+ }
+
var builder = new StringBuilder();
- if (dictionary[property] != null)
- foreach (var modelState in dictionary[property].Errors)
+ if (dictionary.TryGetValue(property, out var modelStateEntry) && modelStateEntry?.Errors != null)
+ {
+ foreach (var modelState in modelStateEntry.Errors)
+ {
builder.Append(CultureInfo.CurrentCulture, $"{modelState.ErrorMessage}
");
+ }
+ }
return new HtmlString(builder.ToString());
}
diff --git a/apps/Backoffice/Frontend/Frontend.csproj b/apps/Backoffice/Frontend/Frontend.csproj
index 9c6db90..bcbd542 100644
--- a/apps/Backoffice/Frontend/Frontend.csproj
+++ b/apps/Backoffice/Frontend/Frontend.csproj
@@ -1,21 +1,21 @@
- net6.0
+ net8.0
CodelyTv.Apps.Backoffice.Frontend
CodelyTv.Apps.Backoffice.Frontend
-
+
-
-
-
-
+
+
+
+
-
-
+
+
diff --git a/apps/Backoffice/Frontend/appsettings.json b/apps/Backoffice/Frontend/appsettings.json
index 86fa1f2..dc56e0d 100644
--- a/apps/Backoffice/Frontend/appsettings.json
+++ b/apps/Backoffice/Frontend/appsettings.json
@@ -17,8 +17,7 @@
"Hostname": "localhost",
"port": "5630"
},
- "Elasticsearch":
- {
+ "Elasticsearch": {
"Host": "http://localhost",
"Port": "9200",
"IndexPrefix": "backoffice"
diff --git a/apps/Mooc/Backend/Backend.csproj b/apps/Mooc/Backend/Backend.csproj
index 4137bab..ad2b764 100644
--- a/apps/Mooc/Backend/Backend.csproj
+++ b/apps/Mooc/Backend/Backend.csproj
@@ -1,7 +1,7 @@
- net6.0
+ net8.0
CodelyTv.Apps.Mooc.Backend
CodelyTv.Apps.Mooc.Backend
@@ -12,6 +12,6 @@
-
-
+
+
diff --git a/docker-compose.yml b/docker-compose.yml
index 31e3f8a..2c071e9 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,9 +1,7 @@
-version: '3.0'
-
services:
mssql:
container_name: codelytv-chsarp_ddd_skeleton-mssql
- image: mcr.microsoft.com/mssql/server:2019-latest
+ image: mcr.microsoft.com/mssql/server:2022-latest
user: root
ports:
- 1433:1433
@@ -17,10 +15,10 @@ services:
- ./database/backoffice.sql:/backoffice.sql
- ./database/data/data:/var/opt/mssql/data
- ./database/data/log:/var/opt/mssql/log
- - ./database/data/secrets:/var/opt/mssql/secrets
+ - ./database/data/secrets:/var/opt/mssql/secrets
rabbitmq:
container_name: codelytv-chsarp_ddd_skeleton-rabbitmq
- image: 'rabbitmq:3.7-management'
+ image: "rabbitmq:3.7-management"
restart: unless-stopped
ports:
- 5630:5672
@@ -30,7 +28,7 @@ services:
- RABBITMQ_DEFAULT_PASS=c0d3ly
elasticsearch:
container_name: codelytv-chsarp_ddd_skeleton-elasticsearch
- image: 'elasticsearch:7.9.1'
+ image: "elasticsearch:7.9.1"
restart: unless-stopped
ports:
- 9300:9300
diff --git a/src/Backoffice/Backoffice.csproj b/src/Backoffice/Backoffice.csproj
index 64a793f..35d85f7 100644
--- a/src/Backoffice/Backoffice.csproj
+++ b/src/Backoffice/Backoffice.csproj
@@ -1,7 +1,7 @@
- net6.0
+ net8.0
CodelyTv.Backoffice
CodelyTv.Backoffice
@@ -11,8 +11,8 @@
-
-
+
+
diff --git a/src/Backoffice/Courses/Application/SearchByCriteria/SearchBackofficeCoursesByCriteriaQueryHandler.cs b/src/Backoffice/Courses/Application/SearchByCriteria/SearchBackofficeCoursesByCriteriaQueryHandler.cs
index 462d3d4..20212f9 100644
--- a/src/Backoffice/Courses/Application/SearchByCriteria/SearchBackofficeCoursesByCriteriaQueryHandler.cs
+++ b/src/Backoffice/Courses/Application/SearchByCriteria/SearchBackofficeCoursesByCriteriaQueryHandler.cs
@@ -4,21 +4,24 @@
namespace CodelyTv.Backoffice.Courses.Application.SearchByCriteria
{
- public class
- SearchBackofficeCoursesByCriteriaQueryHandler : QueryHandler
+ public class SearchBackofficeCoursesByCriteriaQueryHandler : QueryHandler
{
private readonly BackofficeCoursesByCriteriaSearcher _searcher;
public SearchBackofficeCoursesByCriteriaQueryHandler(BackofficeCoursesByCriteriaSearcher searcher)
{
- _searcher = searcher;
+ _searcher = searcher ?? throw new ArgumentNullException(nameof(searcher));
}
public async Task Handle(SearchBackofficeCoursesByCriteriaQuery query)
{
- var filters = Filters.FromValues(query.Filters);
- var order = Order.FromValues(query.OrderBy, query.OrderType);
+ if (query == null)
+ {
+ throw new ArgumentNullException(nameof(query));
+ }
+
+ Filters filters = Filters.FromValues(query.Filters) ?? throw new InvalidOperationException("Filters are missing");
+ var order = Order.FromValues(query.OrderBy ?? throw new InvalidOperationException("OrderBy is missing"), query.OrderType ?? throw new InvalidOperationException("OrderType is missing"));
return await _searcher.Search(filters, order, query.Limit, query.Offset);
}
diff --git a/src/Backoffice/Courses/Domain/BackofficeCourse.cs b/src/Backoffice/Courses/Domain/BackofficeCourse.cs
index 322db05..5a620dc 100644
--- a/src/Backoffice/Courses/Domain/BackofficeCourse.cs
+++ b/src/Backoffice/Courses/Domain/BackofficeCourse.cs
@@ -11,41 +11,51 @@ public class BackofficeCourse
public BackofficeCourse(string id, string name, string duration)
{
- Id = id;
- Name = name;
- Duration = duration;
+ Id = id ?? throw new ArgumentNullException(nameof(id));
+ Name = name ?? throw new ArgumentNullException(nameof(name));
+ Duration = duration ?? throw new ArgumentNullException(nameof(duration));
}
private BackofficeCourse()
{
+ Id = string.Empty;
+ Name = string.Empty;
+ Duration = string.Empty;
}
public Dictionary ToPrimitives()
{
- var primitives = new Dictionary
+ return new Dictionary
{
- {"id", Id},
- {"name", Name},
- {"duration", Duration}
+ { "id", Id },
+ { "name", Name },
+ { "duration", Duration }
};
-
- return primitives;
}
public static BackofficeCourse FromPrimitives(Dictionary body)
{
- return new BackofficeCourse(body["id"].ToString(), body["name"].ToString(), body["duration"].ToString());
+ if (body == null)
+ {
+ throw new ArgumentNullException(nameof(body));
+ }
+
+ return new BackofficeCourse(
+ body["id"]?.ToString() ?? throw new InvalidOperationException("ID is missing"),
+ body["name"]?.ToString() ?? throw new InvalidOperationException("Name is missing"),
+ body["duration"]?.ToString() ?? throw new InvalidOperationException("Duration is missing")
+ );
}
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
if (this == obj) return true;
+ if (obj == null || GetType() != obj.GetType()) return false;
var item = obj as BackofficeCourse;
if (item == null) return false;
- return Id.Equals(item.Id) && Name.Equals(item.Name) &&
- Duration.Equals(item.Duration);
+ return Id.Equals(item.Id) && Name.Equals(item.Name) && Duration.Equals(item.Duration);
}
public override int GetHashCode()
diff --git a/src/Backoffice/Courses/Infrastructure/Persistence/Elasticsearch/BackofficeCourseElasticSearchDescriptor.cs b/src/Backoffice/Courses/Infrastructure/Persistence/Elasticsearch/BackofficeCourseElasticSearchDescriptor.cs
index 0292a7f..7f722b4 100644
--- a/src/Backoffice/Courses/Infrastructure/Persistence/Elasticsearch/BackofficeCourseElasticSearchDescriptor.cs
+++ b/src/Backoffice/Courses/Infrastructure/Persistence/Elasticsearch/BackofficeCourseElasticSearchDescriptor.cs
@@ -7,7 +7,12 @@ public static class BackofficeCourseElasticsearchDescriptor
{
public static CreateIndexDescriptor CreateBackofficeCourseDescriptor(this CreateIndexDescriptor descriptor)
{
- return descriptor?.Map(m => m.AutoMap().Properties(pr => pr
+ if (descriptor == null)
+ {
+ throw new ArgumentNullException(nameof(descriptor));
+ }
+
+ return descriptor.Map(m => m.AutoMap().Properties(pr => pr
.Keyword(i => i.Name("id"))
.Keyword(i => i.Name("name"))
));
diff --git a/src/Backoffice/Courses/Infrastructure/Persistence/Elasticsearch/ElasticsearchBackofficeCourseRepository.cs b/src/Backoffice/Courses/Infrastructure/Persistence/Elasticsearch/ElasticsearchBackofficeCourseRepository.cs
index f7cd142..2b29d27 100644
--- a/src/Backoffice/Courses/Infrastructure/Persistence/Elasticsearch/ElasticsearchBackofficeCourseRepository.cs
+++ b/src/Backoffice/Courses/Infrastructure/Persistence/Elasticsearch/ElasticsearchBackofficeCourseRepository.cs
@@ -18,19 +18,30 @@ public ElasticsearchBackofficeCourseRepository(ElasticsearchClient client) : bas
public async Task Save(BackofficeCourse course)
{
- await Persist(course.Id, JsonConvert.SerializeObject(course?.ToPrimitives()));
+ if (course == null)
+ {
+ throw new ArgumentNullException(nameof(course));
+ }
+
+ await Persist(course.Id ?? throw new InvalidOperationException("Course ID is missing"),
+ JsonConvert.SerializeObject(course.ToPrimitives() ?? throw new InvalidOperationException("Course primitives are missing")));
}
public async Task> Matching(Criteria criteria)
{
+ if (criteria == null)
+ {
+ throw new ArgumentNullException(nameof(criteria));
+ }
+
var docs = await SearchByCriteria(criteria);
- return docs?.Select(BackofficeCourse.FromPrimitives).ToList();
+ return docs?.Select(BackofficeCourse.FromPrimitives).ToList() ?? Enumerable.Empty();
}
public async Task> SearchAll()
{
var docs = await SearchAllInElastic();
- return docs?.Select(BackofficeCourse.FromPrimitives).ToList();
+ return docs?.Select(BackofficeCourse.FromPrimitives).ToList() ?? Enumerable.Empty();
}
protected override string ModuleName()
diff --git a/src/Backoffice/Shared/Infrastructure/Persistence/Elasticsearch/ElasticsearchExtension.cs b/src/Backoffice/Shared/Infrastructure/Persistence/Elasticsearch/ElasticsearchExtension.cs
index e277b09..4eb52eb 100644
--- a/src/Backoffice/Shared/Infrastructure/Persistence/Elasticsearch/ElasticsearchExtension.cs
+++ b/src/Backoffice/Shared/Infrastructure/Persistence/Elasticsearch/ElasticsearchExtension.cs
@@ -12,8 +12,18 @@ public static class ElasticsearchExtensions
{
public static void AddElasticsearch(this IServiceCollection services, IConfiguration configuration)
{
- var defaultIndex = configuration["Elasticsearch:IndexPrefix"];
- var url = $"{configuration["Elasticsearch:Host"]}:{configuration["Elasticsearch:Port"]}";
+ if (configuration == null)
+ {
+ throw new ArgumentNullException(nameof(configuration));
+ }
+
+ var defaultIndex = configuration["Elasticsearch:IndexPrefix"] ?? throw new InvalidOperationException("Elasticsearch index prefix is missing");
+
+ var host = configuration["Elasticsearch:Host"] ?? throw new InvalidOperationException("Elasticsearch host is missing");
+
+ var port = configuration["Elasticsearch:Port"] ?? throw new InvalidOperationException("Elasticsearch port is missing");
+
+ var url = $"{host}:{port}";
var settings = new ConnectionSettings(new Uri(url)).DefaultIndex(defaultIndex);
diff --git a/src/Mooc/Courses/Domain/Course.cs b/src/Mooc/Courses/Domain/Course.cs
index 79648b7..38eae8f 100644
--- a/src/Mooc/Courses/Domain/Course.cs
+++ b/src/Mooc/Courses/Domain/Course.cs
@@ -19,6 +19,9 @@ public Course(CourseId id, CourseName name, CourseDuration duration)
private Course()
{
+ Id = null!;
+ Name = null!;
+ Duration = null!;
}
public static Course Create(CourseId id, CourseName name, CourseDuration duration)
@@ -30,7 +33,7 @@ public static Course Create(CourseId id, CourseName name, CourseDuration duratio
return course;
}
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
if (this == obj) return true;
diff --git a/src/Mooc/Courses/Domain/CourseRepository.cs b/src/Mooc/Courses/Domain/CourseRepository.cs
index f1083fb..06d31bf 100644
--- a/src/Mooc/Courses/Domain/CourseRepository.cs
+++ b/src/Mooc/Courses/Domain/CourseRepository.cs
@@ -5,6 +5,6 @@ namespace CodelyTv.Mooc.Courses.Domain
public interface CourseRepository
{
Task Save(Course course);
- Task Search(CourseId id);
+ Task Search(CourseId id);
}
}
diff --git a/src/Mooc/Courses/Infrastructure/FileCourseRepository.cs b/src/Mooc/Courses/Infrastructure/FileCourseRepository.cs
index bd13ada..d987677 100644
--- a/src/Mooc/Courses/Infrastructure/FileCourseRepository.cs
+++ b/src/Mooc/Courses/Infrastructure/FileCourseRepository.cs
@@ -20,7 +20,7 @@ await Task.Run(() =>
});
}
- public async Task Search(CourseId id)
+ public async Task Search(CourseId id)
{
if (File.Exists(FileName(id.Value)))
{
diff --git a/src/Mooc/Courses/Infrastructure/Persistence/MsSqlCourseRepository.cs b/src/Mooc/Courses/Infrastructure/Persistence/MsSqlCourseRepository.cs
index b30e386..20907f6 100644
--- a/src/Mooc/Courses/Infrastructure/Persistence/MsSqlCourseRepository.cs
+++ b/src/Mooc/Courses/Infrastructure/Persistence/MsSqlCourseRepository.cs
@@ -11,17 +11,27 @@ public class MsSqlCourseRepository : CourseRepository
public MsSqlCourseRepository(MoocContext context)
{
- _context = context;
+ _context = context ?? throw new ArgumentNullException(nameof(context));
}
public async Task Save(Course course)
{
+ if (course == null)
+ {
+ throw new ArgumentNullException(nameof(course));
+ }
+
await _context.Courses.AddAsync(course);
await _context.SaveChangesAsync();
}
- public async Task Search(CourseId id)
+ public async Task Search(CourseId id)
{
+ if (id == null)
+ {
+ throw new ArgumentNullException(nameof(id));
+ }
+
return await _context.Courses.FirstOrDefaultAsync(c => c.Id.Equals(id));
}
}
diff --git a/src/Mooc/CoursesCounters/Application/Find/CoursesCounterResponse.cs b/src/Mooc/CoursesCounters/Application/Find/CoursesCounterResponse.cs
index 2acc199..c247189 100644
--- a/src/Mooc/CoursesCounters/Application/Find/CoursesCounterResponse.cs
+++ b/src/Mooc/CoursesCounters/Application/Find/CoursesCounterResponse.cs
@@ -11,7 +11,7 @@ public CoursesCounterResponse(int total)
Total = total;
}
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
if (this == obj) return true;
diff --git a/src/Mooc/CoursesCounters/Domain/CoursesCounter.cs b/src/Mooc/CoursesCounters/Domain/CoursesCounter.cs
index dd79378..b00fc85 100644
--- a/src/Mooc/CoursesCounters/Domain/CoursesCounter.cs
+++ b/src/Mooc/CoursesCounters/Domain/CoursesCounter.cs
@@ -20,6 +20,9 @@ public CoursesCounter(CoursesCounterId id, CoursesCounterTotal total, List Search();
+ Task Search();
}
}
diff --git a/src/Mooc/CoursesCounters/Infrastructure/Persistence/MsSqlCoursesCounterRepository.cs b/src/Mooc/CoursesCounters/Infrastructure/Persistence/MsSqlCoursesCounterRepository.cs
index 42b5e0b..07ece12 100644
--- a/src/Mooc/CoursesCounters/Infrastructure/Persistence/MsSqlCoursesCounterRepository.cs
+++ b/src/Mooc/CoursesCounters/Infrastructure/Persistence/MsSqlCoursesCounterRepository.cs
@@ -24,7 +24,7 @@ public async Task Save(CoursesCounter counter)
await _context.SaveChangesAsync();
}
- public async Task Search()
+ public async Task Search()
{
return await _context.CoursesCounter.SingleOrDefaultAsync();
}
diff --git a/src/Mooc/Mooc.csproj b/src/Mooc/Mooc.csproj
index e05a3df..9fbc70e 100644
--- a/src/Mooc/Mooc.csproj
+++ b/src/Mooc/Mooc.csproj
@@ -1,7 +1,7 @@
- net6.0
+ net8.0
CodelyTv.Mooc
CodelyTv.Mooc
@@ -11,13 +11,13 @@
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
diff --git a/src/Mooc/Shared/Infrastructure/Persistence/EntityFramework/EntityConfigurations/DomainEventPrimitiveConfiguration.cs b/src/Mooc/Shared/Infrastructure/Persistence/EntityFramework/EntityConfigurations/DomainEventPrimitiveConfiguration.cs
index 7e0a0d4..7c57b85 100644
--- a/src/Mooc/Shared/Infrastructure/Persistence/EntityFramework/EntityConfigurations/DomainEventPrimitiveConfiguration.cs
+++ b/src/Mooc/Shared/Infrastructure/Persistence/EntityFramework/EntityConfigurations/DomainEventPrimitiveConfiguration.cs
@@ -12,19 +12,29 @@ public class DomainEventPrimitiveConfiguration : IEntityTypeConfiguration builder)
{
+ if (builder == null)
+ {
+ throw new ArgumentNullException(nameof(builder));
+ }
+
builder.ToTable(nameof(MoocContext.DomainEvents).ToDatabaseFormat());
builder.HasKey(x => x.AggregateId);
builder.Property(x => x.Body)
- .HasConversion(v => JsonConvert.SerializeObject(v),
- v => JsonConvert.DeserializeObject>(v));
+ .HasConversion(
+ v => JsonConvert.SerializeObject(v) ?? string.Empty,
+ v => JsonConvert.DeserializeObject>(v) ?? new Dictionary()
+ );
builder.Property(x => x.AggregateId)
.HasColumnName(nameof(DomainEventPrimitive.AggregateId).ToDatabaseFormat());
builder.Property(x => x.OccurredOn)
- .HasConversion(v => Utils.StringToDate(v), v => Utils.DateToString(v))
+ .HasConversion(
+ v => Utils.StringToDate(v),
+ v => Utils.DateToString(v) ?? string.Empty
+ )
.HasColumnName(nameof(DomainEventPrimitive.OccurredOn).ToDatabaseFormat());
}
}
diff --git a/src/Mooc/Shared/Infrastructure/Persistence/EntityFramework/ValueConverter/ExistingCoursesConverter.cs b/src/Mooc/Shared/Infrastructure/Persistence/EntityFramework/ValueConverter/ExistingCoursesConverter.cs
index 71014d0..3c8d1fa 100644
--- a/src/Mooc/Shared/Infrastructure/Persistence/EntityFramework/ValueConverter/ExistingCoursesConverter.cs
+++ b/src/Mooc/Shared/Infrastructure/Persistence/EntityFramework/ValueConverter/ExistingCoursesConverter.cs
@@ -7,7 +7,7 @@ namespace CodelyTv.Mooc.Shared.Infrastructure.Persistence.EntityFramework.ValueC
{
public class ExistingCoursesConverter : ValueConverter, string>
{
- public ExistingCoursesConverter(ConverterMappingHints mappingHints = null)
+ public ExistingCoursesConverter(ConverterMappingHints? mappingHints = null)
: base(v => ConvertConfiguration.ObjectToJson(v),
v => ConvertConfiguration.ObjectFromJson(v),
mappingHints
diff --git a/src/Retention/Retention.csproj b/src/Retention/Retention.csproj
index 9357407..4c09666 100644
--- a/src/Retention/Retention.csproj
+++ b/src/Retention/Retention.csproj
@@ -1,7 +1,7 @@
- net6.0
-
+ net8.0
+
diff --git a/src/Shared/Cli/CommandBuilder.cs b/src/Shared/Cli/CommandBuilder.cs
index 551978f..32be541 100644
--- a/src/Shared/Cli/CommandBuilder.cs
+++ b/src/Shared/Cli/CommandBuilder.cs
@@ -11,7 +11,7 @@ public abstract class CommandBuilder
private readonly string[] _args;
private readonly Dictionary Commands;
- protected ServiceProvider Provider { get; set; }
+ protected ServiceProvider? Provider { get; set; }
protected CommandBuilder(string[] args, Dictionary commands)
{
@@ -24,11 +24,18 @@ protected CommandBuilder(string[] args, Dictionary commands)
public virtual void Run()
{
var command = GetCommand();
-
+ if (Provider == null) throw new SystemException("Provider is not set");
using var scope = Provider.CreateScope();
var service = scope.ServiceProvider.GetService(command);
- ((Command) service).Execute(_args);
+ if (service is Command commandService)
+ {
+ commandService.Execute(_args);
+ }
+ else
+ {
+ throw new SystemException("Command is not a valid command");
+ }
}
protected Type GetCommand()
diff --git a/src/Shared/Domain/Bus/Command/CommandHandlerWrapper.cs b/src/Shared/Domain/Bus/Command/CommandHandlerWrapper.cs
index 239371e..796bd10 100644
--- a/src/Shared/Domain/Bus/Command/CommandHandlerWrapper.cs
+++ b/src/Shared/Domain/Bus/Command/CommandHandlerWrapper.cs
@@ -11,10 +11,25 @@ internal abstract class CommandHandlerWrapper
internal class CommandHandlerWrapper : CommandHandlerWrapper
where TCommand : Command
{
- public override async Task Handle(Command domainEvent, IServiceProvider provider)
+ public override async Task Handle(Command command, IServiceProvider provider)
{
- var handler = (CommandHandler) provider.GetService(typeof(CommandHandler));
- await handler.Handle((TCommand) domainEvent);
+ if (command == null)
+ {
+ throw new ArgumentNullException(nameof(command));
+ }
+
+ if (provider == null)
+ {
+ throw new ArgumentNullException(nameof(provider));
+ }
+
+ var handler = provider.GetService(typeof(CommandHandler)) as CommandHandler;
+ if (handler == null)
+ {
+ throw new InvalidOperationException($"Handler for {typeof(TCommand).Name} not found");
+ }
+
+ await handler.Handle((TCommand)command);
}
}
}
diff --git a/src/Shared/Domain/Bus/Event/DomainEvent.cs b/src/Shared/Domain/Bus/Event/DomainEvent.cs
index 002a398..e295be4 100644
--- a/src/Shared/Domain/Bus/Event/DomainEvent.cs
+++ b/src/Shared/Domain/Bus/Event/DomainEvent.cs
@@ -10,16 +10,16 @@ public abstract class DomainEvent
public string EventId { get; }
public string OccurredOn { get; }
- protected DomainEvent(string aggregateId, string eventId, string occurredOn)
+ protected DomainEvent(string aggregateId, string? eventId, string? occurredOn)
{
AggregateId = aggregateId;
EventId = eventId ?? Uuid.Random().Value;
OccurredOn = occurredOn ?? Utils.DateToString(DateTime.Now);
}
- protected DomainEvent()
- {
- }
+ // protected DomainEvent()
+ // {
+ // }
public abstract string EventName();
public abstract Dictionary ToPrimitives();
diff --git a/src/Shared/Domain/Bus/Event/DomainEventPrimitive.cs b/src/Shared/Domain/Bus/Event/DomainEventPrimitive.cs
index e72ffde..e9b5c13 100644
--- a/src/Shared/Domain/Bus/Event/DomainEventPrimitive.cs
+++ b/src/Shared/Domain/Bus/Event/DomainEventPrimitive.cs
@@ -4,10 +4,10 @@ namespace CodelyTv.Shared.Domain.Bus.Event
{
public class DomainEventPrimitive
{
- public string Id { get; set; }
- public string AggregateId { get; set; }
- public string Name { get; set; }
- public string OccurredOn { get; set; }
- public Dictionary Body { get; set; }
+ public string Id { get; set; } = string.Empty;
+ public string AggregateId { get; set; } = string.Empty;
+ public string Name { get; set; } = string.Empty;
+ public string OccurredOn { get; set; } = string.Empty;
+ public Dictionary Body { get; set; } = new Dictionary();
}
}
diff --git a/src/Shared/Domain/Bus/Query/QueryBus.cs b/src/Shared/Domain/Bus/Query/QueryBus.cs
index d8cb4b8..8d9d3c9 100644
--- a/src/Shared/Domain/Bus/Query/QueryBus.cs
+++ b/src/Shared/Domain/Bus/Query/QueryBus.cs
@@ -4,6 +4,6 @@ namespace CodelyTv.Shared.Domain.Bus.Query
{
public interface QueryBus
{
- Task Ask(Query request);
+ Task Ask(Query request) where TResponse : class;
}
}
diff --git a/src/Shared/Domain/Bus/Query/QueryHandlerWrapper.cs b/src/Shared/Domain/Bus/Query/QueryHandlerWrapper.cs
index 6be1d2b..9d5d3f7 100644
--- a/src/Shared/Domain/Bus/Query/QueryHandlerWrapper.cs
+++ b/src/Shared/Domain/Bus/Query/QueryHandlerWrapper.cs
@@ -13,10 +13,13 @@ internal class QueryHandlerWrapper : QueryHandlerWrapper Handle(Query query, IServiceProvider provider)
{
- var handler =
- (QueryHandler) provider.GetService(typeof(QueryHandler));
+ var service = provider.GetService(typeof(QueryHandler));
+ if (!(service is QueryHandler handler))
+ {
+ throw new SystemException("Query is not a valid query");
+ }
- return await handler.Handle((TQuery) query);
+ return await handler.Handle((TQuery)query);
}
}
}
diff --git a/src/Shared/Domain/Courses/Domain/CourseCreatedDomainEvent.cs b/src/Shared/Domain/Courses/Domain/CourseCreatedDomainEvent.cs
index 24d8e1e..d9e80ed 100644
--- a/src/Shared/Domain/Courses/Domain/CourseCreatedDomainEvent.cs
+++ b/src/Shared/Domain/Courses/Domain/CourseCreatedDomainEvent.cs
@@ -9,15 +9,17 @@ public class CourseCreatedDomainEvent : DomainEvent
public string Name { get; }
public string Duration { get; }
- public CourseCreatedDomainEvent(string id, string name, string duration, string eventId = null,
- string occurredOn = null) : base(id, eventId, occurredOn)
+ public CourseCreatedDomainEvent(string id, string name, string duration, string? eventId = null,
+ string? occurredOn = null) : base(id, eventId, occurredOn)
{
Name = name;
Duration = duration;
}
- public CourseCreatedDomainEvent()
+ public CourseCreatedDomainEvent() : base(string.Empty, null, null)
{
+ Name = string.Empty;
+ Duration = string.Empty;
}
public override string EventName()
@@ -40,7 +42,7 @@ public override DomainEvent FromPrimitives(string aggregateId, Dictionary filters)
Values = filters;
}
- public static Filters FromValues(List> filters)
+ public static Filters? FromValues(List> filters)
{
if (filters == null) return null;
diff --git a/src/Shared/Domain/ReflectionHelper.cs b/src/Shared/Domain/ReflectionHelper.cs
index 8d83f40..7849ea6 100644
--- a/src/Shared/Domain/ReflectionHelper.cs
+++ b/src/Shared/Domain/ReflectionHelper.cs
@@ -7,17 +7,17 @@ namespace CodelyTv.Shared.Domain
{
public static class ReflectionHelper
{
- public static Assembly GetAssemblyByName(string name)
+ public static Assembly? GetAssemblyByName(string name)
{
if (name == null) return null;
name = name.ToUpper(CultureInfo.InvariantCulture);
return AppDomain.CurrentDomain.GetAssemblies()
- .FirstOrDefault(x => x.FullName.ToUpper(CultureInfo.InvariantCulture)
- .Contains(name, StringComparison.InvariantCulture));
+ .FirstOrDefault(x => x.FullName?.ToUpper(CultureInfo.InvariantCulture)
+ .Contains(name, StringComparison.InvariantCulture) ?? false);
}
- public static Type GetType(string name)
+ public static Type? GetType(string name)
{
if (string.IsNullOrEmpty(name)) return null;
@@ -25,16 +25,21 @@ public static Type GetType(string name)
.FirstOrDefault(type => type.Name.Equals(name, StringComparison.InvariantCulture));
}
- public static Type GetType(string assemblyName, string name)
+ public static Type? GetType(string assemblyName, string name)
{
if (string.IsNullOrEmpty(assemblyName) && string.IsNullOrEmpty(name)) return null;
var assembly = GetAssemblyByName(assemblyName);
+ if (assembly == null)
+ {
+ throw new ArgumentException("Assembly not found", nameof(assemblyName));
+ }
+
return GetType(assembly, name);
}
- public static Type GetType(Assembly assembly, string name)
+ public static Type? GetType(Assembly assembly, string name)
{
if (assembly == null) return null;
diff --git a/src/Shared/Domain/ValueObject/IntValueObject.cs b/src/Shared/Domain/ValueObject/IntValueObject.cs
index 85a36f7..92a0075 100644
--- a/src/Shared/Domain/ValueObject/IntValueObject.cs
+++ b/src/Shared/Domain/ValueObject/IntValueObject.cs
@@ -23,7 +23,7 @@ protected override IEnumerable
diff --git a/test/src/Backoffice/Backoffice.csproj b/test/src/Backoffice/Backoffice.csproj
index 02aabb4..bf60447 100644
--- a/test/src/Backoffice/Backoffice.csproj
+++ b/test/src/Backoffice/Backoffice.csproj
@@ -1,7 +1,7 @@
- net6.0
+ net8.0
false
CodelyTv.Test.Backoffice
CodelyTv.Test.Backoffice
@@ -9,13 +9,13 @@
-
-
-
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/test/src/Mooc/CoursesCounters/CoursesCounterModuleUnitTestCase.cs b/test/src/Mooc/CoursesCounters/CoursesCounterModuleUnitTestCase.cs
index fff0eec..6770422 100644
--- a/test/src/Mooc/CoursesCounters/CoursesCounterModuleUnitTestCase.cs
+++ b/test/src/Mooc/CoursesCounters/CoursesCounterModuleUnitTestCase.cs
@@ -25,7 +25,7 @@ protected void ShouldSearch(CoursesCounter counter)
protected void ShouldSearch()
{
- Repository.Setup(x => x.Search()).ReturnsAsync((CoursesCounter) null);
+ Repository.Setup(x => x.Search()).ReturnsAsync((CoursesCounter?)null);
}
}
}
diff --git a/test/src/Mooc/Mooc.csproj b/test/src/Mooc/Mooc.csproj
index face3ab..671a2e7 100644
--- a/test/src/Mooc/Mooc.csproj
+++ b/test/src/Mooc/Mooc.csproj
@@ -1,7 +1,7 @@
- net6.0
+ net8.0
false
CodelyTv.Test.Mooc
CodelyTv.Test.Mooc
@@ -9,16 +9,16 @@
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
-
+
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/test/src/Mooc/MoocContextApplicationTestCase.cs b/test/src/Mooc/MoocContextApplicationTestCase.cs
index 57d9d38..b1f22b5 100644
--- a/test/src/Mooc/MoocContextApplicationTestCase.cs
+++ b/test/src/Mooc/MoocContextApplicationTestCase.cs
@@ -1,3 +1,5 @@
+#nullable enable
+
using System;
using System.Collections.Generic;
using System.Net.Http;
@@ -14,11 +16,11 @@ namespace CodelyTv.Test.Mooc
public class MoocContextApplicationTestCase : IClassFixture>
{
private readonly MoocWebApplicationFactory _factory;
- private HttpClient _client;
+ private HttpClient? _client;
public MoocContextApplicationTestCase(MoocWebApplicationFactory factory)
{
- _factory = factory;
+ _factory = factory ?? throw new ArgumentNullException(nameof(factory));
}
protected void CreateAnonymousClient()
@@ -29,6 +31,11 @@ protected void CreateAnonymousClient()
protected async Task AssertRequestWithBody(HttpMethod method, string endpoint, string body,
int expectedStatusCode)
{
+ if (_client == null)
+ {
+ throw new InvalidOperationException("HttpClient is not initialized. Call CreateAnonymousClient() first.");
+ }
+
using (var request = new HttpRequestMessage
{
Method = method,
@@ -38,13 +45,18 @@ protected async Task AssertRequestWithBody(HttpMethod method, string endpoint, s
{
var response = await _client.SendAsync(request);
- Assert.Equal(expectedStatusCode, (int) response.StatusCode);
+ Assert.Equal(expectedStatusCode, (int)response.StatusCode);
}
}
protected async Task AssertResponse(HttpMethod method, string endpoint, int expectedStatusCode,
string expectedResponse)
{
+ if (_client == null)
+ {
+ throw new InvalidOperationException("HttpClient is not initialized. Call CreateAnonymousClient() first.");
+ }
+
using (var request = new HttpRequestMessage
{
Method = method,
@@ -52,14 +64,19 @@ protected async Task AssertResponse(HttpMethod method, string endpoint, int expe
})
{
var response = await _client.SendAsync(request);
- var result = response.Content.ReadAsStringAsync().Result;
- Assert.Equal(expectedStatusCode, (int) response.StatusCode);
+ var result = await response.Content.ReadAsStringAsync();
+ Assert.Equal(expectedStatusCode, (int)response.StatusCode);
Assert.Equal(expectedResponse, result);
}
}
protected async Task GivenISendEventsToTheBus(List domainEvents)
{
+ if (domainEvents == null)
+ {
+ throw new ArgumentNullException(nameof(domainEvents));
+ }
+
using (var scope = _factory.Server.Host.Services.CreateScope())
{
var eventBus = scope.ServiceProvider.GetRequiredService();
diff --git a/test/src/Mooc/MoocWebApplicationFactory.cs b/test/src/Mooc/MoocWebApplicationFactory.cs
index 4bf400e..04ef193 100644
--- a/test/src/Mooc/MoocWebApplicationFactory.cs
+++ b/test/src/Mooc/MoocWebApplicationFactory.cs
@@ -13,6 +13,11 @@ public class MoocWebApplicationFactory : ApplicationTestCase
{
private string _databaseName;
+ public MoocWebApplicationFactory()
+ {
+ _databaseName = Guid.NewGuid().ToString();
+ }
+
public HttpClient GetAnonymousClient()
{
SetDatabaseName();
@@ -33,7 +38,7 @@ protected override Action Services()
.AddEntityFrameworkInMemoryDatabase()
.BuildServiceProvider();
- // Add a database context using an in-memory
+ // Add a database context using an in-memory
// database for testing.
services.AddDbContext(options =>
{
diff --git a/test/src/Mooc/Shared/Infrastructure/Bus/Event/RabbitMq/RabbitMqEventBusShould.cs b/test/src/Mooc/Shared/Infrastructure/Bus/Event/RabbitMq/RabbitMqEventBusShould.cs
index c608496..c19ddca 100644
--- a/test/src/Mooc/Shared/Infrastructure/Bus/Event/RabbitMq/RabbitMqEventBusShould.cs
+++ b/test/src/Mooc/Shared/Infrastructure/Bus/Event/RabbitMq/RabbitMqEventBusShould.cs
@@ -42,7 +42,7 @@ public async Task PublishDomainEventFromRabbitMq()
{
var domainEvent = CourseCreatedDomainEventMother.Random();
- await _bus.Publish(new List {domainEvent});
+ await _bus.Publish(new List { domainEvent });
await _consumer.Consume();
@@ -64,18 +64,50 @@ private static DomainEventSubscribersInformation FakeSubscriber()
});
}
- private static void CreateQueue(IModel channel,
- DomainEventSubscribersInformation domainEventSubscribersInformation)
+ private static void CreateQueue(IModel channel, DomainEventSubscribersInformation domainEventSubscribersInformation)
{
+ if (channel == null)
+ {
+ throw new ArgumentNullException(nameof(channel));
+ }
+
+ if (domainEventSubscribersInformation == null)
+ {
+ throw new ArgumentNullException(nameof(domainEventSubscribersInformation));
+ }
+
foreach (var subscriberInformation in domainEventSubscribersInformation.All())
{
+ if (subscriberInformation == null)
+ {
+ continue;
+ }
+
var domainEventsQueueName = RabbitMqQueueNameFormatter.Format(subscriberInformation);
var queue = channel.QueueDeclare(domainEventsQueueName,
- true,
- false,
- false);
- dynamic domainEvent = Activator.CreateInstance(subscriberInformation.SubscribedEvent);
- channel.QueueBind(queue, TestDomainEvents, (string) domainEvent.EventName());
+ durable: true,
+ exclusive: false,
+ autoDelete: false);
+
+ var domainEvent = Activator.CreateInstance(subscriberInformation.SubscribedEvent);
+ if (domainEvent == null)
+ {
+ throw new InvalidOperationException($"Unable to create instance of {subscriberInformation.SubscribedEvent.FullName}");
+ }
+
+ var eventNameMethod = domainEvent.GetType().GetMethod("EventName");
+ if (eventNameMethod == null)
+ {
+ throw new InvalidOperationException("The 'EventName' method is not found in the subscribed event.");
+ }
+
+ var eventName = eventNameMethod.Invoke(domainEvent, null) as string;
+ if (eventName == null)
+ {
+ throw new InvalidOperationException("The 'EventName' method returned null or is not a string.");
+ }
+
+ channel.QueueBind(queue.QueueName, TestDomainEvents, eventName);
}
}
diff --git a/test/src/Shared/Domain/Criterias/FilterOperatorMother.cs b/test/src/Shared/Domain/Criterias/FilterOperatorMother.cs
index 7f38cea..51f48b9 100644
--- a/test/src/Shared/Domain/Criterias/FilterOperatorMother.cs
+++ b/test/src/Shared/Domain/Criterias/FilterOperatorMother.cs
@@ -8,8 +8,13 @@ public static class FilterOperatorMother
public static FilterOperator Random()
{
Array values = Enum.GetValues(typeof(FilterOperator));
+ if (values.Length == 0)
+ {
+ throw new InvalidOperationException("The FilterOperator enum does not contain any values.");
+ }
+
Random random = new Random();
- return (FilterOperator)values.GetValue(random.Next(values.Length));
+ return (FilterOperator)(values.GetValue(random.Next(values.Length)) ?? throw new InvalidOperationException("Unable to get a random value from the FilterOperator enum."));
}
}
}
diff --git a/test/src/Shared/Domain/Criterias/OrderByMother.cs b/test/src/Shared/Domain/Criterias/OrderByMother.cs
index f69046a..4133c50 100644
--- a/test/src/Shared/Domain/Criterias/OrderByMother.cs
+++ b/test/src/Shared/Domain/Criterias/OrderByMother.cs
@@ -4,7 +4,7 @@ namespace CodelyTv.Test.Shared.Domain.Criterias
{
public static class OrderByMother
{
- public static OrderBy Create(string fieldName = null)
+ public static OrderBy Create(string? fieldName = null)
{
return new OrderBy(fieldName ?? WordMother.Random());
}
diff --git a/test/src/Shared/Domain/Criterias/OrderTypeMother.cs b/test/src/Shared/Domain/Criterias/OrderTypeMother.cs
index 0affc66..8584496 100644
--- a/test/src/Shared/Domain/Criterias/OrderTypeMother.cs
+++ b/test/src/Shared/Domain/Criterias/OrderTypeMother.cs
@@ -8,8 +8,13 @@ public static class OrderTypeMother
public static OrderType Random()
{
Array values = Enum.GetValues(typeof(OrderType));
+ if (values.Length == 0)
+ {
+ throw new InvalidOperationException("The OrderType enum does not contain any values.");
+ }
+
Random random = new Random();
- return (OrderType)values.GetValue(random.Next(values.Length));
+ return (OrderType)(values.GetValue(random.Next(values.Length)) ?? throw new InvalidOperationException("Unable to get a random value from the OrderType enum."));
}
}
}
diff --git a/test/src/Shared/Infrastructure/ApplicationTestCase.cs b/test/src/Shared/Infrastructure/ApplicationTestCase.cs
index 9f52f1b..b3193d3 100644
--- a/test/src/Shared/Infrastructure/ApplicationTestCase.cs
+++ b/test/src/Shared/Infrastructure/ApplicationTestCase.cs
@@ -12,6 +12,6 @@ protected override void ConfigureWebHost(IWebHostBuilder builder)
builder.ConfigureServices(Services());
}
- protected abstract Action Services();
+ protected new abstract Action Services();
}
}
diff --git a/test/src/Shared/Infrastructure/InfrastructureTestCase.cs b/test/src/Shared/Infrastructure/InfrastructureTestCase.cs
index fd03cc3..92ea309 100644
--- a/test/src/Shared/Infrastructure/InfrastructureTestCase.cs
+++ b/test/src/Shared/Infrastructure/InfrastructureTestCase.cs
@@ -55,7 +55,13 @@ private static IConfigurationRoot Configuration()
protected T GetService()
{
- return _host.Services.GetService();
+ var service = _host.Services.GetService();
+ if (service == null)
+ {
+ throw new Exception($"Service of type {typeof(T)} not found.");
+ }
+
+ return service;
}
protected abstract Action Services();
diff --git a/test/src/Shared/Shared.csproj b/test/src/Shared/Shared.csproj
index b31b1c3..b308bae 100644
--- a/test/src/Shared/Shared.csproj
+++ b/test/src/Shared/Shared.csproj
@@ -1,7 +1,7 @@
- net6.0
+ net8.0
false
CodelyTv.Test.Shared
CodelyTv.Test.Shared
@@ -13,16 +13,16 @@
-
-
-
-
-
+
+
+
+
+
-
+