Coder Social home page Coder Social logo

ardalis / cleanarchitecture Goto Github PK

View Code? Open in Web Editor NEW
14.8K 412.0 2.6K 2.95 MB

Clean Architecture Solution Template: A starting point for Clean Architecture with ASP.NET Core

License: MIT License

C# 100.00%
clean-architecture architecture ddd dotnet csharp domain-driven-design hacktoberfest

cleanarchitecture's Introduction

.NET Core publish Ardalis.CleanArchitecture Template to nuget Ardalis.CleanArchitecture.Template on NuGet

Follow @ardalis   Follow @nimblepros

Clean Architecture

A starting point for Clean Architecture with ASP.NET Core. Clean Architecture is just the latest in a series of names for the same loosely-coupled, dependency-inverted architecture. You will also find it named hexagonal, ports-and-adapters, or onion architecture.

This architecture is used in the DDD Fundamentals course by Steve Smith and Julie Lerman.

🏫 Contact Steve's company, NimblePros, for Clean Architecture or DDD training and/or implementation assistance for your team.

Troubleshooting Chrome Errors

By default the site uses HTTPS and expects you to have a self-signed developer certificate for localhost use. If you get an error with Chrome see this answer for mitigation instructions.

Table Of Contents

Give a Star! ⭐

If you like or are using this project to learn or start your solution, please give it a star. Thanks!

Or if you're feeling really generous, we now support GitHub sponsorships - see the button above.

Versions

The main branch is now using .NET 8. If you need a previous version use one of these tagged commits:

Learn More

Getting Started

To use this template, there are a few options:

  • Install using dotnet new (recommended)
  • Download this Repository (and modify as needed)

Using the dotnet CLI template

First, install the template from NuGet (https://www.nuget.org/packages/Ardalis.CleanArchitecture.Template/):

dotnet new install Ardalis.CleanArchitecture.Template

You should see the template in the list of templates from dotnet new list after this installs successfully. Look for "ASP.NET Clean Architecture Solution" with Short Name of "clean-arch".

Navigate to the parent directory in which you'd like the solution's folder to be created.

Run this command to create the solution structure in a subfolder name Your.ProjectName:

dotnet new clean-arch -o Your.ProjectName

The Your.ProjectName directory and solution file will be created, and inside that will be all of your new solution contents, properly namespaced and ready to run/test!

Example: powershell screenshot showing steps

Thanks @dahlsailrunner for your help getting this working!

Known Issues:

  • Don't include hyphens in the name. See #201.
  • Don't use 'Ardalis' as your namespace (conflicts with dependencies).

What about Controllers and Razor Pages?

As of version 9, this solution template only includes support for API Endpoints using the FastEndpoints library. If you want to use my ApiEndpoints library, Razor Pages, and/or Controllers you can use the last template that included them, version 7.1. Alternately, they're easily added to this template after installation.

Add Ardalis.ApiEndpoints

To use Ardalis.ApiEndpoints instead of (or in addition to) FastEndpoints, just add the reference and use the base classes from the documentation.

dotnet add package Ardalis.ApiEndpoints

Add Controllers

You'll need to add support for controllers to the Program.cs file. You need:

builder.Services.AddControllers(); // ControllersWithView if you need Views

// and

app.MapControllers();

Once these are in place, you should be able to create a Controllers folder and (optionally) a Views folder and everything should work as expected. Personally I find Razor Pages to be much better than Controllers and Views so if you haven't fully investigated Razor Pages you might want to do so right about now before you choose Views.

Add Razor Pages

You'll need to add support for Razor Pages to the Program.cs file. You need:

builder.Services.AddRazorPages();

// and

app.MapRazorPages();

Then you just add a Pages folder in the root of the project and go from there.

Using the GitHub Repository

To get started based on this repository, you need to get a copy locally. You have three options: fork, clone, or download. Most of the time, you probably just want to download.

You should download the repository, unblock the zip file, and extract it to a new folder if you just want to play with the project or you wish to use it as the starting point for an application.

You should fork this repository only if you plan on submitting a pull request. Or if you'd like to keep a copy of a snapshot of the repository in your own GitHub account.

You should clone this repository if you're one of the contributors and you have commit access to it. Otherwise you probably want one of the other options.

Running Migrations

You shouldn't need to do this to use this template, but if you want migrations set up properly in the Infrastructure project, you need to specify that project name when you run the migrations command.

In Visual Studio, open the Package Manager Console, and run Add-Migration InitialMigrationName -StartupProject Your.ProjectName.Web -Context AppDbContext -Project Your.ProjectName.Infrastructure.

In a terminal with the CLI, the command is similar. Run this from the Web project directory:

dotnet ef migrations add MIGRATIONNAME -c AppDbContext -p ../Your.ProjectName.Infrastructure/Your.ProjectName.Infrastructure.csproj -s Your.ProjectName.Web.csproj -o Data/Migrations

To use SqlServer, change options.UseSqlite(connectionString)); to options.UseSqlServer(connectionString)); in the Your.ProjectName.Infrastructure.StartupSetup file. Also remember to replace the SqliteConnection with DefaultConnection in the Your.ProjectName.Web.Program file, which points to your Database Server.

