Git Product home page Git Product logo

dotnet-architecture / eshoponcontainers Goto Github PK

View Code? Open in Web Editor NEW
24.6K 24.6K 10.4K 645.6 MB

Cross-platform .NET sample microservices and container based application that runs on Linux Windows and macOS. Powered by .NET 7, Docker Containers and Azure Kubernetes Services. Supports Visual Studio, VS for Mac and CLI based environments with Docker CLI, dotnet CLI, VS Code or any other code editor. Moved to https://github.com/dotnet/eShop.

Home Page: https://dot.net/architecture

PowerShell 1.80% Shell 1.30% C# 55.95% HTML 5.82% JavaScript 17.86% CSS 3.60% TypeScript 4.04% Batchfile 0.08% Smarty 1.27% Dockerfile 4.16% SCSS 2.61% Mustache 1.53%
ddd ddd-patterns docker microservices netcore spa windowscontainers xamarin

eshoponcontainers's Introduction

eShop has moved!

As of November 2023, the eShop sample application has been updated and moved to https://github.com/dotnet/eShop. Active development will continue there.

This repo is now a read-only archive. If you'd like to refer to the old code that was in here, you can find it in the "dev" branch.

eshoponcontainers's People

Contributors

andrelmp avatar ardalis avatar billwagner avatar cesardelatorre avatar chlowell avatar christian147 avatar colindembovsky avatar davidbritch avatar davidfowl avatar dependabot[bot] avatar dsrodenas avatar eiximenis avatar ericuss avatar erikpique avatar erjain avatar jacano avatar jsuarezruiz avatar marcoscobena avatar mvelosop avatar nishanil avatar onurkanbakirci avatar rafsanulhasan avatar ramon-tomas-c avatar reubenbond avatar sughosneo avatar sychevigor avatar taraskovalenko avatar tjain-ms avatar unaizorrilla avatar vishipayyallore 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

eshoponcontainers's Issues

PaymentMethod, Buyer, etc. (foreign keys) are also navigation properties in Order but they are not child entities

Related to: #18

The Enumerable object PaymentMethod is child of the Aggregate-Roots "Buyer". Ok, that's right.

However, in the Order AGGREGATE-ROOT, because it is referenced through the EF graph (navigation property), it feels like it is also a child-VO (embedded). Can we fix that?
Do we really need it as an object within the Order entity?

If we maintain it as a reference through the EF graph..., how can we make clearer in the model that it is NOT a child entity but just a reference?

