Add project files.
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
namespace VizhTalk.BuildingBlocks.Domain.Contract;
|
||||
|
||||
public abstract record CommandBase<T> : ICommand<T>
|
||||
{
|
||||
public Guid Id { get; private set; }
|
||||
protected CommandBase()
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
}
|
||||
protected CommandBase(Guid id)
|
||||
{
|
||||
Id = id;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract record CommandBase : ICommand
|
||||
{
|
||||
public Guid Id { get; private set; }
|
||||
protected CommandBase()
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
}
|
||||
protected CommandBase(Guid id)
|
||||
{
|
||||
Id = id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace VizhTalk.BuildingBlocks.Domain.Contract;
|
||||
|
||||
public interface ICommand<out TResult>
|
||||
{
|
||||
Guid Id { get; }
|
||||
}
|
||||
|
||||
public interface ICommand
|
||||
{
|
||||
Guid Id { get; }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Domain.Contract
|
||||
{
|
||||
public interface IGuardException
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace VizhTalk.BuildingBlocks.Domain.Contract;
|
||||
|
||||
public interface INotification
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace VizhTalk.BuildingBlocks.Domain.Contract;
|
||||
|
||||
public interface IQuery<out TResult>
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace VizhTalk.BuildingBlocks.Domain;
|
||||
|
||||
public class DomainEventBase : IDomainEvent
|
||||
{
|
||||
public Guid Id { get; }
|
||||
|
||||
public DateTime OccurredOn { get; }
|
||||
|
||||
public DomainEventBase()
|
||||
{
|
||||
this.Id = Guid.NewGuid();
|
||||
this.OccurredOn = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
|
||||
using VizhTalk.BuildingBlocks.Domain.Exceptions;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Domain;
|
||||
|
||||
public abstract class Entity<T>
|
||||
where T : ITypeIdValueBase
|
||||
{
|
||||
public Entity()
|
||||
{
|
||||
IsDeleted = false;
|
||||
IsActive = true;
|
||||
}
|
||||
public T Id { get; protected set; }
|
||||
public bool IsDeleted { get; protected set; }
|
||||
public bool IsActive { get; protected set; }
|
||||
|
||||
private List<IDomainEvent> _domainEvents;
|
||||
|
||||
public void ClearDomainEvents()
|
||||
{
|
||||
_domainEvents?.Clear();
|
||||
}
|
||||
|
||||
protected void AddDomainEvent(IDomainEvent domainEvent)
|
||||
{
|
||||
_domainEvents ??= [];
|
||||
|
||||
this._domainEvents.Add(domainEvent);
|
||||
}
|
||||
public IReadOnlyList<IDomainEvent> DomainEvents => _domainEvents;
|
||||
protected void CheckRule(IBusinessRule rule)
|
||||
{
|
||||
if (rule.IsBroken())
|
||||
{
|
||||
throw new BusinessRuleValidationException(rule);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
namespace VizhTalk.BuildingBlocks.Domain.Exceptions;
|
||||
|
||||
public class BusinessRuleValidationException : Exception
|
||||
{
|
||||
public IBusinessRule BrokenRule { get; }
|
||||
|
||||
public string Details { get; }
|
||||
|
||||
public BusinessRuleValidationException(IBusinessRule brokenRule)
|
||||
: base(brokenRule.Message)
|
||||
{
|
||||
BrokenRule = brokenRule;
|
||||
this.Details = brokenRule.Message;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{BrokenRule.GetType().FullName}: {BrokenRule.Message}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VizhTalk.BuildingBlocks.Domain.Contract;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Domain.Exceptions.GuardExceptions;
|
||||
|
||||
public class NullOrEmptyException(string message) : Exception(message), IGuardException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace VizhTalk.BuildingBlocks.Domain.Exceptions;
|
||||
|
||||
public interface IBusinessRule
|
||||
{
|
||||
bool IsBroken();
|
||||
|
||||
string Message { get; }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace VizhTalk.BuildingBlocks.Domain.Exceptions;
|
||||
|
||||
public class ValueObjectValidationException : Exception
|
||||
{
|
||||
public ValueObjectValidationException(string message)
|
||||
:base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace VizhTalk.BuildingBlocks.Domain.Guards
|
||||
{
|
||||
public static class Guard
|
||||
{
|
||||
public static void NullOrEmpty(this string value, string name)
|
||||
=> StringGuard.NullOrEmpty(value, name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using VizhTalk.BuildingBlocks.Domain.Exceptions.GuardExceptions;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Domain.Guards;
|
||||
|
||||
internal static class StringGuard
|
||||
{
|
||||
internal static void NullOrEmpty(string value,string name)
|
||||
{
|
||||
if(string.IsNullOrEmpty(value))
|
||||
throw new NullOrEmptyException($"{name} cannot be empty");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Domain;
|
||||
|
||||
public interface IAggregateRoot
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
using VizhTalk.BuildingBlocks.Domain.Contract;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Domain
|
||||
{
|
||||
public interface IDomainEvent : INotification
|
||||
{
|
||||
Guid Id { get; }
|
||||
|
||||
DateTime OccurredOn { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace VizhTalk.BuildingBlocks.Domain;
|
||||
|
||||
public interface IRepositoryBase<TDomain, TId>
|
||||
where TDomain : Entity<TId> where TId : ITypeIdValueBase
|
||||
{
|
||||
Task<TDomain> CreateAsync(TDomain entity, CancellationToken cancellationToken = default);
|
||||
Task<TDomain> UpdateAsync(TDomain entity, CancellationToken cancellationToken = default);
|
||||
Task DeleteAsync(TId id, CancellationToken cancellationToken = default);
|
||||
Task<TDomain> GetByIdAsync(TId id, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace VizhTalk.BuildingBlocks.Domain;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
|
||||
public class IgnoreMemberAttribute : Attribute
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
namespace VizhTalk.BuildingBlocks.Domain;
|
||||
|
||||
public abstract class TypedIdValueBase<T> : IEquatable<TypedIdValueBase<T>> , ITypeIdValueBase
|
||||
{
|
||||
public T Value { get; }
|
||||
|
||||
protected TypedIdValueBase(T value)
|
||||
{
|
||||
|
||||
if (EqualityComparer<T>.Default.Equals(value, default(T)))
|
||||
{
|
||||
throw new InvalidOperationException($"Id value cannot be empty ! : id is {value}");
|
||||
}
|
||||
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return obj is TypedIdValueBase<T> other && Equals(other);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Value!.GetHashCode();
|
||||
}
|
||||
|
||||
public bool Equals(TypedIdValueBase<T>? other)
|
||||
{
|
||||
return EqualityComparer<T>.Default.Equals(this.Value, other.Value);
|
||||
}
|
||||
|
||||
public static bool operator ==(TypedIdValueBase<T>? obj1, TypedIdValueBase<T>? obj2)
|
||||
{
|
||||
if (object.Equals(obj1, null))
|
||||
{
|
||||
if (object.Equals(obj2, null))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return obj1.Equals(obj2);
|
||||
}
|
||||
|
||||
public static bool operator !=(TypedIdValueBase<T>? x, TypedIdValueBase<T>? y)
|
||||
{
|
||||
return !(x == y);
|
||||
}
|
||||
}
|
||||
public interface ITypeIdValueBase { }
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
|
||||
|
||||
using System.Reflection;
|
||||
using VizhTalk.BuildingBlocks.Domain.Exceptions;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Domain;
|
||||
|
||||
public abstract class ValueObject : IEquatable<ValueObject>
|
||||
{
|
||||
private List<PropertyInfo> _properties;
|
||||
|
||||
private List<FieldInfo> _fields;
|
||||
|
||||
public static bool operator ==(ValueObject? obj1, ValueObject? obj2)
|
||||
{
|
||||
if (object.Equals(obj1, null))
|
||||
{
|
||||
if (object.Equals(obj2, null))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return obj1.Equals(obj2);
|
||||
}
|
||||
|
||||
public static bool operator !=(ValueObject? obj1, ValueObject? obj2)
|
||||
{
|
||||
return !(obj1 == obj2);
|
||||
}
|
||||
|
||||
public bool Equals(ValueObject? obj)
|
||||
{
|
||||
return Equals(obj as object);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj == null || GetType() != obj.GetType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return GetProperties().All(p => PropertiesAreEqual(obj, p))
|
||||
&& GetFields().All(f => FieldsAreEqual(obj, f));
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int hash = 17;
|
||||
foreach (var prop in GetProperties())
|
||||
{
|
||||
var value = prop.GetValue(this, null);
|
||||
hash = HashValue(hash, value);
|
||||
}
|
||||
|
||||
foreach (var field in GetFields())
|
||||
{
|
||||
var value = field.GetValue(this);
|
||||
hash = HashValue(hash, value);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
protected static void CheckRule(IBusinessRule rule)
|
||||
{
|
||||
if (rule.IsBroken())
|
||||
{
|
||||
throw new BusinessRuleValidationException(rule);
|
||||
}
|
||||
}
|
||||
|
||||
private bool PropertiesAreEqual(object obj, PropertyInfo p)
|
||||
{
|
||||
return object.Equals(p.GetValue(this, null), p.GetValue(obj, null));
|
||||
}
|
||||
|
||||
private bool FieldsAreEqual(object obj, FieldInfo f)
|
||||
{
|
||||
return object.Equals(f.GetValue(this), f.GetValue(obj));
|
||||
}
|
||||
|
||||
private IEnumerable<PropertyInfo> GetProperties()
|
||||
{
|
||||
if (this._properties == null)
|
||||
{
|
||||
this._properties = GetType()
|
||||
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
||||
.Where(p => p.GetCustomAttribute(typeof(IgnoreMemberAttribute)) == null)
|
||||
.ToList();
|
||||
|
||||
// Not available in Core
|
||||
// !Attribute.IsDefined(p, typeof(IgnoreMemberAttribute))).ToList();
|
||||
}
|
||||
|
||||
return this._properties;
|
||||
}
|
||||
|
||||
private IEnumerable<FieldInfo> GetFields()
|
||||
{
|
||||
if (this._fields == null)
|
||||
{
|
||||
this._fields = GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Where(p => p.GetCustomAttribute(typeof(IgnoreMemberAttribute)) == null)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
return this._fields;
|
||||
}
|
||||
|
||||
private int HashValue(int seed, object value)
|
||||
{
|
||||
var currentHash = value?.GetHashCode() ?? 0;
|
||||
|
||||
return (seed * 23) + currentHash;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user