To update the database use this command from the Web project folder (replace Clean.Architecture with your project's name):

dotnet ef database update -c AppDbContext -p ../Clean.Architecture.Infrastructure/Clean.Architecture.Infrastructure.csproj -s Clean.Architecture.Web.csproj

Goals

The goal of this repository is to provide a basic solution structure that can be used to build Domain-Driven Design (DDD)-based or simply well-factored, SOLID applications using .NET Core. Learn more about these topics here:

If you're used to building applications as single-project or as a set of projects that follow the traditional UI -> Business Layer -> Data Access Layer "N-Tier" architecture, I recommend you check out these two courses (ideally before DDD Fundamentals):

Steve Smith also maintains Microsoft's reference application, eShopOnWeb, and its associated free eBook. Check them out here:

Note that the goal of this project and repository is not to provide a sample or reference application. It's meant to just be a template, but with enough pieces in place to show you where things belong as you set up your actual solution. Instead of useless "Class1.cs" there are a few real classes in place. Delete them as soon as you understand why they're there and where you should put your own, similar files.

History and Shameless Plug Section

I've used this starter kit to teach the basics of ASP.NET Core using Domain-Driven Design concepts and patterns for some time now (starting when ASP.NET Core was still in pre-release). Typically I teach a one- or two-day hands-on workshop ahead of events like DevIntersection, or private on-site workshops for companies looking to bring their teams up to speed with the latest development technologies and techniques. Feel free to contact me if you'd like information about upcoming workshops.

Design Decisions and Dependencies

The goal of this sample is to provide a fairly bare-bones starter kit for new projects. It does not include every possible framework, tool, or feature that a particular enterprise application might benefit from. Its choices of technology for things like data access are rooted in what is the most common, accessible technology for most business software developers using Microsoft's technology stack. It doesn't (currently) include extensive support for things like logging, monitoring, or analytics, though these can all be added easily. Below is a list of the technology dependencies it includes, and why they were chosen. Most of these can easily be swapped out for your technology of choice, since the nature of this architecture is to support modularity and encapsulation.

Where To Validate

Validation of user input is a requirement of all software applications. The question is, where does it make sense to implement it in a concise and elegant manner? This solution template includes 4 separate projects, each of which might be responsible for performing validation as well as enforcing business invariants (which, given validation should already have occurred, are usually modeled as exceptions).

The domain model itself should generally rely on object-oriented design to ensure it is always in a consistent state. It leverages encapsulation and limits public state mutation access to achieve this, and it assumes that any arguments passed to it have already been validated, so null or other improper values yield exceptions, not validation results, in most cases.

The use cases / application project includes the set of all commands and queries the system supports. It's frequently responsible for validating its own command and query objects.

The Web project includes all API endpoints, which include their own request and response types, following the REPR pattern. The FastEndpoints library includes built-in support for validation using FluentValidation on the request types. This is a natural place to perform input validation as well.

Having validation occur both within the API endpoints and then again at the use case level is redundant, so in this template the choice has been made to validate at the edge of the application, in the API endpoints. This means some future consumer of the Use Cases project will also need to be responsible for its own validation as well, but in the vast majority of cases there won't be any other consumers of the use cases outside of the API endpoints.

The Core Project

The Core project is the center of the Clean Architecture design, and all other project dependencies should point toward it. As such, it has very few external dependencies. The Core project should include the Domain Model including things like:

  • Entities
  • Aggregates
  • Value Objects
  • Domain Events
  • Domain Event Handlers
  • Domain Services
  • Specifications
  • Interfaces
  • DTOs (sometimes)

The Use Cases Project

An optional project, I've included it because many folks were demanding it and it's easier to remove than to add later. This is also often referred to as the Application or Application Services layer. The Use Cases project is organized following CQRS into Commands and Queries. Commands mutate the domain model and thus should always use Repository abstractions for their data access. Queries are readonly, and thus do not need to use the repository pattern, but instead can use whatever query service or approach is most convenient. However, since the Use Cases project is set up to depend on Core and not directly on Infrastructure, there will still need to be abstractions defined for its data access. And it can use things like specifications, which can sometimes help encapsulate query logic as well as result type mapping. But it doesn't have to use repository/specification - it can just issue a SQL query or call a stored procedure if that's the most efficient way to get the data.

Although this is an option project to include (without it, your API endpoints would just work directly with the domain model or query services), it does provide a nice UI-ignorant place to add automated tests.

The Infrastructure Project

Most of your application's dependencies on external resources should be implemented in classes defined in the Infrastructure project. These classes should implement interfaces defined in Core. If you have a very large project with many dependencies, it may make sense to have multiple Infrastructure projects (e.g. Infrastructure.Data), but for most projects one Infrastructure project with folders works fine. The sample includes data access and domain event implementations, but you would also add things like email providers, file access, web api clients, etc. to this project so they're not adding coupling to your Core or UI projects.

The Infrastructure project depends on Microsoft.EntityFrameworkCore.SqlServer and Autofac. The former is used because it's built into the default ASP.NET Core templates and is the least common denominator of data access. If desired, it can easily be replaced with a lighter-weight ORM like Dapper. Autofac (formerly StructureMap) is used to allow wireup of dependencies to take place closest to where the implementations reside. In this case, an InfrastructureRegistry class can be used in the Infrastructure class to allow wireup of dependencies there, without the entry point of the application even having to have a reference to the project or its types. Learn more about this technique. The current implementation doesn't include this behavior - it's something I typically cover and have students add themselves in my workshops.

The Web Project

The entry point of the application is the ASP.NET Core web project. This is actually a console application, with a public static void Main method in Program.cs. It currently uses the default MVC organization (Controllers and Views folders) as well as most of the default ASP.NET Core project template code. This includes its configuration system, which uses the default appsettings.json file plus environment variables, and is configured in Startup.cs. The project delegates to the Infrastructure project to wire up its services using Autofac.

The SharedKernel Project

Many solutions will also reference a separate Shared Kernel project/package. I recommend creating a separate SharedKernel project and solution if you will require sharing code between multiple bounded contexts (see DDD Fundamentals). I further recommend this be published as a NuGet package (most likely privately within your organization) and referenced as a NuGet dependency by those projects that require it.

Previously a project for SharedKernel was included in this project. However, for the above reasons I've made it a separate package, Ardalis.SharedKernel, which you should replace with your own when you use this template.

If you want to see another example of a SharedKernel package, the one I use in my updated Pluralsight DDD course is on NuGet here.

The Test Projects

Test projects could be organized based on the kind of test (unit, functional, integration, performance, etc.) or by the project they are testing (Core, Infrastructure, Web), or both. For this simple starter kit, the test projects are organized based on the kind of test, with unit, functional and integration test projects existing in this solution. In terms of dependencies, there are three worth noting:

  • xunit I'm using xunit because that's what ASP.NET Core uses internally to test the product. It works great and as new versions of ASP.NET Core ship, I'm confident it will continue to work well with it.

  • NSubstitute I'm using NSubstitute as a mocking framework for white box behavior-based tests. If I have a method that, under certain circumstances, should perform an action that isn't evident from the object's observable state, mocks provide a way to test that. I could also use my own Fake implementation, but that requires a lot more typing and files. NSubstitute is great once you get the hang of it, and assuming you don't have to mock the world (which we don't in this case because of good, modular design).

  • Microsoft.AspNetCore.TestHost I'm using TestHost to test my web project using its full stack, not just unit testing action methods. Using TestHost, you make actual HttpClient requests without going over the wire (so no firewall or port configuration issues). Tests run in memory and are very fast, and requests exercise the full MVC stack, including routing, model binding, model validation, filters, etc.

Patterns Used

This solution template has code built in to support a few common patterns, especially Domain-Driven Design patterns. Here is a brief overview of how a few of them work.

Domain Events

Domain events are a great pattern for decoupling a trigger for an operation from its implementation. This is especially useful from within domain entities since the handlers of the events can have dependencies while the entities themselves typically do not. In the sample, you can see this in action with the ToDoItem.MarkComplete() method. The following sequence diagram demonstrates how the event and its handler are used when an item is marked complete through a web API endpoint.

Domain Event Sequence Diagram

Related Projects

cleanarchitecture's People

Contributors

ardalis avatar arielsrv avatar blackclaws avatar coop56 avatar dependabot-preview[bot] avatar dependabot[bot] avatar efleming18 avatar emopusta avatar johnlbevan avatar kylemcmaster avatar michal880 avatar mickymcq avatar misinformeddna avatar morgankenyon avatar nicumaxian avatar onslaughtq avatar peteraritchie avatar printscharming avatar robertbjarum avatar sadukie avatar sauravbhattacharya001 avatar shadynagy avatar snowfrogdev avatar szlatkow avatar taraskovalenko avatar tijmenuu avatar toxicgorilla avatar vanenshi avatar woppilif avatar xeinaemm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cleanarchitecture's Issues

Move SharedKernel to separate project

Convert SharedKernel to be its own project.
Set up that project to use nuget.
Change Core to reference the nuget package created by SharedKernel.

  • Should the nuget package nupkg file be in source?
  • Should the nuget package reference be via nuget.org?

Is it clean to have Autofac Referenced in Infrastructure?

I've been looking through the code, I like it and it is very similar to how some projects I've written are laid out. I have an issue though with referencing Autofac in the DomainEventDispatcher class and therefore in the Infrastructure project.

As the web project acts as the composition root shouldn't this be the only place that uses an IoC container? I work with some legacy projects that have Ninject referenced into internal Nuget packages and it's making it very hard to move away from Ninject cleanly or easily.

Question: Application Core Services code explosion

I liked the layout and ideas in CleanArchitecture (thank you for your work!) so I've implemented it in our new application.

One thing I'm noticing as development continues, is that our services in the ApplicationCore project that utilize the repositories and specifications, are causing large amount of code to be added as I add various specifications to support our requirements (Typically specifications with differing breakdowns of what navigable entities are included rather than one huge 'bring back the world' call). I understand the reasoning behind the separation and not using the context directly at that layer. However, it is getting to the point that it is making me re-think if it's the best setup for us. This led me to find this article and wonder if I should change to utilizing services in the infrastructure project that access the context directly.

I'd appreciate peoples thoughts on this - and/or if am I misunderstanding something.

Where to add ASP.NET Identity

Hi,In which project I will add ASP.NET Identity?. I want to use ASP.NET Identity and wondering where I will add ASP.NET Identity. What you will suggest

Hi ardalis: I have a question regarding the design

Is this really a clean architecture?

I looked into the core, infrastructure and web... code in all projects is arranged according to technology specific naming instead of user case/user flow oriented organization of code.
i.e. code is arrenged in entities, events, interface and services at higher level. Shouldn't it be arranged according to usecases

Autofac and PrePersistence domain events

Hi Ardalis,

How do you conect autofac to pre persistence domain events?

I use a class based on Uri Dahan's and with structure map I used to plug it on the Raise like:

namespace SIIC.Core.SharedKernel
{
    /// <summary>
    /// http://msdn.microsoft.com/en-gb/magazine/ee236415.aspx#id0400046
    /// </summary>
    public static class DomainEvents
    {
        [ThreadStatic] //so that each thread has its own callbacks
        private static List<Delegate> _actions;

        static DomainEvents()
        {
        }

        public static IContainer Container { get; set; }

        //Registers a callback for the given domain event
        public static void Register<T>(Action<T> callback) where T : BaseDomainEventPre
        {
            if (_actions == null)
            {
                _actions = new List<Delegate>();
            }
            _actions.Add(callback);
        }

        public static void ClearCallbacks() => _actions = null;

        //Raises the given domain event
        public static void Raise<T>(T args) where T : BaseDomainEventPre
        {
            if (_actions == null) return;

            if (Container != null)
            {
                foreach (var handler in Container.GetAllInstances<IHandlePre<T>>())
                {
                    handler.HandlePre(args);
                } 
            }

            foreach (var action in _actions.OfType<Action<T>>())
            {
                action(args);
            }
        }
    }
}

Do you have any idea how to replace Container.GetAllInstances<IHandlePre<T>> in autofac?

Infrastructure Registry

HI Steve,
I was trying to implement Infrastructure registry to remove reference of Infrastructure project from Web. But now code uses Autofac and your article on ardalis.com refers structuremap. I tried a lot but couldn't resolve it. can you please guide?

Diagram and Documentation

Hi @ardalis

This is very interesting template for DDD design and it could be great if you could provide a diagram and document of the components of your implementation.

Thanks and Regards
Duy

EntityFramework and other metadata

The template works with EntityFramework because BaseEntity has an Id property that EF picks up by convention as a primary key. If you were to rename that to MyCustomPrimarykey rather than Id things start to fail at runtime with The entity type 'ToDoItem' requires a primary key to be defined..

The answer to this is usually to add a [Key] attribute to the primary key field but how would you go about doing that while still maintaining the "clean architecture" paradigm? I noticed there is a ToDoItemDTO in the Web project because of the [Required] attribute, but if you did another ToDoItemEntity you now are duplicating your model several times over if you need to annotate all of your properties for various reasons.

Is being more lax on "Duplicate Code" the best path or is there something I'm overlooking?

Failing Test : Cannot find reference assembly 'dotnet-aspnet-codegenerator-design.dll'

Hi Ardalis,

Firstly a great project, lots of thought has gone into it I can see.

I simply fresh cloned, built, and run all tests. There is a single failed test.

I will find a workaround, I think removing Microsoft.VisualStudio.Web.CodeGeneration/ors but wanted to let you know.

Test Name:	CleanArchitecture.Tests.Integration.Web.HomeControllerIndexShould.ReturnViewWithCorrectMessage
Test FullName:	CleanArchitecture.Tests.Integration.Web.HomeControllerIndexShould.ReturnViewWithCorrectMessage
Test Source:	C:\repos\nbegvso\CleanArchitecture\tests\CleanArchitecture.Tests\Integration\Web\HomeControllerIndexShould.cs : line 10
Test Outcome:	Failed
Test Duration:	0:00:13.428

Result StackTrace:	
at Microsoft.Extensions.DependencyModel.Resolution.ReferenceAssemblyPathResolver.TryResolveAssemblyPaths(CompilationLibrary library, List'1 assemblies)
   at Microsoft.Extensions.DependencyModel.Resolution.CompositeCompilationAssemblyResolver.TryResolveAssemblyPaths(CompilationLibrary library, List'1 assemblies)
   at Microsoft.Extensions.DependencyModel.CompilationLibrary.ResolveReferencePaths(ICompilationAssemblyResolver resolver, List'1 assemblies)
   at Microsoft.Extensions.DependencyModel.CompilationLibrary.ResolveReferencePaths()
   at Microsoft.AspNetCore.Mvc.ApplicationParts.AssemblyPart.<>c.<GetReferencePaths>b__8_0(CompilationLibrary library)
   at System.Linq.Enumerable.SelectManySingleSelectorIterator'2.MoveNext()
   at Microsoft.AspNetCore.Mvc.Razor.Compilation.MetadataReferenceFeatureProvider.PopulateFeature(IEnumerable'1 parts, MetadataReferenceFeature feature)
   at Microsoft.AspNetCore.Mvc.ApplicationParts.ApplicationPartManager.PopulateFeature[TFeature](TFeature feature)
   at Microsoft.AspNetCore.Mvc.Razor.Internal.DefaultRazorReferenceManager.GetCompilationReferences()
   at System.Threading.LazyInitializer.EnsureInitializedCore[T](T& target, Boolean& initialized, Object& syncLock, Func'1 valueFactory)
   at Microsoft.AspNetCore.Mvc.Razor.Internal.DefaultRazorReferenceManager.get_CompilationReferences()
   at Microsoft.AspNetCore.Mvc.Razor.Internal.LazyMetadataReferenceFeature.get_References()
   at Microsoft.CodeAnalysis.Razor.CompilationTagHelperFeature.GetDescriptors()
   at Microsoft.AspNetCore.Razor.Language.DefaultRazorTagHelperBinderPhase.ExecuteCore(RazorCodeDocument codeDocument)
   at Microsoft.AspNetCore.Razor.Language.RazorEnginePhaseBase.Execute(RazorCodeDocument codeDocument)
   at Microsoft.AspNetCore.Razor.Language.DefaultRazorEngine.Process(RazorCodeDocument document)
   at Microsoft.AspNetCore.Razor.Language.RazorTemplateEngine.GenerateCode(RazorCodeDocument codeDocument)
   at Microsoft.AspNetCore.Mvc.Razor.Internal.RazorViewCompiler.CompileAndEmit(String relativePath)
   at Microsoft.AspNetCore.Mvc.Razor.Internal.RazorViewCompiler.CreateCacheEntry(String normalizedPath)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter'1.GetResult()
   at Microsoft.AspNetCore.Mvc.Razor.Internal.DefaultRazorPageFactoryProvider.CreateFactory(String relativePath)
   at Microsoft.AspNetCore.Mvc.Razor.RazorViewEngine.CreateCacheResult(HashSet'1 expirationTokens, String relativePath, Boolean isMainPage)
   at Microsoft.AspNetCore.Mvc.Razor.RazorViewEngine.OnCacheMiss(ViewLocationExpanderContext expanderContext, ViewLocationCacheKey cacheKey)
   at Microsoft.AspNetCore.Mvc.Razor.RazorViewEngine.LocatePageFromViewLocations(ActionContext actionContext, String pageName, Boolean isMainPage)
   at Microsoft.AspNetCore.Mvc.Razor.RazorViewEngine.FindView(ActionContext context, String viewName, Boolean isMainPage)
   at Microsoft.AspNetCore.Mvc.ViewEngines.CompositeViewEngine.FindView(ActionContext context, String viewName, Boolean isMainPage)
   at Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ViewResultExecutor.FindView(ActionContext actionContext, ViewResult viewResult)
   at Microsoft.AspNetCore.Mvc.ViewResult.<ExecuteResultAsync>d__26.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeResultAsync>d__19.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeNextResultFilterAsync>d__24.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResultExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeNextResourceFilter>d__22.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeFilterPipelineAsync>d__17.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeAsync>d__15.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Builder.RouterMiddleware.<Invoke>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIIndexMiddleware.<Invoke>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.<Invoke>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Hosting.Internal.RequestServicesContainerMiddleware.<Invoke>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.TestHost.ClientHandler.<>c__DisplayClass3_0.<<SendAsync>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.TestHost.ClientHandler.<SendAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable'1.ConfiguredTaskAwaiter.GetResult()
   at System.Net.Http.HttpClient.<FinishSendAsyncBuffered>d__58.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter'1.GetResult()
   at CleanArchitecture.Tests.Integration.Web.HomeControllerIndexShould.<ReturnViewWithCorrectMessage>d__0.MoveNext() in C:\repos\nbegvso\CleanArchitecture\tests\CleanArchitecture.Tests\Integration\Web\HomeControllerIndexShould.cs:line 11
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Result Message:	System.InvalidOperationException : Cannot find reference assembly 'dotnet-aspnet-codegenerator-design.dll' file for package dotnet-aspnet-codegenerator-design

Multi-tenancy over different dbs

Hi, as first thank you for sharing this valuable piece of code!
I'm evaluating to use cleanarchitecture as core building block of a project having multi-tenancy concept delivered by different physical DBs (each tenant in its db) and I wonder how I can adapt your solution to my case without incurring in problems related to ORM warm-up or db session/connection handling.
May be swap EF with Dapper would make life easier in this context?

Modify to support CQRS?

@ardalis would be very interesting how you take this architecture using DDD and layer it with CQRS.

I'd be very interested to see how you'd structure your project. Could even be in a separate branch of this repo.

Remove libman dependencies

Currently you can't build the project/solution if you don't have internet because of the libman dependencies (and because of nuget as well, but assuming you already have packages in your local nuget cache). This was an issue during a workshop today. There's no need in most cases for bootstrap/jquery to be in this template so these can be safely removed.

Registering Domain Events

Hello,
Thank you for this project!
How do you register a listener for domain events in an existing class (as oposed to creating a new class to implement IHandle)?

In a previous example I've seen you do it with the Register method in a Domain Events Class, (e.g.: DomainEvents.Register<NameOfEventEvent>(Handle);) , but in this project you seem to have left it out.

How do you achieve it here, and why did you leave it out?
Thank you,
Damião

Factories for testing

First off, very cool project and thanks for doing this.

I would recommend structuring the test project to demonstrate / include factories for domain objects as opposed to in-line instantiation. Instead you would do something like:

var todoItem = TodoItemsFactory.Get();
var todoItems = TodoItemsFactory.Get(5);

Internally, I would expect the factory to use something like Bogus or some other data 'faker'. I'd be happy to open a PR if you agree.

looks AddSingleton not works

Hi guys
when I use AddSingleton before BuildDependencyInjectionProvider in startup.cs
when I resolve it from HomeController, it will be a new object everytime , think may be caused by BuildDependencyInjectionProvider with autofac?
Thanks

Moving from bower

Due to fact that bower was deprecated(maintainers recommend using a different solution) for ASP.NET Core 2.1 we should switch to a different solution.

As Adam mentioned in this post I would recommend Yarn as an alternative.

Is Dispatching domain events after savechanges always a good idea?

I hope you don't mind i'm asking a question here. If so, apologies and simply disregard the question.
I saw that you dispatch the domain events after you execute savechanges.
That would be ok for me, for types of actions that should not rollback the current 'transaction'.
.e.g, after placing and order we send as domain event an email. When that email fails the original place order transaction should not be rollbacked.
On the other hand, there could be domain events which are logically part of the current transaction. So, if they fail, the whole transaction should fail as a whole.
So, I would foresee an event dispatcher before save changes and one after.
What is your view on this?
Thanks.

Use cases X traditional business layer

Hi @ardalis,

First of all, thanks for sharing this template with us. This might sound very basic but I was wondering where should I add the business logic? Let's say we have a payroll system. It needs to calculate the salary of the employees based on working hours, rates, taxes and etc. Where should I put this logic? I believe you'll answer the Use Cases layer. Is it correct to assume that the Use Cases layer is the same as the Business layer of a tradicional multilayered architecture?

Here's my current structure:

Application

  • core layer
    • core - entities, dto's and interfaces - including services (e.g IEmployeeService)
    • application - service implementations (e.g EmployeeService - business logic -> calculate salary)
  • infrastructure
    • infrastructure (third parties, identity, etc)
    • persistence (DbContext, repositories, migrations, etc)

Thanks,

Yuri

Question: Existing Database / Refactor

Say I have an existing database that doesn't allow me to use the BaseEntity with the id property because primary keys are not uniform and are different per table. How can I refactor the clean architecture to have the primary keys be present in each entity instead of within an base class? I do not want to have to change each table and many rows of data and keys to support this structure and nor do I want to start a new database to conform to this. Is it possible? I mean I could just start with a new database if that is the last possible resort to start using this architecture as a baseline. Thanks in advance.

Will

Core Assembly and Data Annotations

Any suggestions for adding data annotations to entities in the .Core project? I added System.ComponentModel.Annotations Nuget package, but I'm not sure this feels right since .Core is .a NET Standard library.

Suggestion for replacement of "StructureMap".

As the development of "StructureMap" has been discontinued, is there any good replacement for it?

Their website suggest using Lamar, but their current build seems to be failing, so I'm not very confident in adding it in my project.

Thanks!

Use Cases

I'm reviewing multiple Clean Architecture solutions and virtually all have a setup with Use Cases in the form of Interactors with a Request and a Response message.
I don't see any of that in this solution; why is that?

Upgrade to ASP.NET Core 2.1

Upgrade the Web project to ASP.NET Core 2.1.
Add a Pages folder and at least one Razor Page to show how they work.

Entity Framework gets slow in long Iteration Loops

Hello,

With the current setup, if we do long insert iteration loops through the use of a repository, Entity Framework will get slower and slower creating real performance issues.

I believe this is due to the dbContext maintaining all past insertions in cache. Also, we cannot use something like:

using (EfRepository<T> repo = new EfRepository<T>) 
{
    .....
}

because the dbContext will be disposed and be unavailable to the repository on the next iteration.

Is there a way to configure StructureMap to allow us to use the above using clause (in the cases we deem it needed), with StructureMap providing a new instance of the dbContext? (Preferably maintaining the current behavior when we don't wish to use the using clause)

Thank you!
Damião Dias

How to use IRepository and load foreign key objects?

Hi Steve,

How can I use the List method

public List<T> List<T>() where T : BaseEntity
        {
            return _dbContext.Set<T>().ToList();
        }

and still use Include to load referencial data in case T is a child and wants to refer to a parent object?

After doing ToList() in List() the client class using IRepository can no longer do that.
Or am I missing something?

Kind regards,

Michel

[Question] Entities used in the Web project

I have a quick question:

Is it OK if we are using Entities from the core layer of the clean architecture into the Web project (the presentation layer)?
I saw HERE that we have a dependency to the Entities from the core layer. Doesn't this brakes the principle of the Clean Architecture that we do not have to depend on the core dependencies?

Thanks in advance!

P.S. Any explanation with more details will be appreciated.

Map complex DTO to Entity

Hi Steve,
I read an article where you recommended to not use direct references to entities in your DTO. So for example if a ProductDTO references to a List of a DetailsDTO, how would you map the DTO back to an entity, when you want to add a new Product to your DB.

I heard that some people are using AutoMapper in order to map DTO's back to an entity. But this article here let me rethink this approach:
https://rogerjohansson.blog/2013/12/01/why-mapping-dtos-to-entities-using-automapper-and-entityframework-is-horrible/
The author was pointing out, that it will lead to problems when there is an existing entity in the DB or you wish to update entities (when using Entity Framework). So now the big question is what would be the cleanest approach to map an DTO containing references back to an Entity?

[Question] Why not use context.Update(entity)?

I was wondering why not use context.Update(entity) in EfRepository?
When I tried to update and save an entity that contained nested entities, the provided EfRepository.Update didn't work.

Also would it be bad to make the EfRepository methods virtual?

Thanks for this clean-code starting point.

ORM related concepts influencing design of Core

@ardalis ,

As per DDD, the core has to be agnostic to databases, presentation etc. But in practice i see that most of the design of core is still influenced by EF. The BaseEntity class is best example of it.

Looking from the perspective of a Desktop application developer, to me the dominance of POCO classes in an application seems to be influenced by RDBMS and ORMs.

For e.g. below is how a ToDoApplication would look like if were not to consider RDBMS.

    public class Person
    {
        public string Name { get; set; }

        public List<ToDoItem> ToDos { get; set; }

        public List<ToDoItem> CompletedItems { get; }

        public void MarkItemAsCompleted(ToDoItem item) { }
    }

    public class ToDoItem
    {
        public string Title { get; set; }

        public void MarkAsCompletedFor(Person user) { }

        public List<Person> Persons { get; set; }

        public List<Person> CompletedBy { get; }
    }

If you completely let go of the ORM, then probably you'll not create the mapping entity ( Person-ToDoItem ) in your core.

The case of Lists

In general, we use Lists to store ordered elements. For e.g. in the code below, as the list is ordered, we are probably going to use item index as a Serial number for the page.

    public class Book
    {
        public string Title { get; set; }

        public List<Page> Content { get; set; }
    }

    public class Page
    {
        public string Title { get; set; }

        public string Content { get; set; }
    }

It is the RDBMS that needs SNo, and Foreign key in the Page entity to link a page to a book. And that shouldn't be a concern of the Core. Right ?

Solution ( In my opinion )

I feel the design of the Core must be driven solely by the functional requirements. Meaning there must be functional classes and not entities, in the Core. Instead of having a BaseEntity in core, i feel the Database Layer must extend the Core Classes, create mapping entities if needed, do the splitting and merging or whatever is required to fit the needs of the ORM or RDBMS. In short, the Core must have the functional classes, while the Database Layer must generate the entities.

StructureMap "traces" left on README

The Web Project still references StructureMap, which can be confusing.
Must be a pre #26 merged.
I'm not sure what's the WithDefaultConventions equivalent (if any) when using Autofac.
Is it still uses conventions as StructureMap did? Autofac's docs states:

By default, all concrete classes in the assembly will be registered.

I'm guessing this paragraph should be rephrased.

Thanks,
Eyal

Best Way of implementing Application Services?

Hi Ardalis,

I was wondering what the best way of implementing an application services? My definition of application services would be the services that or Web App uses to call into our domain.

Looking at this project I'm guessing when you say Domain Services you also meant application services, so in that case it should belong in the core project? Or should the application services go into another project and if it does how should it's dependecies be done? Should it just depend on the Core project?

Thanks for your help ardalis and let me know if I've got any of the terminology wrong as I've only recently got into architecting my apps properly 😋

How to handle Clean arthitecture multiple databases

As I understand, repositories are in infrastructure project. So I planning to refactor my project and I want to be sure about place of repository logics.

In my case, I have 2 relational databases, one bigdata and one cache. So, in my case if data is in cache, I got it from cache. If not, I got relational db and put the cache and return data. It is inside in Business Logic. However, in my old project, usage of this layer has some disadvantages.

I try to understand how to clean arthitecture handle it?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.