This is RIGHT because PaymentMethod is a child of Buyer

    public class Buyer
       :Entity,IAggregateRoot
    {
        public string FullName { get; private set; }
        public HashSet<PaymentMethod> PaymentMethods { get; private set; }

**The following "feels" wrong because Buyer, PaymentMethod are NOT Order's childs **

    public class Order
        : Entity, IAggregateRoot
    {
        public int BuyerId { get; private set; }
        <b>public Buyer Buyer { get; private set; } </b>
        public DateTime OrderDate { get; private set; }
        //...
        public int PaymentMethodId { get; private set; }
        <b>public PaymentMethod PaymentMethod { get; private set; } </b>

I know that in the ConfigureOrder(), the PaymentMethod is configured as:

        orderConfiguration.HasOne(o => o.PaymentMethod)
            .WithMany()
            .HasForeignKey(o => o.PaymentMethodId)
            .OnDelete(DeleteBehavior.Restrict);

So, as a ForeignKey, but, do we really need the "object" here referenced through the EF graph?
Can we have just the PaymentMethodID in the Order so it is clearer that the PaymentMethod is NOT a child-entity of the Order Aggregate-Root?

Please, review.

Need another case for a Decorator using MediatR and the CommandHandlers (Transactions based on context.Database.BeginTransaction() could be..)

We need another case for a Decorator using MediatR and the CommandHandlers with .NET Core.
Just having a LogDecorator doesn't justify the use of Decorators in a generic way based with MediatR.

[UPDATE]: Probably a Validator decorator or resiliency decorator would be better than a Transaction decorator that could be an anti-pattern here, after further discussions.


A good candidate for this would be a TRANSACTION decorator, using the following underneath:

EF Core transactions can be explicitly controlled with context.Database.BeginTransaction()
EF Core also supports cross-context transaction (relational databases only), so you can also share a transaction across multiple context instances. This functionality is only available when using a relational database provider because it requires the use of DbTransaction and DbConnection, which are specific to relational databases. To share a transaction, the contexts must share both a DbConnection and a DbTransaction.
See: https://docs.microsoft.com/en-us/ef/core/saving/transactions


Any other good candidate for additional Decorators other than this?
Please, answer this thread in GitHub when possible.

Review EF Core 1.1 code in the "Ordering" microservice (Domain-Driven Design microservice)

Review EF Core code in the "Ordering" microservice. Take into account that this microservice should be implementing a more complex context with more Domain Logic that will eventually grow more. Therefore, this microservice was designed following more advanced Domain-Driven Design patterns like a No-Anemic Domain Model, Aggregate-Roots, CQS (Command-Query Separation) so transactions/updates are done with EF Core code implemented in Repository pattern objects but Queries are segregated and performed directly with Dapper. It is also implementing other patterns like Commands, CommandHandlers with decorators, etc.

Make immutable Commands and remove behavior from the Command classes - i.e. CreateOrderCommand

  1. Commands are immutable because their expected usage is to be sent directly to the domain model side for processing. They do not need to change during their projected lifetime in traveling from client to server. The same happens with Events.
    In a C# class, immutability is not having any setters, or other methods which change internal state.
    --> Need to change the implementation of the CreateOrderCommand that can be changed after created.
    Instead of setters being used now, need to provide everything in the constructor.
    The only issue/exception that we might need ti do is about the "BuyerIdentityGuid" that is not coming from the client but we find it out at the server side...
    i.e.: No it is not immutable:
    https://github.com/dotnet/eShopOnContainers/blob/migration/net11/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommand.cs
    NOT GOOD:

public class CreateOrderCommand
:IAsyncRequest
{
private readonly List _orderItems;
public string City { get; set; }
public string Street { get; set; }
public string State { get; set; }
public string Country { get; set; }
...
}

BETTER:

public class ChangeOrderStatus : IAsyncRequest
{
public int OrderId { get; }
public Status NewStatus { get; }

public ChangeOrderStatus (int orderId, Status newStatus)
{
    OrderId = orderId;
    NewStatus = newStatus;
}

}

---> Properties with ONLY getters.
---> The only method here should be the constructor which should be the only way (usually) to create/update the command object, so it is immutable.

  1. Also, according to the definition of a Command, "Commands are simply data structures that contain data for reading, and no behavior. We call such structures "Data Transfer Objects" (DTOs). The name indicates the purpose. In many languages they are represented as classes, but they are not true classes in the real OO sense.

Our current implementation of CreateOrderCommand has a method/behavior. That is great for Domain entities but doesn't male sense for Commands/DTOs.
See: https://github.com/dotnet/eShopOnContainers/blob/migration/net11/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommand.cs

It has a behavior method:
public void AddOrderItem(OrderItemDTO item)
{
_orderItems.Add(item);
}
We should be able to provide a whole List/IEnumerable as part of the constructor, if needed...
I fact, the "order.AddOrderItem(new OrderItemDTO()" is only being used from a Test.
Everything should be provided in the constructor.
The only exception we might need to do is for the "BuyerIdentityGuid". Not sure what solution can we have for this, as we discover the user Identity after getting the Command from the client....

Minor Pending Refactoring issues in Web Apps (SPA & MVC)

  • PENDING ISSUES

    • (Pending) SPA and MVC app: Show tooltip when hovering "Add" saying "You cannot add to basket util you login".
  • DONE (Move here "done issues" from above, when done)

    • (Done) SPA app: Add a different banner-photo to the SPA, so it feels a different application than the MVC app.
    • (Done) MVC app: Disable "Add to basket" button until you have logged-in.

Minor issue/bug: Remove "eShopOnContainers" from WebSPA project's name, namespace and Docker image name

For consistency in naming.
All the projects, except the WebSPA are like:
webmvc, ordering.api, catalog.api, basket.api.
Except the WebSPA which is "eshoponcontainers.webspa"
Please, when possible, remove the "eShopOnContainers" and keep it consistent with the rest of the projects.
Also, Docker Images are like:
eshop/webmvc
eshop/eshoponcontainers.webspa
eshop/ordering.api
eshop/catalog.api
eshop/basket.api
eshop/identity.api

Same thing, remove the "eShopOnContainers" from the webspa image's name.

The OrderItem child entity should not be implemented as a data-class and used from anywhere (Related to ISSUE #19)

I think that the OrderItem child entity should not be implemented as a open data-entity class with public setters and used from anywhere. It is used from the CreateOrderCommand and the CreateOrderCommandHandler, for instance...
This issue is related to ISSUE #19:
#19

This is the current implementation:

public class OrderItem : Entity
{
    public int ProductId { get;  set; }
    public string ProductName { get;  set; }
    public string PictureUrl { get; set; }
    public int OrderId { get;  set; }
    public decimal UnitPrice { get;  set; }
    public decimal Discount { get;  set; }
    public int Units { get;  set; }
}

I think this is not a good Domain Child Entity.
It should be something like:

public class OrderItem : Entity
{
    public int ProductId { get;  private set; }
    public string ProductName { get;   private set; }
    public string PictureUrl { get;  private set; }
    public int OrderId { get;   private set; }
    public decimal UnitPrice { get;   private set; }
    public decimal Discount { get;   private set; }
    public int Units { get;   private set; }
    OrderItem(params needed except the Order.Id that can be taken from the parent Order)
    {
        //... Update attributes from params
    }
    //Plus any update/set method we might need to update any field or group of fields, like:
    public UpdatePictureUrl(string newPictureUrl)
    {
         //Validations and logic
         //...
         PictureUrl = newPictureUrl;
    }

    public UpdateDiscount(decimal newDiscount)
    {
         //Validations and logic
         //...
         Discount = newDiscount;
    }
}

Then, the operation "new OrderItem()" should ONLY be done by the Order AGGREGATE-ROOT, from within the order.AddOrderItem(params needed) method, and in that method we should place all the VALIDATIONS and DOMAIN LOGIC related to the creation of an OrderItem, which by the way, need to enrich, as we have little logic/validations in the Order AggregateRoot.

Implement Domain Events

We should create and save Domain events at the Entity level (AggregateRoot or child entity).
In each method that needs to generate an event, right after updating the model we should store/save the events, like:
public class Order : Entity
{
//Plain Order fields (No properties if not needed. This is new since EF 1.1)
//Like:
private DateTime _orderDate;
//...

// Using a private collection field, better for DDD Aggregate's encapsulation
private readonly HashSet<OrderItem> _orderItems;
public IEnumerable<OrderItem> OrderItems => _orderItems.ToList();

public void AddOrderLine(order line params....)
{
    var orderItem = new OrderItem(productId, productName, unitPrice, discount, pictureUrl, units);
    _orderItems.Add(orderItem);

    **//THIS IS WHEN WE ADD/SAVE A DOMAIN EVENT for this entity
    Events.Add(new OrderItemAddedEvent(this.Id, orderItem));**
}

This would be following a similar approach than Jimmy Bogard's here:
https://lostechies.com/jimmybogard/2014/05/13/a-better-domain-events-pattern/

Need to implement Wait-Retry when consuming services and starting the first time the solution from VS 2017

Need to implement Wait-Retry when consuming services and starting the first time the solution from VS 2017

For instance, when starting the whole solution, the first time it usually fails because some container might not be ready. After refreshing the browser the app usually works.
This is because the app and services have dependencies and when deploying some of them might still not be ready.
These are the errors you usually get the first time:

An unhandled exception occurred while processing the request.
CurlException: Couldn't connect to server
System.Net.Http.CurlHandler.ThrowIfCURLEError(CURLcode error)
HttpRequestException: An error occurred while sending the request.
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Stack Query Cookies Headers
CurlException: Couldn't connect to server
System.Net.Http.CurlHandler.ThrowIfCURLEError(CURLcode error)
System.Net.Http.CurlHandler+MultiAgent.FinishRequest(StrongToWeakReference easyWrapper, CURLcode messageResult)

Show raw exception details
HttpRequestException: An error occurred while sending the request.
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult()
System.Net.Http.HttpClient+d__58.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult()
System.Net.Http.HttpClient+d__32.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.eShopOnContainers.WebMVC.Services.CatalogService+d__4.MoveNext() in D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebMVC\Services\CatalogService.cs
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.eShopOnContainers.WebMVC.Controllers.CatalogController+d__2.MoveNext() in D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebMVC\Controllers\CatalogController.cs
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+d__27.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+d__25.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+d__22.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ResourceExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+d__20.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Builder.RouterMiddleware+d__4.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+d__18.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+d__18.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+d__18.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+d__18.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware+d__7.MoveNext()

Minor Pending Refactoring issues in Microservices

  • PENDING ISSUES

  • DONE (Move here "done issues" from above, when done)

    • (DONE) Rename entity class Payment to PaymentMethod in the Ordering microservice:
      We are using just "Payment Methods". We don't really have any "Payment" in the current version of this app.

Need to implement Validations on every Domain Entity constructor and update method (Ordering Domain Model)

The current implementation in the Ordering Domain Model has almost no Validations in place. This is a very important area in a Domain Model as Domain Entities and Aggregates are responsible for their "always valid" state.
Invariant enforcement is the responsibility of the domain entity itself (especially of the Aggregate-Root) and therefore an entity shouldn't even be able to exist without being valid.

Take into account:
http://gorodinski.com/blog/2012/05/19/validation-in-domain-driven-design-ddd/
http://enterprisecraftsmanship.com/2015/03/07/functional-c-primitive-obsession/

Consider to use the SPECIFICATION VALIDATION pattern for this.
To be confirmed, might not be the best approach..:
https://www.codeproject.com/Tips/790758/Specification-and-Notification-Patterns
http://web.archive.org/web/20130117134221/http://codeinsanity.com/archive/2008/12/02/a-framework-for-validation-and-business-rules.aspx
Specifications: https://github.com/riteshrao/ncommon/tree/v1.2/NCommon/src/Specifications
Validations: https://github.com/riteshrao/ncommon/tree/v1.2/NCommon/src/Rules (especially the classes for ValidationResult and ValidationError)
https://lostechies.com/jimmybogard/2007/10/25/specifications-versus-validators/

[OPTION 1: Single validation per attribute/field with Data Annotations]
For simple validations, we could use DataAnnotations with optional regular expressions: like explained here:
https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/validation
But I don't like how intrusive are those data annotations in my domain model... as it takes a dependency on ModelState.IsValid and MVC controllers, I believe. The model validation occurs prior to each controller action being invoked, and it is the action method’s responsibility to inspect ModelState.IsValid and react appropriately. So, use it or not depending on how coupled you’d like your model to be with that infrastructure
In any case, it would be important to be able not to create an entity object if those data annotations are not satisfied, so we follow the "always valid entity" principle. I don't like the "ModelState.IsValid()" used in ASP.NET. Entities should always be valid or not created if the validation failed.
...Instead of data annotations attributes we could also have model validations by inheriting the entity class from IValidateObject... See code below at the end of this issue for sample code with IValidateObject.

OPTION 2: [Validation rules are specific to your business]
In addition to that, there are other cases which are not specific to a single data attribute but involves multiple fields with more complex invariants. In that case we need to implement that validation logic in the constructor or update methods or we could also use "custom validation attributes" as explained here:
https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation

Exceptions or notifications (Notification pattern) should be thrown when the invariant rules are violated. We need to implement a consistent/unified way to propagate validation notification to the multiple client apps, Web MVC, Web SPA and Xamarin Mobile Apps.


SAMPLE CODE TO USE IValidatableObject instead of Data Annotations attributes

public abstract class EntityBase : IValidatableObject
{
#region Implementation of IValidatableObject
public abstract System.Collections.Generic.IEnumerable Validate(ValidationContext validationContext);
#endregion
}
public class Employee:EntityBase
{
public string FullName { get; set; }
public virtual Address Address { get; set; }
public ICollection Benefits {get;set;}
public override IEnumerable Validate(ValidationContext validationContext)
{
if (Address == null)
{
yield return new EnhancedMappedValidationResult(d => d.Address, "Address is mandatory");
}
if (FullName == null)
{
yield return new EnhancedMappedValidationResult(d => d.FullName, "FullName is mandatory");
}
}
}
public class EnhancedMappedValidationResult : ValidationResult
{
///


/// Property in error on which the validation result error is assigned.
/// Getter only because we want the exception to be set when the validation result
/// is created.
///

///
/// The property.
///
public Expression<Func<TEntity, object>> Property { get; private set; }
///
/// Initializes by setting the propertu and the error.
///

/// The property.
/// The error message.
public EnhancedMappedValidationResult(Expression<Func<TEntity, object>> property, string errorMessage)
: base(errorMessage, new List())
{
Property = property;
((List)base.MemberNames).Add(LambdaUtilities.GetExpressionText(Property));
}
}

Implement Integration events between multiple microservices

Implement Event-Driven communication between microservices/containers based on Event-Bus interfaces and any simple inter-process communication implementation (That implementation could be swapped by any more advanced Service Bus, like Azure Service Bus using Topics) Integration Events.

Integration events could be raised after handling Domain Events as part of the Domain Events "side effects".

IMPORTANT: Need to tackle resilient publish, so how to avoid that data is not consistent if after updating data locally the network or Event Bus fails when trying to publish.
See links like: https://docs.particular.net/nservicebus/azure/ways-to-live-without-transactions

Review EF Core 1.0 code in the "Catalog" microservice (Simple data-driven and CRUD microservice)

Need to review and provide feedback on the EF Core 1.0 code in "Catalog" microservice by the EF product team.
Take into account that this microservice implementation is supposed to be "the simpler, the better", as it is a simple data-driven and CRUD microservice.

Add more Domain logic/rules to the Order Aggregate-Root and its methods

The Order Aggregate-Root should have more sample domain logic, invariants and business rules validations so it makes sense to use the DDD Aggregate-Root pattern.
See here the Order AggregateRoot here:
https://github.com/dotnet/eShopOnContainers/blob/master/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs

We actually just have the AddOrderItem(OrderItem item) method in here but with almost no domain logic or business validations.

I know that this is a simple example and not a real e-Commerce, but in this case, we need to show where to implement the business/domain logic --> in the Aggregate-Roots methods.

So, we need to add more domain logic here. It is actually too poor in regards domain logic.

Anyone reading this issue (Jimmy?), please, can you suggest interesting domain rules/logic to add to the Order Aggregate-Root.

Consider to use the Notification pattern and the Specification pattern for Validations at the Domain Model Layer

This might be worth to do it in the ORDERING Domain Model Layer flowing to the Application Layer and Web API.
At the end of the day, an specification is an interface that defines one method: IsSatisfiedBy() which returns boolean to assert that the specification is satisfied. So, every single business rule could be represented by a class that implements the ISpecification interface. We can chain many specifications in order to validate the entities when created of updated.

Then, we can use the Notification pattern in order to return a collection of validation errors, instead of the simple "exception approach" we are currently implementing which is only returning the first exception you get instead of all the possible errors.
For example, see these blog post for further details:
https://www.codeproject.com/Tips/790758/Specification-and-Notification-Patterns

Notification Pattern: https://martinfowler.com/articles/replaceThrowWithNotification.html

I'm not 100% sure about using the SPECIFICATION pattern as it might complicate the code too much for this "easy to get started" sample app.
However I think we should use the NOTIFICATION pattern so we can return a list of all the errors or inconsistencies found when creating/updating a Domain object.

Please, answer with additional implementation approaches for .NET Core and ASP.NET Core.

PowerShell build-bits.ps1: Issue/error when building SPA JS dependencies before dotnet bits

In the new PowerShell build-bits.ps1 compatible with .CSPROJ and VS 2017 there's an error in when building SPA JS dependencies before dotnet bits.
Please, fix it. Might be related to issue with VS 2017 when running the SPA app?

Errors in PowerShell like the following:

ERROR in ./Client/globals.scss
Module build failed : error : Missing binding D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebS
PA\node_modules\node-sass\vendor\win32-x64-48\binding.node [D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnC
ontainers.WebSPA\eShopOnContainers.WebSPA.csproj]
Node Sass could not find a binding for your current environment: Windows 64-bit with Node.js 6.x

Found bindings for the following environments:
- Windows 64-bit with Node.js 5.x

This usually happens because your environment has changed since running npm install.
Run npm rebuild node-sass to build the binding for your current environment.
at Object. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\n
ode-sass\lib\index.js:15:11)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at Object. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\s
ass-loader\index.js:4:12)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:13:17)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:165:10)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:173:18
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:36:3)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:165:10)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:185:6
at runSyncOrAsync (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loade
r-runner\lib\LoaderRunner.js:124:12)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:175:3
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:36:3)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at runLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\LoaderRunner.js:362:2)
at NormalModule.doBuild (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules
\webpack\lib\NormalModule.js:131:2)

