Web Devs
641 subscribers
218 photos
22 videos
17 files
233 links
Articles, News, Jokes, Quotes, Back-End and UI/UX for web developers.
Github : https://github.com/fullStackDevsGroup
Advertising: @adsfullStackDevs
Download Telegram
Forwarded from Web Devs
Web Devs
Photo
#NewVersion
#ABluePersianDateTimePicker
توضیحات تکمیلی


نحوه استفاده از این picker به صورت زیر به صورت میلادی و شمسی می باشد . میتونید اچ تی ام ال این صفحه را مشاهده کنید و المنت های خودتونو به سادگی بسازید و به دلخواه css هارو تغییر دهید.
🔹 با اتریبوت زیر پلاگین فعال میشوند
data-abdatetimepicker="true"

🔹 با اتریبوت زیر روزهای قبل امروز غیر فعال میشوند

data-disablebeforetoday="true"

🔸 با اتریبوت زیر مشخص میکنید وقتی روی تاریخی انتخاب کردین مقدار کجا وارد شود

data-targetselector="[data-name='end-date']"

🔹 با اتریبوت زیر میتونید تعیین کنید با کدام ایونت روی المنت فعال شود مثل
data-trigger="click"

🔸 با اتریبوت زیر روزهای قبل امروز غیر فعال میشوند

data-disablebeforetoday="true"

🔹 با اتریبوت زیر میتوانید روزهای بعد از روز جاری را غیر فعال کنید:

data-disableaftertoday="true"

🔸 با اتریبوت زیر میتوانید تعیین کنید وقتی پلاگین باز میشود در کجای المنت باز شود مثلا وقتی میخوایین بالای المنت پلاگین باز شود :
data-Placement="top"

🔹 با اتریبوت زیر میتونید تاریخ میلادی را استفاده کنید

data-isgregorian="true"

🔸 با اتریبوت زیر میتونید ساعت دقیقه ثانیه رو نمایش ندید

data-enabletimepicker="true"

البته یه سمپل page زمانی که پکیج رو نصب کنید توی فولدر Static به نام SampleDateTime.html اضافه خواهد شد که شما میتونید سمپل تگ استفاده از این پلاگین رو ببینید.

✔️ ورژن جدید ریلیز شده :

Install-Package ABluePersianDateTimePicker -Version 1.0.5
dotnet add package ABluePersianDateTimePicker --version 1.0.5
<PackageReference Include="ABluePersianDateTimePicker" Version="1.0.5" />
paket add ABluePersianDateTimePicker --version 1.0.5

@fullStackDevs
#OAuth


در این پست می آموزیم که OAuth چیست.
درابتدا باید بدانیم که OAuth مخفف Open Authorization میباشد.
🔳 OAuth
یک پروتکل برای اهدای مجوز برای دسترسی به اطلاعات کاربر توسط اپلیکیشنی دیگر است.

🔸 این پروتکل ابتدا در سال 2007 معرفی شد و توسط توییتر استفاده شد و با توجه به استقبال و گستردگی ان در سال 2010 نسخه OAuth 2.0 توسط IEFT (جامعه بین المللی آزاد از طراحان شبکه ، اپراتورها ، فروشندگان و محققانی است که بر روی تدوین استانداردهای فنی برای اینترنت کار می کنند.) معرفی شد.

▪️ برای مثال ممکن است موقع ثبت نام در سایتی گزینه هایی همچون “login with Google” یا “login with Facebook” را دیده باشید که عملیات login را بسیار ساده میکند و با اعطای مجوز دسترسی به اطلاعاتتان به سایتی که میخواهید در آن حساب بسازید عملیات ورود و ساخت حساب را انجام میدهید.
سه اجزایی که در یک مکانیزم OAuth وجود دارند عبارتند از :
1️⃣ OAuth Provider,Resource Provider
سرویسی که با دریافت تاییدیه امکان استفاده از اطلاعات کاربر را به یک اپلیکیشن دیگر میدهد. مانند گوگل ، فیس بوک و... که بایستی پروتکل OAuth را پیاده سازی کرده باشد.
2️⃣ OAuth Client
وب سایت یا اپلیکیشنی که اجازه دسترسی به اطلاعاتمان را به آن میدهیم.
3️⃣ Resource Owner

شخصی که اطلاعات آن در اختیار Resource Provider است.
طی این فرایند شما با اعطای مجوز به OAuth Client و دریافت یک access token این امکان را به OAuth Client میدهید که به اطلاعات شما از طریق آن access token دسترسی داشته باشد .

