Giter Club home page Giter Club logo

ddd-net-ef-core's Introduction

An Example of using DDD with .NET Core 3.1

Build Status

  • Domain Driven Design (aka DDD)
  • .NET Core 3.1
  • EntityFramework Core 3.1

Overview

Domain Models

In the Product Catalog bounded context, I have a following Aggregate-Roots, Entities and Value Objects

  1. Aggregate-Roots:

    1. Product
    2. Category
    3. Catalog
  2. Entities:

    1. CatalogCategory
    2. CatalogProduct
  3. Value Objects:

    1. CategoryId
    2. ProductId
    3. CatalogId
    4. CatalogCategoryId
    5. CatalogProductId

Aggregate Root Relationships

  1. Catalog and Category

    • The CatalogCategory represents the instance of Category in specific Catalog
  2. Category and Category

    • In specific Catalog, the categories can be organized as tree structure. Therefore, the CatalogCategory can have another as its parent.
  3. Product, Category and Catalog

    • The CatalogProduct represents the instance of Product in specific CatalogCategory
  1. DDDEfCore.ProductCatalog.Services.Commands: for Create, Update and delete operators by consuming repositories.
  2. DDDEfCore.ProductCatalog.Services.Queries: for all of the query operators by using Dapper

Highlighted Points

Strongly-Typed Entities Id

I want to use Strongly-Typed Ids for all models (i.e. CatalogId, CatalogCategoryId and so on) because of the benefits that described very well in the series of Using strongly-typed entity IDs to avoid primitive obsession part 1, part-2, part-3. Therefore, I have to add some advance steps to accomplish this need

  1. For EntityFramework Core
  • Use Value Conversion feature to define the mapping.

            builder
                .Property(x => x.Id)
                .UsePropertyAccessMode(PropertyAccessMode.Field)
                .HasConversion(x => x.Id, id => (CatalogId)id);
  1. For Dapper
  • Custom SqlMapper.TypeHandler

        public class StronglyTypedIdMapper<TIdenity> : SqlMapper.TypeHandler<TIdenity> where TIdenity : IdentityBase
        {
            #region Overrides of TypeHandler<TIdenityType>
    
            public override void SetValue(IDbDataParameter parameter, TIdenity value)
            {
                parameter.Value = value.Id;
            }
    
            public override TIdenity Parse(object value)
            {
                return IdentityFactory.Create<TIdenity>(value);
            }
    
            #endregion
        }
  1. For .NET Core
  • Custom TypeConverter

        public class StronglyTypedIdConverter<TIdentity> : TypeConverter where TIdentity : IdentityBase
        {
            #region Overrides of TypeConverter
    
            public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
            {
                return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
            }
    
            public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
            {
                var stringValue = value as string;
                if (!string.IsNullOrEmpty(stringValue) && Guid.TryParse(stringValue, out var guid))
                {
                    return IdentityFactory.Create<TIdentity>(guid);
                }
    
                return base.ConvertFrom(context, culture, value);
            }
    
            #endregion
        }
  • Custom JsonConverter

        public class IdentityJsonConverter<TIdentity> : JsonConverter<TIdentity> where TIdentity : IdentityBase
        {
            public override bool CanConvert(Type typeToConvert)
            {
                return typeToConvert == typeof(TIdentity);
            }
    
            public override TIdentity Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
            {
                return IdentityFactory.Create<TIdentity>(reader.GetGuid());
            }
    
            public override void Write(Utf8JsonWriter writer, TIdentity value, JsonSerializerOptions options)
            {
                writer.WriteStringValue(value.Id);
            }
        }

For CQRS

For Testing

About Test Projects

  1. DDDEfCore.ProductCatalog.Core.DomainModels.Tests

    • Unit Test for the behaviors of Domain Models
  2. DDDEfCore.ProductCatalog.Infrastructure.EfCore.Tests

    • Integration Test with EntityFramework Core and SqlServer for repositories of Aggregate-Roots
  3. DDDEfCore.ProductCatalog.Services.Commands.Tests

  4. DDDEfCore.ProductCatalog.Services.Queries.Tests

    • Integration Test with Dapper and SqlServer for Query Handlers.
  5. DDDEfCore.ProductCatalog.WebApi.Tests

    • Integration Test with Web Api by consuming Microsoft.AspNetCore.TestHost

Interesting Points

For every test project, I use the following packages

  • Shoudly: Should testing for .NET - the way Asserting Should be!
  • AutoFixture: AutoFixture is an open source library for .NET designed to minimize the 'Arrange' phase of your unit tests in order to maximize maintainability. Its primary goal is to allow developers to focus on what is being tested rather than how to setup the test scenario, by making it easier to create object graphs containing test data.
  • Respawn: Intelligent database cleaner for integration tests

How to run

Run Test Projects

  • In every integration test project, there are appsettings.json files that store connectstrings value. You have to change these values before running.

Test Results

Run via swagger from Visual Studio

  • You have to change the connectionstring value in appsettings.Development.json under DDDEfCore.ProductCatalog.WebApi

  • After run the WebApi by Ctrl+F5 from Visual Studio, assume the Url is http://localhost:[port]

    • Switch to swagger via swagger

    Swagger

How to see the codecoverage report

  • Use PowerShell, change location to cake; then execute the following command
.\build.ps1
  • After run successfully, go to code_coverage folder, and open the index.html by browser to see the report

Give a Star! ⭐

If you liked this project or if it helped you, please give a star ⭐ for this repository. Thank you!!!

ddd-net-ef-core's People

Contributors

kimcuhoang avatar

Watchers

James Cloos avatar

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.