10 Framework CSS که باید بشناسیم
روش نصب NET SDK. بر روی لینوکس Ubuntu
برای نصب از طریق دانلود فایل های دات نت به صورت آفلاین بر روی سرور بدون اینترنت میتوانید از روش زیر هم استفاده کنید.
- ابتدا فایل های دات نت رو بسته به معماری سیستم دانلود کنید. (Arm32 | Arm32 Alpine | Arm64 | Arm64 Alpine | x64 | x64 Alpine)
- سپس فایل دات نت رو به سرور خود منتقل کنید و از طریق دستورات زیر، خط فرمان dotnet رو به ترمینال اضافه کنید:
export DOTNET_ROOT="$HOME/yourpath/dotnet" export PATH="$PATH:$HOME/yourpath/dotnet"
مشابه با Edit the system environment variables در ویندوز
و اکنون با نوشتن دستور dotnet --version میتوانید نگارش ورژن دات رو مشاهده کنید.
همچنین اگر نیاز به نصب tools هایی مانند ef core نیاز دارید میتوانید از دستور زیر استفاده کنید:
dotnet tool install --global dotnet-ef export PATH="$PATH:$HOME/.dotnet/tools"
این روش در خود مستندات مایکروسافت توضیح داده شده اما استفاده از پکیج های داخلی ابونتو و یا اجرای اسکریپت ها خیلی آسون تر هستش و این روش صرفا موقعی استفاده میشه که امکان اجرای دستورات بر روی یک سیستم آفلاین وجود ندارد.
در بعضی از مواقع ممکن است که در هنگام استفاده از اصل تزریق وابستگیها، با یک مشکل روبرو شویم و آن این است که اگر از کلاسی استفاده میکنیم که به سورس آن دسترسی نداریم، نمیتوانیم برای آن یک Interface تهیه کنیم و اصل (Depend on abstractions, not on concretions) از بین میرود، حال چه باید کرد.
برای اینکه موضوع تزریق وابستگیها (DI) به صورت کامل در قسمتهای دیگر سایت توضیح داده شده است، دوباره آن را برای شما بازگو نمیکنیم .
لطفا به کدهای ذیل توجه کنید:
کد بدون تزریق وابستگیها
به سازنده کلاس ProductService و تهیه یک نمونه جدید از وابستگی مورد نیاز آن دقت نمائید:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web; namespace ASPPatterns.Chap2.Service { public class Product { } public class ProductRepository { public IList<Product> GetAllProductsIn(int categoryId) { IList<Product> products = new List<Product>(); // Database operation to populate products … return products; } } public class ProductService { private ProductRepository _productRepository; public ProductService() { _productRepository = new ProductRepository(); } public IList<Product> GetAllProductsIn(int categoryId) { IList<Product> products; string storageKey = string.Format("products_in_category_id_{0}", categoryId); products = (List<Product>)HttpContext.Current.Cache.Get(storageKey); if (products == null) { products = _productRepository.GetAllProductsIn(categoryId); HttpContext.Current.Cache.Insert(storageKey, products); } return products; } } }
using System; using System.Collections.Generic; namespace ASPPatterns.Chap2.Service { public interface IProductRepository { IList<Product> GetAllProductsIn(int categoryId); } public class ProductRepository : IProductRepository { public IList<Product> GetAllProductsIn(int categoryId) { IList<Product> products = new List<Product>(); // Database operation to populate products … return products; } } public class ProductService { private IProductRepository _productRepository; public ProductService(IProductRepository productRepository) { _productRepository = productRepository; } public IList<Product> GetAllProductsIn(int categoryId) { //… } } }
اما از این جهت که شما دسترسی به سورس Http context class را ندارید، نمیتوانید به سادگی یک Interface را برای آن ایجاد کنید و سپس یک تزریق وابستگی را مانند کلاس ProductRepository برای آن تهیه نمائید.
خوشبختانه این مشکل قبلا حل شده است و الگویی که به ما جهت پیاده سازی آن کمک کند، وجود دارد و آن الگوی آداپتر (Adapter Pattern) میباشد.
این الگو عمدتا برای ایجاد یک Interface از یک کلاس به صورت یک Interface سازگار و قابل استفاده میباشد. بنابراین میتوانیم این الگو را برای تبدیل HTTP Context caching API به یک API سازگار و قابل استفاده به کار ببریم.
در ادامه میتوان Interface سازگار جدید را در داخل productservice که از اصل تزریق وابستگیها (DI ) استفاده میکند تزریق کنیم.
یک اینترفیس جدید را با نام ICacheStorage به صورت ذیل ایجاد میکنیم:
public interface ICacheStorage { void Remove(string key); void Store(string key, object data); T Retrieve<T>(string key); }
public class ProductService { private IProductRepository _productRepository; private ICacheStorage _cacheStorage; public ProductService(IProductRepository productRepository, ICacheStorage cacheStorage) { _productRepository = productRepository; _cacheStorage = cacheStorage; } public IList<Product> GetAllProductsIn(int categoryId) { IList<Product> products; string storageKey = string.Format("products_in_category_id_{0}", categoryId); products = _cacheStorage.Retrieve<List<Product>>(storageKey); if (products == null) { products = _productRepository.GetAllProductsIn(categoryId); _cacheStorage.Store(storageKey, products); } return products; } }
پس چگونه الگوی Adapter میتواند به ما کمک کند تا از این مشکل خارج شویم؟
هدف این الگو به صورت ذیل در GOF مشخص شده است .«تبدیل Interface از یک کلاس به یک Interface مورد انتظار Client»
تصویر ذیل، مدل این الگو را به کمک UML نشان میدهد:
همانطور که در این تصویر ملاحظه میکنید، یک Client ارجاعی به یک Abstraction در تصویر (Target) دارد (ICacheStorage در کد نوشته شده). کلاس Adapter اجرای Target را بر عهده دارد و به سادگی متدهای Interface را نمایندگی میکند. در اینجا کلاس Adapter، یک نمونه از کلاس Adaptee را استفاده میکند و در هنگام اجرای قراردادهای Target، از این نمونه استفاده خواهد کرد.
در شکل ملاحظه مینمایید که یک کلاس جدید با نام HttpContextCacheAdapter مورد نیاز است. این کلاس یک کلاس روکش (محصور کننده یا Wrapper) برای متدهای HTTP Context cache است. برای اجرای الگوی Adapter کلاس HttpContextCacheAdapter را به شکل ذیل ایجاد میکنیم:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web; namespace ASPPatterns.Chap2.Service { public class HttpContextCacheAdapter : ICacheStorage { public void Remove(string key) { HttpContext.Current.Cache.Remove(key); } public void Store(string key, object data) { HttpContext.Current.Cache.Insert(key, data); } public T Retrieve<T>(string key) { T itemStored = (T)HttpContext.Current.Cache.Get(key); if (itemStored == null) itemStored = default(T); return itemStored; } } }
منبع : Professional Asp.Net Design Pattern
Security Advisory Notice for 16.6.2
CVE-2020-1108 / CVE-2020-1108.NET Core Denial of Service Vulnerability
To comprehensively address CVE-2020-1108, Microsoft has released updates for .NET Core 2.1 and .NET Core 3.1. Customers who use any of these versions of .NET Core should install the latest version of .NET Core. See the Release Notes for the latest version numbers and instructions for updating .NET Core.
CVE-2020-1202 / CVE-2020-1203 Diagnostics Hub Standard Collector Service Elevation of Privilege Vulnerability
An elevation of privilege vulnerability exists when the Diagnostics Hub Standard Collector or the Visual Studio Standard Collector fails to properly handle objects in memory.
CVE-2020-1293 / CVE-2020-1278 / CVE-2020-1257 Diagnostics Hub Standard Collector Service Elevation of Privilege Vulnerability
An elevation of privilege vulnerability exists when the Diagnostics Hub Standard Collector Service improperly handles file operations
Top Issues Fixed in Visual Studio 2019 version 16.6.2
- Visual Studio 2019 16.60 hang at run or build when modified not saved in C++/CLI project
- An unhandled exception of type 'System.NullReferenceException' occurred in Microsoft.VisualStudio.DesignTools.WpfTap.dll
- Recurring null reference when reopening documents
- "Create new project" dialog search does not find templates for third-party language providers
- IntelliSense shows that "tilde-slash" (~/) points to ASP .NET Core 3.1 project root instread of wwwroot subfolder after upgrading Visual Studio Enterprise 16.5.6->16.6.0
- Fixed a compiler error (error C2475: redefinition; 'constexpr' specifier mismatch) affecting std::atomic when compiled as C++/CX in C++17 mode.
- URL completion values and format was fixed in Razor views. App-relative URL format is now used again and the values in the URL completion list show files and folders rooted under app root, i.e. wwwroot.
- Fixed a crash when using snippets.
- Restore item templates that could be hidden by extensions.
تدارک یک آزمایش برای بررسی میزان افزایش کارآیی متدهای LINQ در دات نت 7
در ادامه یک آزمایش سادهی بررسی کارآیی متدهای Enumerable.Max, Enumerable.Min, Enumerable.Average, Enumerable.Sum را با استفاده از کتابخانهی معروف BenchmarkDotNet مشاهده میکنید:
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Running; using System.Collections.Generic; using System.Linq; [MemoryDiagnoser(displayGenColumns: false)] public partial class Program { static void Main(string[] args) => BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); [Params (10, 10000)] public int Size { get; set; } private IEnumerable<int> items; [GlobalSetup] public void Setup() { items = Enumerable.Range(1, Size).ToArray(); } [Benchmark] public int Min() => items.Min(); [Benchmark] public int Max() => items.Max(); [Benchmark] public double Average() => items.Average(); [Benchmark] public int Sum() => items.Sum(); }
در مورد کار با آرایهها:
- زمان اجرای یافتن Min در آرایههای کوچک، در دات نت 7، نسبت به دات نت 6، حدودا 10 برابر کاهش یافته و اگر این آرایه بزرگتر شود و برای مثال حاوی 10 هزار المان باشد، این زمان 20 برابر کاهش یافتهاست.
- این کاهش زمانها برای سایر متدهای LINQ نیز تقریبا به همین صورت است؛ منها متد Sum که اندازهی آرایه، تاثیری را بر روی نتیجهی نهایی ندارد.
- همچنین در دات نت 7، با فراخوانی متدهای LINQ، افزایش حافظهای مشاهده نمیشود.
در مورد کار با لیستها:
- در دات نت 6، اعمال صورت گرفتهی توسط LINQ بر روی آرایهها، نسبت به لیستها، همواره سریعتر است.
- در دات نت 7 هم در مورد مجموعههای کوچک، وضعیت همانند دات نت 6 است. اما اگر مجموعهها بزرگتر شوند، تفاوتی بین مجموعهها و آرایهها وجود ندارد و حتی وضعیت مجموعهها بهتر است: کارآیی کار با لیستها 32 برابر بیشتر شدهاست!
اما چگونه در دات نت 7، چنین بهبود کارآیی خیرهکنندهای در متدهای LINQ حاصل شدهاست؟
برای بررسی چگونگی بهبود کارآیی متدهای LINQ در دات نت 7 باید به نحوهی پیاده سازی آنها در نگارشهای مختلف دات نت مراجعه کرد. برای مثال پیاده سازی متد الحاقی Min تا دات نت 6 به صورت زیر است:
public static int Min(this IEnumerable<int> source) { if (source == null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } int value; using (IEnumerator<int> e = source.GetEnumerator()) { if (!e.MoveNext()) { ThrowHelper.ThrowNoElementsException(); } value = e.Current; while (e.MoveNext()) { int x = e.Current; if (x < value) { value = x; } } } return value; }
اما ... پیاده سازی این متد در دات نت 7 متفاوت است:
public static int Min(this IEnumerable<int> source) => MinInteger(source); private static T MinInteger<T>(this IEnumerable<T> source) where T : struct, IBinaryInteger<T> { T value; if (source.TryGetSpan(out ReadOnlySpan<T> span)) { if (Vector.IsHardwareAccelerated && span.Length >= Vector<T>.Count * 2) { .... // Optimized implementation return ....; } } .... //Implementation as in .NET 6 }
اما ... ReadOnlySpan چیست؟ نوعهای Span و ReadOnlySpan، یک ناحیهی پیوستهی مدیریت شده و مدیریت نشدهی حافظه را بیان میکنند. یک Span از نوع ref struct است؛ یعنی تنها میتواند بر روی stack قرار گیرد که مزیت آن، عدم نیاز به تخصیص حافظهی اضافی و بهبود کارآیی است. همچنین ساختار داخلی Span در سی شارپ 11 اندکی تغییر کردهاست که در آن از ref fields جهت دسترسی امن به این ناحیهی از حافظه استفاده میشود. پیشتر از نوع داخلی ByReference برای اشاره به ابتدای این ناحیهی از حافظه استفاده میشد که به همراه بررسی امنیتی در این باره نبود.
پس از دریافت ReadOnlySpan، به سطر زیر میرسیم:
if (Vector.IsHardwareAccelerated && span.Length >= Vector<T>.Count * 2)
private static T MinInteger<T>(this IEnumerable<T> source) where T : struct, IBinaryInteger<T> { .... if (Vector.IsHardwareAccelerated && span.Length >= Vector<T>.Count * 2) { var mins = new Vector<T>(span); index = Vector<T>.Count; do { mins = Vector.Min(mins, new Vector<T>(span.Slice(index))); index += Vector<T>.Count; } while (index + Vector<T>.Count <= span.Length); value = mins[0]; for (int i = 1; i < Vector<T>.Count; i++) { if (mins[i] < value) { value = mins[i]; } } .... }
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.