@fullStackDevs
#OpenID


💡 What is Open ID?

در پست های قبل به OAuth پرداختیم و گفتیم که این پروتکل مختص به Authorization است و با ارائه یک توکن دسترسی اجازه استفاده از اطلاعات را میدهد و اپلیکیشن جانبی مان اطلاعاتی در مورد کاربر جاری که از این توکن استفاده میکند ،ندارد.

اما اپن آیدی پروتکلی برای authentication و تصدیق هویت میباشد این پروتکل لایه ای بر روی OAuth 2.0 میباشد .
با استفاده از این پروتکل، Token ID ای دریافت میکنید که JWT بوده و اپلیکیشن جانبی تان علاوه بر دسترسی از طریق این توکن اطلاعاتی هم درباره کاربر جاری دارد.
اپن آیدی اجازه استفاده از یک حساب(اکانت) برای چندین سایت بدون اینکه نیاز به تغییر رمز عبور داشته باشید میدهد.

💢 مراحل انجام کار

1. ارسال اطلاعات کلاینت به Identity Provider
2. دریافت این اطلاعات در سمت Identity Provider و شناسایی و لاگین کاربر
3. ارسال یک Access Token و یک ID Token (اگر کلاینت درخواست کند) از سمت identity Provider به کلاینت.
4. دریافت این توکن ها در سمت کلاینت و کلاینت میتواند با استفاده از Access Token درسمت Identity Provider برای دسترسی به اطلاعات api هایی رو صدا بزند و همچنین از ID Token برای بازیابی اطلاعات کاربر استفاده کند.

این پروتکل برای اولین بار در سال 2005 معرفی و پیاده سازی شد و نسخه بعدی آن که OpenID Connect نامیده میشود در فوریه 2014 ارئه گردید.


@fullStackDevs
نمونه ای از یک سیستم فروش بیمه ای بسیار ساده است که با استفاده از یک معماری Microservice ارائه شده است ، بعضی از تکنولوژی های استفاده شده :
▪️.NET Core 2.1
▪️Entity Framework Core
▪️MediatR
▪️JWT Tokens
▪️RawRabbit
▪️NHibernate
▪️Dapper
▪️SignalR
▪️DDD
▪️CQRS
...
🔲 Running with Docker
لینک سورس در گیت هاب

@fullStackDevs
#DesignPatterns

در مهندسی نرم افزار الگو های طراحی یک راه حل عمومیه تکرار پذیر برای حل یک مشکل رایج در هنگام طراحی نرم افزار می باشد.
به عبارتی الگو های طراحی یک راه کار نهایی که به طور مستقیم میتوان انرا به کد تبدیل کرد نیست بلکه توضیح یا قالبی است برای اینکه ، چطور میتوان مشکلی که به راه های متفاوت پدیدار میشود را حل کرد.
الگو های طراحی روند سرعت توسعه نرم افزار را با ارائه روش های تست شده افزایش میدهند.
یک طراحی موثر و تاثیر گذاری نیازمند مسائلی است که ممکن است تا زمان پیاده سازی قابل رویت نباشد .
استفاده از الگوهای طراحی باعث جلوگیری از مسائل جرئی که بروز مشکلاتی بزرگ را دربر دارد، میشوند.
استفاده از الگوهای طراحی باعث میشود که کد شما قابل انعطاف تر و نگهداری آن آسان تر و همچنین راحتر بتوان دوباره از ان استفاده کرد و هیچ لزومی ندارد که همیشه این الگوهای طراحی را در پروژه های خود استفاده کنید ،الگوهای طراحی برای توسعه پروژه منظور نمی شوند بلکه برای حل مسائل متداول در نظر گرفته شده اند.هر وقت که به آنها نیاز داشتید بایستی الگوی مناسبی برای جلوگیری از بروز چنین مشکلی در آینده پیاده سازی کنید برای تشخیص اینکه برای چه مشکلی از چه الگویی استفاده کنید فقط باید سعی کنید که الگو های طراحی و مهم تر از ان هدف از هر الگو را درک کنید
الگوهای طراحی براساس هدف هر الگو به سه دسته تقسیم میشوند.
🔹Behavioural
🔸Creational
🔹Structural