ERROR in ./~/bootstrap/scss/bootstrap.scss
Module build failed : error : Missing binding D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebS
PA\node_modules\node-sass\vendor\win32-x64-48\binding.node [D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnC
ontainers.WebSPA\eShopOnContainers.WebSPA.csproj]
Node Sass could not find a binding for your current environment: Windows 64-bit with Node.js 6.x

Found bindings for the following environments:
- Windows 64-bit with Node.js 5.x

This usually happens because your environment has changed since running npm install.
Run npm rebuild node-sass to build the binding for your current environment.
at Object. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\n
ode-sass\lib\index.js:15:11)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at Object. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\s
ass-loader\index.js:4:12)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:13:17)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:165:10)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:173:18
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:36:3)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:165:10)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:185:6
at runSyncOrAsync (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loade
r-runner\lib\LoaderRunner.js:124:12)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:175:3
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:36:3)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at runLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\LoaderRunner.js:362:2)
at NormalModule.doBuild (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules
\webpack\lib\NormalModule.js:131:2)

ERROR in ./~/font-awesome/scss/font-awesome.scss
Module build failed : error : Missing binding D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebS
PA\node_modules\node-sass\vendor\win32-x64-48\binding.node [D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnC
ontainers.WebSPA\eShopOnContainers.WebSPA.csproj]
Node Sass could not find a binding for your current environment: Windows 64-bit with Node.js 6.x

Found bindings for the following environments:
- Windows 64-bit with Node.js 5.x

This usually happens because your environment has changed since running npm install.
Run npm rebuild node-sass to build the binding for your current environment.
at Object. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\n
ode-sass\lib\index.js:15:11)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at Object. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\s
ass-loader\index.js:4:12)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:13:17)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:165:10)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:173:18
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:36:3)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:165:10)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:185:6
at runSyncOrAsync (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loade
r-runner\lib\LoaderRunner.js:124:12)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:175:3
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:36:3)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at runLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\LoaderRunner.js:362:2)
at NormalModule.doBuild (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules
\webpack\lib\NormalModule.js:131:2)

ERROR in ./~/font-awesome/scss/font-awesome.scss
Module build failed : error : Missing binding D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebS
PA\node_modules\node-sass\vendor\win32-x64-48\binding.node [D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnC
ontainers.WebSPA\eShopOnContainers.WebSPA.csproj]
Node Sass could not find a binding for your current environment: Windows 64-bit with Node.js 6.x

Found bindings for the following environments:
- Windows 64-bit with Node.js 5.x

This usually happens because your environment has changed since running npm install.
Run npm rebuild node-sass to build the binding for your current environment.
at Object. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\n
ode-sass\lib\index.js:15:11)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at Object. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\s
ass-loader\index.js:4:12)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:13:17)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:165:10)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:173:18
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:36:3)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:165:10)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:185:6
at runSyncOrAsync (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loade
r-runner\lib\LoaderRunner.js:124:12)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:175:3
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:36:3)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at runLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\LoaderRunner.js:362:2)
at NormalModule.doBuild (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules
\webpack\lib\NormalModule.js:131:2)

ERROR in ./~/font-awesome/scss/font-awesome.scss
Module build failed: ModuleBuildError: Module build failed: Error: Missing binding D:\GITREPOS\eShopOnContainers-vs201
7\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\node-sass\vendor\win32-x64-48\binding.node
Node Sass could not find a binding for your current environment: Windows 64-bit with Node.js 6.x

Found bindings for the following environments:
- Windows 64-bit with Node.js 5.x

This usually happens because your environment has changed since running npm install.
Run npm rebuild node-sass to build the binding for your current environment.
at Object. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\n
ode-sass\lib\index.js:15:11)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at Object. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\s
ass-loader\index.js:4:12)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:13:17)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:165:10)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:173:18
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:36:3)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at runLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\LoaderRunner.js:362:2)
at NormalModule.doBuild (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules
\webpack\lib\NormalModule.js:131:2)
at NormalModule.build (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\w
ebpack\lib\NormalModule.js:179:15)
at Compilation.buildModule (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modu
les\webpack\lib\Compilation.js:127:9)
at Compilation. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modu
les\webpack\lib\Compilation.js:404:8)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webpack\lib\NormalMod
uleFactory.js:74:13
at NormalModuleFactory.applyPluginsAsyncWaterfall (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnCont
ainers.WebSPA\node_modules\tapable\lib\Tapable.js:196:70)
at onDoneResolving (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webp
ack\lib\NormalModuleFactory.js:49:11)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webpack\lib\NormalMod
ule.js:143:35
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:364:11
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:170:18
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:27:11)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:165:10)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:173:18
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:36:3)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at runLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\LoaderRunner.js:362:2)
at NormalModule.doBuild (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules
\webpack\lib\NormalModule.js:131:2)
at NormalModule.build (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\w
ebpack\lib\NormalModule.js:179:15)
at Compilation.buildModule (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modu
les\webpack\lib\Compilation.js:127:9)
at Compilation. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modu
les\webpack\lib\Compilation.js:404:8)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webpack\lib\NormalMod
uleFactory.js:74:13
at NormalModuleFactory.applyPluginsAsyncWaterfall (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnCont
ainers.WebSPA\node_modules\tapable\lib\Tapable.js:196:70)
at onDoneResolving (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webp
ack\lib\NormalModuleFactory.js:49:11)
at onDoneResolving (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webp
ack\lib\NormalModuleFactory.js:165:6)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webpack\lib\NormalMod
uleFactory.js:161:6
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib\async.js:72
6:13
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib\async.js:52
:16
at async.forEachOf.async.eachOf (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node
_modules\async\lib\async.js:236:30)
at _parallel (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib
async.js:717:9)
at Object.async.parallel (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_module
s\async\lib\async.js:731:9)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webpack\lib\NormalMod
uleFactory.js:154:11
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib\async.js:72
6:13
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib\async.js:52
:16
at done (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib\async
.js:246:17)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib\async.js:44
:16
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib\async.js:72
3:17

ERROR in D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\extract-text-webpac
k-plugin\loader.js?{"id":1,"omit":0,"remove":true}!D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers
.WebSPA\node_modules\css-loader\index.js?minimize!D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.
WebSPA\node_modules\sass-loader\index.js!D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\no
de_modules\font-awesome\scss\font-awesome.scss doesn't export content

