Add project files.
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
using VizhTalk.BuildingBlocks.Application.Contract;
|
||||
using VizhTalk.BuildingBlocks.Domain.Contract;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Application.Configuration.Commnad;
|
||||
|
||||
public interface ICommandHandler<in TCommand>
|
||||
where TCommand : ICommand
|
||||
{
|
||||
Task Handle(TCommand request, CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
public interface ICommandHandler<in TCommand, TResult>
|
||||
where TCommand : ICommand<TResult>
|
||||
{
|
||||
Task<TResult> Handle(TCommand request, CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using VizhTalk.BuildingBlocks.Domain.Contract;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Application.Contract;
|
||||
|
||||
public interface INotificationHandler<T>
|
||||
where T : INotification
|
||||
{
|
||||
Task Handle(T notification, CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using VizhTalk.BuildingBlocks.Application.Contract;
|
||||
using VizhTalk.BuildingBlocks.Domain.Contract;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Application.Configuration.Query;
|
||||
|
||||
public interface IQueryHandler<in TQuery, TResult>
|
||||
where TQuery : IQuery<TResult>
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Application.Contract;
|
||||
|
||||
public interface IExecutionContextAccessor
|
||||
{
|
||||
Guid UserId { get; }
|
||||
|
||||
Guid CorrelationId { get; }
|
||||
|
||||
bool IsAvailable { get; }
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using VizhTalk.BuildingBlocks.Domain;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Application.Events;
|
||||
|
||||
public class DomainNotificationBase<T> : IDomainEventNotification<T>
|
||||
where T : IDomainEvent
|
||||
{
|
||||
public T DomainEvent { get; }
|
||||
|
||||
public Guid Id { get; }
|
||||
|
||||
public DomainNotificationBase(T domainEvent, Guid id)
|
||||
{
|
||||
this.Id = id;
|
||||
this.DomainEvent = domainEvent;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using VizhTalk.BuildingBlocks.Application.Contract;
|
||||
using VizhTalk.BuildingBlocks.Domain.Contract;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Application.Events;
|
||||
|
||||
public interface IDomainEventNotification<out TEventType> : IDomainEventNotification
|
||||
{
|
||||
TEventType DomainEvent { get; }
|
||||
}
|
||||
|
||||
public interface IDomainEventNotification : INotification
|
||||
{
|
||||
Guid Id { get; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace VizhTalk.BuildingBlocks.Application.Outbox;
|
||||
|
||||
public interface IOutbox
|
||||
{
|
||||
void Add(OutboxMessage message);
|
||||
|
||||
Task Save();
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace VizhTalk.BuildingBlocks.Application.Outbox;
|
||||
|
||||
public class OutboxMessage
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public DateTime OccurredOn { get; set; }
|
||||
|
||||
public string Type { get; set; }
|
||||
|
||||
public string Data { get; set; }
|
||||
|
||||
public DateTime? ProcessedDate { get; set; }
|
||||
|
||||
public OutboxMessage(Guid id, DateTime occurredOn, string type, string data)
|
||||
{
|
||||
this.Id = id;
|
||||
this.OccurredOn = occurredOn;
|
||||
this.Type = type;
|
||||
this.Data = data;
|
||||
}
|
||||
|
||||
private OutboxMessage()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\VizhTalk.BuildingBlocks.Domain\VizhTalk.BuildingBlocks.Domain.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Data\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -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>
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace VizhTalk.BuildingBlocks.Infrastructure;
|
||||
|
||||
public class BiDictionary<TFirst, TSecond>
|
||||
{
|
||||
private readonly IDictionary<TFirst, TSecond> _firstToSecond = new Dictionary<TFirst, TSecond>();
|
||||
|
||||
private readonly IDictionary<TSecond, TFirst> _secondToFirst = new Dictionary<TSecond, TFirst>();
|
||||
|
||||
public void Add(TFirst first, TSecond second)
|
||||
{
|
||||
if (_firstToSecond.ContainsKey(first) ||
|
||||
_secondToFirst.ContainsKey(second))
|
||||
{
|
||||
throw new ArgumentException("Duplicate first or second");
|
||||
}
|
||||
|
||||
_firstToSecond.Add(first, second);
|
||||
_secondToFirst.Add(second, first);
|
||||
}
|
||||
|
||||
public bool TryGetByFirst(TFirst first, out TSecond second)
|
||||
{
|
||||
return _firstToSecond.TryGetValue(first, out second);
|
||||
}
|
||||
|
||||
public bool TryGetBySecond(TSecond second, out TFirst first)
|
||||
{
|
||||
return _secondToFirst.TryGetValue(second, out first);
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using VizhTalk.BuildingBlocks.Domain;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Infrastructure.DomainEventsDispatching;
|
||||
|
||||
public class DomainEventsAccessor : IDomainEventsAccessor
|
||||
{
|
||||
private readonly DbContext _dbContext;
|
||||
|
||||
public DomainEventsAccessor(DbContext dbContext)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
public IReadOnlyCollection<IDomainEvent> GetAllDomainEvents()
|
||||
{
|
||||
var domainEntities = this._dbContext.ChangeTracker
|
||||
.Entries<Entity<ITypeIdValueBase>>()
|
||||
.Where(x => x.Entity.DomainEvents != null && x.Entity.DomainEvents.Any()).ToList();
|
||||
|
||||
return domainEntities
|
||||
.SelectMany(x => x.Entity.DomainEvents)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public void ClearAllDomainEvents()
|
||||
{
|
||||
var domainEntities = this._dbContext.ChangeTracker
|
||||
.Entries<Entity<ITypeIdValueBase>>()
|
||||
.Where(x => x.Entity.DomainEvents != null && x.Entity.DomainEvents.Any()).ToList();
|
||||
|
||||
domainEntities
|
||||
.ForEach(entity => entity.Entity.ClearDomainEvents());
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Newtonsoft.Json;
|
||||
using VizhTalk.BuildingBlocks.Application.Events;
|
||||
using VizhTalk.BuildingBlocks.Application.Outbox;
|
||||
using VizhTalk.BuildingBlocks.Domain;
|
||||
using VizhTalk.BuildingBlocks.Infrastructure.Serialization;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Infrastructure.DomainEventsDispatching;
|
||||
|
||||
public class DomainEventsDispatcher : IDomainEventsDispatcher
|
||||
{
|
||||
private readonly IExecutor _executor;
|
||||
|
||||
private readonly IServiceProvider _provider;
|
||||
|
||||
private readonly IOutbox _outbox;
|
||||
|
||||
private readonly IDomainEventsAccessor _domainEventsProvider;
|
||||
|
||||
private readonly IDomainNotificationsMapper _domainNotificationsMapper;
|
||||
|
||||
public DomainEventsDispatcher(
|
||||
IExecutor executor,
|
||||
IServiceProvider provider,
|
||||
IOutbox outbox,
|
||||
IDomainEventsAccessor domainEventsProvider,
|
||||
IDomainNotificationsMapper domainNotificationsMapper)
|
||||
{
|
||||
_executor = executor;
|
||||
_provider = provider;
|
||||
_outbox = outbox;
|
||||
_domainEventsProvider = domainEventsProvider;
|
||||
_domainNotificationsMapper = domainNotificationsMapper;
|
||||
}
|
||||
|
||||
public async Task DispatchEventsAsync()
|
||||
{
|
||||
var domainEvents = _domainEventsProvider.GetAllDomainEvents();
|
||||
|
||||
List<IDomainEventNotification<IDomainEvent>> domainEventNotifications = [];
|
||||
foreach (var domainEvent in domainEvents)
|
||||
{
|
||||
Type domainEvenNotificationType = typeof(IDomainEventNotification<>);
|
||||
var domainNotificationWithGenericType = domainEvenNotificationType.MakeGenericType(domainEvent.GetType());
|
||||
var domainNotification = _provider.GetServices(domainNotificationWithGenericType);
|
||||
|
||||
if (domainNotification != null)
|
||||
{
|
||||
domainEventNotifications.Add(domainNotification as IDomainEventNotification<IDomainEvent>);
|
||||
}
|
||||
}
|
||||
|
||||
_domainEventsProvider.ClearAllDomainEvents();
|
||||
|
||||
foreach (var domainEvent in domainEvents)
|
||||
{
|
||||
await _executor.Execute(domainEvent);
|
||||
}
|
||||
|
||||
foreach (var domainEventNotification in domainEventNotifications)
|
||||
{
|
||||
var type = _domainNotificationsMapper.GetName(domainEventNotification.GetType());
|
||||
var data = JsonConvert.SerializeObject(domainEventNotification, new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = new AllPropertiesContractResolver()
|
||||
});
|
||||
|
||||
var outboxMessage = new OutboxMessage(
|
||||
domainEventNotification.Id,
|
||||
domainEventNotification.DomainEvent.OccurredOn,
|
||||
type,
|
||||
data);
|
||||
|
||||
_outbox.Add(outboxMessage);
|
||||
}
|
||||
await _outbox.Save();
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
|
||||
using VizhTalk.BuildingBlocks.Application.Contract;
|
||||
using VizhTalk.BuildingBlocks.Domain.Contract;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Infrastructure.DomainEventsDispatching;
|
||||
|
||||
public class DomainEventsDispatcherNotificationHandlerDecorator<T> : INotificationHandler<T>
|
||||
where T : INotification
|
||||
{
|
||||
private readonly INotificationHandler<T> _decorated;
|
||||
private readonly IDomainEventsDispatcher _domainEventsDispatcher;
|
||||
|
||||
public DomainEventsDispatcherNotificationHandlerDecorator(
|
||||
IDomainEventsDispatcher domainEventsDispatcher,
|
||||
INotificationHandler<T> decorated)
|
||||
{
|
||||
_domainEventsDispatcher = domainEventsDispatcher;
|
||||
_decorated = decorated;
|
||||
}
|
||||
|
||||
public async Task Handle(T notification, CancellationToken cancellationToken)
|
||||
{
|
||||
await _decorated.Handle(notification, cancellationToken);
|
||||
|
||||
await _domainEventsDispatcher.DispatchEventsAsync();
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
namespace VizhTalk.BuildingBlocks.Infrastructure.DomainEventsDispatching;
|
||||
|
||||
public class DomainNotificationsMapper : IDomainNotificationsMapper
|
||||
{
|
||||
private readonly BiDictionary<string, Type> _domainNotificationsMap;
|
||||
|
||||
public DomainNotificationsMapper(BiDictionary<string, Type> domainNotificationsMap)
|
||||
{
|
||||
_domainNotificationsMap = domainNotificationsMap;
|
||||
}
|
||||
|
||||
public string GetName(Type type)
|
||||
{
|
||||
return _domainNotificationsMap.TryGetBySecond(type, out var name) ? name : null;
|
||||
}
|
||||
|
||||
public Type GetType(string name)
|
||||
{
|
||||
return _domainNotificationsMap.TryGetByFirst(name, out var type) ? type : null;
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
using VizhTalk.BuildingBlocks.Domain;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Infrastructure.DomainEventsDispatching;
|
||||
|
||||
public interface IDomainEventsAccessor
|
||||
{
|
||||
IReadOnlyCollection<IDomainEvent> GetAllDomainEvents();
|
||||
|
||||
void ClearAllDomainEvents();
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Infrastructure.DomainEventsDispatching;
|
||||
|
||||
public interface IDomainEventsDispatcher
|
||||
{
|
||||
Task DispatchEventsAsync();
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
namespace VizhTalk.BuildingBlocks.Infrastructure.DomainEventsDispatching;
|
||||
public interface IDomainNotificationsMapper
|
||||
{
|
||||
string GetName(Type type);
|
||||
|
||||
Type GetType(string name);
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
using VizhTalk.BuildingBlocks.Application.Configuration.Commnad;
|
||||
using VizhTalk.BuildingBlocks.Application.Contract;
|
||||
using VizhTalk.BuildingBlocks.Domain.Contract;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Infrastructure.DomainEventsDispatching;
|
||||
|
||||
public class UnitOfWorkCommandHandlerDecorator<TCommand> : ICommandHandler<TCommand>
|
||||
where TCommand : ICommand
|
||||
{
|
||||
private readonly ICommandHandler<TCommand> _decorated;
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly IDomainEventsDispatcher _domainEventsDispatcher;
|
||||
|
||||
public UnitOfWorkCommandHandlerDecorator(
|
||||
ICommandHandler<TCommand> decorated,
|
||||
IUnitOfWork unitOfWork,
|
||||
IDomainEventsDispatcher domainEventsDispatcher)
|
||||
{
|
||||
_decorated = decorated;
|
||||
_unitOfWork = unitOfWork;
|
||||
_domainEventsDispatcher = domainEventsDispatcher;
|
||||
}
|
||||
|
||||
public async Task Handle(TCommand command, CancellationToken cancellationToken)
|
||||
{
|
||||
await this._decorated.Handle(command, cancellationToken);
|
||||
|
||||
await this._unitOfWork.CommitAsync(cancellationToken);
|
||||
|
||||
await this._domainEventsDispatcher.DispatchEventsAsync();
|
||||
}
|
||||
}
|
||||
public class UnitOfWorkCommandHandlerDecorator<TCommand,TResponse> : ICommandHandler<TCommand, TResponse>
|
||||
where TCommand : ICommand<TResponse>
|
||||
{
|
||||
private readonly ICommandHandler<TCommand, TResponse> _decorated;
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly IDomainEventsDispatcher _domainEventsDispatcher;
|
||||
|
||||
public UnitOfWorkCommandHandlerDecorator(
|
||||
ICommandHandler<TCommand, TResponse> decorated,
|
||||
IUnitOfWork unitOfWork,
|
||||
IDomainEventsDispatcher domainEventsDispatcher)
|
||||
{
|
||||
_decorated = decorated;
|
||||
_unitOfWork = unitOfWork;
|
||||
_domainEventsDispatcher = domainEventsDispatcher;
|
||||
}
|
||||
|
||||
public async Task<TResponse> Handle(TCommand command, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await this._decorated.Handle(command, cancellationToken);
|
||||
|
||||
await this._unitOfWork.CommitAsync(cancellationToken);
|
||||
|
||||
await this._domainEventsDispatcher.DispatchEventsAsync();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using Humanizer;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Reflection;
|
||||
using VizhTalk.BuildingBlocks.Domain;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Infrastructure.EF.Helpers
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
public static ModelBuilder FindEntities(this ModelBuilder modelBuilder)
|
||||
{
|
||||
var entityTypes = typeof(Entity<>).Assembly
|
||||
.GetTypes()
|
||||
.Where(t => t.IsClass && !t.IsAbstract && typeof(Entity<>).IsAssignableFrom(t));
|
||||
|
||||
foreach (var type in entityTypes)
|
||||
modelBuilder.Entity(type);
|
||||
|
||||
return modelBuilder;
|
||||
}
|
||||
public static ModelBuilder PluralizeEntities(this ModelBuilder modelBuilder)
|
||||
{
|
||||
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
|
||||
{
|
||||
var tableName = entityType.ClrType.Name.Pluralize();
|
||||
modelBuilder.Entity(entityType.ClrType).ToTable(tableName);
|
||||
}
|
||||
return modelBuilder;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using VizhTalk.BuildingBlocks.Domain;
|
||||
using VizhTalk.BuildingBlocks.Domain.Contract;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Infrastructure;
|
||||
|
||||
public interface IExecutor
|
||||
{
|
||||
Task Execute(ICommand command, CancellationToken cancellationToken = default);
|
||||
Task<TResult> Execute<TResult>(ICommand<TResult> command, CancellationToken cancellationToken = default);
|
||||
Task<TResult> Execute<TResult>(IQuery<TResult> query, CancellationToken cancellationToken = default);
|
||||
Task Execute(IDomainEvent notification, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace VizhTalk.BuildingBlocks.Infrastructure;
|
||||
|
||||
public interface IUnitOfWork
|
||||
{
|
||||
Task<int> CommitAsync(
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Infrastructure.Inbox
|
||||
{
|
||||
public interface IInbox
|
||||
{
|
||||
void Add(InboxMessage message);
|
||||
|
||||
Task Save();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace VizhTalk.BuildingBlocks.Infrastructure.Inbox;
|
||||
|
||||
public class InboxMessage
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public DateTime OccurredOn { get; set; }
|
||||
|
||||
public string Type { get; set; }
|
||||
|
||||
public string Data { get; set; }
|
||||
|
||||
public DateTime? ProcessedDate { get; set; }
|
||||
|
||||
public InboxMessage(DateTime occurredOn, string type, string data)
|
||||
{
|
||||
this.Id = Guid.NewGuid();
|
||||
this.OccurredOn = occurredOn;
|
||||
this.Type = type;
|
||||
this.Data = data;
|
||||
}
|
||||
|
||||
private InboxMessage()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Infrastructure.Mapper;
|
||||
|
||||
internal static class ReplaceMediatorOpenTypes
|
||||
{
|
||||
public static void Replace(this IServiceCollection services)
|
||||
{
|
||||
//services.Replace(new ServiceDescriptor()) // ToDo
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using System.Reflection;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Infrastructure.Serialization;
|
||||
public class AllPropertiesContractResolver : DefaultContractResolver
|
||||
{
|
||||
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
|
||||
{
|
||||
var properties = type.GetProperties(
|
||||
BindingFlags.Public |
|
||||
BindingFlags.NonPublic |
|
||||
BindingFlags.Instance)
|
||||
.Select(p => this.CreateProperty(p, memberSerialization))
|
||||
.ToList();
|
||||
|
||||
properties.ForEach(p =>
|
||||
{
|
||||
p.Writable = true;
|
||||
p.Readable = true;
|
||||
});
|
||||
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using VizhTalk.BuildingBlocks.Infrastructure.DomainEventsDispatching;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Infrastructure;
|
||||
|
||||
public class UnitOfWork : IUnitOfWork
|
||||
{
|
||||
private readonly DbContext _context;
|
||||
private readonly IDomainEventsDispatcher _domainEventsDispatcher;
|
||||
|
||||
public UnitOfWork(
|
||||
DbContext context,
|
||||
IDomainEventsDispatcher domainEventsDispatcher)
|
||||
{
|
||||
this._context = context;
|
||||
this._domainEventsDispatcher = domainEventsDispatcher;
|
||||
}
|
||||
|
||||
public async Task<int> CommitAsync(
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
await this._domainEventsDispatcher.DispatchEventsAsync();
|
||||
|
||||
return await _context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer" Version="3.0.0-beta.96" />
|
||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.19" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.19" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.19" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="Scrutor" Version="6.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\VizhTalk.BuildingBlocks.Application\VizhTalk.BuildingBlocks.Application.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,18 @@
|
||||
using VizhTalk.Gateway.Web.BFF.Queries;
|
||||
using VizhTalk.Grpc.Learning.Language;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
builder.Services.AddGrpcClient<LanguageGrpc.LanguageGrpcClient>(o =>
|
||||
{
|
||||
o.Address = new Uri("https://localhost:5000");
|
||||
});
|
||||
|
||||
builder.Services.AddScoped<LanguageQuery>();
|
||||
|
||||
builder.AddGraphQL()
|
||||
.AddQueryType<LanguageQuery>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
app.MapGraphQL();
|
||||
app.Run();
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:37086",
|
||||
"sslPort": 44394
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "http://localhost:5137",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:7211;http://localhost:5137",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using VizhTalk.Grpc.Learning.Language;
|
||||
|
||||
namespace VizhTalk.Gateway.Web.BFF.Queries
|
||||
{
|
||||
public class LanguageQuery(LanguageGrpc.LanguageGrpcClient languageGrpcClient)
|
||||
{
|
||||
[GraphQLName("Languages")]
|
||||
public async Task<GetAllLanguageReply> GetAll()
|
||||
{
|
||||
return await languageGrpcClient.GetAllAsync(new Empty());
|
||||
}
|
||||
[GraphQLName("Language")]
|
||||
public async Task<Language> GetLanguageByTitle(GetLanguageByTitleRequest request)
|
||||
=> await languageGrpcClient.GetLanguageByTitleAsync(request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Grpc.AspNetCore" Version="2.71.0" />
|
||||
<PackageReference Include="HotChocolate.AspNetCore" Version="16.0.0-p.7.40" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\VizhTalk.Services.Grpc.Learning\VizhTalk.Grpc.Learning.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using VizhTalk.BuildingBlocks.Domain.Contract;
|
||||
using VizhTalk.BuildingBlocks.Infrastructure;
|
||||
|
||||
namespace VizhTalk.Learning.Application;
|
||||
|
||||
public interface ILearningModule : IExecutor
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\VizhTalk.BuildingBlocks.Application\VizhTalk.BuildingBlocks.Application.csproj" />
|
||||
<ProjectReference Include="..\VizhTalk.BuildingBlocks.Infrastructure\VizhTalk.BuildingBlocks.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VizhTalk.Learning.Domain.Entities
|
||||
{
|
||||
internal class Course
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using VizhTalk.BuildingBlocks.Domain;
|
||||
using VizhTalk.Learning.Domain.TypeIds;
|
||||
using VizhTalk.Learning.Domain.ValueObjects;
|
||||
|
||||
namespace VizhTalk.Learning.Domain.Entities;
|
||||
|
||||
public class Language : Entity<LanguageId>, IAggregateRoot
|
||||
{
|
||||
public LanguageTitle Title { get; private set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VizhTalk.Learning.Domain.Entities
|
||||
{
|
||||
internal class Learn
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VizhTalk.Learning.Domain.Entities
|
||||
{
|
||||
internal class Lesson
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VizhTalk.Learning.Domain.Entities
|
||||
{
|
||||
internal class LessonType
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VizhTalk.Learning.Domain.Entities
|
||||
{
|
||||
internal class Option
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VizhTalk.Learning.Domain.Entities
|
||||
{
|
||||
internal class Section
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VizhTalk.Learning.Domain.Entities
|
||||
{
|
||||
internal class Test
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VizhTalk.Learning.Domain.Entities
|
||||
{
|
||||
internal class TestOption
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VizhTalk.Learning.Domain.Entities
|
||||
{
|
||||
internal class Unit
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VizhTalk.BuildingBlocks.Domain;
|
||||
|
||||
namespace VizhTalk.Learning.Domain.TypeIds
|
||||
{
|
||||
public class LanguageId : TypedIdValueBase<LanguageId>
|
||||
{
|
||||
public LanguageId(LanguageId value) : base(value)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using VizhTalk.BuildingBlocks.Domain;
|
||||
using VizhTalk.BuildingBlocks.Domain.Guards;
|
||||
|
||||
namespace VizhTalk.Learning.Domain.ValueObjects
|
||||
{
|
||||
public class LanguageTitle : ValueObject
|
||||
{
|
||||
public LanguageTitle(string title)
|
||||
{
|
||||
Guard.NullOrEmpty(title, nameof(LanguageTitle));
|
||||
Value = title;
|
||||
}
|
||||
public string Value { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Events\" />
|
||||
<Folder Include="Exceptions\" />
|
||||
<Folder Include="Rules\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\VizhTalk.BuildingBlocks.Domain\VizhTalk.BuildingBlocks.Domain.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VizhTalk.Learning.Application;
|
||||
|
||||
namespace VizhTalk.Learning.Infrastructure.Configuration
|
||||
{
|
||||
public static class Assemblies
|
||||
{
|
||||
public static Assembly Infrastructure = typeof(LearningStartup).Assembly;
|
||||
public static Assembly Application = typeof(ILearningModule).Assembly;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using VizhTalk.BuildingBlocks.Application.Configuration.Commnad;
|
||||
using VizhTalk.BuildingBlocks.Application.Contract;
|
||||
using VizhTalk.BuildingBlocks.Domain;
|
||||
using VizhTalk.BuildingBlocks.Domain.Contract;
|
||||
using VizhTalk.Learning.Application;
|
||||
|
||||
namespace VizhTalk.Learning.Infrastructure.Configuration;
|
||||
|
||||
public class LearningModule(IServiceProvider serviceProvider) : ILearningModule
|
||||
{
|
||||
public async Task Execute(ICommand command, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var handlerType = typeof(ICommandHandler<>).MakeGenericType(command.GetType());
|
||||
var handler = serviceProvider.GetRequiredService(handlerType);
|
||||
dynamic dynamicHandler = handler;
|
||||
dynamic dynamicCommand = command;
|
||||
await dynamicHandler.Handle(dynamicCommand, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<TResult> Execute<TResult>(ICommand<TResult> command, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var handlerType = typeof(ICommandHandler<,>).MakeGenericType(command.GetType());
|
||||
var handler = serviceProvider.GetRequiredService(handlerType);
|
||||
dynamic dynamicHandler = handler;
|
||||
dynamic dynamicCommand = command;
|
||||
return await dynamicHandler.Handle(dynamicCommand, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<TResult> Execute<TResult>(IQuery<TResult> query, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var handlerType = typeof(ICommandHandler<,>).MakeGenericType(query.GetType());
|
||||
var handler = serviceProvider.GetRequiredService(handlerType);
|
||||
dynamic dynamicHandler = handler;
|
||||
dynamic dynamicQuery = query;
|
||||
return await dynamicHandler.Handle(dynamicQuery, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task Execute(IDomainEvent notification, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var handlerType = typeof(INotificationHandler<>).MakeGenericType(notification.GetType());
|
||||
var handler = serviceProvider.GetRequiredService(handlerType);
|
||||
dynamic dynamicHandler = handler;
|
||||
dynamic dynamicNotification = notification;
|
||||
await dynamicHandler.Handle(dynamicNotification, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using VizhTalk.BuildingBlocks.Infrastructure.EF.Helpers;
|
||||
|
||||
namespace VizhTalk.Learning.Infrastructure.EF;
|
||||
|
||||
public class LearningDbContext : DbContext
|
||||
{
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
modelBuilder.FindEntities()
|
||||
.PluralizeEntities();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using VizhTalk.BuildingBlocks.Application.Configuration.Commnad;
|
||||
using VizhTalk.BuildingBlocks.Application.Configuration.Query;
|
||||
using VizhTalk.BuildingBlocks.Application.Events;
|
||||
using VizhTalk.BuildingBlocks.Application.Outbox;
|
||||
using VizhTalk.BuildingBlocks.Infrastructure;
|
||||
using VizhTalk.BuildingBlocks.Infrastructure.DomainEventsDispatching;
|
||||
using VizhTalk.Learning.Application;
|
||||
using VizhTalk.Learning.Infrastructure.Configuration;
|
||||
using VizhTalk.Learning.Infrastructure.EF;
|
||||
|
||||
namespace VizhTalk.Learning.Infrastructure;
|
||||
|
||||
public static class LearningStartup
|
||||
{
|
||||
public static void Initialize(this IServiceCollection services, string connectionString)
|
||||
{
|
||||
services.AddDbContext<LearningDbContext>(op =>
|
||||
{
|
||||
op.UseSqlServer(connectionString);
|
||||
});
|
||||
services.AddScoped<ILearningModule, LearningModule>();
|
||||
services.AddScoped<IExecutor, LearningModule>();
|
||||
services.AddScoped<IUnitOfWork, UnitOfWork>();
|
||||
services.AddScoped<IDomainEventsAccessor, DomainEventsAccessor>();
|
||||
services.AddScoped<IDomainEventsDispatcher, DomainEventsDispatcher>();
|
||||
services.AddScoped<IDomainNotificationsMapper, DomainNotificationsMapper>();
|
||||
services.Scan(scan => scan.
|
||||
FromAssemblies(Assemblies.Application, Assemblies.Infrastructure)
|
||||
.AddClasses(classes => classes.AssignableTo(typeof(ICommandHandler<>)), publicOnly: false)
|
||||
.AsImplementedInterfaces()
|
||||
.WithScopedLifetime()
|
||||
.AddClasses(classes => classes.AssignableTo(typeof(ICommandHandler<,>)), publicOnly: false)
|
||||
.AsImplementedInterfaces()
|
||||
.WithScopedLifetime()
|
||||
.AddClasses(classes => classes.AssignableTo(typeof(IQueryHandler<,>)), publicOnly: false)
|
||||
.AsImplementedInterfaces()
|
||||
.WithScopedLifetime()
|
||||
.AddClasses(classes => classes.AssignableTo(typeof(ICommandHandler<>)), publicOnly: false)
|
||||
.AsImplementedInterfaces()
|
||||
.WithScopedLifetime());
|
||||
services.Decorate(typeof(ICommandHandler<>), typeof(UnitOfWorkCommandHandlerDecorator<>));
|
||||
services.AddScoped(sa =>
|
||||
{
|
||||
var notifications = sa.GetServices<IDomainEventNotification>();
|
||||
var notificationDic = new BiDictionary<string, Type>();
|
||||
foreach (var notification in notifications)
|
||||
notificationDic.Add(notification!.ToString()!, notification!.GetType());
|
||||
|
||||
return notificationDic;
|
||||
});
|
||||
services.AddScoped<IOutbox>(sa =>
|
||||
{
|
||||
return null; // ToDo
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VizhTalk.BuildingBlocks.Application.Outbox;
|
||||
|
||||
namespace VizhTalk.Learning.Infrastructure.Outbox
|
||||
{
|
||||
public class OutboxAccessor : IOutbox
|
||||
{
|
||||
public OutboxAccessor()
|
||||
{
|
||||
|
||||
}
|
||||
public void Add(OutboxMessage message)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task Save()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\VizhTalk.BuildingBlocks.Infrastructure\VizhTalk.BuildingBlocks.Infrastructure.csproj" />
|
||||
<ProjectReference Include="..\VizhTalk.Learning.Application\VizhTalk.Learning.Application.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,16 @@
|
||||
using VizhTalk.Learning.Infrastructure;
|
||||
using VizhTalk.Learning.Presentation.Services;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddGrpc();
|
||||
|
||||
builder.Services.Initialize("");
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
app.MapGrpcService<LanguageService>();
|
||||
|
||||
app.Run();
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "https://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using Google.Protobuf.Collections;
|
||||
using Grpc.Core;
|
||||
using VizhTalk.Grpc.Learning.Language;
|
||||
|
||||
namespace VizhTalk.Learning.Presentation.Services;
|
||||
|
||||
public class LanguageService : LanguageGrpc.LanguageGrpcBase
|
||||
{
|
||||
public static GetAllLanguageReply Languages = new GetAllLanguageReply();
|
||||
public LanguageService()
|
||||
{
|
||||
Languages.Languages.Add(new Language() { Title = "English" });
|
||||
Languages.Languages.Add(new Language() { Title = "Germany" });
|
||||
Languages.Languages.Add(new Language() { Title = "Persian" });
|
||||
Languages.Languages.Add(new Language() { Title = "Spain" });
|
||||
}
|
||||
public override async Task<GetAllLanguageReply> GetAll(Empty request, ServerCallContext context)
|
||||
{
|
||||
return Languages;
|
||||
}
|
||||
public override async Task<Language> GetLanguageByTitle(GetLanguageByTitleRequest request, ServerCallContext context)
|
||||
{
|
||||
var language = Languages.Languages.FirstOrDefault(x => x.Title == request.Title);
|
||||
|
||||
return language;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Grpc.AspNetCore" Version="2.57.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\VizhTalk.Learning.Infrastructure\VizhTalk.Learning.Infrastructure.csproj" />
|
||||
<ProjectReference Include="..\VizhTalk.Services.Grpc.Learning\VizhTalk.Grpc.Learning.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"Kestrel": {
|
||||
"EndpointDefaults": {
|
||||
"Protocols": "Http2"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
syntax="proto3";
|
||||
|
||||
option csharp_namespace="VizhTalk.Grpc.Learning.Language";
|
||||
|
||||
package greet;
|
||||
|
||||
message Language {
|
||||
string title = 1;
|
||||
}
|
||||
|
||||
message GetAllLanguageReply {
|
||||
repeated Language languages = 1;
|
||||
}
|
||||
|
||||
message Empty {}
|
||||
|
||||
message GetLanguageByTitleRequest {
|
||||
string title = 1;
|
||||
}
|
||||
|
||||
service LanguageGrpc {
|
||||
rpc GetAll (Empty) returns (GetAllLanguageReply);
|
||||
rpc GetLanguageByTitle (GetLanguageByTitleRequest) returns (Language);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Google.Protobuf" Version="3.32.0" />
|
||||
<PackageReference Include="Grpc.Net.Client" Version="2.71.0" />
|
||||
<PackageReference Include="Grpc.Tools" Version="2.58.0" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Protobuf Include="Language.proto" GrpcServices="Both" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.8.34330.188
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Gateways", "Gateways", "{FCA7DC48-FD9C-43FA-AC1B-464049337778}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{5B01E22E-8A79-4C40-A0B7-97D4EC2D120E}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "User", "User", "{AC8EE492-AB63-4799-946A-98F819478EB2}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Chat", "Chat", "{E507BEFF-5CB6-43BA-B95A-B6975840B043}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Learning", "Learning", "{1305E6AB-69E5-47BD-B03C-694832C4D46A}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AI", "AI", "{35CC083E-B7AE-4495-A95A-68C0C0F9A2F7}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CDN", "CDN", "{9E64DF44-8256-40C8-8AFA-B841CE80DD0E}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Meetting", "Meetting", "{26FDAD4D-55F4-445B-BE66-65193D21D14D}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Profile", "Profile", "{D74A2A69-224B-4498-8E99-1BC086C594CB}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UserProgress", "UserProgress", "{75826056-3765-4A48-9827-02ED1F27E40D}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Services", "Services", "{F1386DBF-90B7-4285-93F2-FD60DFBAD600}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Grpcs", "Grpcs", "{16D91427-4F51-48CD-A2F2-6CC1B9A9D8A5}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VizhTalk.Learning.Domain", "VizhTalk.Learning.Domain\VizhTalk.Learning.Domain.csproj", "{B294A620-DADE-4D31-9BF5-C1CC5D7E29EB}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VizhTalk.Learning.Application", "VizhTalk.Learning.Application\VizhTalk.Learning.Application.csproj", "{B5065F1D-F391-4511-8697-966806841816}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VizhTalk.Learning.Infrastructure", "VizhTalk.Learning.Infrastructure\VizhTalk.Learning.Infrastructure.csproj", "{1495DF56-D227-4D68-86CA-0249D886C07C}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BuildingBlocks", "BuildingBlocks", "{45B6CABB-4197-4C70-BF3F-F3AE7C8CB380}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VizhTalk.BuildingBlocks.Application", "VizhTalk.BuildingBlocks.Application\VizhTalk.BuildingBlocks.Application.csproj", "{EBFE2D6C-BA5B-460E-B57C-A8295BBCD727}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VizhTalk.BuildingBlocks.Domain", "VizhTalk.BuildingBlocks.Domain\VizhTalk.BuildingBlocks.Domain.csproj", "{22CD7011-A8DB-4DB6-8597-1601E7EF8725}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VizhTalk.BuildingBlocks.Infrastructure", "VizhTalk.BuildingBlocks.Infrastructure\VizhTalk.BuildingBlocks.Infrastructure.csproj", "{B2014B29-FE4E-4B59-829E-2AAC38B039AA}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VizhTalk.Grpc.Learning", "VizhTalk.Services.Grpc.Learning\VizhTalk.Grpc.Learning.csproj", "{A3F0C4E9-3957-4B25-8AB5-6751ECB01F39}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VizhTalk.Learning.Presentation", "VizhTalk.Learning.Presentation\VizhTalk.Learning.Presentation.csproj", "{8327C994-F1D5-493B-8EF7-B60EB888E92A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VizhTalk.Gateway.Web.BFF", "VizhTalk.Gateway.BFF\VizhTalk.Gateway.Web.BFF.csproj", "{21DDD623-E75A-4D16-894B-2DEA0CA5C073}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{B294A620-DADE-4D31-9BF5-C1CC5D7E29EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B294A620-DADE-4D31-9BF5-C1CC5D7E29EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B294A620-DADE-4D31-9BF5-C1CC5D7E29EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B294A620-DADE-4D31-9BF5-C1CC5D7E29EB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B5065F1D-F391-4511-8697-966806841816}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B5065F1D-F391-4511-8697-966806841816}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B5065F1D-F391-4511-8697-966806841816}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B5065F1D-F391-4511-8697-966806841816}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1495DF56-D227-4D68-86CA-0249D886C07C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1495DF56-D227-4D68-86CA-0249D886C07C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1495DF56-D227-4D68-86CA-0249D886C07C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1495DF56-D227-4D68-86CA-0249D886C07C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EBFE2D6C-BA5B-460E-B57C-A8295BBCD727}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EBFE2D6C-BA5B-460E-B57C-A8295BBCD727}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EBFE2D6C-BA5B-460E-B57C-A8295BBCD727}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EBFE2D6C-BA5B-460E-B57C-A8295BBCD727}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{22CD7011-A8DB-4DB6-8597-1601E7EF8725}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{22CD7011-A8DB-4DB6-8597-1601E7EF8725}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{22CD7011-A8DB-4DB6-8597-1601E7EF8725}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{22CD7011-A8DB-4DB6-8597-1601E7EF8725}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B2014B29-FE4E-4B59-829E-2AAC38B039AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B2014B29-FE4E-4B59-829E-2AAC38B039AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B2014B29-FE4E-4B59-829E-2AAC38B039AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B2014B29-FE4E-4B59-829E-2AAC38B039AA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A3F0C4E9-3957-4B25-8AB5-6751ECB01F39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A3F0C4E9-3957-4B25-8AB5-6751ECB01F39}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A3F0C4E9-3957-4B25-8AB5-6751ECB01F39}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A3F0C4E9-3957-4B25-8AB5-6751ECB01F39}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8327C994-F1D5-493B-8EF7-B60EB888E92A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8327C994-F1D5-493B-8EF7-B60EB888E92A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8327C994-F1D5-493B-8EF7-B60EB888E92A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8327C994-F1D5-493B-8EF7-B60EB888E92A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{21DDD623-E75A-4D16-894B-2DEA0CA5C073}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{21DDD623-E75A-4D16-894B-2DEA0CA5C073}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{21DDD623-E75A-4D16-894B-2DEA0CA5C073}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{21DDD623-E75A-4D16-894B-2DEA0CA5C073}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{AC8EE492-AB63-4799-946A-98F819478EB2} = {5B01E22E-8A79-4C40-A0B7-97D4EC2D120E}
|
||||
{E507BEFF-5CB6-43BA-B95A-B6975840B043} = {5B01E22E-8A79-4C40-A0B7-97D4EC2D120E}
|
||||
{1305E6AB-69E5-47BD-B03C-694832C4D46A} = {5B01E22E-8A79-4C40-A0B7-97D4EC2D120E}
|
||||
{35CC083E-B7AE-4495-A95A-68C0C0F9A2F7} = {5B01E22E-8A79-4C40-A0B7-97D4EC2D120E}
|
||||
{9E64DF44-8256-40C8-8AFA-B841CE80DD0E} = {5B01E22E-8A79-4C40-A0B7-97D4EC2D120E}
|
||||
{26FDAD4D-55F4-445B-BE66-65193D21D14D} = {5B01E22E-8A79-4C40-A0B7-97D4EC2D120E}
|
||||
{D74A2A69-224B-4498-8E99-1BC086C594CB} = {5B01E22E-8A79-4C40-A0B7-97D4EC2D120E}
|
||||
{75826056-3765-4A48-9827-02ED1F27E40D} = {5B01E22E-8A79-4C40-A0B7-97D4EC2D120E}
|
||||
{16D91427-4F51-48CD-A2F2-6CC1B9A9D8A5} = {F1386DBF-90B7-4285-93F2-FD60DFBAD600}
|
||||
{B294A620-DADE-4D31-9BF5-C1CC5D7E29EB} = {1305E6AB-69E5-47BD-B03C-694832C4D46A}
|
||||
{B5065F1D-F391-4511-8697-966806841816} = {1305E6AB-69E5-47BD-B03C-694832C4D46A}
|
||||
{1495DF56-D227-4D68-86CA-0249D886C07C} = {1305E6AB-69E5-47BD-B03C-694832C4D46A}
|
||||
{45B6CABB-4197-4C70-BF3F-F3AE7C8CB380} = {5B01E22E-8A79-4C40-A0B7-97D4EC2D120E}
|
||||
{EBFE2D6C-BA5B-460E-B57C-A8295BBCD727} = {45B6CABB-4197-4C70-BF3F-F3AE7C8CB380}
|
||||
{22CD7011-A8DB-4DB6-8597-1601E7EF8725} = {45B6CABB-4197-4C70-BF3F-F3AE7C8CB380}
|
||||
{B2014B29-FE4E-4B59-829E-2AAC38B039AA} = {45B6CABB-4197-4C70-BF3F-F3AE7C8CB380}
|
||||
{A3F0C4E9-3957-4B25-8AB5-6751ECB01F39} = {16D91427-4F51-48CD-A2F2-6CC1B9A9D8A5}
|
||||
{8327C994-F1D5-493B-8EF7-B60EB888E92A} = {1305E6AB-69E5-47BD-B03C-694832C4D46A}
|
||||
{21DDD623-E75A-4D16-894B-2DEA0CA5C073} = {FCA7DC48-FD9C-43FA-AC1B-464049337778}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {9BD8917D-0A5E-401B-B153-400D610B23E4}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
Reference in New Issue
Block a user