1️⃣ Creational
این نوع الگو ها در مورد نحوه نمونه سازی از کلاس ها میباشند و انها را میتوان به class-creation و object-creational دسته بندی کرد.این به این معنی است که در زمان انجام Job و پیاده سازی الگو برای دسترسی به ویژگی های یک کلاس یا میتوان از طریق ارث بری از ویژگی های ان استفاده کرد یا اینکه با ساخت یک نمونه از کلاس هدف به ویژگی های ان نیز دسترسی داشت.
الگو های Creational عبارتند از :
Factory Method, Abstract Factory, Builder, Singleton, Object Pool, Prototype

2️⃣ Structural
این نوع از الگوها مربوط به سازماندهی کلاس ها و اشیاء مختلف برای تشکیل ساختارهای بزرگتر و ارائه قابلیت های جدید است.
الگو های Structural عبارتند از :
Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Private Class Data, Proxy

3️⃣ Behavioral
این نوع از الگو ها در مورد شناسایی الگوهای ارتباطی مشترک بین اشیاء و تحقق این الگوهاست دروافع الگوهای رفتاری آن الگوهایی هستند که به طور خاص به ارتباط بین اشیاء مربوط می شوند.
الگو های Behavioral عبارتند از :
Command, Interpreter, Iterator, Mediator, Memento, Null Object, Observer, State, Strategy, Template method, Visitor

در ادامه نیز به بررسی این الگو ها میپردازیم.

💎 Acting out rather than speaking out became a pattern 💎


@fullStackDevs
👍1
#PersianDateTime
#CSharp
🔹 ساختار تاریخ شمسی با متد های تبدیل به تاریخ میلادی و یا هجری
🔸 متدهای مختلف برای بدست آوردن رشته های مختلف تاریخ شمسی با فرمت های متفاوت و اعداد فارسی
🔹 پشتیبانی از سال کبیسه
🔸 شبیه سازی کامل ساختار DateTime
.NetFramework 4.5

نصب پکیج :

Install-Package ABluePersianDateTime -Version 1.0.5
dotnet add package ABluePersianDateTime --version 1.0.5
paket add ABluePersianDateTime --version 1.0.5

@fullStackDevs
#EF_Core3
#FromSqlRaw
#ExecuteSqlRaw
🔹 بررسی تغییرجدیدی که از preview 4 بروی EF Core 3.0 اعمال شده است.
در نسخه های قبلی از این متد FromSql برای اجرای یک raw SQL query به صورت مستقیم استفاده میشد.
اما در نسخه جدید (3.0) از متد های

FromSqlRaw ، ExecuteSqlRaw ExecuteSqlRawAsync

برای اجرای یک raw SQL query که پارامتر های آن به صورت جدا در کوئری استرینگ مقدار دهی میشوند، استفاده میشوند.این متد ها جایگزین متد FromSql شده اند.

context.Products.FromSqlRaw(
"SELECT * FROM Products WHERE Name = {0}",
product.Name);

همچنین از متدهای

FromSqlInterpolated, ExecuteSqlInterpolated, ExecuteSqlInterpolatedAsync

برای اجرای یک raw SQL query استفاده میشوند با این تفاوت که در این متدها پارامتر های کوئری در مابین کوئری استرینگ و نه به صورت جدا مقداردهی میشوند.

context.Products.FromSqlInterpolated(
$"SELECT * FROM Products WHERE
Name = {product.Name}"
);

تغییر دیگری که در نسخه جدید اتفاق افتاده است محل صدا زدن این متد هاست. در نسخه های قبل تر از (3.0 )متد FromSql را در هر جای کوئری لینک خود میتوانستید صدا بزنید اما از در نسخه جدید متد های جایگزین شده را فقط مستقیما بروی DbSet<> می توانید صدا بزنید.
هدف از انجام این تغییر هم فقط برای جلوگیری از ابهام در کوئری، آن هم در سناریوهای خاص بوده است.

@fullStackDevs
در EF و همچنین Ef Core برای انجام Configuration هایی بروی Entity کلاس ها از Fluent API Configuration استفاده میکنیم و بایستی این Configuration ها را به ModelBuilder معرفی کنید. عموما میبینیم که برای انجام اینکار ، Extension Method ای مینویسند و با Reflection این کار را انجام میدهند اما خود Ef و Ef core متدی برای انجام اینکار دارد و اصلا نیازی به نوشتن Extension Method نیست .
این متد به عنوان پارامتر ورودی،اسمبلی ای که Configuration های شما در آن قرار دهد را دریافت میکند , پارامتر بعدی که میتوانید به این متد پاس دهید predicate ای برای اعمال Limitation هایی میباشد .با این متد میتوانید تمامیه Configuration هایی که باید به ModelBuilder افزوده شوند را Apply کنید.
#Value_Conversions
#EFCore

