├── .nuget ├── NuGet.exe └── NuGet.Config ├── Crucial-CQRS.png ├── API ├── Global.asax ├── Models │ ├── User.cs │ ├── Category.cs │ └── Question.cs ├── Mappers │ ├── QuestionToQuestionMapper.cs │ └── CategoryMapper.cs ├── NLog.config ├── Global.asax.cs ├── App_Start │ ├── WebApiConfig.cs │ ├── RealtimeStartup.cs │ └── Bootstraper.cs ├── Web.Debug.config ├── Web.Release.config ├── Properties │ └── AssemblyInfo.cs ├── packages.config └── Controllers │ └── QuestionController.cs ├── Web ├── Web.config ├── templates │ ├── settings.html │ ├── menu.html │ ├── category │ │ ├── new.html │ │ └── category.html │ └── question │ │ ├── new.html │ │ └── question.html ├── js │ ├── settings │ │ ├── controller.js │ │ └── module.js │ ├── layout.js │ ├── category │ │ ├── module.js │ │ └── factory.js │ ├── question │ │ ├── module.js │ │ └── factory.js │ ├── utils │ │ └── utils.js │ ├── app.js │ └── signalr │ │ └── signalrHubProxy.js ├── readme.txt ├── css │ └── layout.css ├── Gruntfile.js ├── package.json ├── vwd.webinfo ├── bower.json └── img │ └── icons │ └── ic_menu_24px.svg ├── Crucial.Qyz ├── packages.config ├── Domain │ ├── QuestionType.cs │ ├── Mementos │ │ ├── UserCategoryMemento.cs │ │ └── Question.cs │ ├── Question.cs │ └── QuestionBase.cs ├── app.config ├── Commands │ ├── Question │ │ ├── QuestionDeleteCommand.cs │ │ ├── QuestionTextChangeCommand.cs │ │ └── QuestionCreateCommand.cs │ └── UserCategory │ │ ├── UserCategoryDeleteCommand.cs │ │ ├── UserCategoryCreateCommand.cs │ │ ├── UserCategoryNameChangeCommand.cs │ │ └── AddQuestionToCategoryCommand.cs ├── Events │ ├── Question │ │ ├── QuestionDeletedEvent.cs │ │ ├── QuestionTextChangedEvent.cs │ │ └── QuestionCreatedEvent.cs │ └── UserCategory │ │ ├── UserCategoryDeletedEvent.cs │ │ ├── UserCategoryCreatedEvent.cs │ │ ├── UserCategoryNameChangedEvent.cs │ │ └── QuestionAddedToCategoryEvent.cs ├── EventHandlers │ ├── Question │ │ ├── QuestionDeletedEventHandler.cs │ │ ├── QuestionCreatedEventHandler.cs │ │ └── QuestionTextChangedEventHandler.cs │ └── UserCategory │ │ ├── UserCategoryNameChangedEventHandler.cs │ │ ├── QuestionAddedToCategoryEventHandler.cs │ │ ├── UserCategoryCreatedEventHandler.cs │ │ └── UserCategoryDeletedEventHandler.cs ├── CommandHandlers │ ├── Question │ │ ├── QuestionDeleteCommandHandler.cs │ │ ├── QuestionCreateCommandHandler.cs │ │ └── QuestionTextChangeCommandHandler.cs │ └── UserCategory │ │ ├── UserCategoryDeleteCommandHandler.cs │ │ ├── UserCategoryCreateCommandHandler.cs │ │ ├── UserCategoryNameChangeCommandHandler.cs │ │ └── AddQuestionToCategoryCommandHandler.cs └── Properties │ └── AssemblyInfo.cs ├── Crucial.EventStore ├── packages.config ├── Mappers │ ├── AggregateMapper.cs │ ├── EventMapper.cs │ └── MementoMapper.cs ├── App.config └── Properties │ └── AssemblyInfo.cs ├── Crucial.Providers ├── packages.config ├── Filesystem │ ├── Entities │ │ ├── Enums │ │ │ └── FilesystemPathSeparator.cs │ │ ├── DirectoryUpdate.cs │ │ ├── Directory.cs │ │ └── Extensions │ │ │ └── DirectoryExtensions.cs │ ├── Interfaces │ │ └── IDirectoryRepository.cs │ ├── Exceptions │ │ ├── GeneralException.cs │ │ ├── PathNotFoundException.cs │ │ └── DirectoryNotEmptyException.cs │ ├── Mappers │ │ └── DirectoryMapper.cs │ └── DirectoryRepository.cs ├── Identity │ ├── Data │ │ ├── Identity.cs │ │ ├── IIdentityDbContext.cs │ │ ├── AspNetUserRoleConfiguration.cs │ │ ├── AspNetUserClaimConfiguration.cs │ │ ├── AspNetUserLoginConfiguration.cs │ │ └── AspNetUserConfiguration.cs │ ├── Interfaces │ │ ├── IIdentityContextProvider.cs │ │ └── IUserRepository.cs │ ├── Entities │ │ ├── Identity.cs │ │ ├── AspNetUserRole.cs │ │ ├── AspNetUserLogin.cs │ │ ├── AspNetUserClaim.cs │ │ └── AspNetUser.cs │ └── UserRepository.cs ├── EventStore │ ├── Entities │ │ ├── BaseMemento.cs │ │ ├── AggregateRoot.cs │ │ ├── Event.cs │ │ └── EventStore.cs │ ├── Data │ │ ├── IEventStoreContext.cs │ │ ├── EventStore.cs │ │ ├── AggregateRootConfiguration.cs │ │ ├── EventConfiguration.cs │ │ └── BaseMementoConfiguration.cs │ ├── EventRepositoryAsync.cs │ ├── MementoRepositoryAsync.cs │ └── AggregateRepositoryAsync.cs ├── Questions │ ├── Entities │ │ ├── Questions.cs │ │ ├── QuestionAnswer.cs │ │ ├── Category.cs │ │ └── Question.cs │ ├── Data │ │ ├── IQuestionsDbContext.cs │ │ ├── Questions.cs │ │ ├── QuestionAnswerConfiguration.cs │ │ ├── QuestionConfiguration.cs │ │ └── CategoryConfiguration.cs │ ├── CategoryRepositoryAsync.cs │ └── QuestionRepositoryAsync.cs ├── Properties │ └── AssemblyInfo.cs └── App.config ├── Crucial.Framework ├── Data │ └── EntityFramework │ │ ├── T4Templating │ │ ├── EF.Reverse.POCO.ttinclude │ │ └── EF.Reverse.POCO.Core.ttinclude │ │ ├── IDatabaseContextProvider.cs │ │ ├── IDbContext.cs │ │ └── DatabaseContextProvider.cs ├── Entities │ ├── EntityBase.cs │ ├── ServiceEntityBase.cs │ ├── ProviderEntityBase.cs │ └── CqrsViewModel.cs ├── IoC │ ├── IAutoRegister.cs │ ├── StructureMap │ │ ├── DependencyResolver.cs │ │ └── ServiceActivator.cs │ └── Windsor │ │ └── Resolver.cs ├── DesignPatterns │ ├── CQRS │ │ ├── Utils │ │ │ ├── IStateHelper.cs │ │ │ ├── ICommandHandlerFactory.cs │ │ │ ├── IEventHandlerFactory.cs │ │ │ ├── StructureMapCommandHandlerFactory.cs │ │ │ ├── Converter.cs │ │ │ ├── StructureMapEventHandlerFactory.cs │ │ │ └── StateHelper.cs │ │ ├── Commands │ │ │ ├── ICommand.cs │ │ │ ├── ICommandHandler.cs │ │ │ └── Command.cs │ │ ├── Exceptions │ │ │ ├── UnregisteredDomainEventException.cs │ │ │ ├── UnregisteredDomainCommandException.cs │ │ │ ├── ConcurrencyException.cs │ │ │ └── AggregateNotFoundException.cs │ │ ├── Messaging │ │ │ ├── ICommandBus.cs │ │ │ ├── IEventBus.cs │ │ │ ├── CommandBus.cs │ │ │ └── EventBus.cs │ │ ├── Domain │ │ │ ├── BasePoco.cs │ │ │ ├── BaseMemento.cs │ │ │ ├── IEventProvider.cs │ │ │ └── AggregateRoot.cs │ │ ├── Events │ │ │ ├── IHandle.cs │ │ │ ├── IEventHandler.cs │ │ │ ├── IEvent.cs │ │ │ └── Event.cs │ │ └── Storage │ │ │ ├── IRepository.cs │ │ │ ├── IOriginator.cs │ │ │ ├── IEventStorage.cs │ │ │ └── Repository.cs │ └── Repository │ │ ├── ICountRepository.cs │ │ ├── IDeleteRepository.cs │ │ ├── IReadRepository.cs │ │ ├── IUpdateRepository.cs │ │ ├── Async │ │ ├── IDeleteRepository.cs │ │ ├── IUpdateRepository.cs │ │ └── ICreateRepository.cs │ │ ├── ICreateRepository.cs │ │ ├── IPageableRepository.cs │ │ └── IQueryableRepository.cs ├── Crucial.Framework.csproj.user ├── Enums │ └── SortOrder.cs ├── Attributes │ └── AllowCrossSiteJsonAttribute.cs ├── packages.config ├── App.config ├── Threading │ └── NamedLocker.cs ├── Interceptors │ └── PerformanceInterceptor.cs ├── Properties │ └── AssemblyInfo.cs └── Logging │ └── ILogger.cs ├── Crucial.Services ├── Interfaces │ ├── IQuestionManager.cs │ └── ICategoryManager.cs ├── app.config ├── ServiceEntities │ ├── Category.cs │ └── Question.cs ├── Mappers │ ├── CategoryMapper.cs │ └── QuestionMapper.cs ├── Properties │ └── AssemblyInfo.cs └── QuestionManager.cs └── Crucial.Tests ├── packages.config ├── NLog.config ├── App.config ├── Properties └── AssemblyInfo.cs └── Bootstrap └── Dependencies.cs /.nuget/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andyhoyle/Crucial-CQRS/HEAD/.nuget/NuGet.exe -------------------------------------------------------------------------------- /Crucial-CQRS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andyhoyle/Crucial-CQRS/HEAD/Crucial-CQRS.png -------------------------------------------------------------------------------- /API/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="API.WebApiApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /Web/Web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Crucial.Qyz/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Web/templates/settings.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |

Hello, {{a}}!

