├── src ├── ScaffoldR.EntityFramework │ ├── packages.config │ ├── Entities │ │ ├── EntityFrameworkUnitOfWork.cs │ │ ├── EntityReaderAdapter.cs │ │ ├── EntityWriterAdapter.cs │ │ └── EntityFrameworkRepository.cs │ ├── ScaffoldR.EntityFramework.nuspec │ ├── App.config │ ├── Extensions │ │ └── ContainerExtensions.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── ScaffoldR.EntityFramework.csproj ├── ScaffoldR │ ├── Core │ │ ├── Entities │ │ │ ├── Entity.cs │ │ │ ├── IEntityReader.cs │ │ │ ├── IEntityWriter.cs │ │ │ └── EntityWithId.cs │ │ ├── Views │ │ │ ├── IViewModel.cs │ │ │ ├── IProcessViewModels.cs │ │ │ └── IHandleViewModel.cs │ │ ├── Transactions │ │ │ ├── TransactionalAttribute.cs │ │ │ └── IProcessTransactions.cs │ │ ├── Commands │ │ │ ├── ICommand.cs │ │ │ ├── IProcessCommands.cs │ │ │ ├── ICreateEntityCommand.cs │ │ │ └── IHandleCommand.cs │ │ ├── Events │ │ │ ├── IEvent.cs │ │ │ ├── IProcessEvents.cs │ │ │ ├── RaiseEventAttribute.cs │ │ │ ├── ITriggerEvent.cs │ │ │ └── IHandleEvent.cs │ │ ├── Tasks │ │ │ └── ITaskFactory.cs │ │ ├── Queries │ │ │ ├── IQuery.cs │ │ │ ├── IProcessQueries.cs │ │ │ └── IHandleQuery.cs │ │ ├── Validation │ │ │ └── IProcessValidation.cs │ │ └── Extensions │ │ │ └── ReflectionExtensions.cs │ ├── packages.config │ ├── Infrastructure │ │ ├── Tasks │ │ │ └── TaskFactory.cs │ │ ├── Transactions │ │ │ └── EmptyTransactionProcessor.cs │ │ ├── FluentValidation │ │ │ ├── ValidateNothingDecorator.cs │ │ │ ├── ValidateCommandDecorator.cs │ │ │ ├── ValidateQueryDecorator.cs │ │ │ ├── ValidationProcessor.cs │ │ │ └── SimpleInjectorValidatorFactory.cs │ │ ├── CompositionRoot │ │ │ ├── Packages │ │ │ │ ├── TaskPackage.cs │ │ │ │ ├── EventPackage.cs │ │ │ │ ├── TransactionPackage.cs │ │ │ │ ├── ValidationPackage.cs │ │ │ │ ├── ViewModelPackage.cs │ │ │ │ ├── QueryPackage.cs │ │ │ │ └── CommandPackage.cs │ │ │ ├── IPackageScaffoldR.cs │ │ │ ├── CompositionRootSettings.cs │ │ │ └── ContainerExtensions.cs │ │ ├── Events │ │ │ ├── EventProcessor.cs │ │ │ ├── MultipleDispatchEventTrigger.cs │ │ │ └── TriggerEventWhenHandlersExistDecorator.cs │ │ ├── Commands │ │ │ ├── CommandProcessor.cs │ │ │ ├── CommandNotNullDecorator.cs │ │ │ ├── CommandTransactionDecorator.cs │ │ │ ├── CommandEventProcessingDecorator.cs │ │ │ └── CommandLifetimeScopeDecorator.cs │ │ ├── Queries │ │ │ ├── QueryProcessor.cs │ │ │ ├── QueryNotNullDecorator.cs │ │ │ ├── QueryLifetimeScopeDecorator.cs │ │ │ └── QueryEventProcessingDecorator.cs │ │ └── Views │ │ │ ├── ViewModelWithArgumentNotNullDecorator.cs │ │ │ ├── ViewModelProcessor.cs │ │ │ ├── ViewModelLifetimeScopeDecorator.cs │ │ │ └── ViewModelWithArgumentLifetimeScopeDecorator.cs │ ├── ScaffoldR.nuspec │ ├── Properties │ │ └── AssemblyInfo.cs │ └── ScaffoldR.csproj ├── ScaffoldR.EntityFramework.Tests │ ├── Fakes │ │ ├── FakeCustomer.cs │ │ ├── FakeDbContext.cs │ │ └── FakeDbContextInitializer.cs │ ├── Helpers │ │ ├── MockedDbContext.cs │ │ └── EntityFrameworkMockHelper.cs │ ├── Entities │ │ ├── EntityFrameworkUnitOfWorkTests.cs │ │ └── EntityFrameworkRepositoryTests.cs │ ├── App.config │ ├── CompositionRoot │ │ ├── CompositionRootTests.cs │ │ └── CompositionRootFixture.cs │ ├── packages.config │ ├── Properties │ │ └── AssemblyInfo.cs │ └── ScaffoldR.EntityFramework.Tests.csproj ├── ScaffoldR.Tests │ ├── Infrastructure │ │ ├── Events │ │ │ ├── Fakes │ │ │ │ └── FakeEventWithoutValidation.cs │ │ │ ├── EventProcessorTests.cs │ │ │ ├── MultipleDispatchEventTriggerTests.cs │ │ │ └── TriggerEventWhenHandlersExistDecoratorTests.cs │ │ ├── Queries │ │ │ ├── Fakes │ │ │ │ ├── FakeQueryWithoutValidator.cs │ │ │ │ └── FakeQueryWithValidator.cs │ │ │ ├── QueryProcessorTests.cs │ │ │ ├── CompositionRootTests.cs │ │ │ ├── QueryLifetimeScopeDecoratorTests.cs │ │ │ └── QueryEventProcessingDecoratorTests.cs │ │ ├── Commands │ │ │ ├── Fakes │ │ │ │ ├── FakeCommandWithoutValidator.cs │ │ │ │ └── FakeCommandWithValidator.cs │ │ │ ├── CommandProcessorTests.cs │ │ │ ├── CompositionRootTests.cs │ │ │ ├── CommandLifetimeScopeDecoratorTests.cs │ │ │ ├── CommandTransactionDecoratorTests.cs │ │ │ └── CommandEventProcessingDecoratorTests.cs │ │ ├── Views │ │ │ ├── Fakes │ │ │ │ └── FakeViewModel.cs │ │ │ └── ViewModelProcessorTests.cs │ │ ├── FluentValidation │ │ │ ├── NerveFrameworkValidatorFactoryTests.cs │ │ │ ├── ValidationProcessorTests.cs │ │ │ ├── CompositionRootTests.cs │ │ │ ├── ValidateQueryDecoratorTests.cs │ │ │ └── ValidateCommandDecoratorTests.cs │ │ ├── CompositionRoot │ │ │ ├── CompositionRootTests.cs │ │ │ └── CompositionRootFixture.cs │ │ └── Entities │ │ │ └── CompositionRootTests.cs │ ├── packages.config │ ├── Properties │ │ └── AssemblyInfo.cs │ └── ScaffoldR.Tests.csproj └── ScaffoldR.sln ├── .gitattributes ├── tools ├── Build.ps1 └── BuildFunctions.ps1 ├── .gitignore ├── README.md └── LICENSE /src/ScaffoldR.EntityFramework/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Entities/Entity.cs: -------------------------------------------------------------------------------- 1 | namespace ScaffoldR.Core.Entities 2 | { 3 | /// 4 | /// A single unit of relational data that can be identified by a primary key. 5 | /// 6 | public abstract class Entity 7 | { 8 | } 9 | } -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Views/IViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace ScaffoldR.Core.Views 2 | { 3 | /// 4 | /// Specifices that the target class is a view model. This is a marker interface and has no methods. 5 | /// 6 | public interface IViewModel 7 | { 8 | // Marker interface 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/ScaffoldR/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Transactions/TransactionalAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ScaffoldR.Core.Transactions 4 | { 5 | /// 6 | /// Marks the class as being a transactional call. 7 | /// 8 | [AttributeUsage(AttributeTargets.Class)] 9 | public class TransactionalAttribute : Attribute 10 | { 11 | 12 | } 13 | } -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Commands/ICommand.cs: -------------------------------------------------------------------------------- 1 | using ScaffoldR.Core.Events; 2 | 3 | namespace ScaffoldR.Core.Commands 4 | { 5 | /// 6 | /// Specifices that the target class is a command. This is a marker interface and has no methods. 7 | /// 8 | public interface ICommand : IEvent 9 | { 10 | // Marker interface 11 | } 12 | } -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Events/IEvent.cs: -------------------------------------------------------------------------------- 1 | namespace ScaffoldR.Core.Events 2 | { 3 | /// 4 | /// Specifices that the target class can be notified by implemented . This is a marker interface and has no methods. 5 | /// 6 | public interface IEvent 7 | { 8 | // Marker interface 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ScaffoldR.EntityFramework.Tests/Fakes/FakeCustomer.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using ScaffoldR.Core.Entities; 3 | 4 | namespace ScaffoldR.EntityFramework.Tests.Fakes 5 | { 6 | public class FakeCustomer : EntityWithId 7 | { 8 | 9 | public string FirstName { get; set; } 10 | 11 | public string LastName { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/Tasks/TaskFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using ScaffoldR.Core.Tasks; 4 | 5 | namespace ScaffoldR.Infrastructure.Tasks 6 | { 7 | internal sealed class TaskFactory : ITaskFactory 8 | { 9 | public void StartTask(Action action) 10 | { 11 | Task.Factory.StartNew(action); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/Transactions/EmptyTransactionProcessor.cs: -------------------------------------------------------------------------------- 1 | using ScaffoldR.Core.Transactions; 2 | 3 | namespace ScaffoldR.Infrastructure.Transactions 4 | { 5 | internal sealed class EmptyTransactionProcessor : IProcessTransactions 6 | { 7 | public void Execute() 8 | { 9 | // I do nothing, this interface is implemented in sub packages. 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Commands/IProcessCommands.cs: -------------------------------------------------------------------------------- 1 | namespace ScaffoldR.Core.Commands 2 | { 3 | /// 4 | /// Processes commands. 5 | /// 6 | public interface IProcessCommands 7 | { 8 | /// 9 | /// Executes the command. 10 | /// 11 | /// The command to be executed. 12 | void Execute(ICommand command); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Transactions/IProcessTransactions.cs: -------------------------------------------------------------------------------- 1 | namespace ScaffoldR.Core.Transactions 2 | { 3 | /// 4 | /// Executes the transaction, e.g. synchronizes data state changes with an underlying data store. 5 | /// 6 | public interface IProcessTransactions 7 | { 8 | /// 9 | /// Executes the transaction 10 | /// 11 | void Execute(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Events/IProcessEvents.cs: -------------------------------------------------------------------------------- 1 | namespace ScaffoldR.Core.Events 2 | { 3 | /// 4 | /// Processes events. 5 | /// 6 | public interface IProcessEvents 7 | { 8 | /// 9 | /// Triggers the event. 10 | /// 11 | /// The event to be raised. 12 | /// An async Task 13 | void Raise(IEvent evt); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Tasks/ITaskFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ScaffoldR.Core.Tasks 4 | { 5 | /// 6 | /// Starts a task. 7 | /// 8 | public interface ITaskFactory 9 | { 10 | /// 11 | /// Starts a task with the specified action. 12 | /// 13 | /// The action to start in the task. 14 | void StartTask(Action action); 15 | } 16 | } -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/FluentValidation/ValidateNothingDecorator.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | 3 | namespace ScaffoldR.Infrastructure.FluentValidation 4 | { 5 | /// 6 | /// Adds an unregistered type resolution for objects missing an IValidator. 7 | /// 8 | /// The type. 9 | internal sealed class ValidateNothingDecorator : AbstractValidator 10 | { 11 | 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/ScaffoldR.EntityFramework.Tests/Helpers/MockedDbContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Entity; 4 | using Moq; 5 | 6 | namespace ScaffoldR.EntityFramework.Tests.Helpers 7 | { 8 | public class MockedDbContext : Mock where TContext : DbContext 9 | { 10 | private Dictionary _tables; 11 | 12 | public Dictionary Tables => _tables ?? (_tables = new Dictionary()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Events/RaiseEventAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ScaffoldR.Core.Events 4 | { 5 | /// 6 | /// Marks the class that it able to raise events after execution. 7 | /// 8 | [AttributeUsage(AttributeTargets.Class)] 9 | public class RaiseEventAttribute : Attribute 10 | { 11 | /// 12 | /// Whether the events should be raised or not 13 | /// 14 | public bool Enabled { get; set; } = true; 15 | } 16 | } -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/CompositionRoot/Packages/TaskPackage.cs: -------------------------------------------------------------------------------- 1 | using ScaffoldR.Core.Tasks; 2 | using ScaffoldR.Infrastructure.Tasks; 3 | using SimpleInjector; 4 | 5 | namespace ScaffoldR.Infrastructure.CompositionRoot.Packages 6 | { 7 | internal sealed class TaskPackage : IPackageScaffoldR 8 | { 9 | public void RegisterServices(Container container, CompositionRootSettings settings) 10 | { 11 | container.Register(Lifestyle.Singleton); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Events/ITriggerEvent.cs: -------------------------------------------------------------------------------- 1 | namespace ScaffoldR.Core.Events 2 | { 3 | /// 4 | /// Triggers events 5 | /// 6 | /// 7 | public interface ITriggerEvent where TEvent : IEvent 8 | { 9 | /// 10 | /// Triggers the event handler of . 11 | /// 12 | /// The event which should be triggered. 13 | void Trigger(TEvent evt); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/Events/Fakes/FakeEventWithoutValidation.cs: -------------------------------------------------------------------------------- 1 | using ScaffoldR.Core.Events; 2 | 3 | namespace ScaffoldR.Tests.Infrastructure.Events.Fakes 4 | { 5 | public class FakeEventWithoutValidation : IEvent 6 | { 7 | public string ReturnValue { get; internal set; } 8 | } 9 | 10 | public class HandleFakeEventWithoutValidation : IHandleEvent 11 | { 12 | public void Handle(FakeEventWithoutValidation @event) 13 | { 14 | @event.ReturnValue = "faked"; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/Queries/Fakes/FakeQueryWithoutValidator.cs: -------------------------------------------------------------------------------- 1 | using ScaffoldR.Core.Queries; 2 | 3 | namespace ScaffoldR.Tests.Infrastructure.Queries.Fakes 4 | { 5 | public class FakeQueryWithoutValidator : IQuery 6 | { 7 | public string ReturnValue { get; internal set; } 8 | } 9 | 10 | public class HandleFakeQueryWithoutValidator : IHandleQuery 11 | { 12 | public string Handle(FakeQueryWithoutValidator query) 13 | { 14 | return "faked"; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Commands/ICreateEntityCommand.cs: -------------------------------------------------------------------------------- 1 | using ScaffoldR.Core.Entities; 2 | 3 | namespace ScaffoldR.Core.Commands 4 | { 5 | /// 6 | /// Defines the command as an entity creation command. 7 | /// 8 | /// The entity type which should be created. 9 | public interface ICreateEntityCommand : ICommand where TEntity : Entity 10 | { 11 | /// 12 | /// The created entity instance. 13 | /// 14 | TEntity CreatedEntity { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Queries/IQuery.cs: -------------------------------------------------------------------------------- 1 | using ScaffoldR.Core.Events; 2 | 3 | namespace ScaffoldR.Core.Queries 4 | { 5 | // ReSharper disable UnusedTypeParameter 6 | /// 7 | /// Specifices that the target class is a query with the return type of . This is a marker interface and has no methods. 8 | /// 9 | /// The return type of the query. 10 | public interface IQuery : IEvent 11 | { 12 | // Marker interface 13 | } 14 | // ReSharper restore UnusedTypeParameter 15 | } -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/Commands/Fakes/FakeCommandWithoutValidator.cs: -------------------------------------------------------------------------------- 1 | using ScaffoldR.Core.Commands; 2 | 3 | namespace ScaffoldR.Tests.Infrastructure.Commands.Fakes 4 | { 5 | public class FakeCommandWithoutValidator : ICommand 6 | { 7 | public string ReturnValue { get; internal set; } 8 | } 9 | 10 | public class HandleFakeCommandWithoutValidator : IHandleCommand 11 | { 12 | public void Handle(FakeCommandWithoutValidator command) 13 | { 14 | command.ReturnValue = "faked"; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Commands/IHandleCommand.cs: -------------------------------------------------------------------------------- 1 | namespace ScaffoldR.Core.Commands 2 | { 3 | /// 4 | /// Handles the . 5 | /// 6 | /// The command which should be handled. 7 | public interface IHandleCommand where TCommand : ICommand 8 | { 9 | /// 10 | /// Handles the . 11 | /// 12 | /// The command. 13 | /// An awaitable task. 14 | void Handle(TCommand command); 15 | } 16 | } -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Events/IHandleEvent.cs: -------------------------------------------------------------------------------- 1 | namespace ScaffoldR.Core.Events 2 | { 3 | /// 4 | /// Handles the . 5 | /// 6 | /// The event which should be handled. 7 | public interface IHandleEvent where TEvent : IEvent 8 | { 9 | /// 10 | /// Handles the . 11 | /// 12 | /// The which should be handled. 13 | /// 14 | void Handle(TEvent evt); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/ScaffoldR.EntityFramework/Entities/EntityFrameworkUnitOfWork.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.Entity; 3 | using ScaffoldR.Core.Transactions; 4 | 5 | namespace ScaffoldR.EntityFramework.Entities 6 | { 7 | internal sealed class EntityFrameworkUnitOfWork : IProcessTransactions 8 | { 9 | private readonly Func _contextProvider; 10 | 11 | public EntityFrameworkUnitOfWork(Func contextProvider) 12 | { 13 | _contextProvider = contextProvider; 14 | } 15 | 16 | public void Execute() 17 | { 18 | _contextProvider().SaveChanges(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/ScaffoldR.EntityFramework/Entities/EntityReaderAdapter.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using ScaffoldR.Core.Entities; 3 | 4 | namespace ScaffoldR.EntityFramework.Entities 5 | { 6 | internal sealed class EntityReaderAdapter : IEntityReader where TEntity : Entity 7 | { 8 | private readonly EntityFrameworkRepository _repository; 9 | 10 | public EntityReaderAdapter(EntityFrameworkRepository repository) 11 | { 12 | _repository = repository; 13 | } 14 | 15 | public IQueryable Query() 16 | { 17 | return _repository.Query(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Queries/IProcessQueries.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ScaffoldR.Core.Queries 4 | { 5 | /// 6 | /// Processes queries. 7 | /// 8 | public interface IProcessQueries 9 | { 10 | /// 11 | /// Executes the query. 12 | /// 13 | /// The result of the query. 14 | /// The query. 15 | /// The query result object. 16 | /// If the query is null. 17 | TResult Execute(IQuery query); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/Events/EventProcessor.cs: -------------------------------------------------------------------------------- 1 | using ScaffoldR.Core.Events; 2 | using SimpleInjector; 3 | 4 | namespace ScaffoldR.Infrastructure.Events 5 | { 6 | internal sealed class EventProcessor : IProcessEvents 7 | { 8 | private readonly Container _container; 9 | 10 | public EventProcessor(Container container) 11 | { 12 | _container = container; 13 | } 14 | 15 | public void Raise(IEvent evt) 16 | { 17 | var triggerType = typeof(ITriggerEvent<>).MakeGenericType(evt.GetType()); 18 | dynamic trigger = _container.GetInstance(triggerType); 19 | trigger.Trigger((dynamic)evt); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/ScaffoldR/ScaffoldR.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $id$ 5 | $version$ 6 | $title$ 7 | $author$ 8 | $author$ 9 | https://github.com/hartmanns/ScaffoldR 10 | https://github.com/hartmanns/ScaffoldR 11 | http://scaffoldr.hartmanns.io/nuget/nuget-icon.png 12 | false 13 | $description$ 14 | Copyright 2015 15 | scaffoldr infrastructure scaffolder cqrs inversion dependency injection 16 | 17 | -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Entities/IEntityReader.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | 3 | namespace ScaffoldR.Core.Entities 4 | { 5 | /// 6 | /// Inform an underlying data store to return a set of read-only entity instances. 7 | /// 8 | /// The entity type to return read-only entity instances of. 9 | public interface IEntityReader where TEntity : Entity 10 | { 11 | /// 12 | /// Inform an underlying data store to return a set of read-only entity instances. 13 | /// 14 | /// IQueryable for set of read-only TEntity instances from an underlying data store. 15 | IQueryable Query(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/CompositionRoot/IPackageScaffoldR.cs: -------------------------------------------------------------------------------- 1 | using SimpleInjector; 2 | 3 | namespace ScaffoldR.Infrastructure.CompositionRoot 4 | { 5 | /// 6 | /// A ScaffoldR encapsules the ScaffoldR infrastructure and registeres the services in the Simple Injector container. 7 | /// 8 | public interface IPackageScaffoldR 9 | { 10 | /// 11 | /// Registers the services in the 12 | /// 13 | /// The Simple Injector container 14 | /// The Composition Root Settings 15 | void RegisterServices(Container container, CompositionRootSettings settings); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/Views/Fakes/FakeViewModel.cs: -------------------------------------------------------------------------------- 1 | using ScaffoldR.Core.Views; 2 | 3 | namespace ScaffoldR.Tests.Infrastructure.Views.Fakes 4 | { 5 | public class FakeViewModel : IViewModel 6 | { 7 | public string ReturnType { get; set; } 8 | } 9 | 10 | public class HandleFakeViewModel : IHandleViewModel 11 | { 12 | public FakeViewModel Handle() 13 | { 14 | return new FakeViewModel {ReturnType = "faked"}; 15 | } 16 | } 17 | 18 | public class HandleFakeViewModelWithArgument : IHandleViewModel 19 | { 20 | public FakeViewModel Handle(string input) 21 | { 22 | return new FakeViewModel { ReturnType = input }; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Queries/IHandleQuery.cs: -------------------------------------------------------------------------------- 1 | namespace ScaffoldR.Core.Queries 2 | { 3 | /// 4 | /// Handles the with the return type of . 5 | /// 6 | /// The query. 7 | /// The return type of the . 8 | public interface IHandleQuery where TQuery : IQuery 9 | { 10 | /// 11 | /// Handles the . 12 | /// 13 | /// The query. 14 | /// Returns the . 15 | TResult Handle(TQuery query); 16 | } 17 | } -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/Commands/CommandProcessor.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using ScaffoldR.Core.Commands; 3 | using SimpleInjector; 4 | 5 | namespace ScaffoldR.Infrastructure.Commands 6 | { 7 | internal sealed class CommandProcessor : IProcessCommands 8 | { 9 | private readonly Container _container; 10 | 11 | public CommandProcessor(Container container) 12 | { 13 | _container = container; 14 | } 15 | 16 | [DebuggerStepThrough] 17 | public void Execute(ICommand command) 18 | { 19 | var handlerType = typeof(IHandleCommand<>).MakeGenericType(command.GetType()); 20 | dynamic handler = _container.GetInstance(handlerType); 21 | 22 | handler.Handle((dynamic)command); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/Queries/QueryProcessor.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using ScaffoldR.Core.Queries; 3 | using SimpleInjector; 4 | 5 | namespace ScaffoldR.Infrastructure.Queries 6 | { 7 | internal sealed class QueryProcessor : IProcessQueries 8 | { 9 | private readonly Container _container; 10 | 11 | public QueryProcessor(Container container) 12 | { 13 | _container = container; 14 | } 15 | 16 | [DebuggerStepThrough] 17 | public TResult Execute(IQuery query) 18 | { 19 | var handlerType = typeof(IHandleQuery<,>).MakeGenericType(query.GetType(), typeof(TResult)); 20 | dynamic handler = _container.GetInstance(handlerType); 21 | return handler.Handle((dynamic)query); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/Queries/Fakes/FakeQueryWithValidator.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | using ScaffoldR.Core.Queries; 3 | 4 | namespace ScaffoldR.Tests.Infrastructure.Queries.Fakes 5 | { 6 | public class FakeQueryWithValidator : IQuery 7 | { 8 | public string InputValue { get; set; } 9 | } 10 | 11 | public class ValidateFakeQueryWithValidator: AbstractValidator 12 | { 13 | public ValidateFakeQueryWithValidator() 14 | { 15 | RuleFor(x => x.InputValue).NotEmpty(); 16 | } 17 | } 18 | 19 | public class HandleFakeQueryWithValidator : IHandleQuery 20 | { 21 | public string Handle(FakeQueryWithValidator query) 22 | { 23 | return "faked"; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/ScaffoldR.EntityFramework.Tests/Entities/EntityFrameworkUnitOfWorkTests.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using ScaffoldR.EntityFramework.Entities; 3 | using ScaffoldR.EntityFramework.Tests.Fakes; 4 | using ScaffoldR.EntityFramework.Tests.Helpers; 5 | using Xunit; 6 | 7 | namespace ScaffoldR.EntityFramework.Tests.Entities 8 | { 9 | public class EntityFrameworkUnitOfWorkTests 10 | { 11 | [Fact] 12 | public void Execute_InvokesSaveChanges_OnDbContext() 13 | { 14 | var context = EntityFrameworkMockHelper.GetMockContext(); 15 | context.Setup(x => x.SaveChanges()).Returns(1); 16 | 17 | var unitOfWork = new EntityFrameworkUnitOfWork(() => context.Object); 18 | unitOfWork.Execute(); 19 | 20 | context.Verify(x => x.SaveChanges(), Times.Once); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/Commands/CommandNotNullDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using ScaffoldR.Core.Commands; 4 | 5 | namespace ScaffoldR.Infrastructure.Commands 6 | { 7 | internal sealed class CommandNotNullDecorator : IHandleCommand where TCommand : ICommand 8 | { 9 | private readonly Func> _handlerFactory; 10 | 11 | public CommandNotNullDecorator(Func> handlerFactory) 12 | { 13 | _handlerFactory = handlerFactory; 14 | } 15 | 16 | [DebuggerStepThrough] 17 | public void Handle(TCommand command) 18 | { 19 | if (Equals(command, null)) throw new ArgumentNullException("command"); 20 | 21 | _handlerFactory().Handle(command); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/Queries/QueryNotNullDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using ScaffoldR.Core.Queries; 4 | 5 | namespace ScaffoldR.Infrastructure.Queries 6 | { 7 | internal sealed class QueryNotNullDecorator : IHandleQuery where TQuery : IQuery 8 | { 9 | private readonly Func> _handlerFactory; 10 | 11 | public QueryNotNullDecorator(Func> handlerFactory) 12 | { 13 | _handlerFactory = handlerFactory; 14 | } 15 | 16 | [DebuggerStepThrough] 17 | public TResult Handle(TQuery query) 18 | { 19 | if (Equals(query, null)) throw new ArgumentNullException(nameof(query)); 20 | return _handlerFactory().Handle(query); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/Views/ViewModelWithArgumentNotNullDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ScaffoldR.Core.Views; 3 | 4 | namespace ScaffoldR.Infrastructure.Views 5 | { 6 | internal sealed class ViewModelWithArgumentNotNullDecorator : IHandleViewModel where TViewModel : IViewModel 7 | { 8 | private readonly Func> _handlerFactory; 9 | 10 | public ViewModelWithArgumentNotNullDecorator(Func> handlerFactory) 11 | { 12 | _handlerFactory = handlerFactory; 13 | } 14 | 15 | public TViewModel Handle(TInput input) 16 | { 17 | if (Equals(input, null)) throw new ArgumentNullException(nameof(input)); 18 | return _handlerFactory().Handle(input); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/ScaffoldR.EntityFramework/ScaffoldR.EntityFramework.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $id$ 5 | $version$ 6 | $title$ 7 | $author$ 8 | $author$ 9 | https://github.com/hartmanns/ScaffoldR 10 | https://github.com/hartmanns/ScaffoldR 11 | http://scaffoldr.hartmanns.io/nuget/nuget-icon.png 12 | false 13 | $description$ 14 | Copyright 2015 15 | scaffoldr infrastructure scaffolder cqrs inversion dependency injection entity framework 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/ScaffoldR.EntityFramework/Entities/EntityWriterAdapter.cs: -------------------------------------------------------------------------------- 1 | using ScaffoldR.Core.Entities; 2 | 3 | namespace ScaffoldR.EntityFramework.Entities 4 | { 5 | internal sealed class EntityWriterAdapter : IEntityWriter where TEntity : Entity 6 | { 7 | private readonly EntityFrameworkRepository _repository; 8 | 9 | public EntityWriterAdapter(EntityFrameworkRepository repository) 10 | { 11 | _repository = repository; 12 | } 13 | 14 | public TEntity Get(object primaryKey) 15 | { 16 | return _repository.Get(primaryKey); 17 | } 18 | 19 | public void Save(TEntity entity) 20 | { 21 | _repository.Save(entity); 22 | } 23 | 24 | public void Delete(TEntity entity) 25 | { 26 | _repository.Delete(entity); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/ScaffoldR.EntityFramework.Tests/Fakes/FakeDbContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.Entity; 3 | 4 | namespace ScaffoldR.EntityFramework.Tests.Fakes 5 | { 6 | public class FakeDbContext : DbContext 7 | { 8 | /// 9 | /// This field is for supporting AppVeyor CI configuration 10 | /// 11 | private static readonly string DefaultConnectionString = 12 | Environment.GetEnvironmentVariable("DefaultConnectionString") ?? 13 | @"Data Source=.\SQLEXPRESS;Initial Catalog=ScaffoldR_IntegrationTests;Integrated Security=True;MultipleActiveResultSets=True;"; 14 | 15 | public virtual DbSet FakeCustomers { get; set; } 16 | 17 | public FakeDbContext() : base(DefaultConnectionString) 18 | { 19 | Database.SetInitializer(new FakeDbContextInitializer()); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/Commands/Fakes/FakeCommandWithValidator.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | using ScaffoldR.Core.Commands; 3 | 4 | namespace ScaffoldR.Tests.Infrastructure.Commands.Fakes 5 | { 6 | public class FakeCommandWithValidator : ICommand 7 | { 8 | public string InputValue { get; set; } 9 | public string ReturnValue { get; internal set; } 10 | } 11 | 12 | public class ValidateFakeCommandWithValidator : AbstractValidator 13 | { 14 | public ValidateFakeCommandWithValidator() 15 | { 16 | RuleFor(x => x.InputValue).NotEmpty(); 17 | } 18 | } 19 | 20 | public class HandleFakeCommandWithValidator : IHandleCommand 21 | { 22 | public void Handle(FakeCommandWithValidator command) 23 | { 24 | command.ReturnValue = "faked"; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/ScaffoldR.EntityFramework.Tests/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/Queries/QueryProcessorTests.cs: -------------------------------------------------------------------------------- 1 | using ScaffoldR.Core.Queries; 2 | using ScaffoldR.Tests.Infrastructure.CompositionRoot; 3 | using ScaffoldR.Tests.Infrastructure.Queries.Fakes; 4 | using Xunit; 5 | 6 | namespace ScaffoldR.Tests.Infrastructure.Queries 7 | { 8 | [Collection("Simple Injector Tests")] 9 | public class QueryProcessorTests 10 | { 11 | private readonly CompositionRootFixture _fixture; 12 | 13 | public QueryProcessorTests(CompositionRootFixture fixture) 14 | { 15 | _fixture = fixture; 16 | } 17 | 18 | [Fact] 19 | public void Execute_InvokesQueryHandler_UsingContainerForResolution() 20 | { 21 | var queries = _fixture.Container.GetInstance(); 22 | var result = queries.Execute(new FakeQueryWithoutValidator()); 23 | 24 | Assert.Equal("faked", result); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/CompositionRoot/Packages/EventPackage.cs: -------------------------------------------------------------------------------- 1 | using ScaffoldR.Core.Events; 2 | using ScaffoldR.Infrastructure.Events; 3 | using SimpleInjector; 4 | 5 | namespace ScaffoldR.Infrastructure.CompositionRoot.Packages 6 | { 7 | internal sealed class EventPackage : IPackageScaffoldR 8 | { 9 | public void RegisterServices(Container container, CompositionRootSettings settings) 10 | { 11 | if (settings.EventAssemblies == null) return; 12 | 13 | container.RegisterSingleton(); 14 | 15 | container.RegisterCollection(typeof(IHandleEvent<>), settings.EventAssemblies); 16 | 17 | container.Register(typeof(ITriggerEvent<>), typeof(MultipleDispatchEventTrigger<>)); 18 | 19 | container.RegisterDecorator( 20 | typeof(ITriggerEvent<>), 21 | typeof(TriggerEventWhenHandlersExistDecorator<>) 22 | ); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/Commands/CommandProcessorTests.cs: -------------------------------------------------------------------------------- 1 | using ScaffoldR.Core.Commands; 2 | using ScaffoldR.Tests.Infrastructure.Commands.Fakes; 3 | using ScaffoldR.Tests.Infrastructure.CompositionRoot; 4 | using Xunit; 5 | 6 | namespace ScaffoldR.Tests.Infrastructure.Commands 7 | { 8 | [Collection("Simple Injector Tests")] 9 | public class CommandProcessorTests 10 | { 11 | private readonly CompositionRootFixture _fixture; 12 | 13 | public CommandProcessorTests(CompositionRootFixture fixture) 14 | { 15 | _fixture = fixture; 16 | } 17 | 18 | [Fact] 19 | public void Execute_InvokesCommandHandler_UsingContainerForResolution() 20 | { 21 | var commands = _fixture.Container.GetInstance(); 22 | var command = new FakeCommandWithoutValidator(); 23 | commands.Execute(command); 24 | 25 | Assert.Equal("faked", command.ReturnValue); 26 | 27 | } 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/FluentValidation/NerveFrameworkValidatorFactoryTests.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | using ScaffoldR.Tests.Infrastructure.Commands.Fakes; 3 | using ScaffoldR.Tests.Infrastructure.CompositionRoot; 4 | using Xunit; 5 | 6 | namespace ScaffoldR.Tests.Infrastructure.FluentValidation 7 | { 8 | [Collection("Simple Injector Tests")] 9 | public class ScaffoldRValidatorFactoryTests 10 | { 11 | private readonly CompositionRootFixture _fixture; 12 | 13 | public ScaffoldRValidatorFactoryTests(CompositionRootFixture fixture) 14 | { 15 | _fixture = fixture; 16 | } 17 | 18 | [Fact] 19 | public void CreateInstance_CanCreateInstanceOf_ValidateNothingValidator() 20 | { 21 | var validator = _fixture.Container.GetInstance(typeof(IValidator)); 22 | 23 | Assert.NotNull(validator); 24 | Assert.IsType(validator); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/FluentValidation/ValidateCommandDecorator.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using FluentValidation; 3 | using ScaffoldR.Core.Commands; 4 | using ScaffoldR.Core.Transactions; 5 | 6 | namespace ScaffoldR.Infrastructure.FluentValidation 7 | { 8 | internal sealed class ValidateCommandDecorator : IHandleCommand where TCommand : ICommand 9 | { 10 | private readonly IHandleCommand _decorated; 11 | private readonly IValidator _validator; 12 | 13 | public ValidateCommandDecorator(IHandleCommand decorated 14 | , IValidator validator 15 | ) 16 | { 17 | _decorated = decorated; 18 | _validator = validator; 19 | } 20 | 21 | [DebuggerStepThrough] 22 | public void Handle(TCommand command) 23 | { 24 | _validator.ValidateAndThrow(command); 25 | 26 | _decorated.Handle(command); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/FluentValidation/ValidateQueryDecorator.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using FluentValidation; 3 | using ScaffoldR.Core.Queries; 4 | using ScaffoldR.Core.Transactions; 5 | 6 | namespace ScaffoldR.Infrastructure.FluentValidation 7 | { 8 | internal sealed class ValidateQueryDecorator : IHandleQuery where TQuery : IQuery 9 | { 10 | private readonly IHandleQuery _decorated; 11 | private readonly IValidator _validator; 12 | 13 | public ValidateQueryDecorator(IHandleQuery decorated 14 | , IValidator validator 15 | ) 16 | { 17 | _decorated = decorated; 18 | _validator = validator; 19 | } 20 | 21 | [DebuggerStepThrough] 22 | public TResult Handle(TQuery query) 23 | { 24 | _validator.ValidateAndThrow(query); 25 | 26 | return _decorated.Handle(query); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/Events/EventProcessorTests.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using ScaffoldR.Core.Events; 3 | using ScaffoldR.Tests.Infrastructure.CompositionRoot; 4 | using ScaffoldR.Tests.Infrastructure.Events.Fakes; 5 | using Xunit; 6 | 7 | namespace ScaffoldR.Tests.Infrastructure.Events 8 | { 9 | [Collection("Simple Injector Tests")] 10 | public class EventProcessorTests 11 | { 12 | private readonly CompositionRootFixture _fixture; 13 | 14 | public EventProcessorTests(CompositionRootFixture fixture) 15 | { 16 | _fixture = fixture; 17 | } 18 | 19 | [Fact] 20 | public void Execute_InvokesEventHandler_UsingContainerForResolution() 21 | { 22 | var events = _fixture.Container.GetInstance(); 23 | var @event = new FakeEventWithoutValidation(); 24 | events.Raise(@event); 25 | Thread.Sleep(1000); // :-( 26 | Assert.Equal("faked", @event.ReturnValue); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/Events/MultipleDispatchEventTrigger.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using ScaffoldR.Core.Events; 4 | 5 | namespace ScaffoldR.Infrastructure.Events 6 | { 7 | /// 8 | /// Fires multiple dispatch event triggers 9 | /// 10 | /// 11 | internal sealed class MultipleDispatchEventTrigger : ITriggerEvent where TEvent : IEvent 12 | { 13 | private readonly IEnumerable> _handleEvents; 14 | 15 | public MultipleDispatchEventTrigger(IEnumerable> handleEvents) 16 | { 17 | _handleEvents = handleEvents; 18 | } 19 | 20 | public void Trigger(TEvent e) 21 | { 22 | if (_handleEvents == null || !_handleEvents.Any()) return; 23 | 24 | foreach (var handler in _handleEvents) 25 | { 26 | handler.Handle(e); 27 | } 28 | } 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/CompositionRoot/CompositionRootTests.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using SimpleInjector.Diagnostics; 3 | using Xunit; 4 | 5 | namespace ScaffoldR.Tests.Infrastructure.CompositionRoot 6 | { 7 | [Collection("Simple Injector Tests")] 8 | public class CompositionRootTests 9 | { 10 | private readonly CompositionRootFixture _fixture; 11 | 12 | public CompositionRootTests(CompositionRootFixture fixture) 13 | { 14 | _fixture = fixture; 15 | } 16 | 17 | [Fact] 18 | public void CompositionRoot_ComposesVerifiedRoot_WithoutDiagnosticsWarnings() 19 | { 20 | _fixture.Container.Verify(); 21 | var results = Analyzer.Analyze(_fixture.Container); 22 | 23 | Assert.False(results.Any()); 24 | } 25 | 26 | [Fact] 27 | public void CompositionRoot_AllowsOverridingRegistrations() 28 | { 29 | Assert.False(_fixture.Container.Options.AllowOverridingRegistrations); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/ScaffoldR.EntityFramework.Tests/CompositionRoot/CompositionRootTests.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using SimpleInjector.Diagnostics; 3 | using Xunit; 4 | 5 | namespace ScaffoldR.EntityFramework.Tests.CompositionRoot 6 | { 7 | [Collection("Simple Injector Tests")] 8 | public class CompositionRootTests 9 | { 10 | private readonly CompositionRootFixture _fixture; 11 | 12 | public CompositionRootTests(CompositionRootFixture fixture) 13 | { 14 | _fixture = fixture; 15 | } 16 | 17 | [Fact] 18 | public void CompositionRoot_ComposesVerifiedRoot_WithoutDiagnosticsWarnings() 19 | { 20 | _fixture.Container.Verify(); 21 | var results = Analyzer.Analyze(_fixture.Container); 22 | 23 | Assert.False(results.Any()); 24 | } 25 | 26 | [Fact] 27 | public void CompositionRoot_AllowsOverridingRegistrations() 28 | { 29 | Assert.False(_fixture.Container.Options.AllowOverridingRegistrations); 30 | } 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/Views/ViewModelProcessor.cs: -------------------------------------------------------------------------------- 1 | using ScaffoldR.Core.Views; 2 | using SimpleInjector; 3 | 4 | namespace ScaffoldR.Infrastructure.Views 5 | { 6 | internal sealed class ViewModelProcessor : IProcessViewModels 7 | { 8 | private readonly Container _container; 9 | 10 | public ViewModelProcessor(Container container) 11 | { 12 | _container = container; 13 | } 14 | 15 | public TViewModel Create() where TViewModel : IViewModel 16 | { 17 | var handler = _container.GetInstance>(); 18 | return handler.Handle(); 19 | } 20 | 21 | public TViewModel Create(TInput input) where TViewModel : IViewModel 22 | { 23 | var handlerType = typeof(IHandleViewModel<,>).MakeGenericType(typeof(TViewModel), typeof(TInput)); 24 | dynamic handler = _container.GetInstance(handlerType); 25 | return handler.Handle((dynamic)input); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Views/IProcessViewModels.cs: -------------------------------------------------------------------------------- 1 | namespace ScaffoldR.Core.Views 2 | { 3 | /// 4 | /// Processes and creates view models. 5 | /// 6 | public interface IProcessViewModels 7 | { 8 | /// 9 | /// Creates the . 10 | /// 11 | /// The view model 12 | TViewModel Create() where TViewModel : IViewModel; 13 | 14 | /// 15 | /// Create the with an argument of type 16 | /// 17 | /// The view model which should be constructed 18 | /// The type of argument for the view model 19 | /// The argument for the view model 20 | /// The view model 21 | TViewModel Create(TInput input) where TViewModel : IViewModel; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/CompositionRoot/Packages/TransactionPackage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ScaffoldR.Core.Transactions; 3 | using ScaffoldR.Infrastructure.Transactions; 4 | using SimpleInjector; 5 | 6 | namespace ScaffoldR.Infrastructure.CompositionRoot.Packages 7 | { 8 | internal sealed class TransactionPackage : IPackageScaffoldR 9 | { 10 | public void RegisterServices(Container container, CompositionRootSettings settings) 11 | { 12 | // When there is no explicit transaction processor registered, give it an empty one. 13 | // The interfaces is most likely to wired up in sub packages for e.g. saving changes to a context. 14 | var registration = new Lazy(() => Lifestyle.Singleton.CreateRegistration(container)); 15 | container.ResolveUnregisteredType += (sender, e) => { 16 | if (e.UnregisteredServiceType == typeof(IProcessTransactions)) e.Register(registration.Value); 17 | }; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/ScaffoldR.EntityFramework.Tests/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Validation/IProcessValidation.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation.Results; 2 | using ScaffoldR.Core.Commands; 3 | using ScaffoldR.Core.Queries; 4 | using ScaffoldR.Core.Transactions; 5 | 6 | namespace ScaffoldR.Core.Validation 7 | { 8 | /// 9 | /// Processes command and query validation. 10 | /// 11 | public interface IProcessValidation 12 | { 13 | /// 14 | /// Validates if a command is valid for execution. 15 | /// 16 | /// The command which should be validated. 17 | /// The of the command. 18 | ValidationResult Validate(ICommand command); 19 | 20 | /// 21 | /// Validates if a query is valid for execution. 22 | /// 23 | /// The query which should be validated. 24 | /// The of the query 25 | ValidationResult Validate(IQuery query); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/Queries/CompositionRootTests.cs: -------------------------------------------------------------------------------- 1 | using ScaffoldR.Core.Queries; 2 | using ScaffoldR.Infrastructure.Queries; 3 | using ScaffoldR.Tests.Infrastructure.CompositionRoot; 4 | using SimpleInjector; 5 | using Xunit; 6 | 7 | namespace ScaffoldR.Tests.Infrastructure.Queries 8 | { 9 | [Collection("Simple Injector Tests")] 10 | public class CompositionRootTests 11 | { 12 | private readonly CompositionRootFixture _fixture; 13 | 14 | public CompositionRootTests(CompositionRootFixture fixture) 15 | { 16 | _fixture = fixture; 17 | } 18 | 19 | [Fact] 20 | public void RegistersIProcessQueries_UsingQueryProcessor_AsSingleton() 21 | { 22 | var instance = _fixture.Container.GetInstance(); 23 | var registration = _fixture.Container.GetRegistration(typeof (IProcessQueries)); 24 | 25 | Assert.NotNull(instance); 26 | Assert.IsType(instance); 27 | Assert.Equal(Lifestyle.Singleton, registration.Lifestyle); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/Queries/QueryLifetimeScopeDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using ScaffoldR.Core.Queries; 4 | using SimpleInjector; 5 | 6 | namespace ScaffoldR.Infrastructure.Queries 7 | { 8 | internal sealed class QueryLifetimeScopeDecorator : IHandleQuery where TQuery : IQuery 9 | { 10 | private readonly Container _container; 11 | private readonly Func> _handlerFactory; 12 | 13 | public QueryLifetimeScopeDecorator(Container container, Func> handlerFactory) 14 | { 15 | _container = container; 16 | _handlerFactory = handlerFactory; 17 | } 18 | 19 | [DebuggerStepThrough] 20 | public TResult Handle(TQuery query) 21 | { 22 | if (_container.GetCurrentLifetimeScope() != null) 23 | return _handlerFactory().Handle(query); 24 | using (_container.BeginLifetimeScope()) 25 | return _handlerFactory().Handle(query); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/Commands/CompositionRootTests.cs: -------------------------------------------------------------------------------- 1 | using ScaffoldR.Core.Commands; 2 | using ScaffoldR.Infrastructure.Commands; 3 | using ScaffoldR.Tests.Infrastructure.CompositionRoot; 4 | using SimpleInjector; 5 | using Xunit; 6 | 7 | namespace ScaffoldR.Tests.Infrastructure.Commands 8 | { 9 | [Collection("Simple Injector Tests")] 10 | public class CompositionRootTests 11 | { 12 | private readonly CompositionRootFixture _fixture; 13 | 14 | public CompositionRootTests(CompositionRootFixture fixture) 15 | { 16 | _fixture = fixture; 17 | } 18 | 19 | [Fact] 20 | public void RegistersIProcessCommands_UsingCommandProcessor_AsSingleton() 21 | { 22 | var instance = _fixture.Container.GetInstance(); 23 | var registration = _fixture.Container.GetRegistration(typeof (IProcessCommands)); 24 | 25 | Assert.NotNull(instance); 26 | Assert.IsType(instance); 27 | Assert.Equal(Lifestyle.Singleton, registration.Lifestyle); 28 | } 29 | 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/Entities/CompositionRootTests.cs: -------------------------------------------------------------------------------- 1 | using ScaffoldR.Core.Transactions; 2 | using ScaffoldR.Infrastructure.Transactions; 3 | using ScaffoldR.Tests.Infrastructure.CompositionRoot; 4 | using SimpleInjector; 5 | using Xunit; 6 | 7 | namespace ScaffoldR.Tests.Infrastructure.Entities 8 | { 9 | [Collection("Simple Injector Tests")] 10 | public class CompositionRootTests 11 | { 12 | private readonly CompositionRootFixture _fixture; 13 | 14 | public CompositionRootTests(CompositionRootFixture fixture) 15 | { 16 | _fixture = fixture; 17 | } 18 | 19 | [Fact] 20 | public void RegistersEmptyProcessTransation_AsSingleton_WhenIProcessTransactionsIsNotRegisted() 21 | { 22 | var instance = _fixture.Container.GetInstance(); 23 | var registration = _fixture.Container.GetRegistration(typeof (IProcessTransactions)); 24 | 25 | Assert.NotNull(instance); 26 | Assert.IsType(instance); 27 | Assert.Equal(Lifestyle.Singleton, registration.Lifestyle); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/Views/ViewModelLifetimeScopeDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using ScaffoldR.Core.Views; 4 | using SimpleInjector; 5 | 6 | namespace ScaffoldR.Infrastructure.Views 7 | { 8 | internal sealed class ViewModelLifetimeScopeDecorator : IHandleViewModel where TViewModel : IViewModel 9 | { 10 | private readonly Container _container; 11 | private readonly Func> _handlerFactory; 12 | 13 | public ViewModelLifetimeScopeDecorator(Container container, Func> handlerFactory) 14 | { 15 | _container = container; 16 | _handlerFactory = handlerFactory; 17 | } 18 | 19 | [DebuggerStepThrough] 20 | public TViewModel Handle() 21 | { 22 | if (_container.GetCurrentLifetimeScope() != null) 23 | { 24 | return _handlerFactory().Handle(); 25 | } 26 | 27 | using (_container.BeginLifetimeScope()) 28 | { 29 | return _handlerFactory().Handle(); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/Commands/CommandTransactionDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ScaffoldR.Core.Commands; 3 | using ScaffoldR.Core.Extensions; 4 | using ScaffoldR.Core.Transactions; 5 | 6 | namespace ScaffoldR.Infrastructure.Commands 7 | { 8 | internal sealed class CommandTransactionDecorator : IHandleCommand where TCommand : ICommand 9 | { 10 | private readonly IProcessTransactions _transactions; 11 | private readonly Func> _handlerFactory; 12 | 13 | public CommandTransactionDecorator(IProcessTransactions transactions, Func> handlerFactory) 14 | { 15 | _transactions = transactions; 16 | _handlerFactory = handlerFactory; 17 | } 18 | 19 | public void Handle(TCommand command) 20 | { 21 | var handler = _handlerFactory(); 22 | handler.Handle(command); 23 | 24 | var attribute = handler.GetType().GetRuntimeAddedAttribute(); 25 | if (attribute != null) 26 | { 27 | _transactions.Execute(); 28 | } 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/Commands/CommandEventProcessingDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ScaffoldR.Core.Commands; 3 | using ScaffoldR.Core.Events; 4 | using ScaffoldR.Core.Extensions; 5 | 6 | namespace ScaffoldR.Infrastructure.Commands 7 | { 8 | internal sealed class CommandEventProcessingDecorator : IHandleCommand where TCommand : ICommand 9 | { 10 | private readonly IProcessEvents _events; 11 | private readonly Func> _handlerFactory; 12 | 13 | public CommandEventProcessingDecorator(IProcessEvents events, Func> handlerFactory) 14 | { 15 | _events = events; 16 | _handlerFactory = handlerFactory; 17 | } 18 | 19 | public void Handle(TCommand command) 20 | { 21 | var handler = _handlerFactory(); 22 | handler.Handle(command); 23 | 24 | var attribute = handler.GetType().GetRuntimeAddedAttribute(); 25 | if (attribute != null && attribute.Enabled) 26 | { 27 | _events.Raise(command); 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/ScaffoldR.EntityFramework.Tests/Fakes/FakeDbContextInitializer.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 ScaffoldR.EntityFramework.Tests.Fakes 9 | { 10 | public class FakeDbContextInitializer : DropCreateDatabaseAlways 11 | { 12 | protected override void Seed(FakeDbContext context) 13 | { 14 | var customers = new List 15 | { 16 | new FakeCustomer 17 | { 18 | Id = 1, 19 | FirstName = "John", 20 | LastName = "Doe" 21 | }, 22 | new FakeCustomer 23 | { 24 | Id = 2, 25 | FirstName = "John", 26 | LastName = "Smith" 27 | } 28 | }; 29 | 30 | foreach (var customer in customers) 31 | { 32 | context.FakeCustomers.Add(customer); 33 | } 34 | 35 | base.Seed(context); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/CompositionRoot/Packages/ValidationPackage.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | using ScaffoldR.Core.Validation; 3 | using ScaffoldR.Infrastructure.FluentValidation; 4 | using SimpleInjector; 5 | 6 | namespace ScaffoldR.Infrastructure.CompositionRoot.Packages 7 | { 8 | internal sealed class ValidationPackage : IPackageScaffoldR 9 | { 10 | public void RegisterServices(Container container, CompositionRootSettings settings) 11 | { 12 | if (settings.FluentValidationAssemblies == null) return; 13 | 14 | ValidatorOptions.CascadeMode = CascadeMode.StopOnFirstFailure; 15 | 16 | container.RegisterSingleton(); 17 | container.RegisterSingleton(); 18 | 19 | container.Register(typeof(IValidator<>), settings.FluentValidationAssemblies); 20 | 21 | // Add unregistered type resolution for objects missing an IValidator 22 | container.RegisterConditional(typeof(IValidator<>), typeof(ValidateNothingDecorator<>), Lifestyle.Singleton, context => !context.Handled); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/Commands/CommandLifetimeScopeDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using ScaffoldR.Core.Commands; 4 | using SimpleInjector; 5 | 6 | namespace ScaffoldR.Infrastructure.Commands 7 | { 8 | internal sealed class CommandLifetimeScopeDecorator : IHandleCommand where TCommand : ICommand 9 | { 10 | private readonly Container _container; 11 | private readonly Func> _handlerFactory; 12 | 13 | public CommandLifetimeScopeDecorator(Container container, Func> handlerFactory) 14 | { 15 | _container = container; 16 | _handlerFactory = handlerFactory; 17 | } 18 | 19 | [DebuggerStepThrough] 20 | public void Handle(TCommand command) 21 | { 22 | if (_container.GetCurrentLifetimeScope() != null) 23 | { 24 | _handlerFactory().Handle(command); 25 | } 26 | else 27 | { 28 | using (_container.BeginLifetimeScope()) 29 | { 30 | _handlerFactory().Handle(command); 31 | } 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/Views/ViewModelWithArgumentLifetimeScopeDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using ScaffoldR.Core.Views; 4 | using SimpleInjector; 5 | 6 | namespace ScaffoldR.Infrastructure.Views 7 | { 8 | internal sealed class ViewModelWithArgumentLifetimeScopeDecorator : IHandleViewModel where TViewModel : IViewModel 9 | { 10 | private readonly Container _container; 11 | private readonly Func> _handlerFactory; 12 | 13 | public ViewModelWithArgumentLifetimeScopeDecorator(Container container, Func> handlerFactory) 14 | { 15 | _container = container; 16 | _handlerFactory = handlerFactory; 17 | } 18 | 19 | [DebuggerStepThrough] 20 | public TViewModel Handle(TInput input) 21 | { 22 | if (_container.GetCurrentLifetimeScope() != null) 23 | { 24 | return _handlerFactory().Handle(input); 25 | } 26 | 27 | using (_container.BeginLifetimeScope()) 28 | { 29 | return _handlerFactory().Handle(input); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/ScaffoldR.EntityFramework/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Views/IHandleViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace ScaffoldR.Core.Views 2 | { 3 | /// 4 | /// Handles the . 5 | /// 6 | /// The view model which should be handled. 7 | public interface IHandleViewModel where TViewModel : IViewModel 8 | { 9 | /// 10 | /// Creates a . 11 | /// 12 | /// An instance of the . 13 | TViewModel Handle(); 14 | } 15 | 16 | /// 17 | /// Handles the with the argument of 18 | /// 19 | /// The argument for the view model 20 | /// The view model which should be handled. 21 | public interface IHandleViewModel where TViewModel : IViewModel 22 | { 23 | /// 24 | /// Creates a . 25 | /// 26 | /// An instance of the . 27 | TViewModel Handle(TInput input); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/CompositionRoot/CompositionRootSettings.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using FluentValidation; 3 | using ScaffoldR.Core.Commands; 4 | using ScaffoldR.Core.Events; 5 | using ScaffoldR.Core.Queries; 6 | using ScaffoldR.Core.Transactions; 7 | using ScaffoldR.Core.Views; 8 | 9 | namespace ScaffoldR.Infrastructure.CompositionRoot 10 | { 11 | /// 12 | /// The main composition settings. 13 | /// 14 | public class CompositionRootSettings 15 | { 16 | /// 17 | /// Where the and are located. 18 | /// 19 | public Assembly[] TransactionAssemblies { get; set; } 20 | 21 | /// 22 | /// Where the are located. 23 | /// 24 | public Assembly[] EventAssemblies { get; set; } 25 | 26 | /// 27 | /// Where the are located 28 | /// 29 | public Assembly[] FluentValidationAssemblies { get; set; } 30 | 31 | /// 32 | /// Where the are located. 33 | /// 34 | public Assembly[] ViewModelAssemblies { get; set; } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/FluentValidation/ValidationProcessor.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using FluentValidation; 3 | using FluentValidation.Results; 4 | using ScaffoldR.Core.Commands; 5 | using ScaffoldR.Core.Queries; 6 | using ScaffoldR.Core.Transactions; 7 | using ScaffoldR.Core.Validation; 8 | using SimpleInjector; 9 | 10 | namespace ScaffoldR.Infrastructure.FluentValidation 11 | { 12 | internal sealed class ValidationProcessor : IProcessValidation 13 | { 14 | private readonly Container _container; 15 | 16 | public ValidationProcessor(Container container) 17 | { 18 | _container = container; 19 | } 20 | 21 | [DebuggerStepThrough] 22 | public ValidationResult Validate(IQuery query) 23 | { 24 | var validatedType = typeof(IValidator<>).MakeGenericType(query.GetType()); 25 | dynamic validator = _container.GetInstance(validatedType); 26 | return validator.Validate((dynamic)query); 27 | } 28 | 29 | [DebuggerStepThrough] 30 | public ValidationResult Validate(ICommand command) 31 | { 32 | var validatedType = typeof(IValidator<>).MakeGenericType(command.GetType()); 33 | dynamic validator = _container.GetInstance(validatedType); 34 | return validator.Validate((dynamic)command); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/Queries/QueryEventProcessingDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using ScaffoldR.Core.Events; 4 | using ScaffoldR.Core.Extensions; 5 | using ScaffoldR.Core.Queries; 6 | 7 | namespace ScaffoldR.Infrastructure.Queries 8 | { 9 | internal sealed class QueryEventProcessingDecorator : IHandleQuery where TQuery : IQuery 10 | { 11 | private readonly IProcessEvents _events; 12 | private readonly Func> _handlerFactory; 13 | 14 | public QueryEventProcessingDecorator(IProcessEvents events, Func> handlerFactory) 15 | { 16 | _events = events; 17 | _handlerFactory = handlerFactory; 18 | } 19 | 20 | [DebuggerStepThrough] 21 | public TResult Handle(TQuery query) 22 | { 23 | var handler = _handlerFactory(); 24 | try 25 | { 26 | return handler.Handle(query); 27 | } 28 | finally 29 | { 30 | var attribute = handler.GetType().GetRuntimeAddedAttribute(); 31 | if (attribute != null && attribute.Enabled) 32 | { 33 | _events.Raise(query); 34 | } 35 | } 36 | } 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/FluentValidation/SimpleInjectorValidatorFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentValidation; 3 | using SimpleInjector; 4 | 5 | namespace ScaffoldR.Infrastructure.FluentValidation 6 | { 7 | /// 8 | /// The Fluent Validation Validator Factory. Used to find instances of the 's. 9 | /// 10 | public class SimpleInjectorValidatorFactory : IValidatorFactory 11 | { 12 | private readonly Container _container; 13 | 14 | /// 15 | /// The constructor of the factory. 16 | /// 17 | /// The Simple Injector Container 18 | public SimpleInjectorValidatorFactory(Container container) 19 | { 20 | _container = container; 21 | } 22 | 23 | /// 24 | /// Gets the validator for the specified type. 25 | /// 26 | public IValidator GetValidator() 27 | { 28 | return _container.GetInstance>(); 29 | } 30 | 31 | /// 32 | /// Gets the validator for the specified type. 33 | /// 34 | public IValidator GetValidator(Type type) 35 | { 36 | var validator = typeof(IValidator<>).MakeGenericType(type); 37 | return _container.GetInstance(validator) as IValidator; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/CompositionRoot/CompositionRootFixture.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using ScaffoldR.Infrastructure.CompositionRoot; 3 | using SimpleInjector; 4 | using SimpleInjector.Extensions.LifetimeScoping; 5 | using Xunit; 6 | 7 | namespace ScaffoldR.Tests.Infrastructure.CompositionRoot 8 | { 9 | public class CompositionRootFixture 10 | { 11 | public Container Container { get; } 12 | 13 | public CompositionRootFixture() 14 | { 15 | Container = new Container(); 16 | Container.Options.DefaultScopedLifestyle = new LifetimeScopeLifestyle(); 17 | 18 | var assemblies = new[] { Assembly.GetExecutingAssembly() }; 19 | 20 | Container.RegisterScaffoldR(settings => 21 | { 22 | settings.EventAssemblies = assemblies; 23 | settings.FluentValidationAssemblies = assemblies; 24 | settings.TransactionAssemblies = assemblies; 25 | settings.ViewModelAssemblies = assemblies; 26 | }); 27 | } 28 | 29 | } 30 | 31 | [CollectionDefinition("Simple Injector Tests")] 32 | public class SimpleInjectorTests : ICollectionFixture 33 | { 34 | // This class has no code, and is never created. Its purpose is simply 35 | // to be the place to apply [CollectionDefinition] and all the 36 | // ICollectionFixture<> interfaces. 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/CompositionRoot/Packages/ViewModelPackage.cs: -------------------------------------------------------------------------------- 1 | using ScaffoldR.Core.Views; 2 | using ScaffoldR.Infrastructure.Views; 3 | using SimpleInjector; 4 | 5 | namespace ScaffoldR.Infrastructure.CompositionRoot.Packages 6 | { 7 | internal sealed class ViewModelPackage : IPackageScaffoldR 8 | { 9 | public void RegisterServices(Container container, CompositionRootSettings settings) 10 | { 11 | if (settings.ViewModelAssemblies == null) return; 12 | 13 | container.RegisterSingleton(); 14 | 15 | container.Register(typeof(IHandleViewModel<>), settings.ViewModelAssemblies); 16 | container.Register(typeof(IHandleViewModel<,>), settings.ViewModelAssemblies); 17 | 18 | container.RegisterDecorator( 19 | typeof(IHandleViewModel<>), 20 | typeof(ViewModelLifetimeScopeDecorator<>), 21 | Lifestyle.Singleton 22 | ); 23 | 24 | container.RegisterDecorator( 25 | typeof(IHandleViewModel<,>), 26 | typeof(ViewModelWithArgumentLifetimeScopeDecorator<,>), 27 | Lifestyle.Singleton 28 | ); 29 | 30 | container.RegisterDecorator( 31 | typeof(IHandleViewModel<,>), 32 | typeof(ViewModelWithArgumentNotNullDecorator<,>), 33 | Lifestyle.Singleton 34 | ); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/ScaffoldR.EntityFramework/Extensions/ContainerExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.Entity; 3 | using ScaffoldR.Core.Entities; 4 | using ScaffoldR.Core.Transactions; 5 | using ScaffoldR.EntityFramework.Entities; 6 | using SimpleInjector; 7 | 8 | namespace ScaffoldR.EntityFramework.Extensions 9 | { 10 | /// 11 | /// Simple Injector container extensions 12 | /// 13 | public static class ContainerExtensions 14 | { 15 | /// 16 | /// Registers the ScaffoldR Entity Framework integration package into the Simple Injector container 17 | /// 18 | /// The DbContext of your application 19 | /// The Simple Injector container object 20 | public static void RegisterEntityFramework(this Container container) where TContext : DbContext 21 | { 22 | if (container == null) 23 | throw new ArgumentNullException(nameof(container)); 24 | 25 | container.Register(Lifestyle.Scoped); 26 | container.Register(Lifestyle.Scoped); 27 | container.Register(typeof(EntityFrameworkRepository<>), typeof(EntityFrameworkRepository<>), Lifestyle.Scoped); 28 | container.Register(typeof(IEntityWriter<>), typeof(EntityWriterAdapter<>)); 29 | container.Register(typeof(IEntityReader<>), typeof(EntityReaderAdapter<>)); 30 | } 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Entities/IEntityWriter.cs: -------------------------------------------------------------------------------- 1 | namespace ScaffoldR.Core.Entities 2 | { 3 | /// 4 | /// Informs an underlying data store to accept sets of writeable entity instances. 5 | /// 6 | /// 7 | public interface IEntityWriter where TEntity : Entity 8 | { 9 | /// 10 | /// Inform an underlying data store to return a single writable entity instance. 11 | /// 12 | /// Primary key value of the entity instance that the underlying data store should return. 13 | /// A single writable entity instance whose primary key matches the argument value(, if one exists in the underlying data store. Otherwise, null. 14 | TEntity Get(object primaryKey); 15 | 16 | /// 17 | /// Inform the underlying data store that a new or existing entity instance's should be saved to a set of entity instances. 18 | /// 19 | /// Entity instance that should be saved to the TEntity set by the underlying data store. 20 | void Save(TEntity entity); 21 | 22 | /// 23 | /// Inform the underlying data store that an existing entity instance should be permanently removed from its set of entity instances. 24 | /// 25 | /// Entity instance that should be permanently removed from the TEntity set by the underlying data store. 26 | void Delete(TEntity entity); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/ScaffoldR.EntityFramework.Tests/CompositionRoot/CompositionRootFixture.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using ScaffoldR.EntityFramework.Extensions; 3 | using ScaffoldR.EntityFramework.Tests.Fakes; 4 | using ScaffoldR.Infrastructure.CompositionRoot; 5 | using SimpleInjector; 6 | using SimpleInjector.Extensions.LifetimeScoping; 7 | using Xunit; 8 | 9 | namespace ScaffoldR.EntityFramework.Tests.CompositionRoot 10 | { 11 | public class CompositionRootFixture 12 | { 13 | public Container Container { get; } 14 | 15 | public CompositionRootFixture() 16 | { 17 | Container = new Container(); 18 | Container.Options.DefaultScopedLifestyle = new LifetimeScopeLifestyle(); 19 | 20 | var assemblies = new[] { Assembly.GetExecutingAssembly() }; 21 | 22 | Container.RegisterScaffoldR(settings => 23 | { 24 | settings.EventAssemblies = assemblies; 25 | settings.FluentValidationAssemblies = assemblies; 26 | settings.TransactionAssemblies = assemblies; 27 | settings.ViewModelAssemblies = assemblies; 28 | }); 29 | 30 | // Register Entity Framework 31 | Container.RegisterEntityFramework(); 32 | } 33 | 34 | } 35 | 36 | [CollectionDefinition("Simple Injector Tests")] 37 | public class SimpleInjectorTests : ICollectionFixture 38 | { 39 | // This class has no code, and is never created. Its purpose is simply 40 | // to be the place to apply [CollectionDefinition] and all the 41 | // ICollectionFixture<> interfaces. 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/ScaffoldR.EntityFramework.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("ScaffoldR.EntityFramework.Tests")] 9 | [assembly: AssemblyDescription("Integration library for Entity Framework for ScaffoldR")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Hartmann Solutions")] 12 | [assembly: AssemblyProduct("ScaffoldR.EntityFramework.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("11a3698e-0217-44f0-9236-6abaa2edcc67")] 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.2.0")] 35 | [assembly: AssemblyVersion("1.0.2.0")] 36 | [assembly: AssemblyFileVersion("1.0.2.0")] 37 | -------------------------------------------------------------------------------- /src/ScaffoldR.EntityFramework/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("ScaffoldR.EntityFramework")] 9 | [assembly: AssemblyDescription("Integration library for Entity Framework for ScaffoldR")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Hartmann Solutions")] 12 | [assembly: AssemblyProduct("ScaffoldR.EntityFramework")] 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("62e4e31b-d3ac-4345-9251-a16faf8758f3")] 24 | [assembly: InternalsVisibleTo("ScaffoldR.EntityFramework.Tests")] 25 | 26 | // Version information for an assembly consists of the following four values: 27 | // 28 | // Major Version 29 | // Minor Version 30 | // Build Number 31 | // Revision 32 | // 33 | // You can specify all the values or you can default the Build and Revision Numbers 34 | // by using the '*' as shown below: 35 | // [assembly: AssemblyVersion("1.0.2.0")] 36 | [assembly: AssemblyVersion("1.0.2.0")] 37 | [assembly: AssemblyFileVersion("1.0.2.0")] 38 | -------------------------------------------------------------------------------- /src/ScaffoldR.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("ScaffoldR")] 9 | [assembly: AssemblyDescription("ScaffoldR is a SOLID platform for structuring or scaffolding .NET applications. ScaffoldR supports commands, queries, events, repositories and validation with intelligent dispatching via C# generic variance.")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Hartmann Solutions")] 12 | [assembly: AssemblyProduct("ScaffoldR")] 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("e4f000b6-1e87-4605-8833-8bb4c8657296")] 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.2.0")] 35 | [assembly: AssemblyVersion("1.0.2.0")] 36 | [assembly: AssemblyFileVersion("1.0.2.0")] 37 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/Events/TriggerEventWhenHandlersExistDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using ScaffoldR.Core.Events; 5 | using ScaffoldR.Core.Tasks; 6 | using SimpleInjector; 7 | 8 | namespace ScaffoldR.Infrastructure.Events 9 | { 10 | internal sealed class TriggerEventWhenHandlersExistDecorator : ITriggerEvent where TEvent : IEvent 11 | { 12 | private readonly Container _container; 13 | private readonly ITaskFactory _taskFactory; 14 | private readonly Func> _factory; 15 | private readonly IEnumerable> _handleEvents; 16 | 17 | public TriggerEventWhenHandlersExistDecorator(Container container, ITaskFactory taskFactory, Func> factory, IEnumerable> handleEvents) 18 | { 19 | _container = container; 20 | _taskFactory = taskFactory; 21 | _factory = factory; 22 | _handleEvents = handleEvents; 23 | } 24 | 25 | public void Trigger(TEvent evt) 26 | { 27 | if (_handleEvents != null && _handleEvents.Any()) 28 | { 29 | _taskFactory.StartTask(() => 30 | { 31 | if (_container.GetCurrentLifetimeScope() != null) 32 | { 33 | _factory().Trigger(evt); 34 | } 35 | else 36 | { 37 | using (_container.BeginLifetimeScope()) 38 | { 39 | _factory().Trigger(evt); 40 | } 41 | } 42 | }); 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/Events/MultipleDispatchEventTriggerTests.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Moq; 3 | using ScaffoldR.Core.Events; 4 | using ScaffoldR.Infrastructure.Events; 5 | using ScaffoldR.Tests.Infrastructure.Events.Fakes; 6 | using Xunit; 7 | 8 | namespace ScaffoldR.Tests.Infrastructure.Events 9 | { 10 | public class MultipleDispatchEventTriggerTests 11 | { 12 | [Fact] 13 | public void HandleAllEventHandlers_WhenMultipleEventHandlersExists() 14 | { 15 | var evt = new FakeEventWithoutValidation(); 16 | Assert.IsAssignableFrom(evt); 17 | 18 | var handlerOneCallback = string.Empty; 19 | var handlerOne = new Mock>(MockBehavior.Strict); 20 | handlerOne.Setup(x => x.Handle(evt)).Callback(() => handlerOneCallback = "handlerOneCallback"); 21 | 22 | var handlerTwoCallback = string.Empty; 23 | var handlerTwo = new Mock>(MockBehavior.Strict); 24 | handlerTwo.Setup(x => x.Handle(evt)).Callback(() => handlerTwoCallback = "handlerTwoCallback"); 25 | 26 | var handlers = new List> 27 | { 28 | handlerOne.Object, 29 | handlerTwo.Object 30 | }; 31 | 32 | var decorator = new MultipleDispatchEventTrigger(handlers); 33 | decorator.Trigger(evt); 34 | 35 | handlerOne.Verify(x => x.Handle(evt), Times.Once); 36 | handlerTwo.Verify(x => x.Handle(evt), Times.Once); 37 | 38 | Assert.Equal("handlerOneCallback", handlerOneCallback); 39 | Assert.Equal("handlerTwoCallback", handlerTwoCallback); 40 | } 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/ScaffoldR/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("ScaffoldR")] 9 | [assembly: AssemblyDescription("ScaffoldR is a SOLID platform for structuring or scaffolding .NET applications. ScaffoldR supports commands, queries, events, repositories and validation with intelligent dispatching via C# generic variance.")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Hartmann Solutions")] 12 | [assembly: AssemblyProduct("ScaffoldR")] 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 | [assembly: InternalsVisibleTo("ScaffoldR.Tests")] 22 | [assembly: InternalsVisibleTo("ScaffoldR.EntityFramework.Tests")] 23 | 24 | // The following GUID is for the ID of the typelib if this project is exposed to COM 25 | [assembly: Guid("60ac8712-cfc6-4065-93a4-7134c74f88f6")] 26 | 27 | // Version information for an assembly consists of the following four values: 28 | // 29 | // Major Version 30 | // Minor Version 31 | // Build Number 32 | // Revision 33 | // 34 | // You can specify all the values or you can default the Build and Revision Numbers 35 | // by using the '*' as shown below: 36 | // [assembly: AssemblyVersion("1.0.2.0")] 37 | [assembly: AssemblyVersion("1.0.2.0")] 38 | [assembly: AssemblyFileVersion("1.0.2.0")] 39 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/Views/ViewModelProcessorTests.cs: -------------------------------------------------------------------------------- 1 | using ScaffoldR.Core.Views; 2 | using ScaffoldR.Infrastructure.Views; 3 | using ScaffoldR.Tests.Infrastructure.CompositionRoot; 4 | using ScaffoldR.Tests.Infrastructure.Views.Fakes; 5 | using SimpleInjector; 6 | using Xunit; 7 | 8 | namespace ScaffoldR.Tests.Infrastructure.Views 9 | { 10 | [Collection("Simple Injector Tests")] 11 | public class ViewModelProcessorTests 12 | { 13 | private readonly CompositionRootFixture _fixture; 14 | 15 | public ViewModelProcessorTests(CompositionRootFixture fixture) 16 | { 17 | _fixture = fixture; 18 | } 19 | 20 | [Fact] 21 | public void RegistersIProcessViewModels_UsingViewModelProcessor_AsSingleton() 22 | { 23 | var instance = _fixture.Container.GetInstance(); 24 | var registration = _fixture.Container.GetRegistration(typeof(IProcessViewModels)); 25 | 26 | Assert.NotNull(instance); 27 | Assert.IsType(instance); 28 | Assert.Equal(Lifestyle.Singleton, registration.Lifestyle); 29 | } 30 | 31 | [Fact] 32 | public void Execute_InvokesViewModelHandler_UsingContainerForResolution() 33 | { 34 | var models = _fixture.Container.GetInstance(); 35 | var viewModel = models.Create(); 36 | 37 | Assert.Equal("faked", viewModel.ReturnType); 38 | } 39 | 40 | [Fact] 41 | public void Execute_InvokesViewModelWithArgumentHandler_UsingContainerForResolution() 42 | { 43 | var models = _fixture.Container.GetInstance(); 44 | var viewModel = models.Create("faked"); 45 | 46 | Assert.Equal("faked", viewModel.ReturnType); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/FluentValidation/ValidationProcessorTests.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using FluentValidation; 3 | using ScaffoldR.Core.Validation; 4 | using ScaffoldR.Infrastructure.FluentValidation; 5 | using ScaffoldR.Tests.Infrastructure.Commands.Fakes; 6 | using ScaffoldR.Tests.Infrastructure.Queries.Fakes; 7 | using SimpleInjector; 8 | using Xunit; 9 | 10 | namespace ScaffoldR.Tests.Infrastructure.FluentValidation 11 | { 12 | public class ValidationProcessorTests 13 | { 14 | [Fact] 15 | public void ValidateCommand_InvokesValidator_UsingContainerForResolution() 16 | { 17 | var container = new Container(); 18 | container.RegisterSingleton(); 19 | container.Register(typeof(IValidator<>), new[] { Assembly.GetExecutingAssembly() }); 20 | container.Verify(); 21 | 22 | var validation = container.GetInstance(); 23 | var result = validation.Validate(new FakeCommandWithValidator { InputValue = null }); 24 | 25 | Assert.False(result.IsValid); 26 | Assert.Equal(1, result.Errors.Count); 27 | } 28 | 29 | [Fact] 30 | public void ValidateQuery_InvokesValidator_UsingContainerForResolution() 31 | { 32 | var container = new Container(); 33 | container.RegisterSingleton(); 34 | container.Register(typeof(IValidator<>), new[] { Assembly.GetExecutingAssembly() }); 35 | container.Verify(); 36 | 37 | var validation = container.GetInstance(); 38 | var result = validation.Validate(new FakeQueryWithValidator { InputValue = null }); 39 | 40 | Assert.False(result.IsValid); 41 | Assert.Equal(1, result.Errors.Count); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/CompositionRoot/Packages/QueryPackage.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using ScaffoldR.Core.Events; 3 | using ScaffoldR.Core.Queries; 4 | using ScaffoldR.Core.Transactions; 5 | using ScaffoldR.Infrastructure.FluentValidation; 6 | using ScaffoldR.Infrastructure.Queries; 7 | using ScaffoldR.Infrastructure.Transactions; 8 | using SimpleInjector; 9 | 10 | namespace ScaffoldR.Infrastructure.CompositionRoot.Packages 11 | { 12 | internal sealed class QueryPackage : IPackageScaffoldR 13 | { 14 | public void RegisterServices(Container container, CompositionRootSettings settings) 15 | { 16 | if (settings.TransactionAssemblies == null) return; 17 | 18 | container.Register(Lifestyle.Singleton); 19 | 20 | container.Register(typeof (IHandleQuery<,>), settings.TransactionAssemblies); 21 | 22 | container.RegisterDecorator( 23 | typeof(IHandleQuery<,>), 24 | typeof(QueryEventProcessingDecorator<,>), 25 | c => 26 | { 27 | var attribute = c.ImplementationType.GetCustomAttribute(); 28 | return attribute != null && attribute.Enabled; 29 | } 30 | ); 31 | 32 | container.RegisterDecorator( 33 | typeof (IHandleQuery<,>), 34 | typeof (ValidateQueryDecorator<,>) 35 | ); 36 | 37 | container.RegisterDecorator( 38 | typeof (IHandleQuery<,>), 39 | typeof (QueryLifetimeScopeDecorator<,>), 40 | Lifestyle.Singleton 41 | ); 42 | 43 | container.RegisterDecorator( 44 | typeof (IHandleQuery<,>), 45 | typeof (QueryNotNullDecorator<,>), 46 | Lifestyle.Singleton 47 | ); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tools/Build.ps1: -------------------------------------------------------------------------------- 1 | Param( 2 | [Parameter(Mandatory=$true)] 3 | [string]$version, 4 | [string]$configuration = "Release", 5 | [boolean]$build = $true, 6 | [boolean]$nuspec = $true, 7 | [boolean]$publish = $false, 8 | [boolean]$pack = $false, 9 | [string]$outputFolder = "..\nuget" 10 | ) 11 | 12 | # Include build functions 13 | . "./BuildFunctions.ps1" 14 | 15 | # The solution we are building 16 | $solution = "../src/ScaffoldR.sln" 17 | 18 | # Assemblies we are releasing 19 | $assemblies = "../src/ScaffoldR", "../src/ScaffoldR.EntityFramework" 20 | 21 | # Test assemblies 22 | $testAssemblies = "../src/ScaffoldR.Tests", "../src/ScaffoldR.EntityFramework.Tests" 23 | 24 | # Start by changing the assembly version 25 | Write-Host "Changing the assembly versions to '$version'..." 26 | Get-ChildItem ($assemblies + $testAssemblies) -Filter "AssemblyInfo.cs" -Recurse | 27 | % { Update-AssemblyVersion $_.FullName $version } 28 | 29 | # Build the entire solution 30 | if ($build) { 31 | Write-Host "Cleaning and building $solution (Configuration: $configuration)" 32 | New-Solution $solution $configuration 33 | } 34 | 35 | # Change dependency version on all depending assemblies 36 | if ($nuspec) { 37 | Write-Host "Changing the ScaffoldR(s) NuGet Spec version dependencies to '$version'..." 38 | Get-ChildItem $assemblies -Filter "ScaffoldR*.nuspec" -Recurse | 39 | % { Update-NugetSpecDependencyVersion $_.FullName "ScaffoldR" $version } 40 | } 41 | 42 | # Pack the assemblies and move to output folder 43 | if ($pack) { 44 | Write-Host "Packaging projects..." 45 | Get-ChildItem $assemblies -Filter "ScaffoldR*.csproj" -Recurse | 46 | % { Invoke-PackNuget $_.FullName $configuration $outputFolder } 47 | } 48 | 49 | # Publish the assemblies 50 | if ($publish) { 51 | Write-Host "Publishing packages..." 52 | Get-ChildItem $outputFolder -Filter "*$version.nupkg" -Recurse | 53 | % { Publish-NugetPackage $_.FullName } 54 | } -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/CompositionRoot/Packages/CommandPackage.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using ScaffoldR.Core.Commands; 3 | using ScaffoldR.Core.Events; 4 | using ScaffoldR.Core.Transactions; 5 | using ScaffoldR.Infrastructure.Commands; 6 | using ScaffoldR.Infrastructure.FluentValidation; 7 | using ScaffoldR.Infrastructure.Transactions; 8 | using SimpleInjector; 9 | 10 | namespace ScaffoldR.Infrastructure.CompositionRoot.Packages 11 | { 12 | internal sealed class CommandPackage : IPackageScaffoldR 13 | { 14 | public void RegisterServices(Container container, CompositionRootSettings settings) 15 | { 16 | if (settings.TransactionAssemblies == null) return; 17 | 18 | container.Register(Lifestyle.Singleton); 19 | container.Register(typeof(IHandleCommand<>), settings.TransactionAssemblies); 20 | 21 | container.RegisterDecorator( 22 | typeof(IHandleCommand<>), 23 | typeof(CommandEventProcessingDecorator<>), 24 | c => 25 | { 26 | var attribute = c.ImplementationType.GetCustomAttribute(); 27 | return attribute != null && attribute.Enabled; 28 | } 29 | ); 30 | 31 | container.RegisterDecorator(typeof(IHandleCommand<>), 32 | typeof(CommandTransactionDecorator<>), 33 | c => c.ImplementationType.GetCustomAttribute() != null 34 | ); 35 | 36 | container.RegisterDecorator( 37 | typeof(IHandleCommand<>), 38 | typeof(ValidateCommandDecorator<>) 39 | ); 40 | 41 | container.RegisterDecorator( 42 | typeof(IHandleCommand<>), 43 | typeof(CommandLifetimeScopeDecorator<>), 44 | Lifestyle.Singleton 45 | ); 46 | 47 | container.RegisterDecorator( 48 | typeof(IHandleCommand<>), 49 | typeof(CommandNotNullDecorator<>), 50 | Lifestyle.Singleton 51 | ); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/ScaffoldR.EntityFramework/Entities/EntityFrameworkRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.Entity; 3 | using System.Linq; 4 | using ScaffoldR.Core.Entities; 5 | 6 | namespace ScaffoldR.EntityFramework.Entities 7 | { 8 | internal sealed class EntityFrameworkRepository : IEntityWriter, IEntityReader where TEntity : Entity 9 | { 10 | private readonly Func _contextProvider; 11 | 12 | public EntityFrameworkRepository(Func contextProvider) 13 | { 14 | _contextProvider = contextProvider; 15 | } 16 | 17 | public void Save(TEntity entity) 18 | { 19 | var context = _contextProvider(); 20 | var entry = context.Entry(entity); 21 | 22 | // If it is not tracked by the context, add it to the context 23 | if (entry.State == EntityState.Detached) 24 | { 25 | // This also sets the entity state to added. 26 | context.Set().Add(entity); 27 | } 28 | else 29 | { 30 | // Tells the context that the entity should be updated during saving changes 31 | entry.State = EntityState.Modified; 32 | } 33 | } 34 | 35 | public void Delete(TEntity entity) 36 | { 37 | var context = _contextProvider(); 38 | var entry = context.Entry(entity); 39 | if (entry.State != EntityState.Deleted) 40 | { 41 | // This also sets the entity state to Deleted. 42 | context.Set().Remove(entity); 43 | } 44 | } 45 | 46 | public IQueryable Query() 47 | { 48 | return _contextProvider().Set().AsNoTracking(); 49 | } 50 | 51 | public TEntity Get(object primaryKey) 52 | { 53 | var context = _contextProvider(); 54 | var entity = context.Set().Find(primaryKey); 55 | if (entity == null) return null; 56 | 57 | // We found the entity, set the state to unchanged. 58 | context.Entry(entity).State = EntityState.Unchanged; 59 | 60 | return entity; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/Commands/CommandLifetimeScopeDecoratorTests.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using ScaffoldR.Core.Commands; 3 | using ScaffoldR.Infrastructure.Commands; 4 | using ScaffoldR.Tests.Infrastructure.Commands.Fakes; 5 | using ScaffoldR.Tests.Infrastructure.CompositionRoot; 6 | using SimpleInjector; 7 | using Xunit; 8 | 9 | namespace ScaffoldR.Tests.Infrastructure.Commands 10 | { 11 | [Collection("Simple Injector Tests")] 12 | public class CommandLifetimeScopeDecoratorTests 13 | { 14 | private readonly CompositionRootFixture _fixture; 15 | 16 | public CommandLifetimeScopeDecoratorTests(CompositionRootFixture fixture) 17 | { 18 | _fixture = fixture; 19 | } 20 | 21 | [Fact] 22 | public void BeginsLifetimeScope_WhenCurrentLifetimeScope_IsNull() 23 | { 24 | var command = new FakeCommandWithValidator(); 25 | var decorated = new Mock>(MockBehavior.Strict); 26 | decorated.Setup(x => x.Handle(command)); 27 | 28 | var decorator = new CommandLifetimeScopeDecorator(_fixture.Container, () => decorated.Object); 29 | Assert.Equal(null, _fixture.Container.GetCurrentLifetimeScope()); 30 | decorator.Handle(command); 31 | 32 | Assert.Equal(null, _fixture.Container.GetCurrentLifetimeScope()); 33 | decorated.Verify(x => x.Handle(command), Times.Once); 34 | } 35 | 36 | [Fact] 37 | public void UsesCurrentLifetimeScope_WhenCurrentLifetimeScope_IsNotNull() 38 | { 39 | var command = new FakeCommandWithValidator(); 40 | var decorated = new Mock>(MockBehavior.Strict); 41 | decorated.Setup(x => x.Handle(command)); 42 | 43 | var decorator = new CommandLifetimeScopeDecorator(_fixture.Container, () => decorated.Object); 44 | Assert.Equal(null, _fixture.Container.GetCurrentLifetimeScope()); 45 | 46 | using (_fixture.Container.BeginLifetimeScope()) 47 | { 48 | decorator.Handle(command); 49 | } 50 | 51 | Assert.Equal(null, _fixture.Container.GetCurrentLifetimeScope()); 52 | 53 | decorated.Verify(x => x.Handle(command), Times.Once); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/Queries/QueryLifetimeScopeDecoratorTests.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using ScaffoldR.Core.Queries; 3 | using ScaffoldR.Infrastructure.Queries; 4 | using ScaffoldR.Tests.Infrastructure.CompositionRoot; 5 | using ScaffoldR.Tests.Infrastructure.Queries.Fakes; 6 | using SimpleInjector; 7 | using Xunit; 8 | 9 | namespace ScaffoldR.Tests.Infrastructure.Queries 10 | { 11 | [Collection("Simple Injector Tests")] 12 | public class QueryLifetimeScopeDecoratorTests 13 | { 14 | private readonly CompositionRootFixture _fixture; 15 | 16 | public QueryLifetimeScopeDecoratorTests(CompositionRootFixture fixture) 17 | { 18 | _fixture = fixture; 19 | } 20 | 21 | [Fact] 22 | public void BeginsLifetimeScope_WhenCurrentLifetimeScope_IsNull() 23 | { 24 | var query = new FakeQueryWithoutValidator(); 25 | var decorated = new Mock>(MockBehavior.Strict); 26 | decorated.Setup(x => x.Handle(query)).Returns("faked"); 27 | 28 | var decorator = new QueryLifetimeScopeDecorator(_fixture.Container, () => decorated.Object); 29 | Assert.Equal(null, _fixture.Container.GetCurrentLifetimeScope()); 30 | 31 | var result = decorator.Handle(query); 32 | 33 | Assert.Equal("faked", result); 34 | decorated.Verify(x => x.Handle(query), Times.Once); 35 | } 36 | 37 | [Fact] 38 | public void UsesCurrentLifetimeScope_WhenCurrentLifetimeScope_IsNotNull() 39 | { 40 | var query = new FakeQueryWithoutValidator(); 41 | var decorated = new Mock>(MockBehavior.Strict); 42 | decorated.Setup(x => x.Handle(query)).Returns("faked"); 43 | 44 | var decorator = new QueryLifetimeScopeDecorator(_fixture.Container, () => decorated.Object); 45 | Assert.Equal(null, _fixture.Container.GetCurrentLifetimeScope()); 46 | 47 | string result; 48 | using (_fixture.Container.BeginLifetimeScope()) 49 | { 50 | result = decorator.Handle(query); 51 | } 52 | 53 | Assert.Equal("faked", result); 54 | 55 | decorated.Verify(x => x.Handle(query), Times.Once); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/ScaffoldR.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.24720.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScaffoldR", "ScaffoldR\ScaffoldR.csproj", "{60AC8712-CFC6-4065-93A4-7134C74F88F6}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScaffoldR.Tests", "ScaffoldR.Tests\ScaffoldR.Tests.csproj", "{E4F000B6-1E87-4605-8833-8BB4C8657296}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScaffoldR.EntityFramework", "ScaffoldR.EntityFramework\ScaffoldR.EntityFramework.csproj", "{62E4E31B-D3AC-4345-9251-A16FAF8758F3}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScaffoldR.EntityFramework.Tests", "ScaffoldR.EntityFramework.Tests\ScaffoldR.EntityFramework.Tests.csproj", "{11A3698E-0217-44F0-9236-6ABAA2EDCC67}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {60AC8712-CFC6-4065-93A4-7134C74F88F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {60AC8712-CFC6-4065-93A4-7134C74F88F6}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {60AC8712-CFC6-4065-93A4-7134C74F88F6}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {60AC8712-CFC6-4065-93A4-7134C74F88F6}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {E4F000B6-1E87-4605-8833-8BB4C8657296}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {E4F000B6-1E87-4605-8833-8BB4C8657296}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {E4F000B6-1E87-4605-8833-8BB4C8657296}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {E4F000B6-1E87-4605-8833-8BB4C8657296}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {62E4E31B-D3AC-4345-9251-A16FAF8758F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {62E4E31B-D3AC-4345-9251-A16FAF8758F3}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {62E4E31B-D3AC-4345-9251-A16FAF8758F3}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {62E4E31B-D3AC-4345-9251-A16FAF8758F3}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {11A3698E-0217-44F0-9236-6ABAA2EDCC67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {11A3698E-0217-44F0-9236-6ABAA2EDCC67}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {11A3698E-0217-44F0-9236-6ABAA2EDCC67}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {11A3698E-0217-44F0-9236-6ABAA2EDCC67}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | EndGlobal 41 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/Commands/CommandTransactionDecoratorTests.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using Moq; 3 | using ScaffoldR.Core.Commands; 4 | using ScaffoldR.Core.Transactions; 5 | using ScaffoldR.Infrastructure.Commands; 6 | using ScaffoldR.Tests.Infrastructure.Commands.Fakes; 7 | using Xunit; 8 | 9 | namespace ScaffoldR.Tests.Infrastructure.Commands 10 | { 11 | public class CommandTransactionDecoratorTests 12 | { 13 | [Fact] 14 | public void ExecuteTransaction_WhenCommandHasTransactionalAttribute() 15 | { 16 | var command = new FakeCommandWithoutValidator(); 17 | Assert.IsAssignableFrom(command); 18 | 19 | var transactionProcessor = new Mock(MockBehavior.Strict); 20 | transactionProcessor.Setup(x => x.Execute()); 21 | 22 | var decorated = new Mock>(MockBehavior.Strict); 23 | var typeDescriptionProvider = TypeDescriptor.AddAttributes(decorated.Object.GetType(), new TransactionalAttribute()); 24 | decorated.Setup(x => x.Handle(command)); 25 | 26 | var decorator = new CommandTransactionDecorator(transactionProcessor.Object, () => decorated.Object); 27 | decorator.Handle(command); 28 | 29 | decorated.Verify(x => x.Handle(command), Times.Once); 30 | transactionProcessor.Verify(x => x.Execute(), Times.Once); 31 | 32 | // Clean the provider for next test, or else it will fail - very odd. 33 | TypeDescriptor.RemoveProvider(typeDescriptionProvider, decorated.Object.GetType()); 34 | } 35 | 36 | [Fact] 37 | public void DoNotExecuteTransaction_WhenCommandDoNotHaveTransactionalAttribute() 38 | { 39 | var command = new FakeCommandWithoutValidator(); 40 | Assert.IsAssignableFrom(command); 41 | 42 | var transactionProcessor = new Mock(MockBehavior.Strict); 43 | transactionProcessor.Setup(x => x.Execute()); 44 | 45 | var decorated = new Mock>(MockBehavior.Strict); 46 | decorated.Setup(x => x.Handle(command)); 47 | 48 | var decorator = new CommandTransactionDecorator(transactionProcessor.Object, () => decorated.Object); 49 | decorator.Handle(command); 50 | 51 | decorated.Verify(x => x.Handle(command), Times.Once); 52 | transactionProcessor.Verify(x => x.Execute(), Times.Never); 53 | } 54 | 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/Events/TriggerEventWhenHandlersExistDecoratorTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Moq; 4 | using ScaffoldR.Core.Events; 5 | using ScaffoldR.Core.Tasks; 6 | using ScaffoldR.Infrastructure.Events; 7 | using ScaffoldR.Tests.Infrastructure.Events.Fakes; 8 | using SimpleInjector; 9 | using Xunit; 10 | 11 | namespace ScaffoldR.Tests.Infrastructure.Events 12 | { 13 | public class TriggerEventWhenHandlersExistDecoratorTests 14 | { 15 | [Fact] 16 | public void TriggerEventHandler_WhenEventHandlersExist() 17 | { 18 | var container = new Container(); 19 | 20 | var evt = new FakeEventWithoutValidation(); 21 | Assert.IsAssignableFrom(evt); 22 | 23 | var handlers = new List> {new HandleFakeEventWithoutValidation()}; 24 | 25 | var decorated = new Mock>(MockBehavior.Strict); 26 | decorated.Setup(x => x.Trigger(evt)); 27 | 28 | var taskFactory = new Mock(MockBehavior.Strict); 29 | taskFactory.Setup(factory => factory.StartTask(It.IsAny())).Callback(action => action()); 30 | 31 | var decorator = new TriggerEventWhenHandlersExistDecorator(container, taskFactory.Object, () => decorated.Object, handlers); 32 | decorator.Trigger(evt); 33 | 34 | taskFactory.Verify(x => x.StartTask(It.IsAny()), Times.Once); 35 | decorated.Verify(x => x.Trigger(evt), Times.Once); 36 | } 37 | 38 | [Fact] 39 | public void DoNotTriggerEventHandler_WhenEventHandlersDoesNotExist() 40 | { 41 | var container = new Container(); 42 | 43 | var evt = new FakeEventWithoutValidation(); 44 | Assert.IsAssignableFrom(evt); 45 | 46 | var decorated = new Mock>(MockBehavior.Strict); 47 | decorated.Setup(x => x.Trigger(evt)); 48 | 49 | var taskFactory = new Mock(MockBehavior.Strict); 50 | taskFactory.Setup(factory => factory.StartTask(It.IsAny())).Callback(action => action()); 51 | 52 | var decorator = new TriggerEventWhenHandlersExistDecorator(container, taskFactory.Object, () => decorated.Object, null); 53 | decorator.Trigger(evt); 54 | 55 | taskFactory.Verify(x => x.StartTask(It.IsAny()), Times.Never); 56 | decorated.Verify(x => x.Trigger(evt), Times.Never); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/FluentValidation/CompositionRootTests.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | using ScaffoldR.Core.Validation; 3 | using ScaffoldR.Infrastructure.FluentValidation; 4 | using ScaffoldR.Tests.Infrastructure.Commands.Fakes; 5 | using ScaffoldR.Tests.Infrastructure.CompositionRoot; 6 | using SimpleInjector; 7 | using Xunit; 8 | using CascadeMode = FluentValidation.CascadeMode; 9 | 10 | namespace ScaffoldR.Tests.Infrastructure.FluentValidation 11 | { 12 | [Collection("Simple Injector Tests")] 13 | public class CompositionRootTests 14 | { 15 | private readonly CompositionRootFixture _fixture; 16 | 17 | public CompositionRootTests(CompositionRootFixture fixture) 18 | { 19 | _fixture = fixture; 20 | } 21 | 22 | [Fact] 23 | public void Sets_ValidatorOptions_CascadeMode_To_StopOnFirstFailure() 24 | { 25 | Assert.Equal(CascadeMode.StopOnFirstFailure, ValidatorOptions.CascadeMode); 26 | } 27 | 28 | [Fact] 29 | public void RegistersIProcessValidation_UsingValidationProcessor_AsSingleton() 30 | { 31 | var instance = _fixture.Container.GetInstance(); 32 | var registration = _fixture.Container.GetRegistration(typeof(IProcessValidation)); 33 | 34 | Assert.NotNull(instance); 35 | Assert.IsType(instance); 36 | Assert.Equal(Lifestyle.Singleton, registration.Lifestyle); 37 | } 38 | 39 | [Fact] 40 | public void RegistersIValidator_Transiently_UsingOpenGenerics_WhenValidatorExists() 41 | { 42 | var instance = _fixture.Container.GetInstance>(); 43 | var registration = _fixture.Container.GetRegistration(typeof(IValidator)); 44 | 45 | Assert.NotNull(instance); 46 | Assert.IsType(instance); 47 | Assert.Equal(Lifestyle.Transient, registration.Lifestyle); 48 | } 49 | 50 | [Fact] 51 | public void RegistersIValidator_AsSingleton_UsingValidateNothingDecorator_WhenValidatorDoesNotExist() 52 | { 53 | var instance = _fixture.Container.GetInstance>(); 54 | var registration = _fixture.Container.GetRegistration(typeof(IValidator)); 55 | 56 | Assert.NotNull(instance); 57 | Assert.IsType>(instance); 58 | Assert.Equal(Lifestyle.Singleton, registration.Lifestyle); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/FluentValidation/ValidateQueryDecoratorTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | using FluentValidation; 4 | using FluentValidation.Results; 5 | using Moq; 6 | using ScaffoldR.Core.Queries; 7 | using ScaffoldR.Core.Transactions; 8 | using ScaffoldR.Infrastructure.FluentValidation; 9 | using ScaffoldR.Tests.Infrastructure.Queries.Fakes; 10 | using Xunit; 11 | 12 | namespace ScaffoldR.Tests.Infrastructure.FluentValidation 13 | { 14 | public class ValidateQueryDecoratorTests 15 | { 16 | [Fact] 17 | public void Handle_ThrowsValidationException_AndDoesNotInvokeDecoratedHandle_WhenValidationFails() 18 | { 19 | var query = new FakeQueryWithoutValidator(); 20 | var decorated = new Mock>(MockBehavior.Strict); 21 | var validator = new Mock>(MockBehavior.Strict); 22 | Expression> expectedQuery = x => ReferenceEquals(x, query); 23 | 24 | var expectedResult = new ValidationResult(new[] { new ValidationFailure("Name", "Invalid."), }); 25 | validator.Setup(x => x.Validate(It.Is(expectedQuery))).Returns(expectedResult); 26 | 27 | var decorator = new ValidateQueryDecorator(decorated.Object, validator.Object); 28 | var exception = Assert.Throws(() => decorator.Handle(query)); 29 | 30 | Assert.NotNull(exception); 31 | validator.Verify(x => x.Validate(It.Is(expectedQuery)), Times.Once); 32 | decorated.Verify(x => x.Handle(It.IsAny()), Times.Never); 33 | } 34 | 35 | [Fact] 36 | public void Handle_InvokesDecoratedHandle_WhenValidationPasses() 37 | { 38 | var query = new FakeQueryWithoutValidator(); 39 | var decorated = new Mock>(MockBehavior.Strict); 40 | var validator = new Mock>(MockBehavior.Strict); 41 | var expectedResult = new ValidationResult(); 42 | validator.Setup(x => x.Validate(query)).Returns(expectedResult); 43 | decorated.Setup(x => x.Handle(query)).Returns("faked"); 44 | 45 | var decorator = new ValidateQueryDecorator(decorated.Object, validator.Object); 46 | var result = decorator.Handle(query); 47 | 48 | Assert.Equal("faked", result); 49 | validator.Verify(x => x.Validate(query), Times.Once); 50 | decorated.Verify(x => x.Handle(query), Times.Once); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/ScaffoldR/Infrastructure/CompositionRoot/ContainerExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Linq.Expressions; 4 | using ScaffoldR.Core.Extensions; 5 | using SimpleInjector; 6 | 7 | namespace ScaffoldR.Infrastructure.CompositionRoot 8 | { 9 | /// 10 | /// The main composition root 11 | /// 12 | public static class ContainerExtensions 13 | { 14 | /// 15 | /// Registers ScaffoldR into the Simple Injector container 16 | /// 17 | /// The Simple Injector Container object 18 | /// The Composition Root Settings 19 | public static void RegisterScaffoldR(this Container container, Action compositionRootSettings) 20 | { 21 | if (container == null) 22 | throw new ArgumentNullException(nameof(container)); 23 | 24 | if (compositionRootSettings == null) 25 | throw new ArgumentNullException(nameof(compositionRootSettings)); 26 | 27 | var provider = new CompositionRootSettings(); 28 | compositionRootSettings(provider); 29 | 30 | container.Options.AllowResolvingFuncFactories(); 31 | container.RegisterScaffoldRPackages(provider); 32 | } 33 | 34 | internal static void RegisterScaffoldRPackages(this Container container, CompositionRootSettings settings) 35 | { 36 | var packages = from assembly in AppDomain.CurrentDomain.GetAssemblies() 37 | from type in assembly.GetSafeTypes() 38 | where typeof(IPackageScaffoldR).IsAssignableFrom(type) 39 | where !type.IsAbstract 40 | select (IPackageScaffoldR)Activator.CreateInstance(type); 41 | 42 | packages.ToList().ForEach(p => p.RegisterServices(container, settings)); 43 | } 44 | 45 | internal static void AllowResolvingFuncFactories(this ContainerOptions options) 46 | { 47 | options.Container.ResolveUnregisteredType += (s, e) => { 48 | var type = e.UnregisteredServiceType; 49 | 50 | if (!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(Func<>)) return; 51 | 52 | var serviceType = type.GetGenericArguments().First(); 53 | var registration = options.Container.GetRegistration(serviceType, true); 54 | var funcType = typeof(Func<>).MakeGenericType(serviceType); 55 | 56 | var factoryDelegate = Expression.Lambda(funcType, registration.BuildExpression()).Compile(); 57 | e.Register(Expression.Constant(factoryDelegate)); 58 | }; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/FluentValidation/ValidateCommandDecoratorTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | using FluentValidation; 4 | using FluentValidation.Results; 5 | using Moq; 6 | using ScaffoldR.Core.Commands; 7 | using ScaffoldR.Core.Transactions; 8 | using ScaffoldR.Infrastructure.FluentValidation; 9 | using ScaffoldR.Tests.Infrastructure.Commands.Fakes; 10 | using Xunit; 11 | 12 | namespace ScaffoldR.Tests.Infrastructure.FluentValidation 13 | { 14 | public class ValidateCommandDecoratorTests 15 | { 16 | [Fact] 17 | public void Handle_ThrowsValidationException_AndDoesNotInvokeDecoratedHandle_WhenValidationFails() 18 | { 19 | var command = new FakeCommandWithValidator(); 20 | var decorated = new Mock>(MockBehavior.Strict); 21 | var validator = new Mock>(MockBehavior.Strict); 22 | Expression> expectedCommand = x => ReferenceEquals(x, command); 23 | 24 | var expectedResult = new ValidationResult(new[] { new ValidationFailure("Name", "Invalid.", command.ReturnValue), }); 25 | validator.Setup(x => x.Validate(It.Is(expectedCommand))).Returns(expectedResult); 26 | var decorator = new ValidateCommandDecorator(decorated.Object, validator.Object); 27 | var exception = Assert.Throws(() => decorator.Handle(command)); 28 | 29 | Assert.NotNull(exception); 30 | validator.Verify(x => x.Validate(It.Is(expectedCommand)), Times.Once); 31 | decorated.Verify(x => x.Handle(It.IsAny()), Times.Never); 32 | } 33 | 34 | [Fact] 35 | public void Handle_InvokesDecoratedHandle_WhenValidationPasses() 36 | { 37 | var command = new FakeCommandWithValidator(); 38 | var decorated = new Mock>(MockBehavior.Strict); 39 | var validator = new Mock>(MockBehavior.Strict); 40 | Expression> expectedCommand = x => ReferenceEquals(x, command); 41 | 42 | var expectedResult = new ValidationResult(); 43 | validator.Setup(x => x.Validate(It.Is(expectedCommand))).Returns(expectedResult); 44 | decorated.Setup(x => x.Handle(It.Is(expectedCommand))); 45 | 46 | var decorator = new ValidateCommandDecorator(decorated.Object, validator.Object); 47 | decorator.Handle(command); 48 | 49 | validator.Verify(x => x.Validate(It.Is(expectedCommand)), Times.Once); 50 | decorated.Verify(x => x.Handle(It.Is(expectedCommand)), Times.Once); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Extensions/ReflectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Linq; 4 | using System.Reflection; 5 | 6 | namespace ScaffoldR.Core.Extensions 7 | { 8 | /// 9 | /// Reflection helper extensions 10 | /// 11 | public static class ReflectionExtensions 12 | { 13 | /// 14 | /// Test to see if the type is generically assignable from the another type 15 | /// 16 | /// A class/interface type 17 | /// A class/interface typ 18 | /// True if the type is generically assignable from the other type - otherwise false 19 | public static bool IsGenericallyAssignableFrom(this Type openGeneric, Type closedGeneric) 20 | { 21 | var interfaceTypes = closedGeneric.GetInterfaces(); 22 | 23 | if (interfaceTypes.Where(interfaceType => interfaceType.IsGenericType).Any(interfaceType => interfaceType.GetGenericTypeDefinition() == openGeneric)) 24 | { 25 | return true; 26 | } 27 | 28 | var baseType = closedGeneric.BaseType; 29 | if (baseType == null) return false; 30 | 31 | return baseType.IsGenericType && 32 | (baseType.GetGenericTypeDefinition() == openGeneric || 33 | openGeneric.IsGenericallyAssignableFrom(baseType)); 34 | } 35 | 36 | /// 37 | /// Get types of the assembly, but only returns assembly where the types can be loaded. 38 | /// 39 | /// The assembly to look at. 40 | /// An array of types. 41 | public static Type[] GetSafeTypes(this Assembly assembly) 42 | { 43 | try 44 | { 45 | return assembly.GetTypes(); 46 | } 47 | catch (ReflectionTypeLoadException ex) 48 | { 49 | return ex.Types; 50 | } 51 | } 52 | 53 | /// 54 | /// Gets a runtime added attribute to a type. 55 | /// 56 | /// The attribute 57 | /// The type. 58 | /// The first attribute or null if none is found. 59 | public static TAttribute GetRuntimeAddedAttribute(this Type type) where TAttribute : Attribute 60 | { 61 | if (type == null) throw new ArgumentNullException(nameof(type)); 62 | 63 | var attributes = TypeDescriptor.GetAttributes(type).OfType(); 64 | var enumerable = attributes as TAttribute[] ?? attributes.ToArray(); 65 | return enumerable.Any() ? enumerable.First() : null; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tools/BuildFunctions.ps1: -------------------------------------------------------------------------------- 1 | Function New-Solution { 2 | 3 | Param( 4 | [Parameter(Mandatory=$true)] 5 | [string]$solution, 6 | [Parameter(Mandatory=$true)] 7 | [string]$configuration 8 | ) 9 | 10 | # Set the path to the .NET folder in order to use "msbuild.exe" 11 | $env:PATH = "C:\Program Files (x86)\MSBuild\14.0\Bin" 12 | 13 | Invoke-Expression "msbuild.exe $solution /nologo /v:m /p:Configuration=$configuration /t:Clean" 14 | Invoke-Expression "msbuild.exe $solution /nologo /v:m /p:Configuration=$configuration /clp:ErrorsOnly" 15 | } 16 | 17 | Function Update-AssemblyVersion() { 18 | 19 | Param( 20 | [Parameter(Mandatory=$true)] 21 | [string]$filePath, 22 | [Parameter(Mandatory=$true)] 23 | [string]$publishVersion 24 | ) 25 | 26 | Write-Host ("-- Updating '{0}' to version '{1}'" -f $filePath, $publishVersion) 27 | 28 | $assemblyVersionPattern = 'AssemblyVersion\("[0-9]+(\.([0-9]+|\*)){1,3}"\)' 29 | $assemblyVersion = 'AssemblyVersion("' + $publishVersion + '")'; 30 | $assemblyFileVersionPattern = 'AssemblyFileVersion\("[0-9]+(\.([0-9]+|\*)){1,3}"\)' 31 | $assemblyFileVersion = 'AssemblyFileVersion("' + $publishVersion + '")'; 32 | 33 | (Get-Content $filePath) | ForEach-Object { 34 | % { $_ -Replace $assemblyVersionPattern, $assemblyVersion } | 35 | % { $_ -Replace $assemblyFileVersionPattern, $assemblyFileVersion } 36 | } | Set-Content $filePath 37 | } 38 | 39 | Function Update-NugetSpecDependencyVersion 40 | { 41 | Param 42 | ( 43 | [Parameter(Mandatory=$true)] 44 | [string]$filePath, 45 | [Parameter(Mandatory=$true)] 46 | [string]$packageId, 47 | [Parameter(Mandatory=$true)] 48 | [string]$publishVersion 49 | ) 50 | 51 | [xml] $toFile = (Get-Content $filePath) 52 | 53 | $nodes = $toFile.SelectNodes("//package/metadata/dependencies/dependency[starts-with(@id, $packageId)]") 54 | foreach ($node in $nodes) 55 | { 56 | Write-Host ("-- Updating '{0}' in '{1}' to version '{2}'" -f $node.id, $filePath, $publishVersion) 57 | $node.version = "[{0}]" -f $publishVersion 58 | } 59 | 60 | $toFile.Save($filePath) 61 | 62 | } 63 | 64 | Function Invoke-PackNuget { 65 | 66 | Param( 67 | [Parameter(Mandatory=$true)] 68 | [string]$project, 69 | [Parameter(Mandatory=$true)] 70 | [string]$configuration, 71 | [Parameter(Mandatory=$true)] 72 | [string]$outputFolder 73 | ) 74 | 75 | if (!(Test-Path -Path $outputFolder)) { 76 | New-Item $outputFolder -Type Directory 77 | } 78 | 79 | Write-Host "-- Packaging '$project'" 80 | Invoke-Expression "..\tools\NuGet.exe pack $project -OutputDirectory '$outputFolder' -Prop Configuration=$configuration" 81 | } 82 | 83 | Function Publish-NugetPackage() { 84 | 85 | Param( 86 | [Parameter(Mandatory=$true)] 87 | [string]$package 88 | ) 89 | 90 | Write-Host "-- Publishing '$package'" 91 | Invoke-Expression "..\tools\NuGet.exe push $package" 92 | 93 | } -------------------------------------------------------------------------------- /src/ScaffoldR/Core/Entities/EntityWithId.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ScaffoldR.Core.Entities 4 | { 5 | /// 6 | /// A single entity that can be identified by a primary key. 7 | /// 8 | /// The type of the entity's primary key. 9 | public abstract class EntityWithId : Entity, IEquatable> 10 | { 11 | /// 12 | /// Primary key of this entity. 13 | /// 14 | public TId Id { get; set; } 15 | 16 | /// 17 | /// Get the hash code for this entity instance based on its Id property. 18 | /// 19 | /// The hash code for this object instance based on its Id property. 20 | public override int GetHashCode() 21 | { 22 | return IsTransient(this) ? 0 : Id.GetHashCode(); 23 | } 24 | 25 | /// 26 | /// Determine whether this entity is equal to another object. 27 | /// 28 | /// The object to compare to this entity when determining equality. 29 | /// True if the other object is an EntityWithId, both entities are not null or 30 | /// transient, and both entities have the same Id value. Otherwise, false. 31 | public override bool Equals(object other) 32 | { 33 | return Equals(other as EntityWithId); 34 | } 35 | 36 | /// 37 | /// Determine whether this entity is equal to another entity. 38 | /// 39 | /// The entity to compare to this entity when determining equality. 40 | /// True if the other entity is not null, neither entity is transient, and both 41 | /// entities share the same Id value. 42 | public virtual bool Equals(EntityWithId other) 43 | { 44 | // instance is never equal to null 45 | if (other == null) return false; 46 | 47 | // when references are equal, they are the same object 48 | if (ReferenceEquals(this, other)) return true; 49 | 50 | // when either object is transient or the id's are not equal, return false 51 | if (IsTransient(this) || IsTransient(other) || !Equals(Id, other.Id)) return false; 52 | 53 | // when the id's are equal and neither object is transient 54 | // return true when one can be cast to the other 55 | // because this entity could be generated by a proxy 56 | var otherType = other.GetUnproxiedType(); 57 | var thisType = GetUnproxiedType(); 58 | return thisType.IsAssignableFrom(otherType) || otherType.IsAssignableFrom(thisType); 59 | } 60 | 61 | private static bool IsTransient(EntityWithId obj) 62 | { 63 | // an object is transient when its id is the default (null for strings or 0 for numbers) 64 | return Equals(obj.Id, default(TId)); 65 | } 66 | 67 | private Type GetUnproxiedType() 68 | { 69 | return GetType(); // return the unproxied type of the object 70 | } 71 | 72 | } 73 | } -------------------------------------------------------------------------------- /src/ScaffoldR.EntityFramework.Tests/Entities/EntityFrameworkRepositoryTests.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Data.Entity; 3 | using System.Data.Entity.Core.Objects.DataClasses; 4 | using System.Linq; 5 | using ScaffoldR.EntityFramework.Entities; 6 | using ScaffoldR.EntityFramework.Tests.Fakes; 7 | using ScaffoldR.EntityFramework.Tests.Helpers; 8 | using Xunit; 9 | 10 | namespace ScaffoldR.EntityFramework.Tests.Entities 11 | { 12 | public class EntityFrameworkRepositoryTests 13 | { 14 | [Fact] 15 | public void Query_CanGetReadOnlyEntity_WhichAreNotTrackedByContext() 16 | { 17 | using (var context = new FakeDbContext()) 18 | { 19 | var repository = new EntityFrameworkRepository(() => context); 20 | var firstCustomer = repository.Query().First(); 21 | var isFirstCustomerTrackedByContext = context.Entry(firstCustomer).State != EntityState.Detached; 22 | 23 | Assert.NotNull(firstCustomer); 24 | Assert.Equal(false, isFirstCustomerTrackedByContext); 25 | } 26 | } 27 | 28 | [Fact] 29 | public void Get_CanGetWritableEntity_WhenEntityExists() 30 | { 31 | using (var context = new FakeDbContext()) 32 | { 33 | var repository = new EntityFrameworkRepository(() => context); 34 | var customer = repository.Get(1); 35 | 36 | Assert.NotNull(customer); 37 | Assert.Equal(EntityState.Unchanged, context.Entry(customer).State); 38 | } 39 | } 40 | 41 | [Fact] 42 | public void Save_CanCreateEntity_WhenEntityIsNotTrackedByContext() 43 | { 44 | using (var context = new FakeDbContext()) 45 | { 46 | var repository = new EntityFrameworkRepository(() => context); 47 | var customer = new FakeCustomer 48 | { 49 | FirstName = "John", 50 | LastName = "Doe" 51 | }; 52 | 53 | repository.Save(customer); 54 | 55 | Assert.Equal(EntityState.Added, context.Entry(customer).State); 56 | } 57 | } 58 | 59 | [Fact] 60 | public void Save_CanUpdateEntity_WhenEntityIsTrackedByContext() 61 | { 62 | using (var context = new FakeDbContext()) 63 | { 64 | var repository = new EntityFrameworkRepository(() => context); 65 | var customer = repository.Get(1); 66 | 67 | Assert.Equal("John", customer.FirstName); 68 | 69 | // Change name 70 | customer.FirstName = "Artina"; 71 | 72 | repository.Save(customer); 73 | var affectedRows = context.SaveChanges(); 74 | 75 | Assert.Equal(1, affectedRows); 76 | customer = repository.Get(1); 77 | Assert.Equal("Artina", customer.FirstName); 78 | } 79 | } 80 | 81 | [Fact] 82 | public void Delete_CanMarkEntityForDeletion_WhenEntityExists() 83 | { 84 | using (var context = new FakeDbContext()) 85 | { 86 | var repository = new EntityFrameworkRepository(() => context); 87 | var customer = repository.Get(1); 88 | Assert.NotNull(customer); 89 | 90 | repository.Delete(customer); 91 | 92 | Assert.Equal(EntityState.Deleted, context.Entry(customer).State); 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/Commands/CommandEventProcessingDecoratorTests.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using Moq; 3 | using ScaffoldR.Core.Commands; 4 | using ScaffoldR.Core.Events; 5 | using ScaffoldR.Infrastructure.Commands; 6 | using ScaffoldR.Tests.Infrastructure.Commands.Fakes; 7 | using Xunit; 8 | 9 | namespace ScaffoldR.Tests.Infrastructure.Commands 10 | { 11 | public class CommandEventProcessingDecoratorTests 12 | { 13 | [Fact] 14 | public void RaiseEvent_AfterCommandIsExecuted_WhenCommandHasRaiseEventAttributeAndEnabledTrue() 15 | { 16 | var command = new FakeCommandWithoutValidator(); 17 | Assert.IsAssignableFrom(command); 18 | 19 | var eventProcessor = new Mock(MockBehavior.Strict); 20 | eventProcessor.Setup(x => x.Raise(command)); 21 | 22 | var attribute = new RaiseEventAttribute 23 | { 24 | Enabled = true 25 | }; 26 | 27 | var decorated = new Mock>(MockBehavior.Strict); 28 | TypeDescriptor.AddAttributes(decorated.Object.GetType(), attribute); 29 | decorated.Setup(x => x.Handle(command)); 30 | 31 | var decorator = new CommandEventProcessingDecorator(eventProcessor.Object, () => decorated.Object); 32 | decorator.Handle(command); 33 | 34 | decorated.Verify(x => x.Handle(command), Times.Once); 35 | eventProcessor.Verify(x => x.Raise(command), Times.Once); 36 | } 37 | 38 | [Fact] 39 | public void DoNotRaiseEvent_AfterCommandIsExecuted_WhenCommandHasRaiseEventAttributeAndEnabledFalse() 40 | { 41 | var command = new FakeCommandWithoutValidator(); 42 | Assert.IsAssignableFrom(command); 43 | 44 | var eventProcessor = new Mock(MockBehavior.Strict); 45 | eventProcessor.Setup(x => x.Raise(command)); 46 | 47 | var attribute = new RaiseEventAttribute 48 | { 49 | Enabled = false 50 | }; 51 | 52 | var decorated = new Mock>(MockBehavior.Strict); 53 | TypeDescriptor.AddAttributes(decorated.Object.GetType(), attribute); 54 | decorated.Setup(x => x.Handle(command)); 55 | 56 | var decorator = new CommandEventProcessingDecorator(eventProcessor.Object, () => decorated.Object); 57 | decorator.Handle(command); 58 | 59 | decorated.Verify(x => x.Handle(command), Times.Once); 60 | eventProcessor.Verify(x => x.Raise(It.IsAny()), Times.Never); 61 | } 62 | 63 | [Fact] 64 | public void DoNotRaiseEvent_AfterCommandIsExecuted_WhenCommandDoesNotHaveRaiseEventAttribute() 65 | { 66 | var command = new FakeCommandWithoutValidator(); 67 | Assert.IsAssignableFrom(command); 68 | 69 | var eventProcessor = new Mock(MockBehavior.Strict); 70 | eventProcessor.Setup(x => x.Raise(command)); 71 | 72 | var decorated = new Mock>(MockBehavior.Strict); 73 | decorated.Setup(x => x.Handle(command)); 74 | 75 | var decorator = new CommandEventProcessingDecorator(eventProcessor.Object, () => decorated.Object); 76 | decorator.Handle(command); 77 | 78 | decorated.Verify(x => x.Handle(command), Times.Once); 79 | eventProcessor.Verify(x => x.Raise(It.IsAny()), Times.Never); 80 | } 81 | 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/ScaffoldR.EntityFramework.Tests/Helpers/EntityFrameworkMockHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Entity; 4 | using System.Linq; 5 | using System.Linq.Expressions; 6 | using Moq; 7 | using ScaffoldR.Core.Entities; 8 | 9 | namespace ScaffoldR.EntityFramework.Tests.Helpers 10 | { 11 | public static class EntityFrameworkMockHelper 12 | { 13 | /// 14 | /// Returns a mock of a DbContext 15 | /// 16 | /// 17 | /// 18 | public static MockedDbContext GetMockContext() where T : DbContext 19 | { 20 | var instance = new MockedDbContext(); 21 | instance.MockTables(); 22 | return instance; 23 | } 24 | 25 | /// 26 | /// Use this method to mock a table, which is a DbSet{T} oject, in Entity Framework. 27 | /// Leave the second list null if no adds or deletes are used. 28 | /// 29 | /// The table data type 30 | /// A List{T} that is being use to replace a database table. 31 | /// 32 | public static DbSet MockDbSet(List table) where T : EntityWithId 33 | { 34 | var dbSet = new Mock>(); 35 | dbSet.As>().Setup(q => q.Provider).Returns(() => table.AsQueryable().Provider); 36 | dbSet.As>().Setup(q => q.Expression).Returns(() => table.AsQueryable().Expression); 37 | dbSet.As>().Setup(q => q.ElementType).Returns(() => table.AsQueryable().ElementType); 38 | dbSet.As>().Setup(q => q.GetEnumerator()).Returns(() => table.AsQueryable().GetEnumerator()); 39 | dbSet.Setup(set => set.Add(It.IsAny())).Callback(table.Add); 40 | dbSet.Setup(set => set.AddRange(It.IsAny>())).Callback>(table.AddRange); 41 | dbSet.Setup(set => set.Remove(It.IsAny())).Callback(t => table.Remove(t)); 42 | dbSet.Setup(set => set.RemoveRange(It.IsAny>())).Callback>(ts => 43 | { 44 | foreach (var t in ts) { table.Remove(t); } 45 | }); 46 | dbSet.Setup(x => x.Find(It.IsAny())).Returns(ids => table.Find(d => d.Id == (int)ids[0])); 47 | return dbSet.Object; 48 | } 49 | 50 | /// 51 | /// Mocks all the DbSet{T} properties that represent tables in a DbContext. 52 | /// 53 | /// 54 | /// 55 | public static void MockTables(this MockedDbContext mockedContext) where T : DbContext 56 | { 57 | var contextType = typeof(T); 58 | var dbSetProperties = contextType.GetProperties().Where(prop => prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>)); 59 | 60 | foreach (var prop in dbSetProperties) 61 | { 62 | var dbSetGenericType = prop.PropertyType.GetGenericArguments()[0]; 63 | var listType = typeof(List<>).MakeGenericType(dbSetGenericType); 64 | var listForFakeTable = Activator.CreateInstance(listType); 65 | var parameter = Expression.Parameter(contextType); 66 | var body = Expression.PropertyOrField(parameter, prop.Name); 67 | var lambdaExpression = Expression.Lambda>(body, parameter); 68 | var method = typeof(EntityFrameworkMockHelper).GetMethod("MockDbSet").MakeGenericMethod(dbSetGenericType); 69 | mockedContext.Setup(lambdaExpression).Returns(method.Invoke(null, new[] { listForFakeTable })); 70 | mockedContext.Tables.Add(prop.Name, listForFakeTable); 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studo 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | *_i.c 42 | *_p.c 43 | *_i.h 44 | *.ilk 45 | *.meta 46 | *.obj 47 | *.pch 48 | *.pdb 49 | *.pgc 50 | *.pgd 51 | *.rsp 52 | *.sbr 53 | *.tlb 54 | *.tli 55 | *.tlh 56 | *.tmp 57 | *.tmp_proj 58 | *.log 59 | *.vspscc 60 | *.vssscc 61 | .builds 62 | *.pidb 63 | *.svclog 64 | *.scc 65 | 66 | # Chutzpah Test files 67 | _Chutzpah* 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | *.cachefile 76 | 77 | # Visual Studio profiler 78 | *.psess 79 | *.vsp 80 | *.vspx 81 | 82 | # TFS 2012 Local Workspace 83 | $tf/ 84 | 85 | # Guidance Automation Toolkit 86 | *.gpState 87 | 88 | # ReSharper is a .NET coding add-in 89 | _ReSharper*/ 90 | *.[Rr]e[Ss]harper 91 | *.DotSettings.user 92 | 93 | # JustCode is a .NET coding addin-in 94 | .JustCode 95 | 96 | # TeamCity is a build add-in 97 | _TeamCity* 98 | 99 | # DotCover is a Code Coverage Tool 100 | *.dotCover 101 | 102 | # NCrunch 103 | _NCrunch_* 104 | .*crunch*.local.xml 105 | 106 | # MightyMoose 107 | *.mm.* 108 | AutoTest.Net/ 109 | 110 | # Web workbench (sass) 111 | .sass-cache/ 112 | 113 | # Installshield output folder 114 | [Ee]xpress/ 115 | 116 | # DocProject is a documentation generator add-in 117 | DocProject/buildhelp/ 118 | DocProject/Help/*.HxT 119 | DocProject/Help/*.HxC 120 | DocProject/Help/*.hhc 121 | DocProject/Help/*.hhk 122 | DocProject/Help/*.hhp 123 | DocProject/Help/Html2 124 | DocProject/Help/html 125 | 126 | # Click-Once directory 127 | publish/ 128 | 129 | # Publish Web Output 130 | *.[Pp]ublish.xml 131 | *.azurePubxml 132 | # TODO: Comment the next line if you want to checkin your web deploy settings 133 | # but database connection strings (with potential passwords) will be unencrypted 134 | *.pubxml 135 | *.publishproj 136 | 137 | # NuGet Packages 138 | *.nupkg 139 | # The packages folder can be ignored because of Package Restore 140 | **/packages/* 141 | # except build/, which is used as an MSBuild target. 142 | !**/packages/build/ 143 | # except composition root packages 144 | !**/src/ScaffoldR/Infrastructure/CompositionRoot/Packages/* 145 | # Uncomment if necessary however generally it will be regenerated when needed 146 | #!**/packages/repositories.config 147 | 148 | # Windows Azure Build Output 149 | csx/ 150 | *.build.csdef 151 | 152 | # Windows Store app package directory 153 | AppPackages/ 154 | 155 | # Others 156 | *.[Cc]ache 157 | ClientBin/ 158 | [Ss]tyle[Cc]op.* 159 | ~$* 160 | *~ 161 | *.dbmdl 162 | *.dbproj.schemaview 163 | *.pfx 164 | *.publishsettings 165 | node_modules/ 166 | bower_components/ 167 | 168 | # RIA/Silverlight projects 169 | Generated_Code/ 170 | 171 | # Backup & report files from converting an old project file 172 | # to a newer Visual Studio version. Backup files are not needed, 173 | # because we have git ;-) 174 | _UpgradeReport_Files/ 175 | Backup*/ 176 | UpgradeLog*.XML 177 | UpgradeLog*.htm 178 | 179 | # SQL Server files 180 | *.mdf 181 | *.ldf 182 | 183 | # Business Intelligence projects 184 | *.rdl.data 185 | *.bim.layout 186 | *.bim_*.settings 187 | 188 | # Microsoft Fakes 189 | FakesAssemblies/ 190 | 191 | # Node.js Tools for Visual Studio 192 | .ntvs_analysis.dat 193 | 194 | # Visual Studio 6 build log 195 | *.plg 196 | 197 | # Visual Studio 6 workspace options file 198 | *.opt 199 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/Infrastructure/Queries/QueryEventProcessingDecoratorTests.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using Moq; 3 | using ScaffoldR.Core.Events; 4 | using ScaffoldR.Core.Queries; 5 | using ScaffoldR.Infrastructure.Queries; 6 | using ScaffoldR.Tests.Infrastructure.Queries.Fakes; 7 | using Xunit; 8 | 9 | namespace ScaffoldR.Tests.Infrastructure.Queries 10 | { 11 | public class QueryEventProcessingDecoratorTests 12 | { 13 | [Fact] 14 | public void RaiseEvent_AfterQueryIsExecuted_WhenQueryHasRaiseEventAttributeAndEnabledTrue() 15 | { 16 | var query = new FakeQueryWithoutValidator(); 17 | Assert.IsAssignableFrom>(query); 18 | 19 | var eventProcessor = new Mock(MockBehavior.Strict); 20 | eventProcessor.Setup(x => x.Raise(query)); 21 | 22 | var attribute = new RaiseEventAttribute 23 | { 24 | Enabled = true 25 | }; 26 | 27 | var decorated = new Mock>(MockBehavior.Strict); 28 | var provider = TypeDescriptor.AddAttributes(decorated.Object.GetType(), attribute); 29 | decorated.Setup(x => x.Handle(query)).Returns("faked"); 30 | 31 | var decorator = new QueryEventProcessingDecorator(eventProcessor.Object, () => decorated.Object); 32 | decorator.Handle(query); 33 | 34 | decorated.Verify(x => x.Handle(query), Times.Once); 35 | eventProcessor.Verify(x => x.Raise(query), Times.Once); 36 | 37 | // Clean up runtime added attributes 38 | TypeDescriptor.RemoveProvider(provider, decorated.Object.GetType()); 39 | } 40 | 41 | [Fact] 42 | public void DoNotRaiseEvent_AfterQueryIsExecuted_WhenQueryHasRaiseEventAttributeAndEnabledFalse() 43 | { 44 | var query = new FakeQueryWithoutValidator(); 45 | Assert.IsAssignableFrom>(query); 46 | 47 | var eventProcessor = new Mock(MockBehavior.Strict); 48 | eventProcessor.Setup(x => x.Raise(query)); 49 | 50 | var attribute = new RaiseEventAttribute 51 | { 52 | Enabled = false 53 | }; 54 | 55 | var decorated = new Mock>(MockBehavior.Strict); 56 | var provider = TypeDescriptor.AddAttributes(decorated.Object.GetType(), attribute); 57 | decorated.Setup(x => x.Handle(query)).Returns("faked"); 58 | 59 | var decorator = new QueryEventProcessingDecorator(eventProcessor.Object, () => decorated.Object); 60 | decorator.Handle(query); 61 | 62 | decorated.Verify(x => x.Handle(query), Times.Once); 63 | eventProcessor.Verify(x => x.Raise(It.IsAny()), Times.Never); 64 | 65 | // Clean up runtime added attributes 66 | TypeDescriptor.RemoveProvider(provider, decorated.Object.GetType()); 67 | } 68 | 69 | [Fact] 70 | public void DoNotRaiseEvent_AfterQueryIsExecuted_WhenQueryDoesNotHaveRaiseEventAttribute() 71 | { 72 | var query = new FakeQueryWithoutValidator(); 73 | Assert.IsAssignableFrom>(query); 74 | 75 | var eventProcessor = new Mock(MockBehavior.Strict); 76 | eventProcessor.Setup(x => x.Raise(query)); 77 | 78 | var decorated = new Mock>(MockBehavior.Strict); 79 | decorated.Setup(x => x.Handle(query)).Returns("faked"); 80 | 81 | var decorator = new QueryEventProcessingDecorator(eventProcessor.Object, () => decorated.Object); 82 | decorator.Handle(query); 83 | 84 | decorated.Verify(x => x.Handle(query), Times.Once); 85 | eventProcessor.Verify(x => x.Raise(It.IsAny()), Times.Never); 86 | } 87 | 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/ScaffoldR.EntityFramework/ScaffoldR.EntityFramework.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {62E4E31B-D3AC-4345-9251-A16FAF8758F3} 8 | Library 9 | Properties 10 | ScaffoldR.EntityFramework 11 | ScaffoldR.EntityFramework 12 | v4.6.1 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | bin\Release\ScaffoldR.EntityFramework.XML 33 | 34 | 35 | 36 | ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll 37 | True 38 | 39 | 40 | ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll 41 | True 42 | 43 | 44 | ..\packages\SimpleInjector.3.1.2\lib\net45\SimpleInjector.dll 45 | True 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | {60AC8712-CFC6-4065-93A4-7134C74F88F6} 72 | ScaffoldR 73 | 74 | 75 | 76 | 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ScaffoldR [![AppVeyor](https://img.shields.io/appveyor/ci/janhartmann/scaffoldr/master.svg)](https://ci.appveyor.com/project/janhartmann/scaffoldr/branch/master) [![NuGet Version](http://img.shields.io/nuget/v/ScaffoldR.svg?style=flat)](https://www.nuget.org/packages/ScaffoldR/) 2 | 3 | ScaffoldR is a [SOLID](https://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29) platform for structuring or scaffolding .NET applications. ScaffoldR supports commands, queries, events, repositories and validation with intelligent dispatching via C# generic variance. 4 | 5 | It is recommended to have some basic knowledge of CQRS (Command Query Responsibility Segregation) and Dependency Injection. A good starting point is these articles: 6 | 7 | * [Meanwhile... on the command side of my architecture](https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=91) 8 | * [Meanwhile... on the query side of my architecture](https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=92) 9 | 10 | ### Dependencies 11 | **[Simple Injector](https://simpleinjector.org)**
12 | Simple Injector is an easy, flexible and fast dependency injection library which ScaffoldR integrates heavily into. 13 | 14 | **[Fluent Validation](https://fluentvalidation.codeplex.com)**
15 | Fluent Validation (FV) is a small validation library for .NET that uses a fluent interface and lambda expressions for building validation rules for your business objects. ScaffoldR uses FV in its validation processor. 16 | 17 | ### Installing ScaffoldR 18 | 19 | You should install [ScaffoldR with NuGet](https://www.nuget.org/packages/ScaffoldR): 20 | 21 | Install-Package ScaffoldR 22 | 23 | This command from Package Manager Console will download and install ScaffoldR and all required dependencies. 24 | 25 | ### Getting Started 26 | 27 | You should register ScaffoldR in the Simple Injector container during startup. In the registration below, we configure the default scope of the container and register the ScaffoldR into it. 28 | 29 | We also make Fluent Validation use Simple Injector for finding the validation classes, using the `SimpleInjectorValidatorFactory`: 30 | 31 | ```cs 32 | var container = new Container(); 33 | container.Options.DefaultScopedLifestyle = Lifestyle.CreateHybrid(() => 34 | container.GetCurrentLifetimeScope() != null, 35 | new LifetimeScopeLifestyle(), 36 | new WebRequestLifestyle() // Example is for .NET MVC application 37 | ); 38 | 39 | container.RegisterScaffoldR(settings => 40 | { 41 | settings.EventAssemblies = new[] { Assembly.GetExecutingAssembly() }; 42 | settings.FluentValidationAssemblies = new[] { Assembly.GetExecutingAssembly() }; 43 | settings.TransactionAssemblies = new[] { Assembly.GetExecutingAssembly() }; 44 | settings.ViewModelAssemblies = new[] { Assembly.GetExecutingAssembly() }; 45 | }); 46 | 47 | FluentValidationModelValidatorProvider.Configure(provider => { 48 | provider.ValidatorFactory = new SimpleInjectorValidatorFactory(container); 49 | provider.AddImplicitRequiredValidator = false; 50 | }); 51 | ``` 52 | 53 | ### Examples 54 | 55 | In this example, we create a command with the nessecery properties to create a cup of coffee. A validator is attached to the command, which validates the command can be executed before the actual execution. 56 | 57 | Finally, we have the handler which does the business and creates the entity (Coffee) in the database. 58 | 59 | ```cs 60 | /// 61 | /// Create a cup of coffee. 62 | /// 63 | public class MakeCoffee : ICommand 64 | { 65 | public int Strength { get; set; } 66 | public bool WithMilk { get; set; } 67 | } 68 | 69 | /// 70 | /// Validates the coffee command, before executing it. 71 | /// 72 | public class ValidateMakeCoffee : AbstractValidator 73 | { 74 | public ValidateMakeCoffee() 75 | { 76 | RuleFor(coffee => coffee.Strength) 77 | .NotEmpty() 78 | .GreaterThan(0) 79 | .LessThanOrEqualTo(10); 80 | } 81 | } 82 | 83 | /// 84 | /// Create the cup of coffee and save it in the database. 85 | /// 86 | public class HandleMakeCoffee : IHandleCommand 87 | { 88 | private readonly IEntityWriter _entityWriter; 89 | 90 | public HandleMakeCoffee(IEntityWriter entityWriter) 91 | { 92 | _entityWriter = entityWriter; 93 | } 94 | 95 | public void Handle(MakeCoffee command) 96 | { 97 | var coffee = new Coffee 98 | { 99 | Strength = command.Strength, 100 | Milk = command.WithMilk 101 | }; 102 | 103 | _entityWriter.Save(coffee); 104 | } 105 | } 106 | ``` 107 | 108 | Now that we have our command, its validator and its handler - we can now execute the command from our controllers or other classes by simple depending on the `IHandleCommand` or using the mediators for executing: 109 | 110 | ```cs 111 | public class CoffeeController : Controller 112 | { 113 | private readonly IProcessCommands _commands; 114 | 115 | public CoffeeController(IProcessCommands commands) 116 | { 117 | _commands = commands; 118 | } 119 | 120 | [HttpPost] 121 | public ActionResult Create() 122 | { 123 | var cup = new MakeCoffee 124 | { 125 | Strength = 10, 126 | WithMilk = false 127 | }; 128 | 129 | // Use the mediator to execute the command 130 | _commands.Execute(cup); 131 | 132 | return View(); 133 | } 134 | } 135 | ``` 136 | 137 | -------------------------------------------------------------------------------- /src/ScaffoldR/ScaffoldR.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {60AC8712-CFC6-4065-93A4-7134C74F88F6} 8 | Library 9 | Properties 10 | ScaffoldR 11 | ScaffoldR 12 | v4.6.1 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | bin\Release\ScaffoldR.XML 33 | 34 | 35 | 36 | ..\packages\FluentValidation.6.0.2.0\lib\Net45\FluentValidation.dll 37 | True 38 | 39 | 40 | ..\packages\SimpleInjector.3.1.2\lib\net45\SimpleInjector.dll 41 | True 42 | 43 | 44 | ..\packages\SimpleInjector.Extensions.LifetimeScoping.3.1.2\lib\net40-client\SimpleInjector.Extensions.LifetimeScoping.dll 45 | True 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 128 | -------------------------------------------------------------------------------- /src/ScaffoldR.EntityFramework.Tests/ScaffoldR.EntityFramework.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {11A3698E-0217-44F0-9236-6ABAA2EDCC67} 8 | Library 9 | Properties 10 | ScaffoldR.EntityFramework.Tests 11 | ScaffoldR.EntityFramework.Tests 12 | v4.6.1 13 | 512 14 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15 | 10.0 16 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 17 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 18 | False 19 | UnitTest 20 | 21 | 22 | 23 | 24 | 25 | true 26 | full 27 | false 28 | bin\Debug\ 29 | DEBUG;TRACE 30 | prompt 31 | 4 32 | 33 | 34 | pdbonly 35 | true 36 | bin\Release\ 37 | TRACE 38 | prompt 39 | 4 40 | 41 | 42 | 43 | ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll 44 | True 45 | 46 | 47 | ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll 48 | True 49 | 50 | 51 | ..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll 52 | True 53 | 54 | 55 | ..\packages\SimpleInjector.3.1.2\lib\net45\SimpleInjector.dll 56 | True 57 | 58 | 59 | ..\packages\SimpleInjector.Extensions.LifetimeScoping.3.1.2\lib\net40-client\SimpleInjector.Extensions.LifetimeScoping.dll 60 | True 61 | 62 | 63 | 64 | 65 | ..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll 66 | True 67 | 68 | 69 | ..\packages\xunit.assert.2.1.0\lib\dotnet\xunit.assert.dll 70 | True 71 | 72 | 73 | ..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll 74 | True 75 | 76 | 77 | ..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll 78 | True 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | Always 104 | 105 | 106 | 107 | 108 | 109 | {62E4E31B-D3AC-4345-9251-A16FAF8758F3} 110 | ScaffoldR.EntityFramework 111 | 112 | 113 | {60AC8712-CFC6-4065-93A4-7134C74F88F6} 114 | ScaffoldR 115 | 116 | 117 | 118 | 119 | 120 | 121 | False 122 | 123 | 124 | False 125 | 126 | 127 | False 128 | 129 | 130 | False 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 140 | 141 | 142 | 143 | 150 | -------------------------------------------------------------------------------- /src/ScaffoldR.Tests/ScaffoldR.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {E4F000B6-1E87-4605-8833-8BB4C8657296} 8 | Library 9 | Properties 10 | ScaffoldR.Tests 11 | ScaffoldR.Tests 12 | v4.6.1 13 | 512 14 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15 | 10.0 16 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 17 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 18 | False 19 | UnitTest 20 | 21 | 22 | 23 | 24 | 25 | true 26 | full 27 | false 28 | bin\Debug\ 29 | DEBUG;TRACE 30 | prompt 31 | 4 32 | 33 | 34 | pdbonly 35 | true 36 | bin\Release\ 37 | TRACE 38 | prompt 39 | 4 40 | 41 | 42 | 43 | ..\packages\FluentValidation.6.0.2.0\lib\Net45\FluentValidation.dll 44 | True 45 | 46 | 47 | ..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll 48 | True 49 | 50 | 51 | ..\packages\SimpleInjector.3.1.2\lib\net45\SimpleInjector.dll 52 | True 53 | 54 | 55 | ..\packages\SimpleInjector.Extensions.LifetimeScoping.3.1.2\lib\net40-client\SimpleInjector.Extensions.LifetimeScoping.dll 56 | True 57 | 58 | 59 | 60 | ..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll 61 | True 62 | 63 | 64 | ..\packages\xunit.assert.2.1.0\lib\dotnet\xunit.assert.dll 65 | True 66 | 67 | 68 | ..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll 69 | True 70 | 71 | 72 | ..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll 73 | True 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | {60AC8712-CFC6-4065-93A4-7134C74F88F6} 120 | ScaffoldR 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | False 131 | 132 | 133 | False 134 | 135 | 136 | False 137 | 138 | 139 | False 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 149 | 150 | 151 | 152 | 159 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2015 Hartmann Solutions 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | --------------------------------------------------------------------------------