🧩 Value Conversions

این ویژگی در EF Core 2.1 اضافه شد.
ویژگی Value Conversion امکان تبدیل مقادیر پراپرتی ها به تایپ های مشخص در هنگام خواندن یا نوشتن در دیتابیس را میدهد.
این تبدیل میتواند از یک نوع به همان نوع یا از یک نوع به نوع دیگر باشد مانند تبدیل مقادیر enum به string و برعکس.
برای مثال برای ذخیره مقادیر enum بصورت string به شکل زیر میتوانیم عمل کنیم :

public class Rider
{
public int Id { get; set; }
public EquineBeast Mount { get; set; }
}

public enum EquineBeast
{
Donkey,
Mule,
Horse,
Unicorn
}
و سپس برای اینکه مقادیر این enum در دیتابیس به صورت string ذخیره شود ، به این صورت "Donkey", "Mule" بایستی Value Conversion ای بدین شکل تعریف کنیم .
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.Entity<Rider>()
.Property(e => e.Mount)
.HasConversion(
v => v.ToString(),
v => (EquineBeast)Enum.Parse(typeof(EquineBeast), v));
}

یا به عنوان مثال حتما تا کنون برای شما پیش آمده که در درون Entity Class خود برای یک پراپرتی از Complex type استفاده کرده باشد.
مثلا برای نگه داری مقدار پول به جای استفاده از type های decimal یا int ، از یک custom type که خود انرا تعریف کرده اید استفاده کرده باشید.

public class MyEntity
{
...
public Money salary { get; set; }
//Money is a class, actually it's my custom type
}
برای ذخیره چنین type هایی در دیتابیس و واکشی انها در قالب custom type مان، میتوانیم از ویژگی Value conversion کمک بگریم.
برای انجام اینکار بایستی برای پراپرتی salary (در مثال بالا) یک ValueConverter در متد OnModelCreating در Context بسازیم اینکار به دو صورت قابل انجام است .
روش اول
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<MyEntity>()
.Property(b => b.Salary )
.HasConversion(
v => JsonConvert.SerializeObject(v),
v => JsonConvert.DeserializeObject<Money>(v));
}
و روش دوم
var converter = new ValueConverter<Money, string>(
v => JsonConvert.SerializeObject(v),
v => JsonConvert.DeserializeObject<Money>(v));

modelBuilder
.Entity<MyEntity>()
.Property(e => e.Salary)
.HasConversion(converter);

✔️ توجه داشته باشد که برای ذخیره شی Money در دیتابیس و واکشی آن از دیتابیس در قالب یک Money روال سریالایز و دیسریالایز کردن آن به Json نیازمند است.

روش دوم برای مواردی که دو پراپرتی از یک value converter استفاده میکنند مناسب است.
*نکته مقادیر null به value converter پاس داده نمیشوند.
خود Ef Core نیز کلاس های value converter از پیش تعریف شده ای دارد که در فضای نام
Microsoft.EntityFrameworkCore.Storage.ValueConversion
وجود دارند .که لیستی ار آنها را در این لینک میتوانید ببینید.به همین خاطر EF Core با دارا بودن لیستی از این value converter بسیاری از تبدیلات نوع ها به نوع های دیگر در هنگام ذخیره مقادیر در دیتابیس را به صورت اتوماتیک انجام میدهد در واقع این امر زمانی مشخص میشود که DataBase Provider خود را مشخص و کانفیگ میکنید.
مثلا مثال enum بالا را میتوانید با value converter های خود ef core انجام دهید.

var converter = new EnumToStringConverter<EquineBeast>();

modelBuilder
.Entity<Rider>()
.Property(e => e.Mount)
.HasConversion(converter);

🎯 و نکته اخر اینکه
با مشخص کردن نوع یک پراپرتی به صورت صریح به کمک اتریبیوت
 [Column(TypeName = "TypeName")]
می توان همین کار را انجام داد و Ef Core متوجه میشود که باید مقدار این پراپرتی رو در هنگام ذخیره در دیتابیس به نوع مورد نظر تبدیل کند.
این ویژگی هنوز محدودیت هایی دارد برای مثال :
-مقادیر null نمیتوانند تبدیل شوند
-امکان اعمال یک value converter به صورت کلی برای دسته ای از پراپرتی ها نیست و باید به صورت تک به تک اعمال شوند.
-استفاده از value conversions ممکن است توانایی EF Core را برای ترجمه عبارات به SQL تحت تأثیر قرار دهد.


