نظرات مطالب
روش نصب 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"

این روش در خود مستندات مایکروسافت توضیح داده شده اما استفاده از پکیج های داخلی ابونتو و یا اجرای اسکریپت ها خیلی آسون تر هستش و این روش صرفا موقعی استفاده میشه که امکان اجرای دستورات بر روی یک سیستم آفلاین وجود ندارد.

مطالب
استفاده از الگوی Adapter در تزریق وابستگی‌ها

در بعضی از مواقع ممکن است که در هنگام استفاده از اصل تزریق وابستگی‌ها، با یک مشکل روبرو شویم و آن این است که اگر از کلاسی استفاده می‌کنیم که به سورس آن دسترسی نداریم، نمی‌توانیم برای آن یک 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)
        {
            //…
        }
    }
}
همانطور که ملاحظه می‌کنید به علت دسترسی به سورس، به راحتی برای استفاده از کلاس ProductRepository در کلاس ProductService، از تزریق وابستگی‌ها استفاده کرده‌ایم.
اما از این جهت که شما دسترسی به سورس 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);
}
حالا که شما یک اینترفیس جدید دارید، می‌توانید کلاس produceservic را به شکل ذیل به روز رسانی کنید تا از این اینترفیس، به جای HTTP Context استفاده کند.
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;
    }
}
مسئله ای که در اینجا وجود دارد این است که HTTP Context Cache API صریحا نمی‌تواند Interface ایی که ما ایجاد کرده‌ایم را اجرا کند.
پس چگونه الگوی Adapter می‌تواند به ما کمک کند تا از این مشکل خارج شویم؟
هدف این الگو به صورت ذیل در GOF مشخص شده است .«تبدیل  Interface از یک کلاس به یک Interface مورد انتظار Client»
تصویر ذیل، مدل این الگو را به کمک UML نشان می‌دهد:
 

همانطور که در این تصویر ملاحظه می‌کنید، یک Client ارجاعی به یک Abstraction در تصویر (Target) دارد (ICacheStorage در کد نوشته شده). کلاس Adapter اجرای Target را بر عهده دارد و به سادگی متدهای Interface را نمایندگی می‌کند. در اینجا کلاس Adapter، یک نمونه از کلاس Adaptee را استفاده می‌کند و در هنگام اجرای قراردادهای Target، از این نمونه استفاده خواهد کرد.

اکنون کلاس‌های خود را در نمودار UML قرار می‌دهیم که به شکل ذیل آنها را ملاحظه می‌کنید.
 


در شکل ملاحظه می‌نمایید که یک کلاس جدید با نام 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;
        }
    }
}
حال به سادگی می‌توان یک caching solution دیگر را پیاده سازی کرد بدون اینکه در کلاس ProductService  اثر یا تغییری ایجاد کند .

منبع : Professional Asp.Net Design Pattern
 
اشتراک‌ها
Visual Studio 2019 version 16.6.2 منتشر شد

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 version 16.6.2 منتشر شد
مطالب
بهبود کارآیی LINQ در دات نت 7
LINQ یا همان Language-Integrated Query، یک زبان ساده‌ی کوئری نوشتن یکپارچه‌ی با دات نت است. به کمک آن می‌توان اعمال پیچیده‌ای را بر روی اشیاء، به زبانی ساده بیان کرد و امروزه تقریبا توسط تمام توسعه دهندگان دات نت مورد استفاده قرار می‌گیرد. اما ... این سادگی، بهایی را نیز به همراه دارد: کمتر بودن سرعت اجرا و همچنین افزایش مصرف حافظه. با توجه به گستردگی استفاده‌ی از LINQ، اگر بهبودی در این زمینه حاصل شود، بر روی کارآیی تمام برنامه‌های دات نتی تاثیر خواهد گذاشت و این امر در دات نت 7 محقق شده‌است. کارآیی متدهای LINQ to Objects در دات نت 7 (مانند متدهای Enumerable.Max, Enumerable.Min, Enumerable.Average, Enumerable.Sum) به شدت افزایش یافته و این افزایش گاهی حتی بیشتر از 10 برابر نسبت به نگارش‌های قبلی دات نت است؛ اما چگونه به چنین کارآیی رسیده‌اند؟


تدارک یک آزمایش برای بررسی میزان افزایش کارآیی متدهای 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();
}
برای آزمایش آن، یکبار target framework پروژه را بر روی net6.0 و بار دیگر بر روی net7.0 قرار داده و برنامه را اجرا می‌کنیم. خلاصه‌ی مفهومی نتایج حاصل به صورت زیر است که ... شگفت‌انگیز هستند!
در مورد کار با آرایه‌ها:


- زمان اجرای یافتن 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;
}
این متد نسبتا ساده‌است. یک IEnumerable را دریافت کرده و سپس با استفاده از متد MoveNext، مقدار فعلی را با مقدار بعدی مقایسه می‌کند. در این مقایسه، کوچکترین مقدار ذخیره می‌شود تا در نهایت به انتهای مجموعه برسیم.
اما ... پیاده سازی این متد در دات نت 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 از مجموعه‌ی ارائه شده، تهیه شود. اگر این کار میسر نشد، کدهای همان روش قبلی دات نت 6 که توضیح داده شد، اجرا می‌شود. البته در آزمایشی که ما تدارک دیدیم، چون از لیست‌ها و آرایه‌ها استفاده شده بود، همواره امکان تهیه‌ی یک ReadOnlySpan از آن‌ها میسر است. بنابراین به قسمت اجرایی همانند دات نت 6 نمی‌رسیم.
اما ... ReadOnlySpan چیست؟ نوع‌های Span و ReadOnlySpan، یک ناحیه‌ی پیوسته‌ی مدیریت شده و مدیریت نشده‌ی حافظه را بیان می‌کنند. یک Span از نوع ref struct است؛ یعنی تنها می‌تواند بر روی stack قرار گیرد که مزیت آن، عدم نیاز به تخصیص حافظه‌ی اضافی و بهبود کارآیی است. همچنین ساختار داخلی Span در سی شارپ 11 اندکی تغییر کرده‌است که در آن از ref fields جهت دسترسی امن به این ناحیه‌ی از حافظه استفاده می‌شود. پیشتر از نوع داخلی ByReference برای اشاره به ابتدای این ناحیه‌ی از حافظه استفاده می‌شد که به همراه بررسی امنیتی در این باره نبود.

پس از دریافت ReadOnlySpan، به سطر زیر می‌رسیم:
if (Vector.IsHardwareAccelerated && span.Length >= Vector<T>.Count * 2)
که بررسی می‌کند آیا سخت افرار فعلی از قابلیت‌های SIMD برخوردار است یا خیر؟ اگر بله، اینبار با استفاده از ریاضیات برداری شتاب یافته‌ی توسط سخت افزار، محاسبات را انجام می‌دهد:
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];
      }
    }
  ....
}
بنابراین به صورت خلاصه در دات نت 7 با استفاده از بکارگیری نوع‌های ویژه‌ی Span و نوع‌های برداری شتاب‌یافته‌ی توسط اکثر سخت افزارهای امروزی، سبب بهبود قابل ملاحظه‌ی کارآیی متدهای LINQ شده‌اند.
اشتراک‌ها
ایده گرفتن از قسمت‌های خوب Domain Driven Design

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. 

ایده گرفتن از قسمت‌های خوب Domain Driven Design