ERROR in ./~/bootstrap/scss/bootstrap.scss
Module build failed : error : Missing binding D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebS
PA\node_modules\node-sass\vendor\win32-x64-48\binding.node [D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnC
ontainers.WebSPA\eShopOnContainers.WebSPA.csproj]
Node Sass could not find a binding for your current environment: Windows 64-bit with Node.js 6.x

Found bindings for the following environments:
- Windows 64-bit with Node.js 5.x

This usually happens because your environment has changed since running npm install.
Run npm rebuild node-sass to build the binding for your current environment.
at Object. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\n
ode-sass\lib\index.js:15:11)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at Object. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\s
ass-loader\index.js:4:12)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:13:17)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:165:10)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:173:18
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:36:3)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:165:10)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:185:6
at runSyncOrAsync (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loade
r-runner\lib\LoaderRunner.js:124:12)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:175:3
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:36:3)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at runLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\LoaderRunner.js:362:2)
at NormalModule.doBuild (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules
\webpack\lib\NormalModule.js:131:2)

ERROR in ./~/bootstrap/scss/bootstrap.scss
Module build failed: ModuleBuildError: Module build failed: Error: Missing binding D:\GITREPOS\eShopOnContainers-vs201
7\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\node-sass\vendor\win32-x64-48\binding.node
Node Sass could not find a binding for your current environment: Windows 64-bit with Node.js 6.x

Found bindings for the following environments:
- Windows 64-bit with Node.js 5.x

This usually happens because your environment has changed since running npm install.
Run npm rebuild node-sass to build the binding for your current environment.
at Object. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\n
ode-sass\lib\index.js:15:11)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at Object. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\s
ass-loader\index.js:4:12)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:13:17)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:165:10)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:173:18
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:36:3)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at runLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\LoaderRunner.js:362:2)
at NormalModule.doBuild (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules
\webpack\lib\NormalModule.js:131:2)
at NormalModule.build (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\w
ebpack\lib\NormalModule.js:179:15)
at Compilation.buildModule (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modu
les\webpack\lib\Compilation.js:127:9)
at Compilation. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modu
les\webpack\lib\Compilation.js:404:8)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webpack\lib\NormalMod
uleFactory.js:74:13
at NormalModuleFactory.applyPluginsAsyncWaterfall (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnCont
ainers.WebSPA\node_modules\tapable\lib\Tapable.js:196:70)
at onDoneResolving (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webp
ack\lib\NormalModuleFactory.js:49:11)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webpack\lib\NormalMod
ule.js:143:35
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:364:11
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:170:18
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:27:11)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:165:10)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:173:18
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:36:3)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at runLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\LoaderRunner.js:362:2)
at NormalModule.doBuild (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules
\webpack\lib\NormalModule.js:131:2)
at NormalModule.build (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\w
ebpack\lib\NormalModule.js:179:15)
at Compilation.buildModule (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modu
les\webpack\lib\Compilation.js:127:9)
at Compilation. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modu
les\webpack\lib\Compilation.js:404:8)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webpack\lib\NormalMod
uleFactory.js:74:13
at NormalModuleFactory.applyPluginsAsyncWaterfall (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnCont
ainers.WebSPA\node_modules\tapable\lib\Tapable.js:196:70)
at onDoneResolving (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webp
ack\lib\NormalModuleFactory.js:49:11)
at onDoneResolving (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webp
ack\lib\NormalModuleFactory.js:165:6)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webpack\lib\NormalMod
uleFactory.js:161:6
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib\async.js:72
6:13
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib\async.js:52
:16
at async.forEachOf.async.eachOf (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node
_modules\async\lib\async.js:236:30)
at _parallel (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib
async.js:717:9)
at Object.async.parallel (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_module
s\async\lib\async.js:731:9)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webpack\lib\NormalMod
uleFactory.js:154:11
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib\async.js:72
6:13
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib\async.js:52
:16
at done (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib\async
.js:246:17)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib\async.js:44
:16
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib\async.js:72
3:17

ERROR in D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\extract-text-webpac
k-plugin\loader.js?{"id":1,"omit":0,"remove":true}!D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers
.WebSPA\node_modules\css-loader\index.js?minimize!D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.
WebSPA\node_modules\sass-loader\index.js!D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\no
de_modules\bootstrap\scss\bootstrap.scss doesn't export content

ERROR in ./Client/globals.scss
Module build failed : error : Missing binding D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebS
PA\node_modules\node-sass\vendor\win32-x64-48\binding.node [D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnC
ontainers.WebSPA\eShopOnContainers.WebSPA.csproj]
Node Sass could not find a binding for your current environment: Windows 64-bit with Node.js 6.x

Found bindings for the following environments:
- Windows 64-bit with Node.js 5.x

This usually happens because your environment has changed since running npm install.
Run npm rebuild node-sass to build the binding for your current environment.
at Object. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\n
ode-sass\lib\index.js:15:11)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at Object. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\s
ass-loader\index.js:4:12)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:13:17)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:165:10)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:173:18
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:36:3)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:165:10)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:185:6
at runSyncOrAsync (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loade
r-runner\lib\LoaderRunner.js:124:12)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:175:3
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:36:3)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at runLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\LoaderRunner.js:362:2)
at NormalModule.doBuild (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules
\webpack\lib\NormalModule.js:131:2)

ERROR in ./Client/globals.scss
Module build failed: ModuleBuildError: Module build failed: Error: Missing binding D:\GITREPOS\eShopOnContainers-vs201
7\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\node-sass\vendor\win32-x64-48\binding.node
Node Sass could not find a binding for your current environment: Windows 64-bit with Node.js 6.x

Found bindings for the following environments:
- Windows 64-bit with Node.js 5.x

This usually happens because your environment has changed since running npm install.
Run npm rebuild node-sass to build the binding for your current environment.
at Object. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\n
ode-sass\lib\index.js:15:11)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at Object. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\s
ass-loader\index.js:4:12)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:13:17)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:165:10)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:173:18
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:36:3)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at runLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\LoaderRunner.js:362:2)
at NormalModule.doBuild (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules
\webpack\lib\NormalModule.js:131:2)
at NormalModule.build (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\w
ebpack\lib\NormalModule.js:179:15)
at Compilation.buildModule (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modu
les\webpack\lib\Compilation.js:127:9)
at Compilation. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modu
les\webpack\lib\Compilation.js:404:8)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webpack\lib\NormalMod
uleFactory.js:74:13
at NormalModuleFactory.applyPluginsAsyncWaterfall (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnCont
ainers.WebSPA\node_modules\tapable\lib\Tapable.js:196:70)
at onDoneResolving (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webp
ack\lib\NormalModuleFactory.js:49:11)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webpack\lib\NormalMod
ule.js:143:35
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:364:11
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:170:18
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:27:11)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:165:10)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib\Loa
derRunner.js:173:18
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\loadLoader.js:36:3)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\loader-runner\lib\LoaderRunner.js:169:2)
at runLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-ru
nner\lib\LoaderRunner.js:362:2)
at NormalModule.doBuild (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules
\webpack\lib\NormalModule.js:131:2)
at NormalModule.build (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\w
ebpack\lib\NormalModule.js:179:15)
at Compilation.buildModule (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modu
les\webpack\lib\Compilation.js:127:9)
at Compilation. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modu
les\webpack\lib\Compilation.js:404:8)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webpack\lib\NormalMod
uleFactory.js:74:13
at NormalModuleFactory.applyPluginsAsyncWaterfall (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnCont
ainers.WebSPA\node_modules\tapable\lib\Tapable.js:196:70)
at onDoneResolving (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webp
ack\lib\NormalModuleFactory.js:49:11)
at onDoneResolving (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webp
ack\lib\NormalModuleFactory.js:165:6)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webpack\lib\NormalMod
uleFactory.js:161:6
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib\async.js:72
6:13
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib\async.js:52
:16
at async.forEachOf.async.eachOf (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node
_modules\async\lib\async.js:236:30)
at _parallel (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib
async.js:717:9)
at Object.async.parallel (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_module
s\async\lib\async.js:731:9)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webpack\lib\NormalMod
uleFactory.js:154:11
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib\async.js:72
6:13
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib\async.js:52
:16
at done (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib\async
.js:246:17)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib\async.js:44
:16
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\async\lib\async.js:72
3:17

ERROR in D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\extract-text-webpac
k-plugin\loader.js?{"id":1,"omit":0,"remove":true}!D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers
.WebSPA\node_modules\css-loader\index.js?minimize!D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.
WebSPA\node_modules\sass-loader\index.js!D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\Cl
ient\globals.scss doesn't export content
Child extract-text-webpack-plugin:
+ 1 hidden modules

  ERROR in ./~/css-loader?minimize!./~/sass-loader!./~/font-awesome/scss/font-awesome.scss