@fullStackDevs
#High_Performance
#EfCore_Best_Practice
#DbContext_pooling

🔸 در این پست به معرفی یک روش جدید Register کردن DbContext به Di Container در متد ConfigureServices در کلاس Startup می پردازیم.
ابتدایی ترین و ساده ترین روش که برای Register کردن custom DbContext خود به سیستم dependency injection استفاده میکنیم تا بعدا نمونه ای از custom DbContext خود به صورت constructor parameters و یا دیگر روش های دریافت Instance از DI، دریافت کنیم روش زیر است :
services.AddDbContext<
BloggingContext
>(options => options.UseSqlServer("ConnectionString"));

🔹 که Register کردن DbContext به این طریق به معنی ساختن یک instance جدید از DbContext برای هر Request میباشد که مطمئنا روال Instance سازی از DbContext هزینه هایی برای اپلیکیشن دارد.
در نسخه 2.0 از Ef Core روش جدید برای Register کردن DbContext به سیستم dependency injection معرفی شد که همانطور که در مثال بعدی خواهید به صورت شفاف مجموعه ای از موارد DbContext قابل استفاده مجدد را ارائه می دهد.

services.AddDbContextPool<BloggingContext>(
options => options.UseSqlServer(
ConnectionString
));

▪️ اگر از این متد برای Register کردن DbContext استفاده کنید زمانیه که در اپلیکیشن درخواست نمونه ای جدید از DbContext داده شود ابتدا در Context Pool چک میشود که ایا نمونه ای از DbContext وجود دارد و اگر نمونه ای وجو داشت،در اختیار درخواست دهنده قرار میدهد.
در نهایت هنگامی که Request پردازش شد و کار ان با نمونه دریافت شده DbContext تمام شد، Ef تمامیه State های قابل ردیابی DbContext را که از آنها آگاه هست را reset کرده و DbContext inctance دوباره به Context Pool بر میگردد.
این روال از نظر مفهومی شبیه connection pooling در Ado.net است و از مزیت های آن میتوان به کاهش هزینه ساخت DbContext instance اشاره کرد.
استفاده از این متد البته باعث محدودیت های اندکی در متد OnConfiguring() در DbContext میشود.

🔻 نکته بسیار مهم

نکته مهم این است که اگر به صورت Custom مکانیزمی را در derived DbContext class خود پیاده کرده باشید که باعث نگه داری state ای شود و از انجایی که Ef core فقط state هایی که از آنها اگاه هست را reset میکند پس در نتیجه state که شما به صورت custom ایجاد کرده اید در DbContext instance باقی میماند و باعث share شدن آن در بین درخواست ها میشود.


@fullStackDevs
#Scrutor

Assembly scanning and decoration extensions for Microsoft.Extensions.DependencyInjection
Scrutor is not a dependency injection (DI) container itself, instead it adds additional capabilities to the built-in container.
The library itself is pretty simple; it provides a single extension method, Scan, along with a fluent API to IServiceCollection that allows you to register "services" based on conventions. That's it!

Useful for lazy Developers😉

Package Manager Console

Install-Package Scrutor

.NET Core CLI

dotnet add package Scrutor

by Kristian Hellang

MoreDetail
Documentation
GitHub

@fullStackDevs
Web Devs
#PersianDateTime #CSharp 🔹 ساختار تاریخ شمسی با متد های تبدیل به تاریخ میلادی و یا هجری 🔸 متدهای مختلف برای بدست آوردن رشته های مختلف تاریخ شمسی با فرمت های متفاوت و اعداد فارسی 🔹 پشتیبانی از سال کبیسه 🔸 شبیه سازی کامل ساختار DateTime .NetFramework 4.5 نصب…
#PersianDateTime
#CSharp
🔹 ساختار تاریخ شمسی با متد های تبدیل به تاریخ میلادی و یا هجری


✔️ اضافه کردن اپراتور منها برای بدست آوردن تفاضل دو تاریخ
مثال:
  PersianDateTime datetime1 = new PersianDateTime(_dateTime);
PersianDateTime datetime2 = new PersianDateTime(_dateTime.AddDays(-10));
var timeSpan = datetime1 - datetime2;

