A simple yet organized project template for building ASP.NET Core APIs in .NET Core 3.1
Tools and Frameworks Used
- .NET Core 3.1
- ASP.NET Core - For building RESTful APIs
- Dapper - For data access.
- AutoMapper - For mapping entity models to DTOs.
- AutoWrapper - For handling request Exceptions and consistent HTTP response format.
- AutoWrapper.Server - For unwrapping the Result attribute from AutoWrapper's ApiResponse output.
- Swashbuckle.AspNetCore - For securing API documentation.
- FluentValidation.AspNetCore - For Model validations
- Serilog.AspNetCore - For logging capabilities
- IdentityServer4.AccessTokenValidation - For JWT Authentication handling
- Microsoft.Extensions.Http.Polly - For handling HttpClient Resilience and Transient fault-handling
- AspNetCoreRateLimit - For controlling the rate of requests that clients can make to an external API based on IP address or client ID.
- AspNetCore.Diagnostics.HealthChecks - For performing health checks
- Microsoft.AspNetCore.Diagnostics.HealthChecks - For getting the results of Health Checks in the application
- AspNetCore.HealthChecks.UI - For Health Status visualization
- xUnit and Moq - For unit testing.
کتابخانه Scroll to Style
scrollToStyle is a versatile tool that lets you manage CSS properties of elements using the page scroll.
You will be able to compel the elements move, change their size, color, opacity, background and many other properties.
Features:
- Management absolutely all the properties of a numeric value
- Browser Support depends only on selected properties
- It manages multiple properties of the same element
- Management fractional property values and control the number of decimal places
- Fixing of the screen during an animation
- Animation range control
Performance of your ASP.NET web application is important. There is a lot of evidence to suggest that slow loading times and clunky interaction, will drive customers elsewhere. Even in the case of internal applications where the users have no option but to use the application, their satisfaction is tightly coupled to speed.
There are a ton of ways to improve the performance of a website, let's look at fifteen of them.
<span class='button goodDetail' id='123' >جزییات کالا</span>
$('.goodDetail').click(function(){ //add to hash data that you need to make the AJAX request later $(window).location.hash = $(this).attr('id'); $.ajax({ type: "POST", url: 'some url', dataType: "html", data:'GoodId='+$(this).attr('id'), success: function(html) { //do something } }) })
$(document).ready(function(){ if ($(window).location.hash.length)) { //we will use $(window).location.hash.replace('#','') in the "data" section of the AJAX request $.ajax({ type: "POST", url: current_url, dataType: "html", data:'GoodId='+$(window).location.hash.replace('#',''), success: function(html) { //do something } }) } });
البته Angular به همراه دایرکتیو ویژهای به نام ngModel است که two-way data binding را با import ماژول ویژهی فرمها میسر میکند:
که آن نیز در اصل از جمع Property Binding و Event Binding تشکیل شدهاست:
<input [ngModel]="username" (ngModelChange)="username = $event">
<input [(ngModel)]='username' />
انقیاد به خواص یا Property binding
فرض کنید دو کامپوننت والد و فرزند را ایجاد کردهایم:
در کامپوننت والد، مقداری را توسط متد deposit هربار 100 آیتم افزایش میدهیم:
import { Component, OnInit } from "@angular/core"; @Component({ selector: "app-parent", templateUrl: "./parent.component.html", styleUrls: ["./parent.component.css"] }) export class ParentComponent implements OnInit { amount = 500; constructor() { } ngOnInit() { } deposit() { this.amount += 100; } }
<h2>Custom two way data binding</h2> <div class="panel panel-primary"> <div class="panel-heading"> <h2 class="panel-title">Parnet Component</h2> </div> <div class="panel-body"> <label>Available amount:</label> {{amount}} <button (click)="deposit()" class="btn btn-success">Deposit 100</button> <div> <app-child [amount]="amount"> </app-child> </div> </div> </div>
کامپوننت فرزند به صورت ذیل تعریف میشود:
import { Component, OnInit, Input } from "@angular/core"; @Component({ selector: "app-child", templateUrl: "./child.component.html", styleUrls: ["./child.component.css"] }) export class ChildComponent implements OnInit { @Input() amount: number; constructor() { } ngOnInit() { } withdraw() { this.amount -= 100; } }
با این قالب:
<div class="panel panel-default"> <div class="panel-heading"> <h2 class="panel-title">Child Component</h2> </div> <div class="panel-body"> <label>Amount available: </label> {{amount}} <button (click)="withdraw()" class="btn btn-danger">Withdraw 100</button> </div> </div>
در اینجا زمانیکه data binding را به صورت ذیل تعریف میکنیم:
<app-child [amount]="amount"> </app-child>
این ارتباط نیز یک طرفهاست. برای مثال اگر بر روی دکمهی Deposit والد کلیک کنیم:
مقدار افزایش یافتهی در والد، به فرزند نیز منتقل میشود و نمایش داده خواهد شد. اما اگر بر روی دکمهی withdraw فرزند کلیک کنیم:
تغییر صورت گرفته، به والد انعکاس پیدا نمیکند. برای اطلاع رسانی به والد، به انقیاد به رخدادها نیاز داریم.
انقیاد به رخدادها یا Event binding
یک کامپوننت میتواند به رخدادهای صادر شدهی توسط کامپوننتی دیگر گوش فرا دهد:
import { Component, OnInit, Input, Output, EventEmitter } from "@angular/core"; @Component({ selector: "app-child", templateUrl: "./child.component.html", styleUrls: ["./child.component.css"] }) export class ChildComponent implements OnInit { @Input() amount: number; @Output() amountChange = new EventEmitter(); constructor() { } ngOnInit() { } withdraw() { this.amount -= 100; this.amountChange.emit(this.amount); } }
اکنون در قالب کامپوننت والد، این رخداد را درون یک () معرفی خواهیم کرد:
<app-child [amount]="amount" (amountChange)="this.amount= $event"> </app-child>
اکنون اگر برنامه را آزمایش کنیم، با کلیک بر روی دکمهی withdraw فرزند، مقدار کاهش یافته به والد نیز منعکس میشود:
پیاده سازی syntax ویژهی Banana in a box
تا اینجا پیاده سازی two way data-binding سفارشی به پایان میرسد. اما تعریف طولانی:
<app-child [amount]="amount" (amountChange)="this.amount= $event"> </app-child>
<app-child [(amount)]="amount"> </app-child>
نکتهی ویژهی آن، وجود پسوند Change در نام رخداد تعریف شدهاست:
@Input() amount: number; @Output() amountChange = new EventEmitter();
بنابراین به صورت خلاصه جهت تعریف یک انقیاد دو طرفه سفارشی:
- ابتدا باید انقیاد به یک خاصیت ورودی x را تعریف کرد.
- سپس نیاز است انقیاد به یک رخداد خروجی همنام، که نام آن، پسوند Change را اضافهتر دارد، یعنی xChange را تعریف کرد.
- اکنون میتوان two-way data binding syntax ویژهای را به نام banana in a box بر روی ایندو تعریف کرد[(x)].
کدهای کامل این مطلب را از اینجا میتوانید دریافت کنید.
A high-performance second-level query cache for EF Core. Nuget Package
Using Example
dbContext.Books .Include(d => d.Pages).ThenInclude(d => d.Lines).Where(d => d.ID == 200) .Cacheable(TimeSpan.FromSeconds(60))
Performance Test
Cacheable vs DataBase
Average database query duration [+00:00:00.0026076]. Average cache query duration [+00:00:00.0000411]. Cached queries are x63 times faster.
Cacheable vs In-MemoryAverage database query duration [+00:00:00.1698972]. Average cache query duration [+00:00:00.0000650]. Cached queries are x2,611 times faster.
Right click on the folder -> Properties -> Security tab -> Click at Edit button -> Enter `IIS AppPool\DefaultAppPool` user (IIS AppPool\<app_pool_name>) -> Click at Check names -> OK -> Then give it `read & execute` or other permissions.
6 نکته برای کدنویسی بهتر سی شارپ
Domain Driven Design: The Good Parts
The greenfield project started out so promising. Instead of devolving into big ball of mud, the team decided to apply domain-driven design principles. Ubiquitous language, proper boundaries, encapsulation, it all made sense.
But along the way, something went completely and utterly wrong. It started with arguments on the proper way of implementing aggregates and entities. Arguments began over project and folder structure. Someone read a blog post that repositories are evil, and ORMs the devil incarnate. Another read that relational databases are last century, we need to store everything as a stream of events. Then came the actor model and frameworks that sounded like someone clearing their throat. Instead of a nice, clean architecture, the team chased the next new approach without ever actually shipping anything.
Beyond the endless technical arguments it causes, domain-driven design can actually produce great software. We have to look past the hype into the true value of DDD, what it can bring to our organizations and how it can enable us to build quality systems. With the advent of microservices, DDD is more important than ever - but only if we can get to the good parts.