ITInnovDesign
Latest Posts:

Apply Design Pattern in asp.net core project for beginner
Apply Design Pattern in asp.net core project for beginner

 

The complete sample code for this post can be found here from my github account

What is Design pattern?

Design patterns are high-level abstract solution templates. We can t hink of them as blueprints for solutions rather than the solutions themselves. You won’t find a framework that you can simply apply to your application; instead, you will typically arrive at design patterns through refactoring your code and
generalizing your problem.

The architect Christopher Alexander who introduced the idea of patterns in 1970 to build a common vocabulary for design discussion wrote:

The elements of this language are entities called patterns. Each pattern describes a problem that occurs over and over again in our environment and then describes the core of the solution to that problem in such a way that you can use this solution a million times over without ever doing it the same way twice

Patterns are essential to software design and development. They enable the expression of intent through a shared vocabulary when problem solving at the design stage as well as within the source code. Patterns promote the use of good object-oriented software design, as they are built around solid object-oriented design principles.

Patterns are an effective way to describe solutions to complex problems. With solid knowledge of design patterns, you can communicate quickly and easily with other members of a team without having to be concerned with the low-level implementation details.

Design patterns are all about the reuse of solutions. All problems are not equal, of course, but if you can break down a problem and find the similarities with problems that have been solved before, you can then apply those solutions. After many years of object-oriented programming, most of the problems you’ll encounter will have been solved countless times before, and there will be a pattern available to assist in your solution implementation. Even if you believe your problem to be unique, by breaking it down to its root
elements, you should be able to generalize it enough to find an appropriate solution.

Design patterns are no silver bullet. You have to fully understand your problem, generalize it, and then apply a pattern applicable to it. However, not all problems require a design pattern. It’s true that design patterns can help make complex problems simple, but they can also make simple problems complex.

Design Principles

Design principles form the foundations that design patterns are built upon. They are more fundamental than design patterns. When you follow proven design principles, your code base becomes infinitely more flexible and adaptable to change, as well as more maintainable. There are a number of common design principles that, like design patterns, have become best practice over the years and helped to form a foundation onto which enterprise-level and maintainable software can be built :

Keep It Simple Stupid (KISS) : An all-too-common issue in software programming is the need to overcomplicate a solution. The goal
of the KISS principle is concerned with the need to keep code simple but not simplistic, thus avoiding any unnecessary complexities.

Don’t Repeat Yourself (DRY): The DRY principle aims to avoiding repetition of any part of a system by abstracting out things that are common and placing those things in a single location. This principle is not only concerned with
code but any logic that is duplicated in a system; ultimately there should only be one representation for every piece of knowledge in a system.

Tell, Don’t Ask : The Tell, Don’t Ask principle is closely aligned with encapsulation and the assigning of responsibilities to their correct classes. The principle states that you should to tell objects what actions you want them to perform rather than asking questions about the state of the object and then making a decision yourself on what action you want to perform. This helps to align the responsibilities and avoid tight coupling between classes.

You Ain’t Gonna Need It (YAGNI) : The YAGNI principle refers to the need to only include functionality that is necessary for the application and put off any temptation to add other features that you may think you need. A design methodology that adheres to YAGNI is test-driven development (TDD). TDD is all about writing tests that prove the functionality of a system and then writing only the code to get the test to pass.

Separation of Concerns (SoC) : SoC is the process of dissecting a piece of software into distinct features that encapsulate unique behavior and data that can be used by other classes. Generally, a concern represents a feature or behavior of a class. The act of separating a program into discrete responsibilities significantly increases code reuse,
maintenance, and testability.

The S.O.L.I.D. Design Principles : The S.O.L.I.D. design principles are a collection of best practices for object-oriented design. All
of the Gang of Four design patterns adhere to these principles in one form or another. The term S.O.L.I.D. comes from the initial letter of each of the five principles that were collected in the book Agile Principles, Patterns, and Practices in C# by Robert C. Martin, or Uncle Bob to his friends.
Single Responsibility Principle (SRP) : The principle of SRP is closely aligned with SoC. It states that every object should only have one
reason to change and a single focus of responsibility. By adhering to this principle, you avoid the problem of monolithic class design that is the software equivalent of a Swiss army knife. By having concise objects, you again increase the readability and maintenance of a system.

O: Open-Closed Principle (OCP) : The OCP states that classes should be open for extension and closed for modification, in that you should be able to add new features and extend a class without changing its internal behavior. The
principle strives to avoid breaking the existing class and other classes that depend on it, which would create a ripple effect of bugs and errors throughout your application.