.NetFramework 4.5

🔳 در پست بعدی تو این هفته compatible با NetCore هم توی ناگت برای استفاده قرار داده میشود.

نصب پکیج :

Install-Package ABluePersianDateTime -Version 1.0.7
dotnet add package ABluePersianDateTime --version 1.0.7
paket add ABluePersianDateTime --version 1.0.7


@fullStackDevs
#Kotlin
#FreeCourse
#DevelopingAndroidApps

دوره رایگان برنامه نویسی اندروید با زبان برنامه نویسی Kotlin منتشر شده توسط شرکت گوگل

https://www.udacity.com/course/developing-android-apps-with-kotlin--ud9012


https://t.me/fullStackDevs
#stackblitz

✔️در مرورگر شما
فقط با یک کلیک برنامه را کامل ایجاد ، ویرایش و استقرار کنید.

یه سایت خوب و کاربردی برای اینکه بتونید انلاین کدی رو چک کنید یا بتونید یه اپلیکیشنی به صورت سمپل درست کنید.
در واقع یه VS Code انلاین هستش که میتونید اپ های زیر را توسعه بدید:
🔹Angular
🔸React
🔹Ionic
🔸TypeScript
🔹RxJS
🔸Svelte

لینک سایت :
StackBlitz

@fullStackDevs
#Boxing
#UnBoxing

🧩 Boxing & unBoxing in C#

زبان برنامه نویسی سی شارپ دارای یک سیستم واحد نوع داده ای است. یعنی تمام دیتا تایپ ها در این زبان به صورت مستقیم یا غیر مستقیم از کلاس object ارث بری میکنندکه شامل value type ها و هم reference type ها میشود.
همانطور که میدانید متغیر های value type مستقیما دربردرانده دیتای خود هستند و دیتای آنها در حافظه stack ذخیره میشود. اما متغیر های reference type که به انها ابجکت گفته میشود، فقط reference ای از دیتای خود دارند و دیتای آن ها در حافظه managed heap ذخیره میشود.

زمانی که یک متغیر valute type را به یک متغیر reference type(آبجکت) اختصاص میدهید(assign) عمل Boxing اتفاق می افتد.
مثال :
int i = 24;
object ob = i;
یا
object ob1=21; 

در هر دو مثال بالا عمل Boxing اتفاق می افتد.
متغیر i که ار نوع integer است دارای مقدار 24 میباشد که در حافظه stack ذخیره شده است و در خط بعد این متغیر به یک object کپی شده است. یعنی آبجکت ob هم اکنون به یک مقدار integer اشاره میکند و هر دو متغیر شامل عدد 24 و به صورت مستقل از هم هستند و تغییر در یکی بر روی دیگری اثری نمیگذارد.
عمل Boxing در سی شارپ حافظه و زمان زیادی را مصرف میکند بدلیل اینکه به آبجکتی که به یک value type اشاره میکند باید مقدار حافظه ای در heap اختصاص داده شود و در مرحله بعد یک کپی از مقدار متغیر value type که در حافظه stack میباشد به حافظه ی heap اختصاص داده شده آن آبجکت، منتقل شود.

عمل unBoxing برعکس Boxing میباشد یعنی زمانی که یک متغیر از نو reference type (آبجکت) را سعی میکنید به یک متغیر از نوع value type تبدیل کنید.
در unBoxing مقدار متغیر reference type از حافظه heap به محل اختصاص داده شده متغیر value type در حافظه stack منتقل میشود . برخلاف عمل Boxing در unBoxing بایستی به صورت صریح این عمل casting را ذکر کنید.مثال :
int i = 24;
object ob = i; //Boxing
int j = (int) ob;//unBoxing

مقدرا اختصاص داده شده به متغییر ob از نوع integer باید دوباره به همان نوع (integer) به صورت صریح cast شود.
در واقع عملیات Boxing به صورت implicit و عملیات unBoxing به صورت explicit انجام میشود.
عملیات unBoxing نیز همانند Boxing حافظه و زمان زیادی مصرف میکند.

@fullStackDevs
🌀 Specification pattern: C# implementation

در این پست به معرفی الگوی Specification میپردازیم و یک مثال فوق العده کاربردی ارائه میدهیم که یک گام معماری و کدتان به Domain Driven Design و Clean Code نزدیکتر میکند.
*توضیحات تکمیلی : این پست را بهتر است با تلگرام دسکتاب و در سایز maximize مطالعه فرمایید.