Module build failed : error : Missing binding D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebS
PA\node_modules\node-sass\vendor\win32-x64-48\binding.node [D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnC
ontainers.WebSPA\eShopOnContainers.WebSPA.csproj]
Node Sass could not find a binding for your current environment: Windows 64-bit with Node.js 6.x

  Found bindings for the following environments:
    - Windows 64-bit with Node.js 5.x

  This usually happens because your environment has changed since running `npm install`.
  Run `npm rebuild node-sass` to build the binding for your current environment.
      at Object.<anonymous> (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul

es\node-sass\lib\index.js:15:11)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at Object. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\sass-loader\index.js:4:12)
at Module._compile (module.js:570:32)
at Object.Module.extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module.load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loade
r-runner\lib\loadLoader.js:13:17)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_m
odules\loader-runner\lib\LoaderRunner.js:169:2)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_m
odules\loader-runner\lib\LoaderRunner.js:165:10)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib
\LoaderRunner.js:173:18
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loade
r-runner\lib\loadLoader.js:36:3)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_m
odules\loader-runner\lib\LoaderRunner.js:169:2)
at runLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loade
r-runner\lib\LoaderRunner.js:362:2)
at NormalModule.doBuild (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_mod
ules\webpack\lib\NormalModule.js:131:2)
at NormalModule.build (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\webpack\lib\NormalModule.js:179:15)
at Compilation.buildModule (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node

modules\webpack\lib\Compilation.js:127:9)
at Compilation. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node

modules\webpack\lib\Compilation.js:404:8)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webpack\lib\Norma
lModuleFactory.js:74:13
at NormalModuleFactory.applyPluginsAsyncWaterfall (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOn
Containers.WebSPA\node_modules\tapable\lib\Tapable.js:196:70)
at onDoneResolving (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules
webpack\lib\NormalModuleFactory.js:49:11)
Child extract-text-webpack-plugin:
+ 1 hidden modules

  ERROR in ./~/css-loader?minimize!./~/sass-loader!./~/bootstrap/scss/bootstrap.scss

Module build failed : error : Missing binding D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebS
PA\node_modules\node-sass\vendor\win32-x64-48\binding.node [D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnC
ontainers.WebSPA\eShopOnContainers.WebSPA.csproj]
Node Sass could not find a binding for your current environment: Windows 64-bit with Node.js 6.x

  Found bindings for the following environments:
    - Windows 64-bit with Node.js 5.x

  This usually happens because your environment has changed since running `npm install`.
  Run `npm rebuild node-sass` to build the binding for your current environment.
      at Object.<anonymous> (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul

es\node-sass\lib\index.js:15:11)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at Object. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\sass-loader\index.js:4:12)
at Module._compile (module.js:570:32)
at Object.Module.extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module.load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loade
r-runner\lib\loadLoader.js:13:17)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_m
odules\loader-runner\lib\LoaderRunner.js:169:2)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_m
odules\loader-runner\lib\LoaderRunner.js:165:10)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib
\LoaderRunner.js:173:18
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loade
r-runner\lib\loadLoader.js:36:3)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_m
odules\loader-runner\lib\LoaderRunner.js:169:2)
at runLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loade
r-runner\lib\LoaderRunner.js:362:2)
at NormalModule.doBuild (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_mod
ules\webpack\lib\NormalModule.js:131:2)
at NormalModule.build (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\webpack\lib\NormalModule.js:179:15)
at Compilation.buildModule (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node

modules\webpack\lib\Compilation.js:127:9)
at Compilation. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node

modules\webpack\lib\Compilation.js:404:8)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webpack\lib\Norma
lModuleFactory.js:74:13
at NormalModuleFactory.applyPluginsAsyncWaterfall (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOn
Containers.WebSPA\node_modules\tapable\lib\Tapable.js:196:70)
at onDoneResolving (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules
webpack\lib\NormalModuleFactory.js:49:11)
Child extract-text-webpack-plugin:
+ 1 hidden modules

  ERROR in ./~/css-loader?minimize!./~/sass-loader!./Client/globals.scss

Module build failed : error : Missing binding D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebS
PA\node_modules\node-sass\vendor\win32-x64-48\binding.node [D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnC
ontainers.WebSPA\eShopOnContainers.WebSPA.csproj]
Node Sass could not find a binding for your current environment: Windows 64-bit with Node.js 6.x

  Found bindings for the following environments:
    - Windows 64-bit with Node.js 5.x

  This usually happens because your environment has changed since running `npm install`.
  Run `npm rebuild node-sass` to build the binding for your current environment.
      at Object.<anonymous> (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul

es\node-sass\lib\index.js:15:11)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at Object. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\sass-loader\index.js:4:12)
at Module._compile (module.js:570:32)
at Object.Module.extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module.load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loade
r-runner\lib\loadLoader.js:13:17)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_m
odules\loader-runner\lib\LoaderRunner.js:169:2)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_m
odules\loader-runner\lib\LoaderRunner.js:165:10)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loader-runner\lib
\LoaderRunner.js:173:18
at loadLoader (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loade
r-runner\lib\loadLoader.js:36:3)
at iteratePitchingLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_m
odules\loader-runner\lib\LoaderRunner.js:169:2)
at runLoaders (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\loade
r-runner\lib\LoaderRunner.js:362:2)
at NormalModule.doBuild (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_mod
ules\webpack\lib\NormalModule.js:131:2)
at NormalModule.build (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modul
es\webpack\lib\NormalModule.js:179:15)
at Compilation.buildModule (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node

modules\webpack\lib\Compilation.js:127:9)
at Compilation. (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node

modules\webpack\lib\Compilation.js:404:8)
at D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules\webpack\lib\Norma
lModuleFactory.js:74:13
at NormalModuleFactory.applyPluginsAsyncWaterfall (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOn
Containers.WebSPA\node_modules\tapable\lib\Tapable.js:196:70)
at onDoneResolving (D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\node_modules
webpack\lib\NormalModuleFactory.js:49:11)

npm ERR! Windows_NT 10.0.14393
npm ERR! argv "C:\Program Files\nodejs\node.exe" "C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js" "r
un" "build:vendor"
npm ERR! node v6.9.5
npm ERR! npm v3.10.10
npm ERR! code ELIFECYCLE
npm ERR! [email protected] build:vendor: node node_modules/webpack/bin/webpack.js --config config/web pack.config.vendor.js
npm ERR! Exit status 2
npm ERR!
npm ERR! Failed at the [email protected] build:vendor script 'node node_modules/webpack/bin/webpack.js
--config config/webpack.config.vendor.js'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the eshopaspnetnetcoredockerspa package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! node node_modules/webpack/bin/webpack.js --config config/webpack.config.vendor.js
npm ERR! You can get information on how to open an issue for this project with:
npm ERR! npm bugs eshopaspnetnetcoredockerspa
npm ERR! Or if that isn't available, you can get their info via:
npm ERR! npm owner ls eshopaspnetnetcoredockerspa
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR! D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\npm-debug.log

npm ERR! Windows_NT 10.0.14393
npm ERR! argv "C:\Program Files\nodejs\node.exe" "C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js" "r
un" "build:prod"
npm ERR! node v6.9.5
npm ERR! npm v3.10.10
npm ERR! code ELIFECYCLE
npm ERR! [email protected] build:prod: npm run setprod && npm run clean:dist && npm run build:vendor && npm run build:main
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] build:prod script 'npm run setprod && npm run clean:dist && n
pm run build:vendor && npm run build:main'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the eshopaspnetnetcoredockerspa package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! npm run setprod && npm run clean:dist && npm run build:vendor && npm run build:main
npm ERR! You can get information on how to open an issue for this project with:
npm ERR! npm bugs eshopaspnetnetcoredockerspa
npm ERR! Or if that isn't available, you can get their info via:
npm ERR! npm owner ls eshopaspnetnetcoredockerspa
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR! D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\npm-debug.log
D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebSPA\eShopOnContainers.WebSPA\eShopOnContainers.WebSPA.csproj(51,5): erro
r MSB3073: The command "npm run build:prod" exited with code 1.

A Command Handler should directly affect one single aggregate... Use Domain Events here?

Explained below, however, I'm not sure I agree on this rule...
An Aggregate is a consistency boundary, but that consistency can be achieved as part of a larger transaction involving multiple aggregates within the whole Command-Handler's task...
In any case, this is something to consider and discuss here plus the advanced solution can be part of a new feature for next sprints.
In any case, this issue is related to this:
#34
The CommandHandler has to be reviewed, looks like it has domain logic Bugs explained in issue #34 ..

In a different page, for this issue, I mean the following:
According to http://cqrs.nu/Faq/command-handlers
"A command handler should only directly affect one aggregate."

We are updating two Aggregates in the CreateOrderCommandHandler:
The Order aggregate and the Buyer aggregate:
https://github.com/dotnet/eShopOnContainers/blob/migration/net11/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs

When implementing DOMAIN EVENTS, this could be a good case for raising an event and create or update a Buyer if it needs to be done.

(In this thread however some folks are ok with affecting multiple Aggregates from the same Command Handler...): https://groups.google.com/forum/#!topic/dddcqrs/vX8Zd6Si1-E

See these discussions, too:
https://groups.google.com/forum/#!topic/dddcqrs/UYXXR4iU8f4
http://stackoverflow.com/questions/23324713/should-the-rule-one-transaction-per-aggregate-be-taken-into-consideration-when