L: Liskov Substitution Principle (LSP) : The LSP dictates that you should be able to use any derived class in place of a parent class and have it
behave in the same manner without modification. This principle is in line with OCP in that it ensures that a derived class does not affect the behavior of a parent class, or, put another way, derived classes must be substitutable for their base classes.

I : Interface Segregation Principle (ISP): The ISP is all about splitting the methods of a contract into groups of responsibility and assigning
interfaces to these groups to prevent a client from needing to implement one large interface and a host of methods that they do not use. The purpose behind this is so that classes wanting to use the same interfaces only need to implement a specific set of methods as opposed to a monolithic interface of methods.

D: Dependency Inversion Principle (DIP) :The DIP is all about isolating your classes from concrete implementations and having them depend on
abstract classes or interfaces. It promotes the mantra of coding to an interface rather than an implementation, which increases flexibility within a system by ensuring you are not tightly coupled to one implementation. Closely linked to the DIP are the DI principle and the IOC principle. DI is the act of supplying a low level or dependent class via a constructor, method, or property. Used in conjunction with DI, these dependent classes can be inverted to interfaces or abstract classes that will lead to loosely coupled systems that are highly testable and easy to change.
In IoC, a system’s flow of control is inverted compared to procedural programming. An example of this is an IoC container, whose purpose is to inject services into client code without having the client code specifying the concrete implementation. The control in this instance that is being inverted is the act of the client obtaining the service, this is for example how asp.net core MVC IoC help us build our application around Interaface by supplying concrete class implementation at runtime.

How to Choose and Apply a Design Pattern

You can choose from many design patterns, so how do you identify which one is appropriate for your problem? To know which design pattern to use and how to apply the solution template to your specific problem, it’s important to understand these guidelines.
➤ You can’t apply patterns without knowing about them. The first important step is to expand your knowledge and study patterns and principles both in the abstract and concrete form. You can implement a pattern in many ways. The more you see different implementations of patterns, the more you will understand the intent of the pattern and how a single pattern can have varying implementations.
➤Do you need to introduce the complexity of a design pattern? It’s common for developers to try to use a pattern to solve every problem when they are studying patterns. You always need to weigh the upfront time needed to implement a pattern for the benefit that it’s going to give. Remember the KISS principle: Keep It Simple, Stupid.
➤Generalize your problem; identify the issues you’re facing in a more abstract manner. Look at how the intent of each pattern and principle is written, and see if your problem fits with the problem that a particular pattern or principle is trying to solve. Remember that design
patterns are high-level solutions; try to abstract your problem, and don’t focus too hard on the details of your specific issue.

➤Look at patterns of a similar nature and patterns in the same group. Just because you have used a pattern before doesn’t mean it will always be the correct pattern choice when solving a problem.
➤Encapsulate what varies. Look at what will likely change with your application. If you know that a special offer discount algorithm will change over time, look for a pattern that will help you change it without impacting the rest of your application.
After you have chosen a design pattern, ensure that you use the language of your pattern along with the language of the domain when naming the participants in a solution. For example, if you are using the strategy pattern to provide a solution for costing various shipping couriers,name them accordingly, such as FedExShippingCostStrategy. By using the pattern’s common vocabulary along with the language of your domain, you will immediately make your code more readable and understandable to other developers with patterns knowledge.

Let’s us now build a small e.commerce called“MyAspnetCoreAmazone” application for demonstration purpose where we will try to apply what have been said above, begining by SoC (speration of concerne) by layering our application.

This application will be backend with asp.net core web API and frontend with angular base on devextreme datagrid, so go ahead fire visual studio 2019 and create an “asp.net core web application”

Choose angular template

At this point you have a full asp.net core project with both client side application base on angular inside ClientApp folder and a solution to create a REST server side application. we will be use good practice here by organizing or application in SoC by layaring it. so go ahead and the following dotnet core class library project:

MyAspnetCoreAmazone.Model : contain Domain entities for our ecommerce.

MyAspnetCoreAmazone.Service : contains buisness logic of our application.

MyAspnetCoreAmazone.Repository : will contains classes use to make CRUD operations in our DB.

From the service project add a refence to mode and repository project, and from repository project add a reference to model project, and in the aps.net core angular/REST API project just reference Model, Repository and Service projects.. so you’ll have the following solution:

For this sample project, we will use Entity framework but not with a code first approach as I did in the project about DDD, we will use a code first from database approach as I’ll create my database first and generate the code first class from the undeline database.

on the left pane in visual studio, create a (localdb)MSSQLLocalDB(see the image bellow)

Add a new table in the created DB name “Products” as in the image bellow:

I have set the identity of the primaryKey ProductId like this from the right properties pane:

just name your table like Products and click on Update

the table is now created so go ahead and add some dummy data into the table:

Now that we have our DB ready, we will generate Entity framework class from tha DB .

Edit your Model project and add the following Nuget pakage (you can copy and past this xml our you can go to nuget pakage and add them one by one)

You should also do that for all the project in the solution (to avoid the error in the immage bellow).

open visual studio Pakage Manage console and fire the following command (set the the default project of the Mangae Console To MyAspnetCoreAmazone.Model)

Scaffold-DbContext “server=(localdb)MSSQLLocalDB;database=MyAspnetCoreAmazone;Persist Security Info=True” Microsoft.EntityFrameworkCore.SqlServer -Tables Products -force

After doing that you’ll have the Entity framework context class and Product Model create for you

Now our domain Model is ready so is time to add some logic to our application.

Our approach as you get from the project organization is based on domain model pattern : The Domain Model pattern is designed to organize complex business logic and relationships. The domain model will hold all
behavior and data related to the business of the simple e-commerce store that we are modeling.

We will apply the Strategy pattern and Factory Pattern to make discount inside our ecommerce application, the strategy pattern is being applied here because it enables algorithms to be selected and changed at runtime where Factory Pattern is beeing use to create object for us, in another word, his sole responsibility will be to return the matching discount strategy for a given CustomerType (The Factory pattern enables a class to delegate the responsibility of creating a valid object). we will add another entity called “Price” in our model project and modify our product table to reference it so go ahead and create another table called “Price ” from visual studio as follow

PriceId it’s primaryKey and it set to be identity field, go ahead and completely modify the created Products table so that it reference the Price Table like this

as you get from the image above, you have add PriceId as Foreign key inside Product Table so now we have to generate on more times all the change so go ahead from Mange Console and fire the following command:

Scaffold-DbContext “server=(localdb)MSSQLLocalDB;database=MyAspnetCoreAmazone;Persist Security Info=True” Microsoft.EntityFrameworkCore.SqlServer -Tables Products, Price -force

In our domain we now have two table Product and Price table so in the model project, add an c# interface “IDiscountStrategy” and insert the code bellow:

add two implementation of this interface “NullDiscountStrategy” and “TradeDiscountStrategy” as follow:

Create a DiscountFactory class that we will use to create our Discount

Now thta we have our discount strategy in place, let modify the geneate EF Price class so that we can apply our discount go ahead, open Price class in the model project and change it so it will lokk like the following code

As you can see from the code above, when it we would like to apply a discount for our product we will use this strategy pattern to do it at runtime delegating all work to the strategy.

The service layer will interact with a data store to retrieve products. We will use another pattern called Repository pattern to achieve this, but you will only specify the interface for the repository in the Model project because you don’t want the model project to be concerned with the specifics of what kind of data store will be used or what kind of technologies will be used to query it. Create a new interface named IProductRepository with the single method as shown here:

To be able to apply a given discount strategy to a collection of products in the service layer, go ahead and add another class called “ProductListExtensionMethods” as in the following snippet:

Remaining in the Model project, You can now create the service class that clients will use to interact with the domain, called it “ProductService

We have now completed all of the business logic that the application will contain. We can Notice how the business layer is not tied to a particular data store and uses interfaces to program against a repository for all of its persistence needs. The business layer can now be tested in complete isolation from any other part of the application and will also not be affected by changes to other layers. The next layer you will work on is the service layer, which will act as the gateway into the application.

The role of the service layer is to act as an entry point into the application; sometimes this is known as a facade. The service layer provides the presentation layer with a strongly typed view model, sometimes called the presentation model. A view model is a strongly typed class that is optimized for specifi c views.

For a client like angular frondend as we will see later inthis post to interact with the service layer, you will be using a Request/Response messaging pattern, . The request part will be supplied by the client and will carry all
necessary parameters; in this case, it will contain the CustomerType enumeration as defined in the domain model. Create a new class named ProductListRequest matching the code that follows:

Go ahead and create another class “ProductListResponse

To convert the Product entity into the ProductViewModel, we need a couple of methods (we can also use automapper but here I’ll manually mapped Product to ProductViewModel): so go ahead and create “ProductMapperExtensionMethods” whitin the service project as follow:

Finally, we need one more class we will called it ProductService that will interact with the domain model service to retrieve a list of products and then convert them to a list of ProductViewModels. Add a new class to the service project named ProductService, with the following definition

Now is time to focus of our repository project, so Move the generate “MyAspnetCoreAmazoneContext.cs” file wich contain the artifact to interact with our DB with Entity framework from the Model project to the Repository project also chanhe his namespace from MyAspnetCoreAmazone.Model to MyAspnetCoreAmazone.Repositoty

Now create a concrete repository class called “ProductRepository” inside repository project with the code bellow:

add two property with not mapped inside the Products class in Model project so that we can correct error(Remember that Design pattern it’s all to continue refactory our code to fit our logic)

we also have to refactory our ProductService class in Service project and Model Project, we wil begin to the ProductService clise inside the Model Project go ahead and open it inside visual studio, right click on the ProductService class and click “Quick Action and Refactorings” from context menu, select “extract interface” and clik OK this will create “IProductService” interface, also do the same thing for ProductService inside Service project.

Now we are ready to create our REST API so that from the angular side we can interact with our small ecommerce sample,.. so let’s move to the “MyAspnetCoreAmazone” Project and first modify the appsettings.json to add the databse connection

we can now open the startup class and registrate dependency injection to our ProductService class and repository as in the following line:

Now we need to add a new controller wich will be the gateway for our application, go ahead an create new controller call “MyAspnetCoreAmazoneController

At this point to test our Rest endpoint we can add swagger to our application via nuget or simply this line inisde .csproj

so modify your startup class so it will be looking like this one:

When testing REST API with swagger, i also set it as default route launchSettings.json file under properties so I can test it before initialize the client side.

But for this demonstration, I’ll go directly to client side to build the angular side, I’ll used devextreme angular DataGrid, follow this link to see how to integrate it in asp.net core angular application template.

Just opent package.json inside ClientApp folder and add this two line inside dependencies section

Open “ClientApp/angular.json” and modify it to include this two line in Styles section:

I sweet very well to work on client side in visual studio code, so open the ClientApp folder inside visual studio code, and from a new terminal, type:

npm install

Now it’s time to create all our client side part of the application, Angular like asp.net core REST API follow follow the classic MVC Pattern, so we will need model, a view and a component to host our datagrid, first let create “ProductListRequest” from angular side,

from the visual studio code terminal, type

ng g class ProductListRequest

inside the generate file ins

Create a typescript interface for ProductListResponse, ProductViewModel

ng g interface ProductListResponse

ng g interface ProductViewModel

Also change your configureService so that the AddControllers DI look like this (this modification have to be done inside visual studio and not visual studio code)

This will ensure that our server and client side will have the same naming convention for Request and Response object.

Now follwing the best practice we learn about SoC and layering our application, we should go ahead and create an angular service to use inside our component

create an angular service called “MyAspnetCoreAmazone

ng g service MyAspnetCoreAmazone

As you get, the organization of client side frontend look exactly like my server side so we can esealy track error. Now we need to regist this service inside app.module.ts by adding it to the providers array so the angular dependency injection will resolved it from our component:

Let’s now create our component (the Controller part in the word MVC)

ng g c MyAspnetCoreAmazone — module app.module

inside the typscript file insert the following code

and inside the html template wich is the V part of MVC pattern insert the following html code:

That all, the last thing we need to do before testing is to add an angular route to see our component so insert a new route inside the route array in app.module.ts

your app.Module should look like this:

modify the esisting NavMenuComponent html template generate by visual studio to add a link to our new component like this

Save all things inside visual studio code and turn back to visual studio an launch the project F5

If all go well you’ll see this initial screen

just click on “My Amazone ecommerce ” link to see your component… et voilà…

The goal here is was not to build a full CRUD angular/asp.net core REST api project but to show you how we can any time add somme Design pattern in our asp.net core solution, thank to the great book Professional Asp.net Design pattern , I know it’s from 2010 but design pattern is for every day and evry time so it remain a great book for me.

If you love this topic.. just share it.

You can found the source code for this demo inside my github account here


Author: admin
01.09.2022, 10:34
Category: Coding
Comments: 1
Views: 1099
-

Share

Comments (1)
admin
admin Administrator

This is a really good topic in design patter, hope to read other topic about design pattern from you. chear

01.09.2022, 14:24


Leave A Comment
processing...