🔸 یکی مزایای استفاده از این الگو را میتواند Encapsulation کردن اطلاعاتی که در مورد Domain میباشد دریک قسمت واحد بشمار آورد.
موارد استفاده از این الگو با ذکر یک مثال به طور کامل بیان شده است.

فرض کنید یکی از کلاس های دامین مدل ما کلاس Movie باشد که به صورت زیر تعریف شده است :

public class Movie : Entity
{
public string Name { get; }
public DateTime ReleaseDate{get;}
public MpaaRating MpaaRating {get;}
public string Genre { get; }
public double Rating { get; }
}

public enum MpaaRating
{
G,
PG13,
R
}
🔹 حالا فرض کنیم که کاربر فیلم های تازه ساخته شده را میخواهد تماشا کند. برای نمایش این فیلم ها به کاربر معمولا در Repository مربوطه متدی به شکل زیر تعریف میکنیم :

public class MovieRepository
{
public IReadOnlyList<Movie> GetByReleaseDate(DateTime minReleaseDate)
{
/* ... */
}
}
یا اگر به فیلم هایی براساس Rate یا Genre یا دیگر شاخص ها نیاز داشته باشیم بدین شکل معمولا متد های ریپازیتوری مان را تعریف میکنیم :
public class MovieRepository
{
public IReadOnlyList<Movie> GetByReleaseDate(DateTime maxReleaseDate) { }

public IReadOnlyList<Movie> GetByRating(double minRating) { }

public IReadOnlyList<Movie> GetByGenre(string genre) { }
}
🔸 ریپازیتوری قدری پیچیده میشود اگر پارامترهای جست و جوی ما پیچیده تر شوند مثلا اگر تمامیه فیلم هایی را که در تاریخ انتشار مشخص و با ژانر خاصی هستند نیاز داشته باشید معمولا دوباره به ازای آن یک متد در ریپازیتوری مربوطه تعریف میکنید.
برای نوشتن این متد روش های زیادی وجود دارد مانند اکستنشن متد،یا یک متدی که به صورت جداگانه این فیلتر ها را بروی Dbset<Movie> اعمال کند. اما این راه حل ها راهای درستی نیستند و از جمله معیاب آن میتوان به نقض کردن اصل DRY میباشد چون بایستی به ازای هر Dbset این متد ها را که حتی ممکن است logic های یکسانی داشته باشند ، تکرار کنید.
اکنون شاید با خود میگویید خب میتوانیم از یک متد Generic برای جلوگیری از این تکرار استفاده کنیم .
راه حل این مشکل استفاده از الگوی specification است . اما با یک پیاده سازی خاص .در این پست دو پیاده سازی از این الگو ارائه خواهییم داد.
پیاده سازی اول یک پیاده سازی ساده با عنوان Naive implementation است.و در ادامه به سمت بهتر کردن ان پیش میرویم.
اولین راه حل برای مقابله با مشکل بالا (ایجاد متد های متعدد برای شاخص های متعدد در جست و جو و مرتب سازی و..) استفاده از امکان expressions در سی شارپ است تا حدی زیادی آنها خودشان هم یک پیاده سازی از الگوی specification هستند. پس میتوانید یک متد در ریپازیتوری خود بنویسیدکه به عنوان پارامتر یک expression ورودی بگیرد مثال :
// Controller
public void SomeMethod()
{
Expression<Func<Movie, bool>> expression = m => m.MpaaRating == MpaaRating.G;
var movies = _repository.Find(expression); // Getting a list of movies
}
// Repository
public IReadOnlyList<Movie> Find(Expression<Func<Movie, bool>> expression)
{
return db
.Where(expression)
.ToList();
}
مشکلی که با این روش وجود دارد این است که با اینکه شروط مربوط به دامین مدل مان را در یک مکان واحد جمع اوری کردیم (در متغیر Expression) اما چنین متغیر هایی در این سطح (Controller) برای چنین اطلاعات مهمی اصلا مناسب نیستند.در این روش امکان دوباره استفاده از این شروط بسیار سخت میشود و حتی تمایل به duplicate در کل اپلیکیشن بشدت افزایش پیدا میکتد.و متاسفانه دوباره در نهایت به مشکل اول باز میگردیم.
حال نوبت به یک پیاده سازیه ساده از الگوی Specification تحت عنوان GenericSpecification میرسد.
public class GenericSpecification<T>
{
public Expression<Func<T , bool>> Expression { get; }

public GenericSpecification(Expression<Func<T , bool>> expression)
{
Expression = expression;
}
public bool IsSatisfiedBy(T entity)
{
return Expression.Compile().Invoke(entity);
}
}
نحوه استفاده از آن در پست بعدی ...