4 |
-------------------------------------------------------------------------------- /Crucial.EventStore/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Crucial.Providers/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Crucial.Framework/Data/EntityFramework/T4Templating/EF.Reverse.POCO.ttinclude: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andyhoyle/Crucial-CQRS/HEAD/Crucial.Framework/Data/EntityFramework/T4Templating/EF.Reverse.POCO.ttinclude -------------------------------------------------------------------------------- /Crucial.Framework/Data/EntityFramework/T4Templating/EF.Reverse.POCO.Core.ttinclude: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andyhoyle/Crucial-CQRS/HEAD/Crucial.Framework/Data/EntityFramework/T4Templating/EF.Reverse.POCO.Core.ttinclude -------------------------------------------------------------------------------- /Crucial.Framework/Entities/EntityBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Crucial.Framework.BaseEntities 7 | { 8 | public class EntityBase 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Crucial.Framework/IoC/IAutoRegister.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Crucial.Framework.IoC 7 | { 8 | public interface IAutoRegister 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Web/js/settings/controller.js: -------------------------------------------------------------------------------- 1 | (function(angular) { 2 | 'use strict'; 3 | 4 | var module = angular.module('Qyz.Settings'); 5 | 6 | module.controller('SettingsController', function($scope) { 7 | $scope.a = 2; 8 | }) 9 | 10 | })(window.angular); -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Utils/IStateHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | namespace Crucial.Framework.DesignPatterns.CQRS.Utils 4 | { 5 | public interface IStateHelper 6 | { 7 | Task RestoreState(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Web/readme.txt: -------------------------------------------------------------------------------- 1 | 1st time only: 2 | --------------------- 3 | npm install -g grunt-cli 4 | npm install -g bower 5 | 6 | this project: 7 | --------------------- 8 | npm install grunt 9 | npm install grunt-contrib-connect --save-dev 10 | bower install 11 | grunt connect 12 | -------------------------------------------------------------------------------- /Crucial.Framework/Crucial.Framework.csproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ShowAllFiles 5 | 6 | -------------------------------------------------------------------------------- /API/Models/User.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace API.Models 7 | { 8 | public class User 9 | { 10 | string Email { get; set; } 11 | 12 | string Name { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /Crucial.Framework/Entities/ServiceEntityBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Crucial.Framework.BaseEntities 7 | { 8 | public abstract class ServiceEntityBase : EntityBase 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Web/js/layout.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('polymer-ready', function() { 2 | var navicon = document.getElementById('navicon'); 3 | var drawerPanel = document.getElementById('drawerPanel'); 4 | navicon.addEventListener('click', function() { 5 | drawerPanel.togglePanel(); 6 | }); 7 | }); -------------------------------------------------------------------------------- /API/Models/Category.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.Entities; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Web; 6 | 7 | namespace API.Models 8 | { 9 | public class Category : CqrsViewModel 10 | { 11 | public string Name { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /Crucial.Framework/Entities/ProviderEntityBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Crucial.Framework.BaseEntities 7 | { 8 | public abstract class ProviderEntityBase : EntityBase 9 | { 10 | 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Crucial.Framework/Enums/SortOrder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Crucial.Framework.Enums 7 | { 8 | public enum SortOrder 9 | { 10 | Ascending, 11 | Descending, 12 | Any 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Web/templates/menu.html: -------------------------------------------------------------------------------- 1 | 2 | Menu 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /API/Models/Question.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.Entities; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Web; 6 | 7 | namespace API.Models 8 | { 9 | public class Question : CqrsViewModel 10 | { 11 | public string QuestionText { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Commands/ICommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Crucial.Framework.DesignPatterns.CQRS.Commands 8 | { 9 | public interface ICommand 10 | { 11 | int Id { get; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Exceptions/UnregisteredDomainEventException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Crucial.Framework.DesignPatterns.CQRS.Exceptions 4 | { 5 | public class UnregisteredDomainEventException : Exception 6 | { 7 | public UnregisteredDomainEventException(string message) : base(message) { } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Exceptions/UnregisteredDomainCommandException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Crucial.Framework.DesignPatterns.CQRS.Exceptions 4 | { 5 | public class UnregisteredDomainCommandException : Exception 6 | { 7 | public UnregisteredDomainCommandException(string message) : base(message) { } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Messaging/ICommandBus.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Crucial.Framework.DesignPatterns.CQRS.Commands; 3 | using System.Threading.Tasks; 4 | 5 | namespace Crucial.Framework.DesignPatterns.CQRS.Messaging 6 | { 7 | public interface ICommandBus 8 | { 9 | Task Send(T command) where T : Command; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Crucial.Providers/Filesystem/Entities/Enums/FilesystemPathSeparator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Crucial.Providers.Filesystem.Entities.Enums 7 | { 8 | public enum FilesystemPathSeparator 9 | { 10 | ForwardSlash = 0, 11 | BackSlash = 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /API/Mappers/QuestionToQuestionMapper.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.Entities.Mappers; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Web; 6 | 7 | namespace API.Mappers 8 | { 9 | public class QuestionToQuestionMapper : ServiceEntityMapper 10 | { 11 | } 12 | } -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Domain/BasePoco.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Crucial.Framework.DesignPatterns.CQRS.Domain 8 | { 9 | public abstract class BasePoco 10 | { 11 | public int Version { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /API/Mappers/CategoryMapper.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.Entities.Mappers; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Web; 6 | 7 | namespace API.Mappers 8 | { 9 | public class CategoryToCategoryMapper : ServiceEntityMapper 10 | { 11 | 12 | } 13 | } -------------------------------------------------------------------------------- /Crucial.Framework/Data/EntityFramework/IDatabaseContextProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Entity; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace Crucial.Framework.Data.EntityFramework 8 | { 9 | public interface IDatabaseContextProvider 10 | { 11 | DbContext DbContext { get; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Events/IHandle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Crucial.Framework.DesignPatterns.CQRS.Events 8 | { 9 | public interface IHandle where TEvent : Event 10 | { 11 | void Handle(TEvent e); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Crucial.Providers/Filesystem/Entities/DirectoryUpdate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Crucial.Providers.Filesystem.Entities 7 | { 8 | public class DirectoryUpdate : Directory 9 | { 10 | public string RenameTo { get; set; } 11 | public List MoveTo { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Events/IEventHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Crucial.Framework.DesignPatterns.CQRS.Events 8 | { 9 | public interface IEventHandler where TEvent : Event 10 | { 11 | Task Handle(TEvent handle); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Exceptions/ConcurrencyException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Crucial.Framework.DesignPatterns.CQRS.Exceptions 7 | { 8 | public class ConcurrencyException : Exception 9 | { 10 | public ConcurrencyException(string message) : base(message) { } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Commands/ICommandHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Crucial.Framework.DesignPatterns.CQRS.Commands 8 | { 9 | public interface ICommandHandler where TCommand : Command 10 | { 11 | Task Execute(TCommand command); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Crucial.Qyz/Domain/QuestionType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Crucial.Qyz.Domain 8 | { 9 | public enum QuestionType 10 | { 11 | SingleTextAnswer, 12 | NumericAnswer, 13 | MultipleChoice, 14 | PictureQuestion, 15 | TreasureHunt 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Exceptions/AggregateNotFoundException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Crucial.Framework.DesignPatterns.CQRS.Exceptions 7 | { 8 | public class AggregateNotFoundException : Exception 9 | { 10 | public AggregateNotFoundException(string message) : base(message) { } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Crucial.Services/Interfaces/IQuestionManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | namespace Crucial.Services.Managers.Interfaces 5 | { 6 | public interface IQuestionManager 7 | { 8 | Task> GetQuestions(); 9 | 10 | Task GetQuestion(int questionId); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Domain/BaseMemento.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Crucial.Framework.DesignPatterns.CQRS.Domain 8 | { 9 | [Serializable] 10 | public class BaseMemento 11 | { 12 | public int Id { get; set; } 13 | public int Version { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/Repository/ICountRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ServiceModel; 6 | 7 | namespace Crucial.Framework.DesignPatterns.Repository 8 | { 9 | [ServiceContract] 10 | public interface ICountRepository 11 | { 12 | [OperationContract] 13 | int Count(TKey o); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Utils/ICommandHandlerFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Crucial.Framework.DesignPatterns.CQRS.Commands; 6 | 7 | namespace Crucial.Framework.DesignPatterns.CQRS.Utils 8 | { 9 | public interface ICommandHandlerFactory 10 | { 11 | ICommandHandler GetHandler() where T : Command; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/Repository/IDeleteRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ServiceModel; 6 | 7 | namespace Crucial.Framework.DesignPatterns.Repository 8 | { 9 | [ServiceContract] 10 | public interface IDeleteRepository 11 | { 12 | [OperationContract] 13 | bool Delete(TKey id); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Domain/IEventProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Crucial.Framework.DesignPatterns.CQRS.Events; 3 | using System.Threading.Tasks; 4 | 5 | namespace Crucial.Framework.DesignPatterns.CQRS.Domain 6 | { 7 | public interface IEventProvider 8 | { 9 | void LoadsFromHistory(IEnumerable history); 10 | IEnumerable GetUncommittedChanges(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Storage/IRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Crucial.Framework.DesignPatterns.CQRS.Domain; 3 | using System.Threading.Tasks; 4 | 5 | namespace Crucial.Framework.DesignPatterns.CQRS.Storage 6 | { 7 | public interface IRepository where T : AggregateRoot, new() 8 | { 9 | void Save(AggregateRoot aggregate, int expectedVersion); 10 | Task GetById(int id); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Messaging/IEventBus.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Crucial.Framework.DesignPatterns.CQRS.Events; 3 | using System.Collections.Generic; 4 | using System.Threading.Tasks; 5 | 6 | namespace Crucial.Framework.DesignPatterns.CQRS.Messaging 7 | { 8 | public interface IEventBus 9 | { 10 | Task Publish(T @event) where T : Event; 11 | Task Replay(IEnumerable eventList); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Web/css/layout.css: -------------------------------------------------------------------------------- 1 | .face { 2 | border-radius: 30px; 3 | border: 1px solid #ddd; 4 | width: 48px; 5 | margin: 16px; 6 | } 7 | md-icon { 8 | margin: auto; 9 | background-repeat: no-repeat no-repeat; 10 | display: inline-block; 11 | vertical-align: middle; 12 | fill: currentcolor; 13 | height: 24px; 14 | width: 24px; 15 | } 16 | .docs-menu-icon { 17 | background: none; 18 | border: none; 19 | margin-right: 16px; 20 | padding: 0; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Events/IEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Crucial.Framework.DesignPatterns.CQRS.Events 8 | { 9 | public interface IEvent 10 | { 11 | int Version { get; set; } 12 | int AggregateId { get; set; } 13 | int Id { get; set; } 14 | DateTime Timestamp { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Storage/IOriginator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Crucial.Framework.DesignPatterns.CQRS.Domain; 7 | 8 | namespace Crucial.Framework.DesignPatterns.CQRS.Storage 9 | { 10 | public interface IOriginator 11 | { 12 | BaseMemento GetMemento(); 13 | void SetMemento(BaseMemento memento); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Crucial.Framework/Data/EntityFramework/IDbContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Entity; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Crucial.Framework.Data.EntityFramework 9 | { 10 | public interface IDbContext where TEntity : class 11 | { 12 | System.Data.Entity.Database Database { get; } 13 | 14 | IDbSet Set(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Crucial.Providers/Identity/Data/Identity.cs: -------------------------------------------------------------------------------- 1 | 2 | 3 | // This file was automatically generated. 4 | // Do not make changes directly to this file - edit the template instead. 5 | // 6 | // The following connection settings were used to generate this file 7 | // 8 | // Configuration file: "API\Web.config" 9 | // Connection String Name: "DefaultConnection" 10 | // Connection String: "Data Source=(local);Initial Catalog=QueryDB;Integrated Security=True" 11 | 12 | -------------------------------------------------------------------------------- /Crucial.Providers/Identity/Interfaces/IIdentityContextProvider.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Providers.Identity.Data; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Data.Entity; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Crucial.Providers.Identity.Interfaces 10 | { 11 | public interface IIdentityContextProvider : Crucial.Framework.Data.EntityFramework.IDatabaseContextProvider 12 | { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Crucial.EventStore/Mappers/AggregateMapper.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Domain; 2 | using Crucial.Framework.Entities.Mappers; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Crucial.EventStore.Mappers 10 | { 11 | public class AggregateMapper : ProviderEntityMapper 12 | { 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/Repository/IReadRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ServiceModel; 6 | 7 | namespace Crucial.Framework.DesignPatterns.Repository 8 | { 9 | [ServiceContract] 10 | public interface IReadRepository where TOutput : BaseEntities.ProviderEntityBase 11 | { 12 | [OperationContract] 13 | TOutput Get(TKey id); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/Repository/IUpdateRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ServiceModel; 6 | 7 | namespace Crucial.Framework.DesignPatterns.Repository 8 | { 9 | [ServiceContract] 10 | public interface IUpdateRepository where TInput : BaseEntities.ProviderEntityBase 11 | { 12 | [OperationContract] 13 | bool Update(TInput o); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Crucial.Providers/Identity/Entities/Identity.cs: -------------------------------------------------------------------------------- 1 | 2 | 3 | // This file was automatically generated. 4 | // Do not make changes directly to this file - edit the template instead. 5 | // 6 | // The following connection settings were used to generate this file 7 | // 8 | // Configuration file: "API\Web.config" 9 | // Connection String Name: "DefaultConnection" 10 | // Connection String: "Data Source=(local);Initial Catalog=QueryDB;Integrated Security=True" 11 | 12 | -------------------------------------------------------------------------------- /Crucial.Qyz/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/Repository/Async/IDeleteRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ServiceModel; 6 | using System.Threading.Tasks; 7 | 8 | namespace Crucial.Framework.DesignPatterns.Repository.Async 9 | { 10 | [ServiceContract] 11 | public interface IDeleteRepositoryAsync 12 | { 13 | [OperationContract] 14 | Task Delete(TKey id); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/Repository/ICreateRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ServiceModel; 6 | 7 | namespace Crucial.Framework.DesignPatterns.Repository 8 | { 9 | [ServiceContract] 10 | public interface ICreateRepository where TInput : BaseEntities.ProviderEntityBase 11 | { 12 | [OperationContract] 13 | TKey Create(TInput o); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Crucial.Services/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Web/js/settings/module.js: -------------------------------------------------------------------------------- 1 | (function (angular) { 2 | 'use strict'; 3 | 4 | var module = angular.module('Qyz.Settings', ['ngRoute']); 5 | 6 | module.config(['$routeProvider', function ($routeProvider) { 7 | $routeProvider 8 | .when('/settings', { 9 | controller: 'SettingsController', 10 | templateUrl: 'templates/settings.html', 11 | title: 'Settings' 12 | }); 13 | }]); 14 | 15 | })(window.angular); -------------------------------------------------------------------------------- /Crucial.Framework/Entities/CqrsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Crucial.Framework.Entities 8 | { 9 | public abstract class CqrsViewModel 10 | { 11 | public int Id { get; set; } 12 | public int Version { get; set; } 13 | 14 | public DateTime CreatedDate { get; set; } 15 | 16 | public DateTime? ModifiedDate { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Crucial.Qyz/Commands/Question/QuestionDeleteCommand.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Commands; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Crucial.Qyz.Commands.Question 9 | { 10 | public class QuestionDeleteCommand : Command 11 | { 12 | public QuestionDeleteCommand(int id, int version) 13 | : base(id, version) 14 | { 15 | 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Crucial.Framework/Attributes/AllowCrossSiteJsonAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Http.Filters; 3 | 4 | public class AllowCrossSiteJsonAttribute : ActionFilterAttribute 5 | { 6 | public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) 7 | { 8 | if (actionExecutedContext.Response != null) 9 | actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Origin", "*"); 10 | 11 | base.OnActionExecuted(actionExecutedContext); 12 | } 13 | } -------------------------------------------------------------------------------- /Crucial.Qyz/Commands/UserCategory/UserCategoryDeleteCommand.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Commands; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Crucial.Qyz.Commands.UserCategory 9 | { 10 | public class UserCategoryDeleteCommand : Command 11 | { 12 | public UserCategoryDeleteCommand(int id, int version) : base(id,version) 13 | { 14 | 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Events/Event.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Crucial.Framework.DesignPatterns.CQRS.Events 8 | { 9 | [Serializable] 10 | public class Event : IEvent 11 | { 12 | public int Version { get; set; } 13 | public int AggregateId { get; set; } 14 | public int Id { get; set; } 15 | public DateTime Timestamp { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /Web/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | grunt.loadNpmTasks('grunt-contrib-connect'); 3 | 4 | grunt.initConfig({ 5 | connect: { 6 | server: { 7 | options: { 8 | port: 8000, 9 | base: { 10 | path: '.', 11 | options: { 12 | index: 'index.html', 13 | maxAge: 300000 14 | } 15 | }, 16 | livereload: true, 17 | keepalive: true 18 | } 19 | } 20 | } 21 | }); 22 | }; -------------------------------------------------------------------------------- /Crucial.Tests/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/Repository/Async/IUpdateRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ServiceModel; 6 | using System.Threading.Tasks; 7 | 8 | namespace Crucial.Framework.DesignPatterns.Repository.Async 9 | { 10 | [ServiceContract] 11 | public interface IUpdateRepositoryAsync where TInput : BaseEntities.ProviderEntityBase 12 | { 13 | [OperationContract] 14 | Task Update(TInput o); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/Repository/Async/ICreateRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ServiceModel; 6 | using System.Threading.Tasks; 7 | 8 | namespace Crucial.Framework.DesignPatterns.Repository.Async 9 | { 10 | [ServiceContract] 11 | public interface ICreateRepositoryAsync where TInput : BaseEntities.ProviderEntityBase 12 | { 13 | [OperationContract] 14 | Task Create(TInput o); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Crucial-CQRS", 3 | "version": "0.0.1", 4 | "description": "Simple quiz application to demo AngularJS, SignalR, and CQRS and Event Sourcing", 5 | "main": "Gruntfile.js", 6 | "dependencies": { 7 | "grunt": "^0.4.5", 8 | "bower": "^1.3.12", 9 | "grunt-contrib-connect": "^0.9.0" 10 | }, 11 | "devDependencies": {}, 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1" 14 | }, 15 | "author": "Andy Hoyle (hoyle1980@gmail.com)", 16 | "license": "MIT" 17 | } 18 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Utils/IEventHandlerFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Crucial.Framework.DesignPatterns.CQRS.Events; 6 | using System.Collections; 7 | 8 | namespace Crucial.Framework.DesignPatterns.CQRS.Utils 9 | { 10 | public interface IEventHandlerFactory 11 | { 12 | IEnumerable> GetHandlers() where T : Event; 13 | 14 | IEnumerable> GetHandlers(T type) where T : Event; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Crucial.Providers/Identity/UserRepository.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.Data.EntityFramework; 2 | using Crucial.Framework.DesignPatterns.Repository; 3 | using Crucial.Providers.Identity.Data; 4 | using Crucial.Providers.Identity.Interfaces; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | 10 | namespace Crucial.Providers.Identity 11 | { 12 | public class UserRepository : BaseRepository, Interfaces.IUserRepository 13 | { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Web/vwd.webinfo: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Crucial.Services/Interfaces/ICategoryManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Crucial.Services.Managers.Interfaces 8 | { 9 | public interface ICategoryManager 10 | { 11 | Task> GetUserCategories(); 12 | 13 | Task GetUserCategory(int categoryId); 14 | 15 | Task> GetQuestionsInCategory(int id); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Web/js/category/module.js: -------------------------------------------------------------------------------- 1 | var module = angular.module('Qyz.Category', ['ngRoute']); 2 | 3 | module.config(['$routeProvider', function ($routeProvider) { 4 | $routeProvider 5 | .when('/', { 6 | controller: 'CategoryController', 7 | templateUrl: 'templates/category/category.html', 8 | title: 'Categories' 9 | }) 10 | .when('/categories/new', { 11 | controller: 'CategoryController', 12 | templateUrl: 'templates/category/new.html', 13 | title: 'Categories' 14 | }); 15 | }]); -------------------------------------------------------------------------------- /Web/js/question/module.js: -------------------------------------------------------------------------------- 1 | var module = angular.module('Qyz.Question', ['ngRoute']); 2 | 3 | module.config(['$routeProvider', function ($routeProvider) { 4 | $routeProvider 5 | .when('/questions', { 6 | controller: 'QuestionController', 7 | templateUrl: 'templates/question/question.html', 8 | title: 'Questions' 9 | }) 10 | .when('/questions/new', { 11 | controller: 'QuestionController', 12 | templateUrl: 'templates/question/new.html', 13 | title: 'Questions' 14 | }); 15 | }]); -------------------------------------------------------------------------------- /Crucial.Qyz/Events/Question/QuestionDeletedEvent.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Events; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace Crucial.Qyz.Events 8 | { 9 | [Serializable] 10 | public class QuestionDeletedEvent : Event 11 | { 12 | public QuestionDeletedEvent(int aggregateId, int version, DateTime createdDate) 13 | { 14 | Timestamp = createdDate; 15 | AggregateId = aggregateId; 16 | Version = version; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Crucial.Services/ServiceEntities/Category.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Crucial.Services.ServiceEntities 8 | { 9 | public class Category : Framework.BaseEntities.ServiceEntityBase 10 | { 11 | public int Id { get; set; } 12 | public string Name { get; set; } 13 | public int Version { get; set; } 14 | public DateTime CreatedDate { get; set; } 15 | 16 | public DateTime? ModifiedDate { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Crucial.Services/ServiceEntities/Question.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Crucial.Services.ServiceEntities 8 | { 9 | public class Question : Framework.BaseEntities.ServiceEntityBase 10 | { 11 | public int Id { get; set; } 12 | public int Version { get; set; } 13 | public string QuestionText { get; set; } 14 | public DateTime CreatedDate { get; set; } 15 | public DateTime? ModifiedDate { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Crucial.Providers/Filesystem/Entities/Directory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Crucial.Providers.Filesystem.Entities 7 | { 8 | public class Directory : Framework.BaseEntities.ProviderEntityBase 9 | { 10 | public string Name { get; set; } 11 | public List PathParts { get; set; } 12 | public Enums.FilesystemPathSeparator Seperator { get; set; } 13 | public bool IsEmpty { get; set; } 14 | public string DriveLetter { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Crucial.Qyz/Commands/UserCategory/UserCategoryCreateCommand.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Commands; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Crucial.Qyz.Commands.UserCategory 9 | { 10 | public class UserCategoryCreateCommand : Command 11 | { 12 | public string Name { get; private set; } 13 | 14 | public UserCategoryCreateCommand(string name) : base (0, -1) 15 | { 16 | Name = name; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Web/js/category/factory.js: -------------------------------------------------------------------------------- 1 | (function (angular) { 2 | 'use strict'; 3 | 4 | var module = angular.module('Qyz.Category'); 5 | 6 | module.factory('Category', ['$resource', function ($resource) { 7 | return $resource('http://localhost:41194/api/categories/:id', { id: '@Id' }, { 8 | update: { 9 | method: 'PUT', params: { id: '@Id' } 10 | }, 11 | delete: { 12 | method: 'POST', params: { id: '@Id' } 13 | } 14 | }); // Note the full endpoint address 15 | }]); 16 | 17 | })(window.angular); -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Commands/Command.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Crucial.Framework.DesignPatterns.CQRS.Commands 8 | { 9 | [Serializable] 10 | public class Command : ICommand 11 | { 12 | public int Id { get; private set; } 13 | public int Version { get; private set; } 14 | public Command(int id, int version) 15 | { 16 | Id = id; 17 | Version = version; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Crucial.Qyz/Events/UserCategory/UserCategoryDeletedEvent.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Events; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace Crucial.Qyz.Events 8 | { 9 | [Serializable] 10 | public class UserCategoryDeletedEvent : Event 11 | { 12 | public UserCategoryDeletedEvent(int aggregateId, int version, DateTime createdDate) 13 | { 14 | Timestamp = createdDate; 15 | AggregateId = aggregateId; 16 | Version = version; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Crucial.Providers/Filesystem/Interfaces/IDirectoryRepository.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.Repository; 2 | using Crucial.Providers.Filesystem.Entities; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace Crucial.Providers.Filesystem.Interfaces 9 | { 10 | public interface IDirectoryRepository : 11 | ICreateRepository, 12 | IUpdateRepository, 13 | IDeleteRepository, 14 | IReadRepository 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /API/NLog.config: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Crucial.Framework/Data/EntityFramework/DatabaseContextProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Data.Entity; 2 | 3 | 4 | namespace Crucial.Framework.Data.EntityFramework 5 | { 6 | public interface IContextProvider 7 | { 8 | T DbContext { get; } 9 | } 10 | 11 | public class ContextProvider : IContextProvider 12 | { 13 | public T DbContext 14 | { 15 | get 16 | { 17 | var ctx = Crucial.Framework.IoC.StructureMapProvider.DependencyResolver.Container.GetInstance(); 18 | return ctx; 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Utils/StructureMapCommandHandlerFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Crucial.Framework.DesignPatterns.CQRS.Commands; 6 | 7 | namespace Crucial.Framework.DesignPatterns.CQRS.Utils 8 | { 9 | public class StructureMapCommandHandlerFactory : ICommandHandlerFactory 10 | { 11 | public ICommandHandler GetHandler() where T : Command 12 | { 13 | return Crucial.Framework.IoC.StructureMapProvider.DependencyResolver.Container.GetInstance>(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Crucial.Qyz/Commands/UserCategory/UserCategoryNameChangeCommand.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Commands; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Crucial.Qyz.Commands.UserCategory 9 | { 10 | public class UserCategoryNameChangeCommand : Command 11 | { 12 | public string Name { get; private set; } 13 | 14 | public UserCategoryNameChangeCommand(int id, string name, int version) 15 | : base(id, version) 16 | { 17 | Name = name; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Crucial.Qyz/Domain/Mementos/UserCategoryMemento.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Domain; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Crucial.Qyz.Domain.Mementos 9 | { 10 | [Serializable] 11 | public class UserCategoryMemento : BaseMemento 12 | { 13 | public string Name { get; set; } 14 | 15 | public UserCategoryMemento(int id, string name, int version) 16 | { 17 | Id = id; 18 | Name = name; 19 | Version = version; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Crucial.Qyz/Commands/Question/QuestionTextChangeCommand.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Commands; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Crucial.Qyz.Commands.Question 9 | { 10 | public class QuestionTextChangeCommand : Command 11 | { 12 | public string QuestionText { get; private set; } 13 | 14 | public QuestionTextChangeCommand(int id, string question, int version) 15 | : base(id, version) 16 | { 17 | QuestionText = question; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Crucial.Qyz/Domain/Mementos/Question.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Domain; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Crucial.Qyz.Domain.Mementos 9 | { 10 | [Serializable] 11 | public class QuestionMemento : BaseMemento 12 | { 13 | public string QuestionText { get; set; } 14 | 15 | public QuestionMemento(int id, string question, int version) 16 | { 17 | Id = id; 18 | QuestionText = question; 19 | Version = version; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Crucial.Tests/NLog.config: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Crucial.Qyz/Commands/UserCategory/AddQuestionToCategoryCommand.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Commands; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Crucial.Qyz.Commands.UserCategory 9 | { 10 | public class AddQuestionToCategoryCommand : Command 11 | { 12 | public int QuestionId { get; private set; } 13 | 14 | public AddQuestionToCategoryCommand(int questionId, int id, int version) 15 | : base(id, version) 16 | { 17 | QuestionId = questionId; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Crucial.Providers/Filesystem/Exceptions/GeneralException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Crucial.Providers.Filesystem.Exceptions 7 | { 8 | class GeneralException : Exception 9 | { 10 | Object _object; 11 | Type _type; 12 | 13 | public GeneralException(Object o, Type t) 14 | { 15 | _object = o; 16 | _type = t; 17 | } 18 | 19 | public string Object 20 | { 21 | get 22 | { 23 | return Object; 24 | } 25 | } 26 | 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Crucial.Providers/Identity/Interfaces/IUserRepository.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.Repository; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace Crucial.Providers.Identity.Interfaces 8 | { 9 | public interface IUserRepository : 10 | IQueryableRepository, 11 | IUpdateRepository, 12 | ICreateRepository, 13 | Framework.IoC.IAutoRegister 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Utils/Converter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Crucial.Framework.DesignPatterns.CQRS.Utils 7 | { 8 | public static class Converter 9 | { 10 | public static Action Convert(Action myActionT) 11 | { 12 | if (myActionT == null) return null; 13 | return new Action(o => myActionT((T)o)); 14 | } 15 | 16 | public static dynamic ChangeTo(dynamic source, Type dest) 17 | { 18 | 19 | return System.Convert.ChangeType(source, dest); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Crucial.Qyz/Events/UserCategory/UserCategoryCreatedEvent.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Events; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Crucial.Qyz.Events 9 | { 10 | [Serializable] 11 | public class UserCategoryCreatedEvent : Event 12 | { 13 | public string Name { get; internal set; } 14 | 15 | public UserCategoryCreatedEvent(int aggregateId, string name, DateTime createdDate) 16 | { 17 | Timestamp = createdDate; 18 | AggregateId = aggregateId; 19 | Name = name; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Crucial.Qyz/Events/UserCategory/UserCategoryNameChangedEvent.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Events; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace Crucial.Qyz.Events 8 | { 9 | [Serializable] 10 | public class UserCategoryNameChangedEvent : Event 11 | { 12 | public string Name { get; internal set; } 13 | public UserCategoryNameChangedEvent(int aggregateId, string name, int version, DateTime createdDate) 14 | { 15 | Timestamp = createdDate; 16 | AggregateId = aggregateId; 17 | Name = name; 18 | Version = version; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/Repository/IPageableRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ServiceModel; 6 | 7 | namespace Crucial.Framework.DesignPatterns.Repository 8 | { 9 | [ServiceContract] 10 | public interface IPageableRepository 11 | where TInput : Framework.BaseEntities.ProviderEntityBase 12 | //causes error 13 | //TODO: Fix this 14 | //where TOutput : Crucial.Framework.BaseEntities.IPageable 15 | { 16 | [OperationContract] 17 | TOutput GetPage(TInput postPager); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Crucial.Qyz/Events/Question/QuestionTextChangedEvent.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Events; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace Crucial.Qyz.Events 8 | { 9 | [Serializable] 10 | public class QuestionTextChangedEvent : Event 11 | { 12 | public string Question { get; internal set; } 13 | public QuestionTextChangedEvent(int aggregateId, string questionText, int version, DateTime createdDate) 14 | { 15 | Timestamp = createdDate; 16 | AggregateId = aggregateId; 17 | Question = questionText; 18 | Version = version; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Storage/IEventStorage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Crucial.Framework.DesignPatterns.CQRS.Domain; 7 | using Crucial.Framework.DesignPatterns.CQRS.Events; 8 | 9 | namespace Crucial.Framework.DesignPatterns.CQRS.Storage 10 | { 11 | public interface IEventStorage 12 | { 13 | Task> GetEvents(int aggregateId); 14 | Task Save(AggregateRoot aggregate); 15 | Task GetMemento(int aggregateId) where T : BaseMemento; 16 | Task SaveMemento(BaseMemento memento); 17 | Task> GetAllEvents(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Crucial.Providers/Filesystem/Exceptions/PathNotFoundException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Crucial.Providers.Filesystem.Entities.Extensions; 6 | 7 | namespace Crucial.Providers.Filesystem.Exceptions 8 | { 9 | public class PathNotFoundException : Exception 10 | { 11 | string _Path; 12 | 13 | public PathNotFoundException(Entities.Directory d) 14 | { 15 | _Path = d.BuildPath(); 16 | } 17 | 18 | public string Path 19 | { 20 | get 21 | { 22 | return _Path; 23 | } 24 | } 25 | 26 | //Todo: ctor for files instead of directories 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Crucial.Qyz/Events/UserCategory/QuestionAddedToCategoryEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Crucial.Framework.DesignPatterns.CQRS.Events; 7 | 8 | namespace Crucial.Qyz.Events 9 | { 10 | 11 | [Serializable] 12 | public class QuestionAddedToCategoryEvent : Event 13 | { 14 | public int QuestionId { get; internal set; } 15 | public QuestionAddedToCategoryEvent(int questionId, int aggregateId, int version, DateTime createdDate) 16 | { 17 | Timestamp = createdDate; 18 | AggregateId = aggregateId; 19 | QuestionId = questionId; 20 | Version = version; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Crucial.Providers/Filesystem/Entities/Extensions/DirectoryExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Crucial.Providers.Filesystem.Entities.Extensions 7 | { 8 | public static class DirectoryExtensions 9 | { 10 | public static string BuildPath(this Directory d) 11 | { 12 | string path = String.Join(d.Seperator.ToChar().ToString(), d.PathParts.ToArray()); 13 | return String.Format("{0}:{1}{2}", d.DriveLetter, d.Seperator.ToChar(), path); 14 | } 15 | 16 | public static char ToChar(this Enums.FilesystemPathSeparator s) 17 | { 18 | return s == Enums.FilesystemPathSeparator.BackSlash ? '/' : '\\'; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Web/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Crucial-CQRS", 3 | "version": "0.0.1", 4 | "homepage": "https://github.com/andyhoyle/Crucial-CQRS", 5 | "authors": [ 6 | "Andy Hoyle hoyle1980@gmail.com" 7 | ], 8 | "description": "Simple quiz application to demo AngularJS, SignalR, and CQRS and Event Sourcing", 9 | "main": "index.html", 10 | "license": "MIT", 11 | "private": true, 12 | "ignore": [ 13 | "**/.*", 14 | "node_modules", 15 | "bower_components", 16 | "test", 17 | "tests" 18 | ], 19 | "dependencies": { 20 | "angular-animate": "1.3.x", 21 | "angular-material": "~0.8.2", 22 | "angular-route": "~1.3.14", 23 | "angular-resource": "~1.3.14", 24 | "angular-material-icons": "~0.4.0", 25 | "svg-morpheus": "~0.1.8", 26 | "moment": "~2.9.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Web/js/utils/utils.js: -------------------------------------------------------------------------------- 1 | var utils = angular.module('Utils', []); 2 | 3 | utils.service('UtilsService', function () { 4 | var outputLog = function (message, coll) { 5 | console.log(message); 6 | angular.forEach(coll, function (u, i) { 7 | console.log(i, u); 8 | }); 9 | }; 10 | 11 | var angularIndexOf = function (arr, obj) { 12 | for (var i = 0; i < arr.length; i++) { 13 | if (arr[i].Id === obj.Id) { 14 | return i; 15 | } 16 | }; 17 | return -1; 18 | }; 19 | 20 | return { 21 | log: outputLog, 22 | indexOf: angularIndexOf 23 | }; 24 | }); 25 | 26 | utils.filter('fromNow', function () { 27 | return function (date) { 28 | return moment(date).fromNow(); 29 | } 30 | }); -------------------------------------------------------------------------------- /Web/templates/category/new.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

{{title}}

4 | 5 |
6 | 7 | 8 | 9 | 10 |
11 |
12 | 13 |
14 |
15 | 16 | 17 | Cancel 18 | 19 | 20 | Save 21 | 22 |
23 |
24 | -------------------------------------------------------------------------------- /Web/templates/question/new.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

{{title}}

4 | 5 |
6 | 7 | 8 | 9 | 10 |
11 |
12 | 13 |
14 |
15 | 16 | 17 | Cancel 18 | 19 | 20 | Save 21 | 22 |
23 |
24 | -------------------------------------------------------------------------------- /Crucial.Providers/EventStore/Entities/BaseMemento.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.ComponentModel.DataAnnotations.Schema; 11 | using System.Data.Common; 12 | 13 | namespace Crucial.Providers.EventStore.Entities 14 | { 15 | // BaseMementoes 16 | public class BaseMemento : Crucial.Framework.BaseEntities.ProviderEntityBase 17 | { 18 | public int Id { get; set; } // Id (Primary key) 19 | public int Version { get; set; } // Version (Primary key) 20 | public byte[] Data { get; set; } // Data 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /Web/js/question/factory.js: -------------------------------------------------------------------------------- 1 | (function (angular) { 2 | 'use strict'; 3 | 4 | var module = angular.module('Qyz.Question'); 5 | 6 | module.factory('Question', ['$resource', function ($resource) { 7 | return $resource('http://localhost:41194/api/questions/:id', 8 | { id: '@Id' }, 9 | { 10 | update: { 11 | method: 'PUT', params: { id: '@Id' } 12 | }, 13 | delete: { 14 | method: 'POST', params: { id: '@Id' } 15 | } 16 | } 17 | ); // Note the full endpoint address 18 | }]); 19 | 20 | module.factory('QuestionActions', function($resource) { 21 | return $resource('http://localhost:41194/api/questions/:id/:action/:actionId', { id: '@Id', action: '@action', actionId: '@actionId' }); 22 | }); 23 | 24 | })(window.angular); -------------------------------------------------------------------------------- /Crucial.Providers/EventStore/Entities/AggregateRoot.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.ComponentModel.DataAnnotations.Schema; 11 | using System.Data.Common; 12 | 13 | namespace Crucial.Providers.EventStore.Entities 14 | { 15 | // AggregateRoots 16 | public class AggregateRoot : Crucial.Framework.BaseEntities.ProviderEntityBase 17 | { 18 | public int Id { get; set; } // Id (Primary key) 19 | public int Version { get; set; } // Version 20 | public int EventVersion { get; set; } // EventVersion 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /Crucial.Framework/IoC/StructureMap/DependencyResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net.Http; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Web.Http; 8 | using System.Web.Http.Controllers; 9 | using System.Web.Http.Dispatcher; 10 | namespace Crucial.Framework.IoC.StructureMapProvider 11 | { 12 | public static class DependencyResolver 13 | { 14 | static StructureMap.Container _container; 15 | 16 | public static void Register(Action configuration) 17 | { 18 | _container = new StructureMap.Container(configuration); 19 | } 20 | 21 | public static StructureMap.Container Container 22 | { 23 | get 24 | { 25 | return _container; 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Crucial.Framework/IoC/StructureMap/ServiceActivator.cs: -------------------------------------------------------------------------------- 1 | using StructureMap; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Net.Http; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Web.Http; 9 | using System.Web.Http.Controllers; 10 | using System.Web.Http.Dispatcher; 11 | 12 | namespace Crucial.Framework.IoC.StructureMapProvider 13 | { 14 | public class ServiceActivator : IHttpControllerActivator 15 | { 16 | public ServiceActivator(HttpConfiguration configuration) { } 17 | 18 | public IHttpController Create(HttpRequestMessage request 19 | , HttpControllerDescriptor controllerDescriptor, Type controllerType) 20 | { 21 | var controller = DependencyResolver.Container.GetInstance(controllerType) as IHttpController; 22 | return controller; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Crucial.Services/Mappers/CategoryMapper.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.Entities.Mappers; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace Crucial.Services.Mappers 8 | { 9 | public class CategoryToCategoryMapper : EntityMapper 10 | { 11 | public override Providers.Questions.Entities.Category ToProviderEntity(ServiceEntities.Category source) 12 | { 13 | var target = base.ToProviderEntity(source); 14 | target.UserId = 100; 15 | return target; 16 | } 17 | 18 | public override ServiceEntities.Category ToServiceEntity(Providers.Questions.Entities.Category source) 19 | { 20 | var target = base.ToServiceEntity(source); 21 | return target; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Crucial.Providers/EventStore/Entities/Event.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.ComponentModel.DataAnnotations.Schema; 11 | using System.Data.Common; 12 | 13 | namespace Crucial.Providers.EventStore.Entities 14 | { 15 | // Event 16 | public class Event : Crucial.Framework.BaseEntities.ProviderEntityBase 17 | { 18 | public int Id { get; set; } // Id (Primary key) 19 | public int AggregateId { get; set; } // AggregateId 20 | public byte[] Data { get; set; } // Data 21 | public DateTime Timestamp { get; set; } // Timestamp 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /Crucial.Providers/Filesystem/Exceptions/DirectoryNotEmptyException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Crucial.Providers.Filesystem.Entities.Extensions; 6 | 7 | namespace Crucial.Providers.Filesystem.Exceptions 8 | { 9 | public class DirectoryNotEmptyException : ArgumentException 10 | { 11 | private Crucial.Providers.Filesystem.Entities.Directory _Directory; 12 | 13 | public DirectoryNotEmptyException(Crucial.Providers.Filesystem.Entities.Directory Directory) 14 | { 15 | _Directory = Directory; 16 | } 17 | 18 | public override string Source 19 | { 20 | get 21 | { 22 | return _Directory.BuildPath(); 23 | } 24 | set 25 | { 26 | base.Source = value; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Crucial.Qyz/Domain/Question.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Crucial.Qyz.Domain 8 | { 9 | 10 | public class QuestionWithAnswers : Question 11 | { 12 | public QuestionWithAnswers(Question question) 13 | { 14 | QuestionText = question.QuestionText; 15 | } 16 | 17 | public QuestionAnswers Answers { get; set; } 18 | } 19 | 20 | public class QuestionAnswerTypeText : QuestionAnswer 21 | { 22 | 23 | } 24 | 25 | public class QuestionAnswerTypePicture : QuestionAnswer 26 | { 27 | 28 | } 29 | 30 | public class QuestionAnswerTypeNumeric : QuestionAnswer 31 | { 32 | 33 | } 34 | 35 | public class QuestionAnswers 36 | { 37 | public Dictionary Answers { get; set; } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /Web/img/icons/ic_menu_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Utils/StructureMapEventHandlerFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using StructureMap; 5 | using Crucial.Framework.DesignPatterns.CQRS.Events; 6 | using System.Collections; 7 | 8 | namespace Crucial.Framework.DesignPatterns.CQRS.Utils 9 | { 10 | public class StructureMapEventHandlerFactory : IEventHandlerFactory 11 | { 12 | public IEnumerable> GetHandlers() where T : Event 13 | { 14 | return Crucial.Framework.IoC.StructureMapProvider.DependencyResolver.Container.GetAllInstances>(); 15 | } 16 | 17 | public IEnumerable> GetHandlers(T type) where T : Event 18 | { 19 | var handlers = Crucial.Framework.IoC.StructureMapProvider.DependencyResolver.Container.GetAllInstances>(); 20 | return handlers; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Crucial.EventStore/Mappers/EventMapper.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Events; 2 | using Crucial.Framework.Entities.Mappers; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Crucial.EventStore.Mappers 10 | { 11 | public class EventMapper : ProviderEntityMapper 12 | { 13 | public override Providers.EventStore.Entities.Event ToProviderEntity(Event source) 14 | { 15 | var target = base.ToProviderEntity(source); 16 | target.Data = DatabaseEventStorage.Serialize(source); 17 | return target; 18 | } 19 | 20 | public override Event ToAnyEntity(Providers.EventStore.Entities.Event source) 21 | { 22 | var target = DatabaseEventStorage.DeSerialize(source.Data); 23 | return target; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Crucial.Providers/Identity/Entities/AspNetUserRole.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.ComponentModel.DataAnnotations.Schema; 11 | using System.Data.Entity; 12 | 13 | namespace Crucial.Providers.Identity.Entities 14 | { 15 | // AspNetUserRoles 16 | public partial class AspNetUserRole : Crucial.Framework.BaseEntities.ProviderEntityBase 17 | { 18 | public int UserId { get; set; } // UserId (Primary key) 19 | public string RoleId { get; set; } // RoleId (Primary key) 20 | 21 | // Foreign keys 22 | public virtual AspNetUser AspNetUser { get; set; } // FK_dbo.AspNetUserRoles_dbo.AspNetUsers_UserId 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /Crucial.Services/Mappers/QuestionMapper.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.Entities.Mappers; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Crucial.Services.Mappers 9 | { 10 | public class QuestionToQuestionMapper : EntityMapper 11 | { 12 | public override Providers.Questions.Entities.Question ToProviderEntity(ServiceEntities.Question source) 13 | { 14 | var target = base.ToProviderEntity(source); 15 | target.UserId = 100; 16 | return target; 17 | } 18 | 19 | public override ServiceEntities.Question ToServiceEntity(Providers.Questions.Entities.Question source) 20 | { 21 | var target = base.ToServiceEntity(source); 22 | target.QuestionText = source.Text; 23 | return target; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Crucial.Providers/EventStore/Entities/EventStore.cs: -------------------------------------------------------------------------------- 1 | 2 | 3 | // This file was automatically generated. 4 | // Do not make changes directly to this file - edit the template instead. 5 | // 6 | // The following connection settings were used to generate this file 7 | // 8 | // Configuration file: "API\Web.config" 9 | // Connection String Name: "EventStore" 10 | // Connection String: "Data Source=(local);Initial Catalog=EventStoreDB;Integrated Security=True" 11 | 12 | // ReSharper disable RedundantUsingDirective 13 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 14 | // ReSharper disable InconsistentNaming 15 | // ReSharper disable PartialTypeWithSinglePart 16 | // ReSharper disable PartialMethodWithSinglePart 17 | // ReSharper disable RedundantNameQualifier 18 | 19 | using System; 20 | using System.Collections.Generic; 21 | using System.ComponentModel.DataAnnotations.Schema; 22 | using System.Data.Common; 23 | 24 | namespace Crucial.Providers.EventStore.Entities 25 | { 26 | } 27 | 28 | -------------------------------------------------------------------------------- /Crucial.Providers/Questions/Entities/Questions.cs: -------------------------------------------------------------------------------- 1 | 2 | 3 | // This file was automatically generated. 4 | // Do not make changes directly to this file - edit the template instead. 5 | // 6 | // The following connection settings were used to generate this file 7 | // 8 | // Configuration file: "API\Web.config" 9 | // Connection String Name: "DefaultConnection" 10 | // Connection String: "Data Source=(local);Initial Catalog=QueryDB;Integrated Security=True" 11 | 12 | // ReSharper disable RedundantUsingDirective 13 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 14 | // ReSharper disable InconsistentNaming 15 | // ReSharper disable PartialTypeWithSinglePart 16 | // ReSharper disable PartialMethodWithSinglePart 17 | // ReSharper disable RedundantNameQualifier 18 | 19 | using System; 20 | using System.Collections.Generic; 21 | using System.ComponentModel.DataAnnotations.Schema; 22 | using System.Data.Common; 23 | 24 | namespace Crucial.Providers.Questions.Entities 25 | { 26 | } 27 | 28 | -------------------------------------------------------------------------------- /Crucial.Qyz/Commands/Question/QuestionCreateCommand.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Commands; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Crucial.Qyz.Commands.Question 9 | { 10 | //public class SingleTextAnswerQuestionCreateCommand : Command 11 | //{ 12 | // public string Question { get; private set; } 13 | // public string Answer { get; private set; } 14 | 15 | // public SingleTextAnswerQuestionCreateCommand(string question, string answer) : base(0, -1) 16 | // { 17 | // Question = question; 18 | // Answer = answer; 19 | // } 20 | //} 21 | 22 | public class QuestionCreateCommand : Command 23 | { 24 | public string QuestionText { get; private set; } 25 | 26 | public QuestionCreateCommand(string question) : base(0, -1) 27 | { 28 | QuestionText = question; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Crucial.EventStore/Mappers/MementoMapper.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Domain; 2 | using Crucial.Framework.Entities.Mappers; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Crucial.EventStore.Mappers 10 | { 11 | public class MementoMapper : ProviderEntityMapper 12 | { 13 | public override Providers.EventStore.Entities.BaseMemento ToProviderEntity(BaseMemento source) 14 | { 15 | var target = base.ToProviderEntity(source); 16 | target.Data = DatabaseEventStorage.Serialize(source); 17 | return target; 18 | } 19 | 20 | public override BaseMemento ToAnyEntity(Providers.EventStore.Entities.BaseMemento source) 21 | { 22 | var target = DatabaseEventStorage.DeSerialize(source.Data); 23 | return target; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Crucial.Providers/Identity/Entities/AspNetUserLogin.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.ComponentModel.DataAnnotations.Schema; 11 | using System.Data.Entity; 12 | 13 | namespace Crucial.Providers.Identity.Entities 14 | { 15 | // AspNetUserLogins 16 | public partial class AspNetUserLogin : Crucial.Framework.BaseEntities.ProviderEntityBase 17 | { 18 | public string LoginProvider { get; set; } // LoginProvider (Primary key) 19 | public string ProviderKey { get; set; } // ProviderKey (Primary key) 20 | public int UserId { get; set; } // UserId (Primary key) 21 | 22 | // Foreign keys 23 | public virtual AspNetUser AspNetUser { get; set; } // FK_dbo.AspNetUserLogins_dbo.AspNetUsers_UserId 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Crucial.Providers/Identity/Entities/AspNetUserClaim.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.ComponentModel.DataAnnotations.Schema; 11 | using System.Data.Entity; 12 | 13 | namespace Crucial.Providers.Identity.Entities 14 | { 15 | // AspNetUserClaims 16 | public partial class AspNetUserClaim : Crucial.Framework.BaseEntities.ProviderEntityBase 17 | { 18 | public int Id { get; set; } // Id (Primary key) 19 | public int UserId { get; set; } // UserId 20 | public string ClaimType { get; set; } // ClaimType 21 | public string ClaimValue { get; set; } // ClaimValue 22 | 23 | // Foreign keys 24 | public virtual AspNetUser AspNetUser { get; set; } // FK_dbo.AspNetUserClaims_dbo.AspNetUsers_UserId 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Crucial.Providers/EventStore/Data/IEventStoreContext.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.ComponentModel.DataAnnotations.Schema; 10 | using System.Data.Entity; 11 | using System.Data.Entity.ModelConfiguration; 12 | using Crucial.Providers.EventStore.Entities; 13 | //using DatabaseGeneratedOption = System.ComponentModel.DataAnnotations.DatabaseGeneratedOption; 14 | using Crucial.Framework.Data.EntityFramework; 15 | using System.Data.Common; 16 | 17 | namespace Crucial.Providers.EventStore.Data 18 | { 19 | public interface IEventStoreContext : IDbContextAsync, IDisposable 20 | { 21 | IDbSet AggregateRoots { get; set; } // AggregateRoots 22 | IDbSet BaseMementoes { get; set; } // BaseMementoes 23 | IDbSet Events { get; set; } // Event 24 | 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Crucial.Providers/Questions/Data/IQuestionsDbContext.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.ComponentModel.DataAnnotations.Schema; 10 | using System.Data.Entity; 11 | using System.Data.Entity.ModelConfiguration; 12 | using Crucial.Providers.Questions.Entities; 13 | //using DatabaseGeneratedOption = System.ComponentModel.DataAnnotations.DatabaseGeneratedOption; 14 | using Crucial.Framework.Data.EntityFramework; 15 | using System.Data.Common; 16 | 17 | namespace Crucial.Providers.Questions.Data 18 | { 19 | public interface IQuestionsDbContext : IDbContextAsync, IDisposable 20 | { 21 | IDbSet Categories { get; set; } // Category 22 | IDbSet Questions { get; set; } // Questions 23 | IDbSet QuestionAnswers { get; set; } // QuestionAnswers 24 | 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Utils/StateHelper.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Messaging; 2 | using Crucial.Framework.DesignPatterns.CQRS.Storage; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Crucial.Framework.DesignPatterns.CQRS.Utils 10 | { 11 | public class StateHelper : Crucial.Framework.DesignPatterns.CQRS.Utils.IStateHelper 12 | { 13 | IEventStorage _eventStore; 14 | IEventBus _eventBus; 15 | 16 | public StateHelper(IEventStorage eventStore, IEventBus eventBus) 17 | { 18 | _eventStore = eventStore; 19 | _eventBus = eventBus; 20 | } 21 | 22 | /// 23 | /// Takes all events from history and replays them to re-generate Query DB 24 | /// 25 | /// 26 | public async Task RestoreState() 27 | { 28 | var events = await _eventStore.GetAllEvents().ConfigureAwait(false); 29 | 30 | _eventBus.Replay(events); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Crucial.Providers/Questions/Entities/QuestionAnswer.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.ComponentModel.DataAnnotations.Schema; 11 | using System.Data.Common; 12 | 13 | namespace Crucial.Providers.Questions.Entities 14 | { 15 | // QuestionAnswers 16 | public partial class QuestionAnswer : Crucial.Framework.BaseEntities.ProviderEntityBase 17 | { 18 | public int Id { get; set; } // Id (Primary key) 19 | public int QuestionId { get; set; } // QuestionId 20 | public string Text { get; set; } // Text 21 | public byte[] Image { get; set; } // Image 22 | public bool CorrectAnswer { get; set; } // CorrectAnswer 23 | 24 | // Foreign keys 25 | public virtual Question Question { get; set; } // FK_dbo.QuestionAnswers_dbo.Questions_QuestionId 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Crucial.Providers/Questions/CategoryRepositoryAsync.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.Repository.Async; 2 | using Crucial.Providers.Questions.Data; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using Crucial.Framework.Data.EntityFramework; 9 | using Crucial.Framework.Logging; 10 | 11 | namespace Crucial.Providers.Questions 12 | { 13 | public interface ICategoryRepositoryAsync : 14 | Crucial.Framework.DesignPatterns.Repository.Async.IReadOnlyRepository, 15 | IUpdateRepositoryAsync, 16 | ICreateRepositoryAsync, 17 | IDeleteRepositoryAsync, 18 | Framework.IoC.IAutoRegister 19 | { 20 | } 21 | 22 | public class CategoryRepositoryAsync : Crucial.Framework.Data.EntityFramework.Async.BaseRepository, ICategoryRepositoryAsync 23 | { 24 | public CategoryRepositoryAsync(IContextProvider cp, ILogger logger) : base(cp, logger) {} 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Crucial.Providers/Questions/QuestionRepositoryAsync.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.Repository.Async; 2 | using Crucial.Providers.Questions.Data; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using Crucial.Framework.Data.EntityFramework; 9 | using Crucial.Framework.Logging; 10 | 11 | namespace Crucial.Providers.Questions 12 | { 13 | public interface IQuestionRepositoryAsync : 14 | Crucial.Framework.DesignPatterns.Repository.Async.IReadOnlyRepository, 15 | IUpdateRepositoryAsync, 16 | ICreateRepositoryAsync, 17 | IDeleteRepositoryAsync, 18 | Framework.IoC.IAutoRegister 19 | { 20 | } 21 | 22 | public class QuestionRepositoryAsync : Crucial.Framework.Data.EntityFramework.Async.BaseRepository, IQuestionRepositoryAsync 23 | { 24 | public QuestionRepositoryAsync(IContextProvider cp, ILogger logger) : base(cp, logger) { } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /API/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Utils; 2 | using Crucial.Providers.Questions.Data; 3 | using Microsoft.AspNet.SignalR; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Configuration; 7 | using System.Data.Entity; 8 | using System.Data.SqlClient; 9 | using System.Linq; 10 | using System.Web; 11 | using System.Web.Http; 12 | using System.Web.Routing; 13 | 14 | namespace API 15 | { 16 | public class WebApiApplication : System.Web.HttpApplication 17 | { 18 | protected void Application_Start() 19 | { 20 | Bootstrapper.BootstrapStructureMap(); 21 | GlobalConfiguration.Configure(WebApiConfig.Register); 22 | 23 | if(ConfigurationManager.AppSettings["RestoreStateOnAppStart"] != null && ConfigurationManager.AppSettings["RestoreStateOnAppStart"].ToUpper() == "TRUE") { 24 | //Force drop db 25 | QuestionsDbContext.Drop(); 26 | 27 | IStateHelper sh = Crucial.Framework.IoC.StructureMapProvider.DependencyResolver.Container.GetInstance(); 28 | sh.RestoreState(); 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Messaging/CommandBus.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Crucial.Framework.DesignPatterns.CQRS.Commands; 4 | using Crucial.Framework.DesignPatterns.CQRS.Exceptions; 5 | using Crucial.Framework.DesignPatterns.CQRS.Utils; 6 | using System.Threading.Tasks; 7 | 8 | namespace Crucial.Framework.DesignPatterns.CQRS.Messaging 9 | { 10 | public class CommandBus:ICommandBus 11 | { 12 | private readonly ICommandHandlerFactory _commandHandlerFactory; 13 | 14 | public CommandBus(ICommandHandlerFactory commandHandlerFactory) 15 | { 16 | _commandHandlerFactory = commandHandlerFactory; 17 | } 18 | 19 | public async Task Send(T command) where T : Command 20 | { 21 | var handler = _commandHandlerFactory.GetHandler(); 22 | if (handler != null) 23 | { 24 | await handler.Execute(command).ConfigureAwait(false); 25 | } 26 | else 27 | { 28 | throw new UnregisteredDomainCommandException("no handler registered"); 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Crucial.Providers/EventStore/EventRepositoryAsync.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.Repository.Async; 2 | using Crucial.Providers.EventStore.Data; 3 | using Crucial.Providers.EventStore.Entities; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using Crucial.Framework.Data.EntityFramework; 10 | using Crucial.Framework.Logging; 11 | 12 | namespace Crucial.Providers.EventStore 13 | { 14 | public interface IEventRepositoryAsync : 15 | Crucial.Framework.DesignPatterns.Repository.Async.IReadOnlyRepository, 16 | IUpdateRepositoryAsync, 17 | ICreateRepositoryAsync, 18 | IDeleteRepositoryAsync, 19 | Framework.IoC.IAutoRegister 20 | { 21 | } 22 | 23 | public class EventRepositoryAsync : Crucial.Framework.Data.EntityFramework.Async.BaseRepository, IEventRepositoryAsync 24 | { 25 | public EventRepositoryAsync(IContextProvider cp, ILogger logger) : base(cp, logger) {} 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Crucial.Qyz/EventHandlers/Question/QuestionDeletedEventHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Crucial.Providers.Questions; 6 | using Crucial.Framework.DesignPatterns.CQRS.Events; 7 | using Crucial.Qyz.Events; 8 | using System.Threading.Tasks; 9 | using Crucial.Framework.DesignPatterns.Repository.Async.Extensions; 10 | 11 | namespace Crucial.Qyz.EventHandlers 12 | { 13 | public class QuestionDeletedEventHandler : IEventHandler 14 | { 15 | private IQuestionRepositoryAsync _questionRepo; 16 | 17 | public QuestionDeletedEventHandler(IQuestionRepositoryAsync questionRepo) 18 | { 19 | _questionRepo = questionRepo; 20 | } 21 | 22 | public async Task Handle(QuestionDeletedEvent handle) 23 | { 24 | var items = await _questionRepo.FindByAsync(c => c.Id == handle.AggregateId).ConfigureAwait(false); 25 | 26 | var item = items.FirstOrDefault(); 27 | 28 | if (item != null) 29 | { 30 | await _questionRepo.Delete(item).ConfigureAwait(false); 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Crucial.Providers/EventStore/MementoRepositoryAsync.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.Repository.Async; 2 | using Crucial.Providers.EventStore.Data; 3 | using Crucial.Providers.EventStore.Entities; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using Crucial.Framework.Data.EntityFramework; 10 | using Crucial.Framework.Logging; 11 | 12 | namespace Crucial.Providers.EventStore 13 | { 14 | public interface IMementoRepositoryAsync : 15 | Crucial.Framework.DesignPatterns.Repository.Async.IReadOnlyRepository, 16 | IUpdateRepositoryAsync, 17 | ICreateRepositoryAsync, 18 | IDeleteRepositoryAsync, 19 | Framework.IoC.IAutoRegister 20 | { 21 | } 22 | 23 | public class MementoRepositoryAsync : Crucial.Framework.Data.EntityFramework.Async.BaseRepository, IMementoRepositoryAsync 24 | { 25 | public MementoRepositoryAsync(IContextProvider cp, ILogger logger) : base(cp, logger) { } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Crucial.Qyz/EventHandlers/Question/QuestionCreatedEventHandler.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Events; 2 | using Crucial.Providers.Questions; 3 | using Crucial.Providers.Questions.Entities; 4 | using Crucial.Qyz.Events; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace Crucial.Qyz.EventHandlers 12 | { 13 | public class QuestionCreatedEventHandler : 14 | IEventHandler 15 | { 16 | private IQuestionRepositoryAsync _questionRepo; 17 | 18 | public QuestionCreatedEventHandler(IQuestionRepositoryAsync questionRepository) 19 | { 20 | _questionRepo = questionRepository; 21 | } 22 | 23 | public async Task Handle(QuestionCreatedEvent handle) 24 | { 25 | Question question = new Question() 26 | { 27 | Id = handle.AggregateId, 28 | Text = handle.Question, 29 | Version = handle.Version, 30 | CreatedDate = handle.Timestamp 31 | }; 32 | 33 | await _questionRepo.Create(question).ConfigureAwait(false); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /API/App_Start/WebApiConfig.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.IoC.StructureMapProvider; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Web.Http; 6 | using System.Web.Http.Dispatcher; 7 | 8 | namespace API 9 | { 10 | public static class WebApiConfig 11 | { 12 | public static void Register(HttpConfiguration config) 13 | { 14 | config.EnableCors(); 15 | 16 | // Web API configuration and services 17 | config.Services.Replace(typeof(IHttpControllerActivator), new ServiceActivator(config)); 18 | 19 | // Web API routes 20 | config.MapHttpAttributeRoutes(); 21 | 22 | //config.Routes.MapHttpRoute( 23 | // name: "ControllerWithAction", 24 | // routeTemplate: "api/{controller}/{id}/{action}/{actionId}", 25 | // defaults: new { id = RouteParameter.Optional, actionId = RouteParameter.Optional } 26 | //); 27 | 28 | config.Routes.MapHttpRoute( 29 | name: "DefaultApi", 30 | routeTemplate: "api/{controller}/{id}", 31 | defaults: new { id = RouteParameter.Optional } 32 | ); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Crucial.Providers/EventStore/Data/EventStore.cs: -------------------------------------------------------------------------------- 1 | 2 | 3 | // This file was automatically generated. 4 | // Do not make changes directly to this file - edit the template instead. 5 | // 6 | // The following connection settings were used to generate this file 7 | // 8 | // Configuration file: "API\Web.config" 9 | // Connection String Name: "EventStore" 10 | // Connection String: "Data Source=(local);Initial Catalog=EventStoreDB;Integrated Security=True" 11 | 12 | // ReSharper disable RedundantUsingDirective 13 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 14 | // ReSharper disable InconsistentNaming 15 | // ReSharper disable PartialTypeWithSinglePart 16 | // ReSharper disable PartialMethodWithSinglePart 17 | // ReSharper disable RedundantNameQualifier 18 | 19 | using System; 20 | using System.ComponentModel.DataAnnotations.Schema; 21 | using System.Data.Entity; 22 | using System.Data.Entity.ModelConfiguration; 23 | using Crucial.Providers.EventStore.Entities; 24 | //using DatabaseGeneratedOption = System.ComponentModel.DataAnnotations.DatabaseGeneratedOption; 25 | using Crucial.Framework.Data.EntityFramework; 26 | using System.Data.Common; 27 | 28 | namespace Crucial.Providers.EventStore.Data 29 | { 30 | } 31 | 32 | -------------------------------------------------------------------------------- /Crucial.Providers/Questions/Data/Questions.cs: -------------------------------------------------------------------------------- 1 | 2 | 3 | // This file was automatically generated. 4 | // Do not make changes directly to this file - edit the template instead. 5 | // 6 | // The following connection settings were used to generate this file 7 | // 8 | // Configuration file: "API\Web.config" 9 | // Connection String Name: "DefaultConnection" 10 | // Connection String: "Data Source=(local);Initial Catalog=QueryDB;Integrated Security=True" 11 | 12 | // ReSharper disable RedundantUsingDirective 13 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 14 | // ReSharper disable InconsistentNaming 15 | // ReSharper disable PartialTypeWithSinglePart 16 | // ReSharper disable PartialMethodWithSinglePart 17 | // ReSharper disable RedundantNameQualifier 18 | 19 | using System; 20 | using System.ComponentModel.DataAnnotations.Schema; 21 | using System.Data.Entity; 22 | using System.Data.Entity.ModelConfiguration; 23 | using Crucial.Providers.Questions.Entities; 24 | //using DatabaseGeneratedOption = System.ComponentModel.DataAnnotations.DatabaseGeneratedOption; 25 | using Crucial.Framework.Data.EntityFramework; 26 | using System.Data.Common; 27 | 28 | namespace Crucial.Providers.Questions.Data 29 | { 30 | } 31 | 32 | -------------------------------------------------------------------------------- /Crucial.Framework/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Crucial.Providers/EventStore/AggregateRepositoryAsync.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.Repository.Async; 2 | using Crucial.Providers.EventStore.Data; 3 | using Crucial.Providers.EventStore.Entities; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using Crucial.Framework.Data.EntityFramework; 10 | using Crucial.Framework.Logging; 11 | 12 | namespace Crucial.Providers.EventStore 13 | { 14 | public interface IAggregateRepositoryAsync : 15 | Crucial.Framework.DesignPatterns.Repository.Async.IReadOnlyRepository, 16 | IUpdateRepositoryAsync, 17 | ICreateRepositoryAsync, 18 | IDeleteRepositoryAsync, 19 | Framework.IoC.IAutoRegister 20 | { 21 | } 22 | 23 | public class AggregateRepositoryAsync : Crucial.Framework.Data.EntityFramework.Async.BaseRepository, IAggregateRepositoryAsync 24 | { 25 | public AggregateRepositoryAsync(IContextProvider cp, ILogger logger) : base(cp, logger) { } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Crucial.Framework/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Crucial.Providers/Identity/Data/IIdentityDbContext.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Collections.ObjectModel; 11 | using System.Linq; 12 | using System.Linq.Expressions; 13 | using System.ComponentModel.DataAnnotations.Schema; 14 | using System.Data.Entity; 15 | using System.Data.Entity.ModelConfiguration; 16 | using Crucial.Providers.Identity.Entities; 17 | using Crucial.Framework.Data.EntityFramework; 18 | //using DatabaseGeneratedOption = System.ComponentModel.DataAnnotations.DatabaseGeneratedOption; 19 | 20 | namespace Crucial.Providers.Identity.Data 21 | { 22 | public interface IIdentityDbContext : IDbContext, IDisposable 23 | { 24 | IDbSet AspNetUsers { get; set; } // AspNetUsers 25 | IDbSet AspNetUserClaims { get; set; } // AspNetUserClaims 26 | IDbSet AspNetUserLogins { get; set; } // AspNetUserLogins 27 | IDbSet AspNetUserRoles { get; set; } // AspNetUserRoles 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /Crucial.Framework/Threading/NamedLocker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | 4 | namespace Crucial.Framework.Threading 5 | { 6 | public class NamedLocker 7 | { 8 | private readonly ConcurrentDictionary _lockDict = new ConcurrentDictionary(); 9 | 10 | //get a lock for use with a lock(){} block 11 | public object GetLock(string name) 12 | { 13 | return _lockDict.GetOrAdd(name, s => new object()); 14 | } 15 | 16 | //run a short lock inline using a lambda 17 | public TResult RunWithLock(string name, Func body) 18 | { 19 | lock (_lockDict.GetOrAdd(name, s => new object())) 20 | { 21 | return body(); 22 | } 23 | } 24 | 25 | //run a short lock inline using a lambda 26 | public void RunWithLock(string name, Action body) 27 | { 28 | lock (_lockDict.GetOrAdd(name, s => new object())) 29 | { 30 | body(); 31 | } 32 | } 33 | 34 | //remove an old lock object that is no longer needed 35 | public void RemoveLock(string name) 36 | { 37 | object o; 38 | _lockDict.TryRemove(name, out o); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Crucial.Providers/Filesystem/Mappers/DirectoryMapper.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.Entities.Mappers; 2 | using Crucial.Providers.Filesystem.Entities; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using Crucial.Providers.Filesystem.Entities.Extensions; 8 | 9 | namespace Crucial.Providers.Filesystem.Mappers 10 | { 11 | public class DirectoryMapper : ProviderEntityMapper 12 | { 13 | public override Directory ToProviderEntity(System.IO.DirectoryInfo source) 14 | { 15 | var d = base.ToProviderEntity(source); 16 | var p = source.FullName.Split(System.IO.Path.DirectorySeparatorChar); 17 | d.PathParts = p.Take(p.Length - 1).ToList(); 18 | d.IsEmpty = true; 19 | d.DriveLetter = source.Root.ToString().Take(1).ToString(); 20 | d.Seperator = System.IO.Path.DirectorySeparatorChar == '/' ? Entities.Enums.FilesystemPathSeparator.ForwardSlash : Entities.Enums.FilesystemPathSeparator.BackSlash; 21 | return d; 22 | } 23 | 24 | public override System.IO.DirectoryInfo ToAnyEntity(Directory source) 25 | { 26 | var d = new System.IO.DirectoryInfo(source.BuildPath()); 27 | return d; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Crucial.Tests/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Crucial.EventStore/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Crucial.Qyz/CommandHandlers/Question/QuestionDeleteCommandHandler.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Commands; 2 | using Crucial.Framework.DesignPatterns.CQRS.Storage; 3 | using Crucial.Qyz.Commands.Question; 4 | using Crucial.Qyz.Domain; 5 | using System; 6 | using System.Threading.Tasks; 7 | 8 | 9 | namespace Crucial.Qyz.CommandHandlers 10 | { 11 | public class QuestionDeleteCommandHandler : ICommandHandler 12 | { 13 | private readonly IRepository _repository; 14 | 15 | public QuestionDeleteCommandHandler(IRepository repository) 16 | { 17 | _repository = repository; 18 | } 19 | 20 | public async Task Execute(QuestionDeleteCommand command) 21 | { 22 | if (command == null) 23 | { 24 | throw new ArgumentNullException("command"); 25 | } 26 | if (_repository == null) 27 | { 28 | throw new InvalidOperationException("Repository is not initialized."); 29 | } 30 | 31 | var aggregate = await _repository.GetById(command.Id).ConfigureAwait(false); 32 | 33 | aggregate.Delete(); 34 | 35 | await Task.Run(() => _repository.Save(aggregate, command.Version)).ConfigureAwait(false); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Crucial.Qyz/EventHandlers/Question/QuestionTextChangedEventHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Crucial.Providers.Questions; 6 | using Crucial.Framework.DesignPatterns.CQRS.Events; 7 | using Crucial.Qyz.Events; 8 | using System.Threading.Tasks; 9 | using Crucial.Framework.DesignPatterns.Repository.Async.Extensions; 10 | 11 | namespace Crucial.Qyz.EventHandlers 12 | { 13 | public class QuestionTextChangedEventHandler : IEventHandler 14 | { 15 | private IQuestionRepositoryAsync _questionRepo; 16 | 17 | public QuestionTextChangedEventHandler(IQuestionRepositoryAsync questionRepo) 18 | { 19 | _questionRepo = questionRepo; 20 | } 21 | 22 | public async Task Handle(QuestionTextChangedEvent handle) 23 | { 24 | var items = await _questionRepo.FindByAsync(c => c.Id == handle.AggregateId).ConfigureAwait(false); 25 | 26 | var item = items.FirstOrDefault(); 27 | 28 | if (item != null) 29 | { 30 | item.Text = handle.Question; 31 | item.Version = handle.Version; 32 | item.ModifiedDate = handle.Timestamp; 33 | } 34 | 35 | await _questionRepo.Update(item); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /API/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /Crucial.Qyz/CommandHandlers/UserCategory/UserCategoryDeleteCommandHandler.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Commands; 2 | using Crucial.Framework.DesignPatterns.CQRS.Storage; 3 | using Crucial.Qyz.Commands.UserCategory; 4 | using Crucial.Qyz.Domain; 5 | using System; 6 | using System.Threading.Tasks; 7 | 8 | 9 | namespace Crucial.Qyz.CommandHandlers 10 | { 11 | public class UserCategoryDeleteCommandHandler : ICommandHandler 12 | { 13 | private readonly IRepository _repository; 14 | 15 | public UserCategoryDeleteCommandHandler(IRepository repository) 16 | { 17 | _repository = repository; 18 | } 19 | 20 | public async Task Execute(UserCategoryDeleteCommand command) 21 | { 22 | if (command == null) 23 | { 24 | throw new ArgumentNullException("command"); 25 | } 26 | if (_repository == null) 27 | { 28 | throw new InvalidOperationException("Repository is not initialized."); 29 | } 30 | 31 | var aggregate = await _repository.GetById(command.Id).ConfigureAwait(false); 32 | 33 | aggregate.Delete(); 34 | 35 | await Task.Run(() => _repository.Save(aggregate, command.Version)).ConfigureAwait(false); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Crucial.Providers/Questions/Entities/Category.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.ComponentModel.DataAnnotations.Schema; 11 | using System.Data.Common; 12 | 13 | namespace Crucial.Providers.Questions.Entities 14 | { 15 | // Category 16 | public partial class Category : Crucial.Framework.BaseEntities.ProviderEntityBase 17 | { 18 | public int Id { get; set; } // Id (Primary key) 19 | public int UserId { get; set; } // UserId 20 | public string Name { get; set; } // Name 21 | public DateTime CreatedDate { get; set; } // CreatedDate 22 | public int Version { get; set; } // Version 23 | public DateTime? ModifiedDate { get; set; } // ModifiedDate 24 | 25 | // Reverse navigation 26 | public virtual ICollection Questions { get; set; } // Many to many mapping 27 | 28 | public Category() 29 | { 30 | Questions = new List(); 31 | InitializePartial(); 32 | } 33 | partial void InitializePartial(); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Crucial.Qyz/EventHandlers/UserCategory/UserCategoryNameChangedEventHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Crucial.Providers.Questions; 6 | using Crucial.Framework.DesignPatterns.CQRS.Events; 7 | using Crucial.Qyz.Events; 8 | using System.Threading.Tasks; 9 | using Crucial.Framework.DesignPatterns.Repository.Async.Extensions; 10 | 11 | namespace Crucial.Qyz.EventHandlers 12 | { 13 | public class UserCategoryNameChangedEventHandler : IEventHandler 14 | { 15 | private ICategoryRepositoryAsync _categoryRepo; 16 | 17 | public UserCategoryNameChangedEventHandler(ICategoryRepositoryAsync categoryRepo) 18 | { 19 | _categoryRepo = categoryRepo; 20 | } 21 | 22 | public async Task Handle(UserCategoryNameChangedEvent handle) 23 | { 24 | var items = await _categoryRepo.FindByAsync(c => c.Id == handle.AggregateId).ConfigureAwait(false); 25 | 26 | var item = items.FirstOrDefault(); 27 | 28 | if (item != null) 29 | { 30 | item.Name = handle.Name; 31 | item.Version = handle.Version; 32 | item.ModifiedDate = handle.Timestamp; 33 | } 34 | 35 | await _categoryRepo.Update(item).ConfigureAwait(false); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Crucial.Qyz/EventHandlers/UserCategory/QuestionAddedToCategoryEventHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Crucial.Framework.DesignPatterns.CQRS.Events; 7 | using Crucial.Framework.DesignPatterns.Repository.Async.Extensions; 8 | using Crucial.Providers.Questions; 9 | using Crucial.Qyz.Events; 10 | 11 | namespace Crucial.Qyz.EventHandlers.UserCategory 12 | { 13 | public class QuestionAddedToCategoryEventHandler : IEventHandler 14 | { 15 | private ICategoryRepositoryAsync _categoryRepo; 16 | 17 | public QuestionAddedToCategoryEventHandler(ICategoryRepositoryAsync categoryRepo) 18 | { 19 | _categoryRepo = categoryRepo; 20 | } 21 | 22 | public async Task Handle(UserCategoryNameChangedEvent handle) 23 | { 24 | var items = await _categoryRepo.FindByAsync(c => c.Id == handle.AggregateId).ConfigureAwait(false); 25 | 26 | var item = items.FirstOrDefault(); 27 | 28 | if (item != null) 29 | { 30 | item.Name = handle.Name; 31 | item.Version = handle.Version; 32 | item.ModifiedDate = handle.Timestamp; 33 | } 34 | 35 | await _categoryRepo.Update(item).ConfigureAwait(false); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Crucial.Qyz/CommandHandlers/Question/QuestionCreateCommandHandler.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Commands; 2 | using Crucial.Framework.DesignPatterns.CQRS.Storage; 3 | using Crucial.Qyz.Commands.Question; 4 | using Crucial.Qyz.Domain; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace Crucial.Qyz.CommandHandlers 12 | { 13 | public class QuestionCreateCommandHandler : ICommandHandler 14 | { 15 | private IRepository _repository; 16 | 17 | public QuestionCreateCommandHandler(IRepository repository) 18 | { 19 | _repository = repository; 20 | } 21 | 22 | public async Task Execute(QuestionCreateCommand command) 23 | { 24 | if (command == null) 25 | { 26 | throw new ArgumentNullException("command"); 27 | } 28 | 29 | if (_repository == null) 30 | { 31 | throw new InvalidOperationException("Repository is not initialized."); 32 | } 33 | 34 | var aggregate = new Question(command.Id, command.QuestionText); 35 | aggregate.Version = -1; 36 | await Task.Run(() => _repository.Save(aggregate, command.Version)).ConfigureAwait(false); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Crucial.Qyz/EventHandlers/UserCategory/UserCategoryCreatedEventHandler.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Events; 2 | using Crucial.Providers.Questions; 3 | using Crucial.Providers.Questions.Entities; 4 | using Crucial.Qyz.Events; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using Crucial.Framework.Logging; 11 | 12 | namespace Crucial.Qyz.EventHandlers 13 | { 14 | public class UserCategoryCreatedEventHandler : IEventHandler 15 | { 16 | private ICategoryRepositoryAsync _categoryRepo; 17 | private ILogger _logger; 18 | 19 | public UserCategoryCreatedEventHandler(ICategoryRepositoryAsync categoryRepository, ILogger logger) 20 | { 21 | _categoryRepo = categoryRepository; 22 | _logger = logger; 23 | } 24 | 25 | public async Task Handle(UserCategoryCreatedEvent handle) 26 | { 27 | Category category = new Category() 28 | { 29 | Id = handle.AggregateId, 30 | Name = handle.Name, 31 | Version = handle.Version, 32 | CreatedDate = handle.Timestamp 33 | }; 34 | 35 | _logger.Trace("UserCategoryCreatedEvent", handle); 36 | 37 | await _categoryRepo.Create(category).ConfigureAwait(false); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Crucial.Qyz/EventHandlers/UserCategory/UserCategoryDeletedEventHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Crucial.Providers.Questions; 6 | using Crucial.Framework.DesignPatterns.CQRS.Events; 7 | using Crucial.Qyz.Events; 8 | using System.Threading.Tasks; 9 | using Crucial.Framework.DesignPatterns.Repository.Async.Extensions; 10 | using Crucial.Framework.Logging; 11 | 12 | namespace Crucial.Qyz.EventHandlers 13 | { 14 | public class UserCategoryDeletedEventHandler : IEventHandler 15 | { 16 | private ICategoryRepositoryAsync _categoryRepo; 17 | private ILogger _logger; 18 | 19 | public UserCategoryDeletedEventHandler(ICategoryRepositoryAsync categoryRepo, ILogger logger) 20 | { 21 | _categoryRepo = categoryRepo; 22 | _logger = logger; 23 | } 24 | 25 | public async Task Handle(UserCategoryDeletedEvent handle) 26 | { 27 | var items = await _categoryRepo.FindByAsync(c => c.Id == handle.AggregateId).ConfigureAwait(false); 28 | 29 | var item = items.FirstOrDefault(); 30 | 31 | _logger.Trace("UserCategoryDeletedEvent", handle.AggregateId); 32 | 33 | if (item != null) 34 | { 35 | await _categoryRepo.Delete(item).ConfigureAwait(false); 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Crucial.Providers/EventStore/Data/AggregateRootConfiguration.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.ComponentModel.DataAnnotations.Schema; 10 | using System.Data.Entity; 11 | using System.Data.Entity.ModelConfiguration; 12 | using Crucial.Providers.EventStore.Entities; 13 | //using DatabaseGeneratedOption = System.ComponentModel.DataAnnotations.DatabaseGeneratedOption; 14 | using Crucial.Framework.Data.EntityFramework; 15 | using System.Data.Common; 16 | 17 | namespace Crucial.Providers.EventStore.Data 18 | { 19 | // AggregateRoots 20 | internal class AggregateRootConfiguration : EntityTypeConfiguration 21 | { 22 | public AggregateRootConfiguration(string schema = "dbo") 23 | { 24 | ToTable(schema + ".AggregateRoots"); 25 | HasKey(x => x.Id); 26 | 27 | Property(x => x.Id).HasColumnName("Id").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 28 | Property(x => x.Version).HasColumnName("Version").IsRequired(); 29 | Property(x => x.EventVersion).HasColumnName("EventVersion").IsRequired(); 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /API/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /Crucial.Providers/EventStore/Data/EventConfiguration.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.ComponentModel.DataAnnotations.Schema; 10 | using System.Data.Entity; 11 | using System.Data.Entity.ModelConfiguration; 12 | using Crucial.Providers.EventStore.Entities; 13 | //using DatabaseGeneratedOption = System.ComponentModel.DataAnnotations.DatabaseGeneratedOption; 14 | using Crucial.Framework.Data.EntityFramework; 15 | using System.Data.Common; 16 | 17 | namespace Crucial.Providers.EventStore.Data 18 | { 19 | // Event 20 | internal class EventConfiguration : EntityTypeConfiguration 21 | { 22 | public EventConfiguration(string schema = "dbo") 23 | { 24 | ToTable(schema + ".Event"); 25 | HasKey(x => x.Id); 26 | 27 | Property(x => x.Id).HasColumnName("Id").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 28 | Property(x => x.AggregateId).HasColumnName("AggregateId").IsRequired(); 29 | Property(x => x.Data).HasColumnName("Data").IsRequired(); 30 | Property(x => x.Timestamp).HasColumnName("Timestamp").IsRequired(); 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /Crucial.Qyz/CommandHandlers/Question/QuestionTextChangeCommandHandler.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Commands; 2 | using Crucial.Framework.DesignPatterns.CQRS.Storage; 3 | using Crucial.Qyz.Commands.Question; 4 | using Crucial.Qyz.Domain; 5 | using System; 6 | using System.Threading.Tasks; 7 | 8 | 9 | namespace Crucial.Qyz.CommandHandlers 10 | { 11 | public class QuestionTextChangeCommandHandler : ICommandHandler 12 | { 13 | private readonly IRepository _repository; 14 | 15 | public QuestionTextChangeCommandHandler(IRepository repository) 16 | { 17 | _repository = repository; 18 | } 19 | 20 | public async Task Execute(QuestionTextChangeCommand command) 21 | { 22 | if (command == null) 23 | { 24 | throw new ArgumentNullException("command"); 25 | } 26 | if (_repository == null) 27 | { 28 | throw new InvalidOperationException("Repository is not initialized."); 29 | } 30 | 31 | var aggregate = await _repository.GetById(command.Id).ConfigureAwait(false); 32 | 33 | if (aggregate.QuestionText != command.QuestionText) 34 | aggregate.ChangeQuestionText(command.QuestionText); 35 | 36 | await Task.Run(() => _repository.Save(aggregate, command.Version)).ConfigureAwait(false); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Crucial.Providers/EventStore/Data/BaseMementoConfiguration.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.ComponentModel.DataAnnotations.Schema; 10 | using System.Data.Entity; 11 | using System.Data.Entity.ModelConfiguration; 12 | using Crucial.Providers.EventStore.Entities; 13 | //using DatabaseGeneratedOption = System.ComponentModel.DataAnnotations.DatabaseGeneratedOption; 14 | using Crucial.Framework.Data.EntityFramework; 15 | using System.Data.Common; 16 | 17 | namespace Crucial.Providers.EventStore.Data 18 | { 19 | // BaseMementoes 20 | internal class BaseMementoConfiguration : EntityTypeConfiguration 21 | { 22 | public BaseMementoConfiguration(string schema = "dbo") 23 | { 24 | ToTable(schema + ".BaseMementoes"); 25 | HasKey(x => new { x.Id, x.Version }); 26 | 27 | Property(x => x.Id).HasColumnName("Id").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); 28 | Property(x => x.Version).HasColumnName("Version").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); 29 | Property(x => x.Data).HasColumnName("Data").IsRequired(); 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /API/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Web")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Web")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("fae851f9-eaf4-4d57-a5c7-b2b851bd8ecc")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /Crucial.Qyz/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Crucial.Qyz")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Crucial.Qyz")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("5f07bc54-536f-455f-9fd1-8cfd0d7f2098")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Crucial.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Crucial.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Crucial.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("bb5830a6-5525-4852-a240-2fba484d1c36")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Crucial.EventStore/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Crucial.EventStore")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Crucial.EventStore")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("015b2b77-a6b0-4bcb-b008-8d273457d823")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Crucial.Framework/Interceptors/PerformanceInterceptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Castle.DynamicProxy; 3 | using System.Diagnostics; 4 | using Crucial.Framework.Logging; 5 | 6 | namespace Crucial.Framework.Interceptors 7 | { 8 | public class PerformanceInterceptor : IInterceptor 9 | { 10 | private readonly ILogger _logger; 11 | 12 | public PerformanceInterceptor(ILogger crucialLogger) 13 | { 14 | _logger = crucialLogger; 15 | } 16 | 17 | public void Intercept(IInvocation invocation) 18 | { 19 | Stopwatch stopWatch = new Stopwatch(); 20 | stopWatch.Start(); 21 | invocation.Proceed(); 22 | stopWatch.Stop(); 23 | 24 | PerformanceLog l = new PerformanceLog 25 | { 26 | Duration = stopWatch.ElapsedMilliseconds, 27 | Method = invocation.Method.Name, 28 | FullClassName = invocation.Method.ReflectedType.FullName, 29 | ClassName = invocation.Method.ReflectedType.Name, 30 | StackTrace = Environment.StackTrace 31 | }; 32 | 33 | _logger.Info(String.Format("\t{0}\t{1}\t{2}\t{3}", l.Duration, l.ClassName, l.Method, l.FullClassName)); 34 | } 35 | } 36 | 37 | public class PerformanceLog 38 | { 39 | public string Method { get; set; } 40 | public string ClassName { get; set; } 41 | public string FullClassName { get; set; } 42 | public string StackTrace { get; set; } 43 | public long Duration { get; set; } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Crucial.Services/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Crucial.Services")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("Crucial.Services")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("07db8608-6b69-4644-9482-ed38692fff52")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Crucial.Framework/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Crucial.Framework")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("Crucial.Framework")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("33b706d6-1d6e-4689-8506-ff45e63d81cd")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Crucial.Providers/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Crucial.Providers")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("Crucial.Providers")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("80937d2e-660c-49ab-a522-eb64822dd9c0")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /API/App_Start/RealtimeStartup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Microsoft.Owin; 4 | using Microsoft.Owin.Cors; 5 | using Owin; 6 | using Microsoft.AspNet.SignalR; 7 | 8 | [assembly: OwinStartup(typeof(API.App_Start.Startup))] 9 | 10 | namespace API.App_Start 11 | { 12 | public class Startup 13 | { 14 | public void Configuration(IAppBuilder app) 15 | { 16 | app.Map("/signalr", map => 17 | { 18 | // Setup the CORS middleware to run before SignalR. 19 | // By default this will allow all origins. You can 20 | // configure the set of origins and/or http verbs by 21 | // providing a cors options with a different policy. 22 | map.UseCors(CorsOptions.AllowAll); 23 | var hubConfiguration = new HubConfiguration 24 | { 25 | // You can enable JSONP by uncommenting line below. 26 | // JSONP requests are insecure but some older browsers (and some 27 | // versions of IE) require JSONP to work cross domain 28 | // EnableJSONP = true 29 | }; 30 | // Run the SignalR pipeline. We're not using MapSignalR 31 | // since this branch already runs under the "/signalr" 32 | // path. 33 | map.RunSignalR(hubConfiguration); 34 | }); 35 | 36 | // Any connection or hub wire up and configuration should go here 37 | //app.MapSignalR(); 38 | } 39 | 40 | } 41 | } -------------------------------------------------------------------------------- /Crucial.Qyz/CommandHandlers/UserCategory/UserCategoryCreateCommandHandler.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Commands; 2 | using Crucial.Framework.DesignPatterns.CQRS.Storage; 3 | using Crucial.Qyz.Commands.UserCategory; 4 | using Crucial.Qyz.Domain; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using Crucial.Framework.Logging; 11 | 12 | namespace Crucial.Qyz.CommandHandlers 13 | { 14 | public class UserCategoryCreateCommandHandler : ICommandHandler 15 | { 16 | private IRepository _repository; 17 | private ILogger _logger; 18 | 19 | public UserCategoryCreateCommandHandler(IRepository repository, ILogger logger) 20 | { 21 | _repository = repository; 22 | _logger = logger; 23 | } 24 | 25 | public async Task Execute(UserCategoryCreateCommand command) 26 | { 27 | if (command == null) 28 | { 29 | throw new ArgumentNullException("command"); 30 | } 31 | 32 | if (_repository == null) 33 | { 34 | throw new InvalidOperationException("Repository is not initialized."); 35 | } 36 | 37 | _logger.Trace("UserCategoryCreateCommand", command); 38 | 39 | var aggregate = new UserCategory(command.Id, command.Name); 40 | aggregate.Version = -1; 41 | await Task.Run(() => _repository.Save(aggregate, command.Version)).ConfigureAwait(false); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Crucial.Qyz/CommandHandlers/UserCategory/UserCategoryNameChangeCommandHandler.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Commands; 2 | using Crucial.Framework.DesignPatterns.CQRS.Storage; 3 | using Crucial.Qyz.Commands.UserCategory; 4 | using Crucial.Qyz.Domain; 5 | using System; 6 | using System.Threading.Tasks; 7 | using Crucial.Framework.Logging; 8 | 9 | 10 | namespace Crucial.Qyz.CommandHandlers 11 | { 12 | public class UserCategoryNameChangeCommandHandler : ICommandHandler 13 | { 14 | private readonly IRepository _repository; 15 | private ILogger _logger; 16 | 17 | public UserCategoryNameChangeCommandHandler(IRepository repository, ILogger logger) 18 | { 19 | _repository = repository; 20 | _logger = logger; 21 | } 22 | 23 | public async Task Execute(UserCategoryNameChangeCommand command) 24 | { 25 | if (command == null) 26 | { 27 | throw new ArgumentNullException("command"); 28 | } 29 | if (_repository == null) 30 | { 31 | throw new InvalidOperationException("Repository is not initialized."); 32 | } 33 | 34 | _logger.Trace("UserCategoryNameChangeCommand", command); 35 | 36 | var aggregate = await _repository.GetById(command.Id).ConfigureAwait(false); 37 | 38 | if (aggregate.Name != command.Name) 39 | aggregate.ChangeName(command.Name); 40 | 41 | await Task.Run(() => _repository.Save(aggregate, command.Version)).ConfigureAwait(false); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Crucial.Framework/IoC/Windsor/Resolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Castle.Windsor; 6 | 7 | namespace Crucial.Framework.IoC.Windsor 8 | { 9 | internal sealed class Resolver 10 | { 11 | private static readonly object LockObj = new object(); 12 | 13 | private static IWindsorContainer container; 14 | 15 | private static Resolver instance = new Resolver(); 16 | 17 | private Resolver() 18 | { 19 | container = new WindsorContainer(); 20 | } 21 | 22 | internal static IWindsorContainer Container 23 | { 24 | get { return container; } 25 | 26 | set 27 | { 28 | lock (LockObj) 29 | { 30 | container = value; 31 | } 32 | } 33 | } 34 | 35 | 36 | internal static Resolver Instance 37 | { 38 | get 39 | { 40 | if (instance == null) 41 | { 42 | lock (LockObj) 43 | { 44 | if (instance == null) 45 | { 46 | instance = new Resolver(); 47 | } 48 | } 49 | } 50 | 51 | return instance; 52 | } 53 | } 54 | 55 | internal static T Resolve() 56 | { 57 | return container.Resolve(); 58 | } 59 | 60 | internal static object Resolve(Type type) 61 | { 62 | return container.Resolve(type); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Crucial.Qyz/CommandHandlers/UserCategory/AddQuestionToCategoryCommandHandler.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Commands; 2 | using Crucial.Framework.DesignPatterns.CQRS.Storage; 3 | using Crucial.Qyz.Commands.UserCategory; 4 | using Crucial.Qyz.Domain; 5 | using System; 6 | using System.Threading.Tasks; 7 | using Crucial.Framework.Logging; 8 | 9 | 10 | namespace Crucial.Qyz.CommandHandlers 11 | { 12 | public class AddQuestionToCategoryCommandHandler : ICommandHandler 13 | { 14 | private readonly IRepository _repository; 15 | private readonly ILogger _logger; 16 | 17 | public AddQuestionToCategoryCommandHandler(IRepository repository, ILogger logger) 18 | { 19 | _repository = repository; 20 | _logger = logger; 21 | } 22 | 23 | public async Task Execute(AddQuestionToCategoryCommand command) 24 | { 25 | if (command == null) 26 | { 27 | throw new ArgumentNullException("command"); 28 | } 29 | if (_repository == null) 30 | { 31 | throw new InvalidOperationException("Repository is not initialized."); 32 | } 33 | 34 | _logger.Trace("AddQuestionToCategoryCommand", command); 35 | 36 | var aggregate = await _repository.GetById(command.Id).ConfigureAwait(false); 37 | 38 | if (!aggregate.Questions.Contains(command.Id)) 39 | aggregate.AddQuestionToCategory(command.QuestionId); 40 | 41 | await Task.Run(() => _repository.Save(aggregate, command.Version)).ConfigureAwait(false); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Messaging/EventBus.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Crucial.Framework.DesignPatterns.CQRS.Events; 6 | using Crucial.Framework.DesignPatterns.CQRS.Messaging; 7 | using Crucial.Framework.DesignPatterns.CQRS.Utils; 8 | using System.Threading.Tasks; 9 | 10 | namespace Crucial.Framework.DesignPatterns.CQRS.Messaging 11 | { 12 | public class EventBus:IEventBus 13 | { 14 | private IEventHandlerFactory _eventHandlerFactory; 15 | 16 | public EventBus(IEventHandlerFactory eventHandlerFactory) 17 | { 18 | _eventHandlerFactory = eventHandlerFactory; 19 | } 20 | 21 | public async Task Publish(T @event) where T : Event 22 | { 23 | var handlers = _eventHandlerFactory.GetHandlers(); 24 | 25 | var eventHandlers = new List(); 26 | 27 | foreach (var eventHandler in handlers) 28 | { 29 | eventHandlers.Add(eventHandler.Handle(@event)); 30 | } 31 | 32 | await Task.WhenAll(eventHandlers); 33 | } 34 | 35 | public async Task Replay(IEnumerable eventList) 36 | { 37 | foreach (dynamic ev in eventList) 38 | { 39 | var handlers = _eventHandlerFactory.GetHandlers(ev); 40 | 41 | List tasks = new List(); 42 | 43 | foreach (var eventHandler in handlers) 44 | { 45 | tasks.Add(eventHandler.Handle(ev)); 46 | } 47 | 48 | await Task.WhenAll(tasks); 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /API/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Crucial.Providers/Questions/Entities/Question.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.ComponentModel.DataAnnotations.Schema; 11 | using System.Data.Common; 12 | 13 | namespace Crucial.Providers.Questions.Entities 14 | { 15 | // Questions 16 | public partial class Question : Crucial.Framework.BaseEntities.ProviderEntityBase 17 | { 18 | public int Id { get; set; } // Id (Primary key) 19 | public int UserId { get; set; } // UserId 20 | public string Text { get; set; } // Text 21 | public byte[] Image { get; set; } // Image 22 | public string AnswerText { get; set; } // AnswerText 23 | public byte Type { get; set; } // Type 24 | public int Version { get; set; } // Version 25 | public DateTime CreatedDate { get; set; } // CreatedDate 26 | public DateTime? ModifiedDate { get; set; } // ModifiedDate 27 | 28 | // Reverse navigation 29 | public virtual ICollection Categories { get; set; } // Many to many mapping 30 | public virtual ICollection QuestionAnswers { get; set; } // QuestionAnswers.FK_dbo.QuestionAnswers_dbo.Questions_QuestionId 31 | 32 | public Question() 33 | { 34 | QuestionAnswers = new List(); 35 | Categories = new List(); 36 | InitializePartial(); 37 | } 38 | partial void InitializePartial(); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Crucial.Providers/Identity/Data/AspNetUserRoleConfiguration.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Collections.ObjectModel; 11 | using System.Linq; 12 | using System.Linq.Expressions; 13 | using System.ComponentModel.DataAnnotations.Schema; 14 | using System.Data.Entity; 15 | using System.Data.Entity.ModelConfiguration; 16 | using Crucial.Providers.Identity.Entities; 17 | //using DatabaseGeneratedOption = System.ComponentModel.DataAnnotations.DatabaseGeneratedOption; 18 | 19 | namespace Crucial.Providers.Identity.Data 20 | { 21 | // AspNetUserRoles 22 | internal partial class AspNetUserRoleConfiguration : EntityTypeConfiguration 23 | { 24 | public AspNetUserRoleConfiguration(string schema = "dbo") 25 | { 26 | ToTable(schema + ".AspNetUserRoles"); 27 | HasKey(x => new { x.UserId, x.RoleId }); 28 | 29 | Property(x => x.UserId).HasColumnName("UserId").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); 30 | Property(x => x.RoleId).HasColumnName("RoleId").IsRequired().HasMaxLength(128).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); 31 | 32 | // Foreign keys 33 | HasRequired(a => a.AspNetUser).WithMany(b => b.AspNetUserRoles).HasForeignKey(c => c.UserId); // FK_dbo.AspNetUserRoles_dbo.AspNetUsers_UserId 34 | InitializePartial(); 35 | } 36 | partial void InitializePartial(); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /Crucial.Providers/Questions/Data/QuestionAnswerConfiguration.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.ComponentModel.DataAnnotations.Schema; 10 | using System.Data.Entity; 11 | using System.Data.Entity.ModelConfiguration; 12 | using Crucial.Providers.Questions.Entities; 13 | //using DatabaseGeneratedOption = System.ComponentModel.DataAnnotations.DatabaseGeneratedOption; 14 | using Crucial.Framework.Data.EntityFramework; 15 | using System.Data.Common; 16 | 17 | namespace Crucial.Providers.Questions.Data 18 | { 19 | // QuestionAnswers 20 | internal class QuestionAnswerConfiguration : EntityTypeConfiguration 21 | { 22 | public QuestionAnswerConfiguration(string schema = "dbo") 23 | { 24 | ToTable(schema + ".QuestionAnswers"); 25 | HasKey(x => x.Id); 26 | 27 | Property(x => x.Id).HasColumnName("Id").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 28 | Property(x => x.QuestionId).HasColumnName("QuestionId").IsRequired(); 29 | Property(x => x.Text).HasColumnName("Text").IsOptional(); 30 | Property(x => x.Image).HasColumnName("Image").IsOptional(); 31 | Property(x => x.CorrectAnswer).HasColumnName("CorrectAnswer").IsRequired(); 32 | 33 | // Foreign keys 34 | HasRequired(a => a.Question).WithMany(b => b.QuestionAnswers).HasForeignKey(c => c.QuestionId); // FK_dbo.QuestionAnswers_dbo.Questions_QuestionId 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /Crucial.Providers/Identity/Data/AspNetUserClaimConfiguration.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Collections.ObjectModel; 11 | using System.Linq; 12 | using System.Linq.Expressions; 13 | using System.ComponentModel.DataAnnotations.Schema; 14 | using System.Data.Entity; 15 | using System.Data.Entity.ModelConfiguration; 16 | using Crucial.Providers.Identity.Entities; 17 | //using DatabaseGeneratedOption = System.ComponentModel.DataAnnotations.DatabaseGeneratedOption; 18 | 19 | namespace Crucial.Providers.Identity.Data 20 | { 21 | // AspNetUserClaims 22 | internal partial class AspNetUserClaimConfiguration : EntityTypeConfiguration 23 | { 24 | public AspNetUserClaimConfiguration(string schema = "dbo") 25 | { 26 | ToTable(schema + ".AspNetUserClaims"); 27 | HasKey(x => x.Id); 28 | 29 | Property(x => x.Id).HasColumnName("Id").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 30 | Property(x => x.UserId).HasColumnName("UserId").IsRequired(); 31 | Property(x => x.ClaimType).HasColumnName("ClaimType").IsOptional(); 32 | Property(x => x.ClaimValue).HasColumnName("ClaimValue").IsOptional(); 33 | 34 | // Foreign keys 35 | HasRequired(a => a.AspNetUser).WithMany(b => b.AspNetUserClaims).HasForeignKey(c => c.UserId); // FK_dbo.AspNetUserClaims_dbo.AspNetUsers_UserId 36 | InitializePartial(); 37 | } 38 | partial void InitializePartial(); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Crucial.Providers/Questions/Data/QuestionConfiguration.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.ComponentModel.DataAnnotations.Schema; 10 | using System.Data.Entity; 11 | using System.Data.Entity.ModelConfiguration; 12 | using Crucial.Providers.Questions.Entities; 13 | //using DatabaseGeneratedOption = System.ComponentModel.DataAnnotations.DatabaseGeneratedOption; 14 | using Crucial.Framework.Data.EntityFramework; 15 | using System.Data.Common; 16 | 17 | namespace Crucial.Providers.Questions.Data 18 | { 19 | // Questions 20 | internal class QuestionConfiguration : EntityTypeConfiguration 21 | { 22 | public QuestionConfiguration(string schema = "dbo") 23 | { 24 | ToTable(schema + ".Questions"); 25 | HasKey(x => x.Id); 26 | 27 | Property(x => x.Id).HasColumnName("Id").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); 28 | Property(x => x.UserId).HasColumnName("UserId").IsRequired(); 29 | Property(x => x.Text).HasColumnName("Text").IsOptional(); 30 | Property(x => x.Image).HasColumnName("Image").IsOptional(); 31 | Property(x => x.AnswerText).HasColumnName("AnswerText").IsOptional(); 32 | Property(x => x.Type).HasColumnName("Type").IsRequired(); 33 | Property(x => x.Version).HasColumnName("Version").IsRequired(); 34 | Property(x => x.CreatedDate).HasColumnName("CreatedDate").IsRequired(); 35 | Property(x => x.ModifiedDate).HasColumnName("ModifiedDate").IsOptional(); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /Crucial.Providers/Questions/Data/CategoryConfiguration.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.ComponentModel.DataAnnotations.Schema; 10 | using System.Data.Entity; 11 | using System.Data.Entity.ModelConfiguration; 12 | using Crucial.Providers.Questions.Entities; 13 | //using DatabaseGeneratedOption = System.ComponentModel.DataAnnotations.DatabaseGeneratedOption; 14 | using Crucial.Framework.Data.EntityFramework; 15 | using System.Data.Common; 16 | 17 | namespace Crucial.Providers.Questions.Data 18 | { 19 | // Category 20 | internal class CategoryConfiguration : EntityTypeConfiguration 21 | { 22 | public CategoryConfiguration(string schema = "dbo") 23 | { 24 | ToTable(schema + ".Category"); 25 | HasKey(x => x.Id); 26 | 27 | Property(x => x.Id).HasColumnName("Id").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); 28 | Property(x => x.UserId).HasColumnName("UserId").IsRequired(); 29 | Property(x => x.Name).HasColumnName("Name").IsRequired().HasMaxLength(128); 30 | Property(x => x.CreatedDate).HasColumnName("CreatedDate").IsRequired(); 31 | Property(x => x.Version).HasColumnName("Version").IsRequired(); 32 | Property(x => x.ModifiedDate).HasColumnName("ModifiedDate").IsOptional(); 33 | HasMany(t => t.Questions).WithMany(t => t.Categories).Map(m => 34 | { 35 | m.ToTable("QuestionCategories", schema); 36 | m.MapLeftKey("Category_Id"); 37 | m.MapRightKey("Question_Id"); 38 | }); 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Domain/AggregateRoot.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Crucial.Framework.DesignPatterns.CQRS.Events; 7 | using Crucial.Framework.DesignPatterns.CQRS.Utils; 8 | 9 | namespace Crucial.Framework.DesignPatterns.CQRS.Domain 10 | { 11 | public class AggregateRoot : IEventProvider 12 | { 13 | private readonly List _changes; 14 | 15 | public int Id { get; set; } 16 | public int Version { get; set; } 17 | public int EventVersion { get; protected set; } 18 | 19 | protected AggregateRoot() 20 | { 21 | _changes = new List(); 22 | } 23 | 24 | public IEnumerable GetUncommittedChanges() 25 | { 26 | return _changes; 27 | } 28 | 29 | public void MarkChangesAsCommitted() 30 | { 31 | _changes.Clear(); 32 | } 33 | 34 | public void LoadsFromHistory(IEnumerable history) 35 | { 36 | if (history.Count() > 0) 37 | { 38 | List tasks = new List(); 39 | 40 | foreach (var e in history) 41 | { 42 | ApplyChange(e, false); 43 | } 44 | 45 | Version = history.Last().Version; 46 | } 47 | 48 | EventVersion = Version; 49 | } 50 | 51 | protected void ApplyChange(Event @event) 52 | { 53 | ApplyChange(@event, true); 54 | } 55 | 56 | private void ApplyChange(Event @event, bool isNew) 57 | { 58 | dynamic d = this; 59 | 60 | d.Handle(Converter.ChangeTo(@event, @event.GetType())); 61 | if (isNew) 62 | { 63 | _changes.Add(@event); 64 | } 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /Crucial.Providers/Identity/Data/AspNetUserLoginConfiguration.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Collections.ObjectModel; 11 | using System.Linq; 12 | using System.Linq.Expressions; 13 | using System.ComponentModel.DataAnnotations.Schema; 14 | using System.Data.Entity; 15 | using System.Data.Entity.ModelConfiguration; 16 | using Crucial.Providers.Identity.Entities; 17 | //using DatabaseGeneratedOption = System.ComponentModel.DataAnnotations.DatabaseGeneratedOption; 18 | 19 | namespace Crucial.Providers.Identity.Data 20 | { 21 | // AspNetUserLogins 22 | internal partial class AspNetUserLoginConfiguration : EntityTypeConfiguration 23 | { 24 | public AspNetUserLoginConfiguration(string schema = "dbo") 25 | { 26 | ToTable(schema + ".AspNetUserLogins"); 27 | HasKey(x => new { x.LoginProvider, x.ProviderKey, x.UserId }); 28 | 29 | Property(x => x.LoginProvider).HasColumnName("LoginProvider").IsRequired().HasMaxLength(128).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); 30 | Property(x => x.ProviderKey).HasColumnName("ProviderKey").IsRequired().HasMaxLength(128).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); 31 | Property(x => x.UserId).HasColumnName("UserId").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); 32 | 33 | // Foreign keys 34 | HasRequired(a => a.AspNetUser).WithMany(b => b.AspNetUserLogins).HasForeignKey(c => c.UserId); // FK_dbo.AspNetUserLogins_dbo.AspNetUsers_UserId 35 | InitializePartial(); 36 | } 37 | partial void InitializePartial(); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /Web/js/app.js: -------------------------------------------------------------------------------- 1 | (function(angular) { 2 | 'use strict'; 3 | 4 | var app = angular.module('qyz', [ 5 | //app 6 | 'Qyz.Category', 7 | 'Qyz.Settings', 8 | 'Qyz.Question', 9 | 'Qyz.SignalR', 10 | //utils 11 | 'Utils', 12 | //angular modules 13 | 'ngResource', 14 | 'ngRoute', 15 | 'ngMaterial', 16 | 'ngMdIcons' 17 | ]); 18 | app.value('signalRServer', 'http://localhost:41194/'); 19 | app.config(['$locationProvider','$routeProvider', function($locationProvider, $routeProvider) { 20 | 21 | $routeProvider 22 | .otherwise({ 23 | redirectTo: '/' 24 | }); 25 | 26 | $locationProvider.html5Mode(true); 27 | }]); 28 | 29 | app.run(['$rootScope', '$route', function($rootScope, $route) { 30 | $rootScope.$on('$routeChangeSuccess', function (newVal, oldVal) { 31 | if (oldVal !== newVal) { 32 | document.title = $route.current.title; 33 | $rootScope.title = $route.current.title; 34 | } 35 | }); 36 | }]); 37 | 38 | app.controller('AppCtrl', function ($scope, $timeout, $mdSidenav, $log) { 39 | $scope.toggleLeft = function () { 40 | $mdSidenav('left').toggle() 41 | .then(function () { 42 | $log.debug("toggle left is done"); 43 | }); 44 | }; 45 | }); 46 | 47 | app.controller('LeftCtrl', function ($scope, $timeout, $mdSidenav, $log) { 48 | $scope.close = function () { 49 | $mdSidenav('left').close() 50 | .then(function () { 51 | $log.debug("close LEFT is done"); 52 | }); 53 | }; 54 | 55 | $scope.open = function () { 56 | $mdSidenav('left').open() 57 | .then(function () { 58 | $log.debug("open LEFT is done"); 59 | }); 60 | }; 61 | }); 62 | 63 | })(window.angular); 64 | 65 | 66 | -------------------------------------------------------------------------------- /Crucial.Qyz/Events/Question/QuestionCreatedEvent.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Events; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Crucial.Qyz.Events 9 | { 10 | [Serializable] 11 | public class QuestionCreatedEvent : Event 12 | { 13 | public string Question { get; internal set; } 14 | 15 | public QuestionCreatedEvent(int aggregateId, string question, DateTime createdDate) 16 | { 17 | Timestamp = createdDate; 18 | AggregateId = aggregateId; 19 | Question = question; 20 | } 21 | } 22 | 23 | [Serializable] 24 | public class PictureQuestionCreatedEvent : Event 25 | { 26 | public byte[] Image { get; set; } 27 | 28 | public string Answer { get; set; } 29 | 30 | public PictureQuestionCreatedEvent(int aggregateId, byte[] image, string answer) 31 | { 32 | AggregateId = aggregateId; 33 | Image = image; 34 | Answer = answer; 35 | } 36 | } 37 | 38 | [Serializable] 39 | public class MultipleChoiceQuestionCreatedEvent : Event 40 | { 41 | public string Question { get; internal set; } 42 | 43 | public Dictionary Answer { get; set; } 44 | 45 | public MultipleChoiceQuestionCreatedEvent(int aggregateId, string question, Dictionary answers) 46 | { 47 | AggregateId = aggregateId; 48 | Answer = answers; 49 | Question = question; 50 | } 51 | } 52 | 53 | [Serializable] 54 | public class NumericAnswerQuestionCreatedEvent : Event 55 | { 56 | public string Question { get; internal set; } 57 | 58 | public int Answer { get; set; } 59 | 60 | public NumericAnswerQuestionCreatedEvent(int aggregateId, string question, int answer) 61 | { 62 | AggregateId = aggregateId; 63 | Question = question; 64 | Answer = answer; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Crucial.Framework/Logging/ILogger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.Entity.Infrastructure; 3 | using System.Data.Entity.Validation; 4 | using System.Net; 5 | using System.Web; 6 | 7 | namespace Crucial.Framework.Logging 8 | { 9 | public interface ILogger 10 | { 11 | bool Initialised { get; } 12 | bool IsDebugEnabled { get; } 13 | bool IsFatalEnabled { get; } 14 | bool IsErrorEnabled { get; } 15 | bool IsInfoEnabled { get; } 16 | bool IsTraceEnabled { get; } 17 | bool IsWarnEnabled { get; } 18 | 19 | void Debug(string message, params Object[] parameters); 20 | void Fatal(string message, params Object[] parameters); 21 | void Error(string message, params Object[] parameters); 22 | void Info(string message, params Object[] parameters); 23 | void Trace(string message, params Object[] parameters); 24 | void Warn(string message, params Object[] parameters); 25 | 26 | void LogException(string message, Exception exception, ExceptionType exceptionType = ExceptionType.Handled); 27 | void LogException(string message, Exception exception, HttpRequestBase httpRequestBase, ExceptionType exceptionType = ExceptionType.Handled); 28 | void LogException(string message, Exception exception, HttpRequest httpRequest, ExceptionType exceptionType = ExceptionType.Handled); 29 | void LogException(Exception exception, ExceptionType exceptionType = ExceptionType.Handled); 30 | void LogException(Exception exception, HttpRequestBase httpRequestBase, ExceptionType exceptionType = ExceptionType.Handled); 31 | void LogException(Exception exception, HttpRequest httpRequest, ExceptionType exceptionType = ExceptionType.Handled); 32 | void LogException(WebException webException, ExceptionType exceptionType = ExceptionType.Handled); 33 | void LogException(DbUpdateException dbUpdateException); 34 | void LogException(DbEntityValidationException dbEntityValidationException); 35 | } 36 | 37 | public enum ExceptionType 38 | { 39 | Handled = 0, 40 | Unhandled = 1 41 | } 42 | } -------------------------------------------------------------------------------- /Web/templates/category/category.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 |
10 |
11 |

{{category.Name}}

12 |

Created {{category.CreatedDate | fromNow}}

13 |

Modified {{category.ModifiedDate | fromNow}}

14 |

15 | Questions about x, y and z 16 |

17 |
18 |
19 | 20 | 21 | 22 |
23 | 24 | 25 | Delete 26 | 27 | 28 | 29 |
30 | 31 |
32 | 33 | 34 | 35 | Add Category 36 | 37 | 38 | 39 | 40 |
41 | -------------------------------------------------------------------------------- /Web/templates/question/question.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 |
10 |
11 |

{{question.QuestionText}}

12 |

Created {{question.CreatedDate | fromNow}}

13 |

Modified {{question.ModifiedDate | fromNow}}

14 |

15 | Questions about x, y and z 16 |

17 |
18 |
19 | 20 | 21 | 22 |
23 | 24 | 25 | Delete 26 | 27 | 28 | 29 |
30 | 31 |
32 | 33 | 34 | 35 | Add question 36 | 37 | 38 | 39 | 40 |
41 | -------------------------------------------------------------------------------- /Crucial.Providers/Identity/Entities/AspNetUser.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.ComponentModel.DataAnnotations.Schema; 11 | using System.Data.Entity; 12 | 13 | namespace Crucial.Providers.Identity.Entities 14 | { 15 | // AspNetUsers 16 | public partial class AspNetUser : Crucial.Framework.BaseEntities.ProviderEntityBase 17 | { 18 | public int Id { get; set; } // Id (Primary key) 19 | public string Email { get; set; } // Email 20 | public bool EmailConfirmed { get; set; } // EmailConfirmed 21 | public string PasswordHash { get; set; } // PasswordHash 22 | public string SecurityStamp { get; set; } // SecurityStamp 23 | public string PhoneNumber { get; set; } // PhoneNumber 24 | public bool PhoneNumberConfirmed { get; set; } // PhoneNumberConfirmed 25 | public bool TwoFactorEnabled { get; set; } // TwoFactorEnabled 26 | public DateTime? LockoutEndDateUtc { get; set; } // LockoutEndDateUtc 27 | public bool LockoutEnabled { get; set; } // LockoutEnabled 28 | public int AccessFailedCount { get; set; } // AccessFailedCount 29 | public string UserName { get; set; } // UserName 30 | 31 | // Reverse navigation 32 | public virtual ICollection AspNetUserClaims { get; set; } // AspNetUserClaims.FK_dbo.AspNetUserClaims_dbo.AspNetUsers_UserId 33 | public virtual ICollection AspNetUserLogins { get; set; } // Many to many mapping 34 | public virtual ICollection AspNetUserRoles { get; set; } // Many to many mapping 35 | 36 | public AspNetUser() 37 | { 38 | AspNetUserClaims = new List(); 39 | AspNetUserLogins = new List(); 40 | AspNetUserRoles = new List(); 41 | InitializePartial(); 42 | } 43 | partial void InitializePartial(); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /Crucial.Providers/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Crucial.Providers/Identity/Data/AspNetUserConfiguration.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantUsingDirective 2 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 3 | // ReSharper disable InconsistentNaming 4 | // ReSharper disable PartialTypeWithSinglePart 5 | // ReSharper disable PartialMethodWithSinglePart 6 | // ReSharper disable RedundantNameQualifier 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Collections.ObjectModel; 11 | using System.Linq; 12 | using System.Linq.Expressions; 13 | using System.ComponentModel.DataAnnotations.Schema; 14 | using System.Data.Entity; 15 | using System.Data.Entity.ModelConfiguration; 16 | using Crucial.Providers.Identity.Entities; 17 | //using DatabaseGeneratedOption = System.ComponentModel.DataAnnotations.DatabaseGeneratedOption; 18 | 19 | namespace Crucial.Providers.Identity.Data 20 | { 21 | // AspNetUsers 22 | internal partial class AspNetUserConfiguration : EntityTypeConfiguration 23 | { 24 | public AspNetUserConfiguration(string schema = "dbo") 25 | { 26 | ToTable(schema + ".AspNetUsers"); 27 | HasKey(x => x.Id); 28 | 29 | Property(x => x.Id).HasColumnName("Id").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 30 | Property(x => x.Email).HasColumnName("Email").IsOptional().HasMaxLength(256); 31 | Property(x => x.EmailConfirmed).HasColumnName("EmailConfirmed").IsRequired(); 32 | Property(x => x.PasswordHash).HasColumnName("PasswordHash").IsOptional(); 33 | Property(x => x.SecurityStamp).HasColumnName("SecurityStamp").IsOptional(); 34 | Property(x => x.PhoneNumber).HasColumnName("PhoneNumber").IsOptional(); 35 | Property(x => x.PhoneNumberConfirmed).HasColumnName("PhoneNumberConfirmed").IsRequired(); 36 | Property(x => x.TwoFactorEnabled).HasColumnName("TwoFactorEnabled").IsRequired(); 37 | Property(x => x.LockoutEndDateUtc).HasColumnName("LockoutEndDateUtc").IsOptional(); 38 | Property(x => x.LockoutEnabled).HasColumnName("LockoutEnabled").IsRequired(); 39 | Property(x => x.AccessFailedCount).HasColumnName("AccessFailedCount").IsRequired(); 40 | Property(x => x.UserName).HasColumnName("UserName").IsRequired().HasMaxLength(256); 41 | InitializePartial(); 42 | } 43 | partial void InitializePartial(); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/CQRS/Storage/Repository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Collections.Generic; 4 | using Crucial.Framework.DesignPatterns.CQRS.Domain; 5 | using Crucial.Framework.DesignPatterns.CQRS.Exceptions; 6 | using Crucial.Framework.DesignPatterns.CQRS.Events; 7 | using System.Threading.Tasks; 8 | using System.Threading; 9 | using Crucial.Framework.Threading; 10 | 11 | namespace Crucial.Framework.DesignPatterns.CQRS.Storage 12 | { 13 | public class Repository : IRepository where T : AggregateRoot, new() 14 | { 15 | private readonly IEventStorage _storage; 16 | private static readonly NamedLocker _locker = new NamedLocker(); 17 | 18 | public Repository(IEventStorage storage) 19 | { 20 | _storage = storage; 21 | } 22 | 23 | public void Save(AggregateRoot aggregate, int expectedVersion) 24 | { 25 | if (aggregate.GetUncommittedChanges().Any()) 26 | { 27 | lock (_locker.GetLock(aggregate.Id.ToString())) 28 | { 29 | var item = new T(); 30 | 31 | if (expectedVersion != -1) 32 | { 33 | item = GetById(aggregate.Id).Result; 34 | 35 | if (item.Version != expectedVersion) 36 | { 37 | throw new ConcurrencyException(string.Format("Aggregate {0} has been previously modified", item.Id)); 38 | } 39 | } 40 | 41 | _storage.Save(aggregate).Wait(); 42 | } 43 | } 44 | } 45 | 46 | public async Task GetById(int id) 47 | { 48 | IEnumerable events; 49 | var memento = await _storage.GetMemento(id).ConfigureAwait(false); 50 | if (memento != null) 51 | { 52 | var list = await _storage.GetEvents(id).ConfigureAwait(false); 53 | events = list.Where(e => e.Version >= memento.Version); 54 | } 55 | else 56 | { 57 | events = await _storage.GetEvents(id).ConfigureAwait(false); 58 | } 59 | 60 | var obj = new T(); 61 | 62 | if (memento != null) 63 | { 64 | ((IOriginator) obj).SetMemento(memento); 65 | } 66 | 67 | await Task.Run(() => obj.LoadsFromHistory(events)).ConfigureAwait(false); 68 | return obj; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Web/js/signalr/signalrHubProxy.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var module = angular.module('Qyz.SignalR', []); 4 | 5 | module.service('signalRHubProxy', ['$rootScope', 'signalRServer', 6 | function ($rootScope, signalRServer) { 7 | function signalRHubProxyFactory(serverUrl, hubName, startOptions) { 8 | var connection = $.hubConnection(signalRServer); 9 | var proxy = connection.createHubProxy(hubName); 10 | 11 | connection.logging = startOptions.logging; 12 | 13 | return { 14 | running: function () { 15 | return connection; 16 | }, 17 | stop: function () { 18 | connection.stop(true, true); 19 | }, 20 | start: function () { 21 | connection.start(startOptions) 22 | .done(function () { 23 | if (startOptions.logging) { 24 | console.log("Hub started:" + hubName); 25 | } 26 | }) 27 | .fail(function (error) { 28 | console.log(error); 29 | }); 30 | }, 31 | on: function (eventName, callback) { 32 | proxy.on(eventName, function (result) { 33 | if (startOptions.logging) { 34 | console.log(result); 35 | } 36 | $rootScope.$apply(function () { 37 | if (callback) { 38 | callback(result); 39 | } 40 | }); 41 | }); 42 | }, 43 | off: function (eventName, callback) { 44 | proxy.off(eventName, function (result) { 45 | $rootScope.$apply(function () { 46 | if (callback) { 47 | callback(result); 48 | } 49 | }); 50 | }); 51 | }, 52 | invoke: function (methodName, callback) { 53 | proxy.invoke(methodName) 54 | .done(function (result) { 55 | $rootScope.$apply(function () { 56 | if (callback) { 57 | callback(result); 58 | } 59 | }); 60 | }); 61 | } 62 | }; 63 | }; 64 | 65 | return signalRHubProxyFactory; 66 | }]); -------------------------------------------------------------------------------- /API/App_Start/Bootstraper.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Messaging; 2 | using Crucial.Framework.DesignPatterns.CQRS.Storage; 3 | using Crucial.Framework.DesignPatterns.CQRS.Utils; 4 | using Crucial.Providers.Questions; 5 | using Crucial.Services.Managers; 6 | using Crucial.Services.Managers.Interfaces; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Linq; 10 | using System.Web; 11 | using StructureMap; 12 | using Crucial.EventStore; 13 | using Crucial.Framework.Data.EntityFramework; 14 | using Crucial.Providers.EventStore.Data; 15 | using Crucial.Framework.IoC.StructureMapProvider; 16 | using Crucial.Framework.Logging; 17 | using Crucial.Providers.Questions.Data; 18 | using StructureMap.Pipeline; 19 | 20 | namespace API 21 | { 22 | static class Bootstrapper 23 | { 24 | public static void BootstrapStructureMap() 25 | { 26 | DependencyResolver.Register(x => 27 | { 28 | x.For(typeof(IContextProvider<>)).Use(typeof(ContextProvider<>)); 29 | x.For(typeof(IRepository<>)).Use(typeof(Repository<>)); 30 | x.For().Use(); 31 | x.For().Use(); 32 | x.For().Use(); 33 | x.For().Use(); 34 | x.For().Use(); 35 | x.For().Use(); 36 | x.For().Use(() => new QuestionsDbContext()); 37 | x.For().Use(() => new EventStoreContext()); 38 | x.For().Use(); 39 | x.For().Use(); 40 | x.For().Use(); 41 | x.For().Use(); 42 | 43 | x.Scan(scanner => 44 | { 45 | scanner.AssemblyContainingType(typeof(CategoryRepositoryAsync)); 46 | scanner.WithDefaultConventions(); 47 | }); 48 | 49 | x.Scan(s => 50 | { 51 | s.AssemblyContainingType(); 52 | s.AssemblyContainingType(); 53 | s.ConnectImplementationsToTypesClosing(typeof(Crucial.Framework.DesignPatterns.CQRS.Commands.ICommandHandler<>)); 54 | s.ConnectImplementationsToTypesClosing(typeof(Crucial.Framework.DesignPatterns.CQRS.Events.IEventHandler<>)); 55 | }); 56 | }); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /API/Controllers/QuestionController.cs: -------------------------------------------------------------------------------- 1 | using API.Mappers; 2 | using Crucial.Framework.DesignPatterns.CQRS.Messaging; 3 | using Crucial.Qyz.Commands; 4 | using Crucial.Qyz.Commands.Question; 5 | using Crucial.Services.Managers.Interfaces; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Net; 10 | using System.Net.Http; 11 | using System.Threading.Tasks; 12 | using System.Web.Http; 13 | using System.Web.Http.Cors; 14 | using Crucial.Qyz.Commands.UserCategory; 15 | 16 | namespace API.Controllers 17 | { 18 | [EnableCors(origins: "http://localhost:8000,http://localhost:6307", headers: "*", methods: "*")] 19 | public class QuestionsController : ApiController 20 | { 21 | ICommandBus _commandBus; 22 | IQuestionManager _questionManager; 23 | QuestionToQuestionMapper _questionMapper; 24 | 25 | public QuestionsController(ICommandBus commandBus, 26 | IQuestionManager questionManager) 27 | { 28 | _commandBus = commandBus; 29 | _questionManager = questionManager; 30 | _questionMapper = new QuestionToQuestionMapper(); 31 | } 32 | 33 | // GET api/ 34 | public async Task> Get() 35 | { 36 | var questions = await _questionManager.GetQuestions().ConfigureAwait(false); 37 | return questions.Select(c => _questionMapper.ToAnyEntity(c)).ToList(); 38 | } 39 | 40 | // GET api//5 41 | public async Task Get(int id) 42 | { 43 | var question = await _questionManager.GetQuestion(id).ConfigureAwait(false); 44 | return _questionMapper.ToAnyEntity(question); 45 | } 46 | 47 | // POST api/ 48 | public async Task Post([FromBody]API.Models.Question value) 49 | { 50 | await _commandBus.Send(new QuestionCreateCommand(value.QuestionText)); 51 | } 52 | 53 | // PUT: api//5 54 | public async Task Put(int id, [FromBody]API.Models.Question value) 55 | { 56 | await _commandBus.Send(new QuestionTextChangeCommand(value.Id, value.QuestionText, value.Version)); 57 | } 58 | 59 | // DELETE: api//5 60 | [HttpPost] 61 | public async Task Delete(int id, [FromBody]API.Models.Question value) 62 | { 63 | await _commandBus.Send(new QuestionDeleteCommand(id, value.Version)); 64 | } 65 | 66 | //[HttpPost] 67 | //public async Task Category(int id, int actionId, [FromBody]API.Models.Question question) 68 | //{ 69 | // await _commandBus.Send(new AddQuestionToCategoryCommand(id, actionId, question.Version)); 70 | //} 71 | //} 72 | } 73 | } -------------------------------------------------------------------------------- /Crucial.Framework/DesignPatterns/Repository/IQueryableRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Runtime.Serialization; 6 | using System.ServiceModel; 7 | using Crucial.Framework.BaseEntities; 8 | using System.Linq.Expressions; 9 | using System.Threading.Tasks; 10 | 11 | namespace Crucial.Framework.DesignPatterns.Repository 12 | { 13 | [ServiceContract] 14 | public interface IQueryableRepository 15 | where TEntity : ProviderEntityBase 16 | { 17 | [OperationContract] 18 | IQueryable FindBy(Expression> predicate); 19 | 20 | [OperationContract] 21 | IQueryable Page(System.Linq.Expressions.Expression> predicate, int pageIndex, int pageSize, Expression> orderByProperty, Framework.Enums.SortOrder sortOrder, out int rowCount); 22 | 23 | [OperationContract] 24 | IQueryable Page(System.Linq.Expressions.Expression> predicate, int pageIndex, int pageSize, Expression> orderByProperty, Framework.Enums.SortOrder sortOrder, Expression> thenByProperty, Framework.Enums.SortOrder thenSortOrder, out int rowCount); 25 | 26 | [OperationContract] 27 | IQueryable Page(Expression> predicate, int pageIndex, 28 | int pageSize, 29 | Expression> orderByProperty, 30 | Framework.Enums.SortOrder sortOrder, 31 | Expression> thenByProperty, 32 | Framework.Enums.SortOrder thenSortOrder, 33 | out int rowCount, 34 | params Expression>[] include); 35 | 36 | [OperationContract] 37 | IQueryable Page(Expression> predicate, int pageIndex, int pageSize, 38 | Expression> orderByProperty, 39 | Framework.Enums.SortOrder sortOrder, out int rowCount, 40 | params Expression>[] include); 41 | 42 | [OperationContract] 43 | IQueryable FindBy(System.Linq.Expressions.Expression> predicate, params System.Linq.Expressions.Expression>[] include); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Crucial.Providers/Filesystem/DirectoryRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Crucial.Providers.Filesystem.Entities.Extensions; 6 | using Crucial.Providers.Filesystem.Mappers; 7 | 8 | namespace Crucial.Providers.Filesystem 9 | { 10 | public class DirectoryRepository : Interfaces.IDirectoryRepository 11 | { 12 | private DirectoryMapper _Mapper; 13 | 14 | public DirectoryRepository() 15 | { 16 | _Mapper = new DirectoryMapper(); 17 | } 18 | 19 | public Entities.Directory Create(Entities.Directory o) 20 | { 21 | var d = System.IO.Directory.CreateDirectory(o.BuildPath()); 22 | return _Mapper.ToProviderEntity(d); 23 | } 24 | 25 | public bool Update(Entities.DirectoryUpdate o) 26 | { 27 | string path = o.BuildPath(); 28 | o.PathParts = o.MoveTo; 29 | string destPath = o.BuildPath(); 30 | 31 | System.IO.Directory.Move(System.IO.Path.Combine(path, o.Name), System.IO.Path.Combine(destPath, o.RenameTo)); 32 | 33 | return true; 34 | } 35 | 36 | public bool Delete(Entities.Directory d) 37 | { 38 | string path = d.BuildPath(); 39 | 40 | if (System.IO.Directory.GetFiles(path).Count() > 0) 41 | { 42 | throw new Exceptions.DirectoryNotEmptyException(d); 43 | } 44 | 45 | try 46 | { 47 | System.IO.Directory.Delete(path); 48 | } 49 | catch (System.IO.DirectoryNotFoundException) 50 | { 51 | throw new Exceptions.PathNotFoundException(d); 52 | } 53 | catch (System.IO.DriveNotFoundException) 54 | { 55 | throw new Exceptions.PathNotFoundException(d); 56 | } 57 | catch (Exception) 58 | { 59 | throw new Exceptions.GeneralException(d, d.GetType()); 60 | } 61 | 62 | return true; 63 | } 64 | //How to you know that these are the only errors that will be thrown? 65 | //Do you not need a general exception to handle just in case? 66 | public Entities.Directory Get(Entities.Directory id) 67 | { 68 | string path = id.BuildPath(); 69 | 70 | System.IO.DirectoryInfo d; 71 | 72 | try 73 | { 74 | d = new System.IO.DirectoryInfo(path); 75 | } 76 | catch (System.IO.DirectoryNotFoundException) 77 | { 78 | throw new Exceptions.PathNotFoundException(id); 79 | } 80 | catch (System.IO.DriveNotFoundException) 81 | { 82 | throw new Exceptions.PathNotFoundException(id); 83 | } 84 | 85 | return _Mapper.ToProviderEntity(d); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Crucial.Qyz/Domain/QuestionBase.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Framework.DesignPatterns.CQRS.Domain; 2 | using Crucial.Framework.DesignPatterns.CQRS.Events; 3 | using Crucial.Framework.DesignPatterns.CQRS.Storage; 4 | using Crucial.Qyz.Domain.Mementos; 5 | using Crucial.Qyz.Events; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | 12 | namespace Crucial.Qyz.Domain 13 | { 14 | 15 | public class Question : AggregateRoot, 16 | IHandle, 17 | IHandle, 18 | IHandle, 19 | IOriginator 20 | { 21 | #region Public Parameterless Constructor 22 | 23 | public Question() 24 | { 25 | 26 | } 27 | 28 | #endregion 29 | 30 | #region Public properties 31 | 32 | public string QuestionText { get; set; } 33 | 34 | #endregion 35 | 36 | #region Internal command implementations 37 | 38 | internal Question(int id, string text) 39 | { 40 | ApplyChange(new QuestionCreatedEvent(id, text, DateTime.UtcNow)); 41 | } 42 | 43 | internal void ChangeQuestionText(string questionText) 44 | { 45 | ApplyChange(new QuestionTextChangedEvent(Id, questionText, Version, DateTime.UtcNow)); 46 | } 47 | 48 | internal void Delete() 49 | { 50 | ApplyChange(new QuestionDeletedEvent(Id, Version, DateTime.UtcNow)); 51 | } 52 | 53 | #endregion 54 | 55 | #region IOriginator implementation 56 | 57 | public BaseMemento GetMemento() 58 | { 59 | return new QuestionMemento(Id, QuestionText, Version); 60 | } 61 | 62 | public void SetMemento(BaseMemento memento) 63 | { 64 | QuestionText = ((QuestionMemento)memento).QuestionText; 65 | Version = memento.Version; 66 | Id = memento.Id; 67 | } 68 | 69 | #endregion 70 | 71 | #region IHandle implementation 72 | 73 | public void Handle(QuestionCreatedEvent e) 74 | { 75 | QuestionText = e.Question; 76 | Version = e.Version; 77 | Id = e.AggregateId; 78 | } 79 | public void Handle(QuestionTextChangedEvent e) 80 | { 81 | QuestionText = e.Question; 82 | Version = e.Version; 83 | Id = e.AggregateId; 84 | } 85 | 86 | public void Handle(QuestionDeletedEvent e) 87 | { 88 | Version = e.Version; 89 | Id = e.AggregateId; 90 | } 91 | 92 | #endregion 93 | } 94 | 95 | public abstract class QuestionAnswer { 96 | 97 | } 98 | 99 | public abstract class QuestionAnswer : QuestionAnswer { 100 | public TAnswerType Answer { get; set; } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Crucial.Tests/Bootstrap/Dependencies.cs: -------------------------------------------------------------------------------- 1 | using Crucial.EventStore; 2 | using Crucial.Framework.DesignPatterns.CQRS.Messaging; 3 | using Crucial.Framework.DesignPatterns.CQRS.Storage; 4 | using Crucial.Framework.DesignPatterns.CQRS.Utils; 5 | using Crucial.Framework.IoC.StructureMapProvider; 6 | using Crucial.Providers.EventStore.Data; 7 | using Crucial.Providers.Questions; 8 | using Crucial.Providers.Questions.Data; 9 | using Crucial.Services.Managers; 10 | using Crucial.Services.Managers.Interfaces; 11 | using Crucial.Providers.EventStore; 12 | using Crucial.Framework.Data.EntityFramework; 13 | using Crucial.Framework.Logging; 14 | using StructureMap.Pipeline; 15 | 16 | namespace Crucial.Tests.Bootstrap 17 | { 18 | public static class Dependencies 19 | { 20 | public static void Setup() 21 | { 22 | DependencyResolver.Register(x => 23 | { 24 | // Actual implementation tested by these tests 25 | x.For(typeof(IContextProvider<>)).Use(typeof(ContextProvider<>)); 26 | x.For(typeof(IRepository<>)).Use(typeof(Repository<>)); 27 | x.For().Use(); 28 | x.For().Use(); 29 | x.For().Use(); 30 | x.For().Use(); 31 | x.For().Use(); 32 | x.For().Use(); 33 | x.For().Use(); 34 | x.For().Use(); 35 | x.For().Use(); 36 | x.For().Use(); 37 | x.For().Use(); 38 | x.For().Use(); 39 | x.For().Use(); 40 | x.For().Use(); 41 | 42 | x.Scan(s => 43 | { 44 | s.AssemblyContainingType(); 45 | s.ConnectImplementationsToTypesClosing(typeof(Crucial.Framework.DesignPatterns.CQRS.Commands.ICommandHandler<>)); 46 | s.ConnectImplementationsToTypesClosing(typeof(Crucial.Framework.DesignPatterns.CQRS.Events.IEventHandler<>)); 47 | }); 48 | 49 | // Mocks 50 | var testEventStore = Effort.DbConnectionFactory.CreateTransient(); 51 | var testQuestionsDb = Effort.DbConnectionFactory.CreateTransient(); 52 | 53 | x.For().Singleton().Use(() => new EventStoreContext(testEventStore,true)); 54 | x.For().Singleton().Use(() => new QuestionsDbContext(testQuestionsDb,true)); 55 | }); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Crucial.Services/QuestionManager.cs: -------------------------------------------------------------------------------- 1 | using Crucial.Providers.Questions; 2 | using Crucial.Services.Mappers; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using Crucial.Framework.DesignPatterns.Repository.Async.Extensions; 9 | using Crucial.Framework.Logging; 10 | using Crucial.Providers.Questions.Entities; 11 | 12 | namespace Crucial.Services.Managers 13 | { 14 | public class QuestionManager : 15 | Crucial.Services.Managers.Interfaces.IQuestionManager, 16 | Crucial.Services.Managers.Interfaces.ICategoryManager 17 | { 18 | private readonly ICategoryRepositoryAsync _categoryRepo; 19 | private readonly IQuestionRepositoryAsync _questionRepo; 20 | 21 | private readonly CategoryToCategoryMapper _categoryMapper; 22 | private readonly QuestionToQuestionMapper _questionMapper; 23 | 24 | public QuestionManager(ICategoryRepositoryAsync categoryRepo, 25 | IQuestionRepositoryAsync questionRepo) 26 | { 27 | _categoryRepo = categoryRepo; 28 | _questionRepo = questionRepo; 29 | _categoryMapper = new CategoryToCategoryMapper(); 30 | _questionMapper = new QuestionToQuestionMapper(); 31 | } 32 | 33 | #region ICategoryManager implementation 34 | 35 | public async Task> GetUserCategories() 36 | { 37 | var categories = await _categoryRepo.FindByAsync(x => x.Id > -1).ConfigureAwait(false); 38 | var categoriesList = categories.ToList(); 39 | return categoriesList.Select(_categoryMapper.ToServiceEntity); 40 | } 41 | 42 | public async Task GetUserCategory(int categoryId) 43 | { 44 | var providerEntity = await _categoryRepo.FindByAsync(x => x.Id == categoryId).ConfigureAwait(false); 45 | return _categoryMapper.ToServiceEntity(providerEntity.FirstOrDefault()); 46 | } 47 | public async Task> GetQuestionsInCategory(int id) 48 | { 49 | var providerEntities = await _categoryRepo.GetAsync(x => x.Where( o => o.Id == id).Select(o => o.Questions).FirstOrDefault()).ConfigureAwait(false); 50 | return providerEntities.ToList().Select(_questionMapper.ToServiceEntity); 51 | } 52 | 53 | #endregion 54 | 55 | #region IQuestionManager implementation 56 | 57 | public async Task> GetQuestions() 58 | { 59 | var questions = await _questionRepo.FindByAsync(x => x.Id > -1).ConfigureAwait(false); 60 | var questionsList = questions.ToList(); 61 | return questionsList.Select(_questionMapper.ToServiceEntity); 62 | } 63 | 64 | public async Task GetQuestion(int questionId) 65 | { 66 | var providerEntity = await _questionRepo.FindByAsync(x => x.Id == questionId).ConfigureAwait(false); 67 | return _questionMapper.ToServiceEntity(providerEntity.FirstOrDefault()); 68 | } 69 | 70 | #endregion 71 | } 72 | } 73 | --------------------------------------------------------------------------------