PowerShell build-images.ps1 does not work anymore now with the .CSPROJ project files

Related to this other bug/issue:
#48

The PowerShell build-images.ps1 does not work anymore now with the .CSPROJ project files
OPTION 1:
The docker-compose.yml files tha tVS 2017 uses are already building the Docker Images as we now have the section like:
build:
context: ./src/Services/Basket/Basket.API
dockerfile: Dockerfile
So we might not need the original Power Shell script and we generate the Docker Images with:
docker-compose up --build

However, this option does not work with our current code. We might need to first build the .NET Core with dotnet build, etc. but that is missing.
A good option would be a simplified PowerShell and Bash files that first compile .NET code, then it just builds the Docker Images with docker-compose up --build .... Thoughts?

In any case, we need any viable approach for folks using just Docker CLI and .NET CLI and just an editor like VS Code.

OPTION 2:
If fixing this Power Shell Script:
There are wrong paths pointing to project.json files which should be pointing to .csproj pathfiles.

Also, and harder to fix, when trying to build a Docker image it throws and error related to the dockerfile line:
dockerfile:
COPY ${source:-obj/Docker/publish} .
Which is new format because of the format required by VS 2017.

When trying to generate a Docker Image with the CLI from a published .NET Core folder, it throws an error like it doesn't know/find "obj/Docker/publish" specified in that former line.
I tried to publish in folders like ".\src\Services\Identity\Identity.API\obj\Docker\publish", instead the older Pub folder, but still getting the same error...

Need to add additional Domain Logic to the "Order" Aggregate-Root

Need to add additional Domain Logic to this Aggregate-Root for scenarios related to Order state changes, stock availability validation, etc.

Current implementation of the Order Aggregate-Root is too simple in regards behavior.
Other than that, using DDD patterns makes no sense. An Order can have a lot more of complexity in Domain Logic..
Code:
https://github.com/dotnet/eShopOnContainers/blob/master/src/Services/Ordering/Ordering.Domain/Order.cs

The Order Aggregate-Root should have more sample domain logic, invariants and business rules validations so it makes sense to use the DDD Aggregate-Root pattern.

We actually just have the AddOrderItem(OrderItem item) method in here but with almost no domain logic or business validations.

I know that this is a simple example and not a real e-Commerce, but in this case, we need to show where to implement the business/domain logic --> in the Aggregate-Roots methods.

So, we need to add more domain logic here. It is actually too poor in regards domain logic.
For instance, you might get the same product item as multiple AddOrderItem(params) invocations. In this method, you could check that out and consolidate the same product items in a single OrderItem with several units (2, 3, 5, whatever the number of units), plus, if there are different amounts of discounts per prouct but the product Id is the same, you should apply the higher discount.., or any other domain logic to be applied.

Anyone reading this issue (Jimmy?), please, can you confirm the approach and suggest interesting domain rules/logic to add to the Order Aggregate-Root?

Is MapOrderItems(dynamic result) really needed in the Ordering Queries?

Looks like this method is only used to calculate the Order.Total and for that needs to go through all the Order Items..
Please, review. It might be possible to calculate the Order.Total in the SQL sentence itself without needing to have this method going through all the order items in a loop..
        private dynamic MapOrderItems(dynamic result)
        {
            dynamic order = new ExpandoObject();
            order.ordernumber = result[0].ordernumber;
            order.date = result[0].date;
            order.status = result[0].status;
            order.street = result[0].street;
            order.city = result[0].city;
            order.zipcode = result[0].zipcode;
            order.country = result[0].country;
            order.orderitems = new List();
            order.total = 0;
            foreach (dynamic item in result)
            {
                dynamic orderitem = new ExpandoObject();
                orderitem.productname = item.productname;
                orderitem.units = item.units;
                orderitem.unitprice = item.unitprice;
                orderitem.pictureurl = item.pictureurl;
                order.total += item.units * item.unitprice;
                order.orderitems.Add(orderitem);
            }
            return order;
        }

Then, the GetOrder() method is calling it right at the end.
public async Task GetOrder(int id)
{
using (var connection = new SqlConnection(_connectionString))
{
connection.Open();

            var result = await connection.QueryAsync<dynamic>(
               @"select o.[Id] as ordernumber,o.OrderDate as date, os.Name as status, 
                    oi.ProductName as productname, oi.Units as units, oi.UnitPrice as unitprice, oi.PictureUrl as pictureurl, 
					oa.Street as street, oa.City as city, oa.Country as country, oa.State as state, oa.ZipCode as zipcode
                    FROM ordering.Orders o
                    LEFT JOIN ordering.Orderitems oi ON o.Id = oi.orderid 
                    LEFT JOIN ordering.orderstatus os on o.StatusId = os.Id
					LEFT JOIN ordering.address oa on o.ShippingAddressId = oa.Id
                    WHERE o.Id=@id"
                    , new { id }
                );

            if (result.AsList().Count == 0)
                throw new KeyNotFoundException();

            return MapOrderItems(result);
        }
    }

Second time you create an order the app crashes

Using VS 2017 deployment.

  • First time you create an order, works ok.
  • Second time you create an order, then the app crashes with the following exceptions

An unhandled exception occurred while processing the request.
CurlException: Transferred a partial file
System.Net.Http.CurlHandler.ThrowIfCURLEError(CURLcode error)
IOException: The read operation failed, see inner exception.
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
HttpRequestException: Error while copying content to a stream.
System.Net.Http.HttpContent+d__48.MoveNext()
Stack Query Cookies Headers
CurlException: Transferred a partial file
System.Net.Http.CurlHandler.ThrowIfCURLEError(CURLcode error)
System.Net.Http.CurlHandler+MultiAgent.FinishRequest(StrongToWeakReference easyWrapper, CURLcode messageResult)

Show raw exception details
IOException: The read operation failed, see inner exception.
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult()
System.Net.Http.StreamToStreamCopy+d__3.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult()
System.Net.Http.HttpContent+d__48.MoveNext()

Show raw exception details
HttpRequestException: Error while copying content to a stream.
System.Net.Http.HttpContent+d__48.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult()
System.Net.Http.HttpClient+d__58.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.eShopOnContainers.WebMVC.Services.OrderingService+d__8.MoveNext() in D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebMVC\Services\OrderingService.cs
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.eShopOnContainers.WebMVC.Controllers.OrderController+d__5.MoveNext() in D:\GITREPOS\eShopOnContainers-vs2017\src\Web\WebMVC\Controllers\OrderController.cs
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+d__27.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+d__25.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+d__22.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ResourceExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+d__20.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Builder.RouterMiddleware+d__4.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+d__18.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+d__18.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+d__18.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+d__18.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware+d__7.MoveNext()

Firewall - PowerShell Script is failing

The current version of the PowerShell Script to set the rules in the local firewall needed for the STS container (Authentication) is failing with the errors below.