@fullStackDevs
ادامه پست قبل :
🌀 Specification pattern

نحوه استفاده از آن


// Controller
public void SomeMethod()
{
var specification = new GenericSpecification<Movie>(
m => m.MpaaRating == MpaaRating.G);
var movies = _repository.Find(specification); // Getting a list of movies
}

// Repository
public IReadOnlyList<Movie> Find(GenericSpecification<Movie> specification)
{
return db
.Where(specification.Expression)
.ToList();
}
🔹 اما در این روش هم باز همان مشکل قبل را داریم و کلاس جنریک specification در اینجا فقط به عنوان یک wrapper برروی expression قبلی مان عمل میکند پس نتیجه ای که میتوانیم بگیریم این است که GenericSpecification یک روش بد میباشد.چون فقط نقش یک Container را ایفا میکند که Client ها به اطلاعات خود را پاس میدهند و مشکل کپسوله سازی اطلاعات دامین مدل ها هنوز پا برجا و حل نشده باقی مانده است.

✔️ اما راهکار چیست؟

🔳 راه حل درست، استفاده از پیاده سازی ای از الگو specification تحت عنوان Strongly-typed specifications میباشد.
در این روش الگوی specification طوری پیاده سازی شده است که در آن اطلاعات دامین مدل نوشته شده و با کمترین امکان تغییر از خارج از کلاس پیاده سازی کننده پیاده سازی شده است. نحوه پیاده سازی :
public abstract class Specification<T>
{
public abstract Expression<Func<T , bool>> ToExpression();

public bool IsSatisfiedBy(T entity)
{
Func<T , bool> predicate = ToExpression().Compile();
return predicate(entity);
}
}
public class MpaaRatingAtMostSpecification : Specification<Movie>
{
private readonly MpaaRating_rating;

public MpaaRatingAtMostSpecification(MpaaRating rating)
{
_rating = rating;
}
public override Expression<Func<Movie, bool>> ToExpression()
{
return movie => movie.MpaaRating <= _rating;
}
}
// Controller
public void SomeMethod()
{
var gRating = new MpaaRatingAtMostSpecification(MpaaRating.G);
IReadOnlyList<Movie> movies = repository.Find(gRating); // Getting a list of movies
}
// Repository
public IReadOnlyList<T> Find(Specification<T> specification)
{

return db.Where(specification.ToExpression()).ToList();
}
}
🔸 در این روش باید به ازای هر شاخص یا عملگری که میخواهید به عنوان یک فیلتر بر روی DbSet انجام شود،باید کلاسی تعریف کنید که از ابستراکت کلاس Specification<T> ارث بری کرده و متد ToExpression() انرا override و پیاده سازی کند. مثلا در مثال بالا ما به ازای شاخص MpaaRating که یک enum در کلاس Movie بود .یک کلاس با نام MpaaRatingAtMostSpecification ایجاد کردیم که از ابستراکت کلاس Specification<T> ارث بری کرده و با override کردن ToExpression() و پیاده سازی آن به صورت :
public override Expression<Func<Movie, bool>> ToExpression()
{
return movie => movie.MpaaRating <= _rating;
}
شرط خود را نوشته و در سطح کنترلر اگر نیاز به فیلتر Movie ها بر اساس شاخص MpaaRating داشتیم با نمونه سازی از این کلاس به صورت :
var gRating = new MpaaRatingAtMostSpecification(MpaaRating.G);
IReadOnlyList<Movie> movies = repository.Find(gRating); // Getting a list of movies
و پاس دادن آن به متد Find ریپازیتوری خودمان :
// Repository
public IReadOnlyList<T> Find(Specification<T> specification)
{
return db.Where(specification.ToExpression())
.ToList();
}
آنرا بر روی Dbset<Movie> اعمال کنیم.پس اگر قرار باشد فیلتری براساس شاخص یا عملگر دیگری اعمال کنید باید یک کلاس جدیدبسازید که از ابستراکت کلاس Specification<T> ارث بری میکند و با پیاده سازی متد ToExpression() شرط مورد نظر خود بنویسید.


لینک مطلب


@fullStackDevs