This is our PowerShell Script failing: add-firewall-docker.ps1 (At the Solution's root)

New-NetFirewallRule : The address is invalid. Addresses may be specified as IP addresses, ranges, or subnets. Also,
the following address keywords are allowed in certain places: LocalSubnet, DNS, DHCP, WINS, DefaultGateway, Internet,
Intranet, IntranetRemoteAccess, PlayToDevice. Keywords can be restricted to IPv4 or IPv6 by appending a 4 or 6.
At D:\GITREPOS\eShopOnContainers-vs2017\add-firewall-docker.ps1:24 char:3

  • New-NetFirewallRule -DisplayName EshopDocker -Confirm -Description ...
  • + CategoryInfo          : InvalidArgument: (MSFT_NetFirewallRule:root/standardcimv2/MSFT_NetFirewallRule) [New-Net
    

FirewallRule], CimException
+ FullyQualifiedErrorId : HRESULT 0x80070057,New-NetFirewallRule

New-NetFirewallRule : The address is invalid. Addresses may be specified as IP addresses, ranges, or subnets. Also,
the following address keywords are allowed in certain places: LocalSubnet, DNS, DHCP, WINS, DefaultGateway, Internet,
Intranet, IntranetRemoteAccess, PlayToDevice. Keywords can be restricted to IPv4 or IPv6 by appending a 4 or 6.
At D:\GITREPOS\eShopOnContainers-vs2017\add-firewall-docker.ps1:25 char:3

  • New-NetFirewallRule -DisplayName EshopDocker -Confirm -Description ...
  • + CategoryInfo          : InvalidArgument: (MSFT_NetFirewallRule:root/standardcimv2/MSFT_NetFirewallRule) [New-Net
    

FirewallRule], CimException
+ FullyQualifiedErrorId : HRESULT 0x80070057,New-NetFirewallRule

Review Foreign-Key ID properties in Aggregate-Root "Order"

Why do we have an ID per each child entity (or potential Value-Object like ShippingAddress) in the Order Aggregate-Root?
Especially about the ShippingAddressId, since the ShippingAddress should be converted to a Value-Object with no IDENTITY, we shouldn't do anything with its ID that should be a "PK Shadow state"...

    public class Order
        : Entity, IAggregateRoot
    {
        public int BuyerId { get; private set; }
        public Buyer Buyer { get; private set; }

        public DateTime OrderDate { get; private set; }
        public int StatusId { get; private set; }
        public OrderStatus Status { get; private set; }

        public ICollection OrderItems { get; private set; }
        public int? ShippingAddressId { get; private set; }
        public Address ShippingAddress { get; private set; }

        public int PaymentId { get; private set; }
        public Payment Payment { get; private set; }

        protected Order() { }
        public Order(int buyerId, int paymentId)
        {

Refactor CreateOrder() MVC Controller

Need to refactor. Our current implementation is:

    [Route("new")]
    [HttpPost]
    public async Task<IActionResult> CreateOrder([FromBody]CreateOrderCommand createOrderCommand)
    {
        if (createOrderCommand.CardTypeId == 0)
        {
            createOrderCommand.CardTypeId = 1;
        }
        createOrderCommand.BuyerIdentityGuid = _identityService.GetUserIdentity();

        var result = await _mediator.SendAsync(createOrderCommand);
        if (result)
        {
            return Ok();
        }
        return BadRequest();
    }
  1. We need to move the obtention of the identity to the CommandHandler, so the Command could be Immutable as we won't need to update the Identity into the Command object
    _identityService.GetUserIdentity();
    This issue is related to issue #36 - #36

  2. The validations of the command could be done based on a MediatR Decorator Pattern, instead of a control sentence within the controller. See:
    Validating Commands with the Decorator Pattern
    http://codeopinion.com/validating-commands/

So the final controller should look like this:

    [Route("new")]
    [HttpPost]
    public async Task<IActionResult> CreateOrder([FromBody]CreateOrderCommand createOrderCommand)
    {
        var result = await _mediator.SendAsync(createOrderCommand);
        if (result)
        {
            return Ok();
        }
        return BadRequest();
    }

Trigger Bower installation from .CSPROJ like we used to do from PROJECT.JSON

Related to #47 as the SPA is not properly being generated/published.
Before the .CSPROJ version for VS 2017, we used to trigger Bower installation from the project.json in the MVC project at the section 'prepublish":').
Please, this need to be migrated to .csproj now, for VS 2017 or dotnet CLI (dotnet build) and PowerShell Script images generation.

Consider to remove the IsTransient() from our Entity base class

Consider to remove the IsTransient() from our Entity base class:
First of all, we are not using the IsTransient() anywhere in the code except in the Entity base class itself.
Do we really need it because any constraint from Entity Framework Core?

But secondly and more importantly, the "IsTransient()" means that there is a possibility that the Entity still doesn't have an Identity.. That would mean that the entity is still "not valid".. That is against the DDD principle where any Domain Entity should be "always valid" since the moment it is validated (taking into account its invariants) and created with the constructor.
See: http://codebetter.com/gregyoung/2009/05/22/always-valid/

Thoughts?

Payment (PaymentMethod) is a child entity so it should NOT be used/created/added from CommandHandlers directly

A Payment (renamed to PaymentMethod, as it should be) is a child entity of the AGGREGATE Buyer, therefore it should be added only through the methods in the AGGREGATE-ROOT Buyer.
Currently we are adding PaymentMethods directly from the NewOrderCommandHandler() with methods like:
PaymentMethod GetExistingPaymentMethodOrAddANewOne(Buyer buyer, NewOrderCommand message)
{
PaymentMethod paymentMethod = PaymentMethodAlreadyExists(buyer, message);

        if (paymentMethod == null)
        {
            paymentMethod = CreatePaymentMethod(message);
            buyer.PaymentMethods.Add(paymentMethod);
        }

        return paymentMethod;

    }

That method is bad. It is creating a child entity from the Application Layer (CommandHandler), and then adding it to the PaymentMethods also from the CommandHandler.
The PaymentMethods should be handled ONLY from the methods in the AGGREGATE-ROOT which is the Buyer AGGREGATE ROOT class.

Please, review confirm and fix.

Implement Global Exception Handling using the ASP.NET Core Middleware

Implement Global Exception Handling using the Custom ASP.NET Core Middleware that will be used from all the eShopOncontainers microservices.
See info like :
“Global Exception Handling in ASP.NET Core Web API”:
http://www.talkingdotnet.com/global-exception-handling-in-aspnet-core-webapi/

http://stackoverflow.com/questions/38630076/asp-net-core-web-api-exception-handling

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/error-handling

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware

Lack of consistency in naming of some Projects in the solution

All the Client applications start with eShopOnContainers (Xamarin, web apps, etc.), like:

  • eShopOnContainers.Droid
  • eShopOnContainers.WebMVC
  • eShopOnContainers.WebSPA

The services (but one) are named right with their short name, like:

  • Ordering.API
  • Catalog.API
  • Basket.API
    This can be OK as client apps refer to the whole app (eShopOnContainers), but microservices are just part of the app context...

However, the Identity service is called as "eShopOnContainers.Identity".
That is not consistent with the rest of the services.
We should rename that service to: "Identity.API" so is aligned to the other services.

Need an Integration Container for easier build and Docker images creation

Another feature in the roadmap is to use an Integration Container based on an Image that has to have all the needed dependencies (like .NET SDK, Client Javascript frameworks, etc.).
That container will be the place where all the microservices will actually be compiled and where the custom Docker images will be created. This will greatly simplify the development setup (no need to make sure that your local dev machine has all the dependencies installed) plus this container could be re-used as "build/integration container" from a CI pipeline in VSTS or any other CI pipeline.
The plan is to have this feature in late February timeframe.

Scenario for Domain Events: Compare Basket Items price vs. Catalog-Product price when converting from Basket to Order

Compare Basket Items price vs. Catalog-Product price when converting from Basket to Order.
If the price changed in the Product from the Catalog, the Order has to have that new price reflected in the "Pre-Order page", but it has to also show a message saying "Warining, the original price was XXXX, but it has changed to XXXX since you added the product to your basket".
Implement this with Domain EVENTS starting when the basket is being converted to an Order.

NewOrderCommand is using a Child-Entity class - It shouldn't. Also change from new (adjective) to Create (verb) as part of the Command name

We must not re-use a child entity from within a CommandClass.
If needed, we should create another class, like OrderLineDTO or similar name used from within the CreateOrderCommand, but a Domain child-entity should not be part of a Command class because we are then able to create a child entity (OrderItem) from outside the Aggregate, in the CommandHandler's code, as it is implemented now.

The order.AddOrderItem() should NOT be like:
order.AddOrderItem(orderItem);

Because then you have created a child entity from the application layer, using it as a data-entity or simple DTO.

The order.AddOrderItem() should be like:
order.AddOrderItem(productName, pictureUrl, unitPrice, discount, units);

So all the the logic and validations are implemented within the Order Aggregate-Root. It is also cleaner as the OrderID will be taken from the parent or AggregateRoot, etc.

(Update: I already renamed this Command class to CreateOrderCommand).
Rename "NewOrderCommand" to "CreateOrderCommand". The Command is "to Create". "New" is not a verb but an adjective. A command should be a verb/action, not and adjective.

public class NewOrderCommand
:IAsyncRequest
{
private readonly List _orderItems;

Implement Order Status changes with a Command like UpdateOrderStatusCommand

This could be related to a SAGA implementation, too...
But it would be good to have another example of a simpler Command for just changing the OrderStatus
(To be discussed/confirmed for future sprints)

public class UpdateOrderStatusCommand
:IAsyncRequest
{
public string Status { get; set; }
public string OrderId { get; set; }
public string BuyerIdentityGuid { get; set; }
}

Are we using the NewOrderViewModel.cs and OrderItemViewModel.cs classes? - Confirm. If not used, delete it

Are we using the NewOrderViewModel.cs and OrderItemViewModel.cs classes?- Confirm. If not used, delete it.

When I search about it I just found the implementation and two functional tests using it.
But looks like the application is not using it. Am I right?

Find all "NewOrderViewModel", Find Results 1, Entire Solution, ""
D:\GITREPOS\eshoponcontainers-master\src\Services\Ordering\Ordering.API\Models\NewOrderViewModel.cs(6): public class NewOrderViewModel
D:\GITREPOS\eshoponcontainers-master\src\Services\Ordering\Ordering.API\Models\NewOrderViewModel.cs(28): public NewOrderViewModel()
D:\GITREPOS\eshoponcontainers-master\test\Services\FunctionalTests\Services\Ordering\OrderingScenarios.cs(67): var order = new NewOrderViewModel()
D:\GITREPOS\eshoponcontainers-master\test\Services\FunctionalTests\Services\Ordering\OrderingScenarios.cs(84): var order = new NewOrderViewModel()
Matching lines: 4 Matching files: 2 Total files searched: 904

Searching by OrderItemViewModel I just see the implementation..

Address within the Order entity should be a Value-Object instead of an Entity - Id for EF can be implemented as a shadow state primary key

The "Address" within the "Order" entity should be a Value-Object instead of an entity, because an Address has no identity within that context, therefore it shouldn't be an Entity but a Value-Object (or even a ComplexType in EF).
https://github.com/dotnet/eShopOnContainers/blob/master/src/Services/Ordering/Ordering.Domain/Address.cs
The issue is that in EF Core still doesn't support ComplexTypes like the traditional EF does.

Implement a base ValueObject type that is hiding the Id with a "Shadow Primary Key"
In EF Core we can "hide" the ID of the entity by using a Shadow state property that us part of the database model but does not have a corresponding property in the CLR Entity class.
See:
http://www.talkingdotnet.com/use-shadow-properties-entity-framework-core/
https://docs.microsoft.com/en-us/ef/core/modeling/shadow-properties

Value-Oject persisted in the same Order's table "a la" ComplexType.
If we want the VO group of fields to be persisted within the same Order table, we'll need to modify the relationship and make it 1:1 explicitly so by default is not 1:many and persisted in another table..

A Value-Oject should be IMMUTABLE throughout its life.
Solution: Put Setters as Private..
One problem in implementing true Immutable Value-Objects in .NET is serialization to be done by Entity Framework. These mechanisms require a parameterless constructor, so the true Immutability of the object is violated.
Here is a post on a possible approach to solve this problem:
https://christianarg.wordpress.com/2010/09/10/c-net-immutable-properties-for-entity-framework-serializable-classes-etc/

VO Comparison operator must be done by comparing fields/properties and/or using hashes..

Other interesting posts about Value-Objects and .NET:
https://www.codeproject.com/Articles/1046193/Value-Object-Design-Pattern-in-Csharp
http://elegantcode.com/2009/06/07/generic-value-object/
http://grabbagoft.blogspot.com/2007/06/generic-value-object-equality.html

Please, reply to this post if you have a good solution in regards this issue and EF Core.

Remove foreign key navigation properties from Aggregate-Root (No direct references across aggregate boundaries)

The Buyer is an Aggregate-Root. do we really need to show it as an object within the Order Aggregate-Root? - Can we just use the BuyerId here?

This issue is similar to the Payment (PaymentMethod) that also appears as an object within the Order.

public class Order
    : Entity, IAggregateRoot
{
    public int BuyerId { get; private set; }
    public Buyer Buyer { get; private set; }

If we maintain it as a reference through the EF graph..., how can we make clearer in the model that it is NOT a child entity but just a reference?

Review, confirm/fix.

Review/Refactor CreateOrderCommandHandler

Looks like this code has BUGs and is not consistent to a regular Ordering Business Domain:

  1. It is always Adding a new Buyer?, no matter if it was found or not in the database the following line is called:
    _buyerRepository.Add(buyer);
    Looks like that internally it might not be adding it because it adds it only if the entity is transient:
    if (buyer.IsTransient())
    {
    return _context.Buyers
    .Add(buyer)
    .Entity;
    }
    But in any case, it doesn't look good in the code. The Ubiquitous Language here is wrong. "Add" should means only Add"... and the validation should occur only in collateral cases.
    Or change the method name to _buyerRepository.AddIfNotExists(buyer); ...
    Might need to discuss this topic.

  2. We have a similar issue right after that, when adding the PaymentMethod to the Buyer.
    I think that it should be more explicit here. Internally, the buyer.AddPaymentMethod() is not adding it if the PayMentMethod Value-Object already exists in the DB, but I think it should be explicit in the Command Handler logic... Or change the method name to buyer.AddPaymentMethodIfNotExists()...
    Might need to discuss this topic.

  3. We might want to use Domain Events here in order to chain the two aggregates' transactions so this CommandHandler would update a single Aggregate, the Order Aggregate.

BELOW IS THE CURRENT CODE (Which I don't like much, needs to evolve):

public class CreateOrderCommandHandler
    : IAsyncRequestHandler<CreateOrderCommand, bool>
{
   //.......
    public async Task<bool> Handle(CreateOrderCommand message)
    {
        //find buyer/payment or add a new one buyer/payment 

        var buyer = await _buyerRepository.FindAsync(message.BuyerFullName);

        if (buyer == null)
        {
            buyer = new Buyer(message.BuyerFullName);
        }

        var payment = buyer.AddPaymentMethod(message.CardTypeId,
            $"Payment Method on {DateTime.UtcNow}",
            message.CardNumber,
            message.CardSecurityNumber,
            message.CardHolderName,
            message.CardExpiration);

        _buyerRepository.Add(buyer);

        await _buyerRepository.UnitOfWork
            .SaveChangesAsync();

        //create order for buyer and payment method

        var order = new Order(buyer.Id, payment.Id, new Address(message.Street, message.City, message.State, message.Country, message.ZipCode));

        foreach (var item in message.OrderItems)
        {
            order.AddOrderItem(item.ProductId, item.ProductName, item.UnitPrice, item.Discount, item.PictureUrl, item.Units);
        }

        _orderRepository.Add(order);

        var result = await _orderRepository.UnitOfWork
            .SaveChangesAsync();

        return result > 0;
    }

OrderStatus and other "enum types" are modeled as Entity in the Domain Model. Need to be modeled as Value-Object

OrderStatus and other "types" are implemented as Entities in the Domain Model. They needs to be modeled as a Value-Object. Here's the current OrderStatus class:
https://github.com/dotnet/eShopOnContainers/blob/master/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/OrderStatus.cs

A similar case happens with CardType, PaymentMethod.

This is a similar issue to the Address VO that is currently modeled as a regular Entity.
But in this case, these are simpler, but we don't want to have them as enum, neither.
See for further info:
https://lostechies.com/jimmybogard/2008/08/12/enumeration-classes/

Both need to be marked as ValueObject and in regards the Id needed by EF, we can hide it as a shadow state primery key.
See ISSUE #4 and let's solve it in a similar way?
#4

Implement a base ValueObject type that is hiding the Id with a "Shadow Primary Key"
In EF Core we can "hide" the ID of the entity by using a Shadow state property that us part of the database model but does not have a corresponding property in the CLR Entity class.
See:
http://www.talkingdotnet.com/use-shadow-properties-entity-framework-core/
https://docs.microsoft.com/en-us/ef/core/modeling/shadow-properties

Value-Oject persisted in the same Order's table "a la" ComplexType.
If we want the VO group of fields to be persisted within the same Order table, we'll need to modify the relationship and make it 1:1 explicitly so by default is not 1:many and persisted in another table..

A Value-Oject should be IMMUTABLE throughout its life.
Solution: Put Setters as Private..
One problem in implementing true Immutable Value-Objects in .NET is serialization to be done by Entity Framework. These mechanisms require a parameterless constructor, so the true Immutability of the object is violated.
Here is a post on a possible approach to solve this problem:
https://christianarg.wordpress.com/2010/09/10/c-net-immutable-properties-for-entity-framework-serializable-classes-etc/

VO Comparison operator must be done by comparing fields/properties and/or using hashes..

Other interesting posts about Value-Objects and .NET:
https://www.codeproject.com/Articles/1046193/Value-Object-Design-Pattern-in-Csharp
http://elegantcode.com/2009/06/07/generic-value-object/
http://grabbagoft.blogspot.com/2007/06/generic-value-object-equality.html

Please, reply to this post if you have a good solution in regards this issue and EF Core.

Use List<> and ToList().AsReadOnly() instead of HashSet<> and just .ToList() - In Simple Entity's collections

Still to be discusses and confirmed, but:
Instead of copying the list via ToList() we could use List<>.AsReadOnly() instead.
This will create a read only wrapper around the private List<>. It's much cheaper because it will not have to copy all items in a new collection. (Just one heap alloc for the wrapper instance). As an addition, the read only collection will reflect all changes made to the underlying collection.
But, I think it has to be a List<> internally. Other than that, I guess it'd need to convert/copy from HastSet<> to List<> with .ToList() first, so we wouldn't improve...

Let's use HashSet<> only if we really need performance when searching across many elements in the collection, which is not the case in the majority of our collection examples..
Let's chat about it and confirm.

Do not hold the ASP.NET Core Configuration object as Singleton in the IoC container

IMPORTANT: We we might not change this until we migrate to .NET 1.1, but we need to make sure what’s the right approach for storing the Configuration.

Current approach:
Storing the Configuration object as Singleton in the IoC container as in:
services.AddSingleton(Configuration);
can be a "bad smell" and not a recommended pattern we might want to encourage. It can be a security hole and a "too open" bag for everything. "Anyone" could read info from there..

Set the Configuration in Configure() like in services.Configure(Configuration) then you can populate "T" so see it from other places.
This approach allows to be more "intentional":
public void ConfigureServices(IServiceCollection services)
{
// Adds services required for using options.
services.AddOptions();
// Register the IConfiguration instance which MyOptions binds against.
services.Configure(Configuration);
...
Check the following related info:
Using Options and configuration objects:
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration#ioptionssnapshot

IMPORTANT: When migrating to .NET 1.1, use the IOptionsSnapshot
(Requires ASP.NET Core 1.1 or higher)

We need to change this configuration in all the Web API services and Web Apps that need to.

Windows Containers (NanoServer) is being tested - work in progress - Issues

[UPDATE] - We're doing tests but we're having issues with internal name resolution for communicating between eachother

Try this:

From: Sandeep Bansal
Please see if adding the following line to DockerFile solves the issue for you (we have a fix on the way for this):
RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord


Windows Containers is still not an implemented/tested scenario with eShopOnContainers.
Our plan is to implement it (using different base images with Windows Nanoserver) in February 2017 timeframe.

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.