اشتراک‌ها
آینده‌ی Microsoft
  • Microsoft will change how it reports financially.
  • Microsoft will become a “consumer-focused enterprise company.”
  • Windows will converge into a single code base capable of running on any platform.
  • Application development will converge into allowing developers to maintain a single code base for an app that will run on any device capable of running Windows.
  • Release frequency will dramatically increase.
  • The “modern” user interface is here to stay.  
آینده‌ی Microsoft
اشتراک‌ها
معرفی NET Core 3 Local Tools.

.NET Tools are great, and we've known them for a while in .NET Core as ".NET Core Global Tools", but often we don't want these tools not to be shared globally across our machine. This is where "Local Tools" come in handy, introduced in .NET Core SDK 3.0. 

معرفی NET Core 3 Local Tools.
مطالب
ایجاد «خواص الحاقی» با استفاده از امکانات TypeDescriptor و یک TypeDescriptionProvider سفارشی

برای ایجاد «خواص الحاقی» قبلا در سایت مطلب ایجاد «خواص الحاقی» تهیه شده‌است. در این مطلب قصد داریم راه حل ارائه شده‌ی در مطلب مذکور را با یک TypeDescriptionProvider سفارشی ترکیب کرده تا به صورت یکدست، از طریق TypeDescriptor بتوان به آن خواص نیز دسترسی داشته باشیم. 

فرض کنید در یک سیستم Modular Monolith، نیاز جدیدی به دست شما رسیده است که به شرح زیر می‌باشد:

نیاز داریم در گریدی از صفحه‌ی X مربوط به «مؤلفه 1»، ستونی جدید را اضافه کنید و دیتای مربوط به این ستون، توسط «مؤلفه 2» مهیا خواهد شد.

شرایط زیر می‌تواند در سیستم حاکم باشد:
  • قبلا «مؤلفه 2» ارجاعی را به «مؤلفه 1» داده است؛ لذا امکان ارجاع معکوس را در این حالت، نداریم.
  • «مؤلفه 1» باید بتواند مستقل از «مؤلفه 2» نیز توزیع شده و کار کند؛ لذا این نیاز برای زمانی است که «مؤلفه 2» برای توزیع در Component Model ما وجود داشته باشد.
  • نمی‌خواهیم در آینده برای نیازهای مشابه در همان صفحه‌ی X، تغییر جدیدی را در «مؤلفه 1» داشته باشیم (اضافه کردن خصوصیت مورد نظر به مدل نمایشی یا اصطلاحا ویو-مدل متناظر با گرید در در زمان طراحی، جواب مساله نمی‌باشد)
  • می‌‌خواهیم به یک طراحی با Loose Coupling (اتصال سست و ضعیف، وابستگی ضعیف) دست پیدا کنیم.

راه حل چیست؟
با توجه به شرایط حاکم، بدون شک برای مهیا کردن دیتای ستون مذکور نمی‌توان به «مؤلفه 2» مستقیما ارجاع داده و «مؤلفه 1» را به «مؤلفه 2» وابسته کنیم. از طرفی چه بسا در نیاز‌های آتی نیز لازم باشد ستون جدید دیگری برای نمایش دیتای خاصی در گرید مذکور، اضافه شود. راه حل پیشنهادی، معکوس سازی این وابستگی می‌باشد. به عنوان مثال با استفاده از Expose کردن یک Interface توسط «مؤلفه 1» و پیاده سازی آن توسط سایر مؤلفه‌ها و استفاده از این پیاده سازی‌ها در زمان اجرا، می‌تواند راه حلی برای این معکوس سازی باشد. 

نمودار UML بالا، نشان دهنده‌ی راه حل پیشنهادی میباشد.

در این حالت «مؤلفه 1» بدون آگاهی از سایر مؤلفه‌ها، همه‌ی پیاده سازی‌های IExtraColumnConenvtion را در زمان اجرا یافته و از آنها برای ایجاد ستون‌های جدید، استفاده خواهد کرد.

واسط مذکور به شکل زیر می‌باشد: 

public interface IConvention
{
}

public interface IExtraColumnConvention<T> : IConvention
{
   string Name { get; }
 
   string Title { get; }
 
   void Populate(IEnumerable<T> list);
}

البته این واسط می‌تواند جزئیات بیشتری را هم شامل شود.


گام اول: طراحی TypeDescriptionProvider


در ‎.NET به دو طریق میتوان به متادیتا‌ی یک Type دسترسی داشت:

  • استفاده از API Reflection موجود در فضای نام System.Reflection 
  • کلاس TypeDescriptor 

به طور کلی هدف از این کلاس در دات نت، ارائه اطلاعاتی در خصوص یک وهله از جمله: Attributeها، Propertyها، Event‌های آن و غیره، می‌باشد. هنگام استفاده از Reflection، اطلاعات بدست آمده از Type، به دلیل اینکه بعد از کامپایل نمی‌توانند تغییر کنند، لذا قابلیت توسعه پذیری را هم ندارند. در مقابل، با استفاده از کلاس TypeDescriptor این توسعه پذیری را برای وهله‌های مختلف می‌توانید داشته باشید.

برای مهیا کردن متادیتای سفارشی (در اینجا اطلاعات مرتبط با خصوصیات الحاقی) برای TypeDescriptor، نیاز است یک TypeDescriptionProvider سفارشی را طراحی کنیم. 

/// <summary>
/// Use this provider when you need access ExtraProperties with TypeDescriptor.GetProperties(instance)
/// </summary>
public class ExtraPropertyTypeDescriptionProvider<T> : TypeDescriptionProvider where T : class
{
    private static readonly TypeDescriptionProvider Default =
        TypeDescriptor.GetProvider(typeof(T));

    public ExtraPropertyTypeDescriptionProvider() : base(Default)
    {
    }

    public override ICustomTypeDescriptor GetTypeDescriptor(Type instanceType, object instance)
    {
        var descriptor = base.GetTypeDescriptor(instanceType, instance);
        return instance == null ? descriptor : new ExtraPropertyCustomTypeDescriptor(descriptor, instance);
    }

    private sealed class ExtraPropertyCustomTypeDescriptor : CustomTypeDescriptor
    {
      //...
    }
}

  در تکه کد بالا، ابتدا تامین کننده‌ی پیش‌فرض مرتبط با نوع جنریک مورد نظر را یافته و به عنوان تامین کننده‌ی پایه معرفی کرده‌ایم. سپس برای معرفی CustomTypeDescritpr باید متد GetTypeDescriptor را بازنویسی کنیم. در اینجا لازم است برای معرفی متادیتا مرتبط با یک نوع، یک پیاده سازی از واسط ICustomTypeDescriptor را ارائه کنیم:
private sealed class ExtraPropertyCustomTypeDescriptor : CustomTypeDescriptor
{
    private readonly IEnumerable<ExtraPropertyDescriptor<T>> _instanceExtraProperties;

    public ExtraPropertyCustomTypeDescriptor(ICustomTypeDescriptor defaultDescriptor, object instance)
        : base(defaultDescriptor)
    {
        _instanceExtraProperties = instance.ExtraPropertyList<T>();
    }

    public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
    {
        var properties = new PropertyDescriptorCollection(null);

        foreach (PropertyDescriptor property in base.GetProperties(attributes))
        {
            properties.Add(property);
        }

        foreach (var property in _instanceExtraProperties)
        {
            properties.Add(property);
        }

        return properties;
    }

    public override PropertyDescriptorCollection GetProperties()
    {
        return GetProperties(null);
    }
}
در سازنده این کلاس، لیست خصوصیات الحاقی وهله جاری، در قالب لیستی از ExtraPropertyDescriptor‌ها دریافت شده و با بازنویسی دو متد GetProperties، لیست بدست آماده را به لیست خصوصیات فعلی آن وهله اضافه کرده‌ایم.
متد الحاقی ExtraPropertList به شکل زیر پیاده‌سازی شده‌است:
public static class ExtraProperties
{
    //...

    public static IEnumerable<ExtraPropertyDescriptor<T>> ExtraPropertyList<T>(this object instance) where T : class
    {
        if (!PropertyCache.TryGetValue(instance, out var properties))
            throw new KeyNotFoundException($"key: {instance.GetType().Name} was not found in dictionary");

        return properties.Select(p =>
            new ExtraPropertyDescriptor<T>(p.PropertyName, p.PropertyValueFunc, p.SetPropertyValueFunc,
                p.PropertyType,
                p.Attributes));
    }
}

در اینجا از همان مکانیزم افزودن خواص الحاقی که در ابتدای مطلب اشاره شد، استفاده شده است. 
ExtraPropertyDescriptor به شکل زیر طراحی شده است:
public sealed class ExtraPropertyDescriptor<T> : PropertyDescriptor where T : class
{
    private readonly Func<object, object> _propertyValueFunc;
    private readonly Action<object, object> _setPropertyValueFunc;
    private readonly Type _propertyType;

    public ExtraPropertyDescriptor(
        string propertyName,
        Func<object, object> propertyValueFunc,
        Action<object, object> setPropertyValueFunc,
        Type propertyType,
        Attribute[] attributes) : base(propertyName, attributes)
    {
        _propertyValueFunc = propertyValueFunc;
        _setPropertyValueFunc = setPropertyValueFunc;
        _propertyType = propertyType;
    }

    public override void ResetValue(object component)
    {
    }

    public override bool CanResetValue(object component) => true;

    public override object GetValue(object component) => _propertyValueFunc(component);

    public override void SetValue(object component, object value) => _setPropertyValueFunc(component, value);

    public override bool ShouldSerializeValue(object component) => true;
    public override Type ComponentType => typeof(T);
    public override bool IsReadOnly => _setPropertyValueFunc == null;
    public override Type PropertyType => _propertyType;
}
در نهایت برای استفاده از تامین کننده‌ی طراحی شده، می‌توان به شکل زیر عمل کرد:
[TypeDescriptionProvider(typeof(ExtraPropertyTypeDescriptionProvider<Person>))]
private class Person
{
    public string Name { get; set; }
    public string Family { get; set; }
}
در اینصورت با آزمایش زیر مشخص است که امکان دسترسی به این خصوصیات الحاقی نیز از طریق TypeDescriptor مهیا می‌باشد:
[Test]
public void Should_TypeDescriptor_GetProperties_Returns_ExtraProperties_And_PredefinedProperties()
{
    //Arrange
    var rabbal = new Person {Name = "GholamReza", Family = "Rabbal"};
    const string propertyName = "Title";
    const string propertyValue = "Software Engineer";

    //Act
    rabbal.ExtraProperty(propertyName, propertyValue);
    var title = TypeDescriptor.GetProperties(rabbal).Find(propertyName, true);

    //Assert
    rabbal.ExtraProperty<string>(propertyName).ShouldBe(propertyValue);
    title.ShouldNotBeNull();
    title.GetValue(rabbal).ShouldBe(propertyValue);
}

گام دوم: استفاده از IExtraColumnConvention برای نمایش ستون‌های الحاقی


فرض کنیم 3 پیاده‌سازی از واسط IExtraColumnConvention را توسط مؤلفه‌های مختلف، به شکل داشته باشیم:
public class Column4Convention : IExtraColumnConvention<Product>
{
   public string Name => "Column4";
 
   public string Title => "Column 4"
 
   public void Populate(IEnumerable<Product> list)
   {
      //TODO: forEach on list and set ExtraProperty
      // item.ExtraProperty(Name,value)
      // item.ExtraProperty(Name,(obj)=> value)
      // item.ExtraProperty(Name,(obj)=> value, (obj,value)=>)
   }
}

public class Column2Convention : IExtraColumnConvention<Product>
{
   public string Name => "Column2";
 
   public string Title => "Column 2"
 
   public void Populate(IEnumerable<Product> list)
   {
      //TODO: forEach on list and set ExtraProperty
   }
}

public class Column3Convention : IExtraColumnConvention<Product>
{
   public string Name => "Column3";
 
   public string Title => "Column 3"
 
   public void Populate(IEnumerable<Product> list)
   {
      //TODO: forEach on list and set ExtraProperty
   }
}

سپس این پیاده‌سازی‌ها از طریق مکانیزمی مانند معرفی آنها به یک IoC Container، توسط میزبان (مؤلفه 1) قابل دسترسی خواهد بود. در نهایت میزبان، قبل از نمایش محصولات، به شکل زیر عمل خواهد کرد:
var products = _productService.PagedList(page:1, pageSize:10);
var columns = _provider.GetServices<IExtraColumnConvention<Product>>();
foreach(var column in columns)
{
  column.Populate(products);
}
از این پس خصوصیات الحاقی اضافه شده‌ی توسط مؤلفه‌های دیگر نیز جزئی از خصوصیات محصولات بوده و از طریق TypeDescriptor.GetProperties قابل دسترسی می‌باشد. البته مشخص است راهکاری که در اینجا مطرح شد، وابستگی خیلی زیادی را به مکانیزم استفاده شده در لایه Presentation برای نمایش اطلاعات دارد.
نکته: امکان تهیه ContractResolver سفارشی برای کتابخانه JSON.NET به منظور Serialize خواص الحاقی اضافه شده در زمان اجرا، نیز وجود دارد.

تامین کننده طراحی شده‌ی در این مطلب، به زیرساخت DNTFrameworkCore اضافه شد.
مطالب
چگونه کدها را مستند سازی کنیم؟
یکی از مهمترین مسائل، به خصوص در کارهای تیمی یا پروژه‌های اشتراکی، قرار دادن کامنت‌ها یا اصطلاحا مستند نویسی است که بسیاری از برنامه نویسان با اینکه نظریه آن‌را به شدت قبول دارند، ولی از انجام آن سرباز می‌زنند که به دو عامل تنبلی و عدم دانش نحوه‌ی مستند نویسی بر می‌گردد. در این مقاله قصد داریم به سوالات زیر پاسخ دهیم:
  • چرا به کامنت گذاری یا مستند نویسی نیاز داریم؟
  • چگونه کامنت بنویسیم؟
  • انواع کامنت‌ها چیست؟
  • چه کامنت‌هایی اشتباه هستند؟

همانطور که بیان کردیم، کامنت گذاری یکی از مهم‌ترین کارهایی است که یک برنامه نویس انجام می‌دهد. به خصوص زمانیکه به صورت تیمی کار می‌کنید، این امر مهم‌تر از قبل خود را نشان می‌دهد. بسیاری از برنامه نویسان که بیشتر دلیل آن تنبلی است، از این کار سرباز می‌زنند و ممکن است آن را اتلاف وقت بدانند. ولی با کامنت گذاری فهم و درک کد، در آینده بالا‌تر می‌رود. در مقاله‌ی تخصصی «هنر کامنت نویسی» نوشته‌ی «برنهارد اسپویدا» بهانه‌های جالبی از برنامه نویسان را برای سرباز زدن از اینکار، ذکر شده است؛ به عنوان نمونه:
من کدم را به خوبی متوجه می‌شوم.
کد خوب، خودش گویای همه چیز هست.
وقتی برای کامنت نویسی وجود ندارد. باید چسبید به کد.


سوالات زیر نیز دلیل این را که چرا باید کامنت گذاری کرد، مشخص می‌کنند:
  • شاید امروز معنای یک کد را متوجه شوید، ولی آیا در آینده، مثلا یک سال بعد هم چنین خواهد بود؟
  •  آیا می‌توانید هر سیستمی را که طراحی می‌کنید، به خاطر بسپارید که فعالیت‌هایش را به چه نحوی انجام می‌دهد؟
  • اگر در یک کار تیمی باشید، شاید شما متوجه کدتان می‌شوید، ولی آیا تضمینی وجود دارد که دیگران هم متوجه روش شما شوند؟
  • آیا کدی که شما بر روی آن فکر کرده‌اید و در ذهن خود روش انجام آن را ترسیم کرده‌اید، می‌تواند برای برنامه نویسی که کد شما را می‌بیند هم رخ دهد؟ 
  • اگر شما به صورت تیمی کاری را انجام دهید و یکی از برنامه نویس‌های شما از تیم جدا شود، چگونه می‌توانید کار او را دنبال کنید؟
  • اگر برای برنامه نویسی اتفاق یا حادثه‌ای پیش بیاید که دسترسی شما به او ممکن نباشد چه؟
کدی که مستند نشود، یا خوب مستند نشود، در اولین مرحله وقت شما یا هر فردی را که روی این کد کار می‌کند، برای مدتی طولانی می‌گیرد. در مرحله‌ی بعدی احتمالا مجبور هستید، کد را خط به خط دنبال کرده تا تاثیر آن را بر ورودی‌ها و خروجی‌ها ببینید. تمام این‌ها باعث هدر رفتن وقت شما شده و ممکن است این اتفاق برای هر تکه کدی رخ بدهد.


سطوح کامنت نویسی بر سه نوع هستند:

Documentary Comments:
این مستند سازی در سطح یک سند مثل فایل یا به خصوص یک پروژه رخ می‌دهد که شامل اطلاعات و تاریخچه‌ی آن سند است که این اطلاعات به شرح زیر هستند:

 File Name   نام سند
 File Number/Version Number   شماره نسخه آن سند
 Creation Date   تاریخ ایجاد آن
 Last Modification Date
 تاریخ آخرین تغییر سند
 Author's Name
 سازنده‌ی سند
 Copyright Notice
 اطلاعاتی در مورد کپی رایت سند
 Purpose Of Program
 هدف کاری برنامه. یک خلاصه از آن چه برنامه انجام می‌دهد.
 Change History
 لیستی از تغییرات مهمی که در جریان ایجاد آن رخ داده است.
 Dependencies  وابستگی‌های سند. بیشتر در سطح پروژه معنا پیدا می‌کند؛ مانند نمونه‌ی آن برای سایت جاری که به صورت عمومی منتشر شده است.
 Special Hardware Requirements
 سخت افزار مورد نیاز برای اجرای برنامه. حتی قسمتی می‌تواند شامل نیازمندی‌های نرم افزاری هم باشد.
نمونه ای از این مستند سازی برای برنامه ای که به زبان پاسکال نوشته شده است:
PCMBOAT5.PAS*************************************************************
**
File: PCMBOAT5.PAS
Author: B. Spuida
Date: 1.5.1999
Revision: 
1.1 
PCM-DAS08 and -16S/12 are supported.
Sorting routine inserted.
Set-files are read in and card as well as
amplification factor are parsed.

1.1.1
Standard deviation is calculated.

1.1.2
Median is output. Modal value is output.

1.1.4
Sign in Set-file is evaluated.
Individual values are no longer output.
(For tests with raw data use PCMRAW.EXE)

To do:
outliers routine to be revised.
Statistics routines need reworking.
Existing Datafile is backed up.

Purpose: 
Used for measurement of profiles using the
Water-SP-probes using the amplifier andthe PCM-DAS08-card, values are acquired
with n = 3000. Measurements are taken in 1
second intervals. The values are sorted using
Quicksort and are stacked "raw" as well as after
dismissing the highest and lowest 200 values as
'outliers'.


Requirements:
The Card must have an A/D-converter.
Amplifier and probes must be connected.
Analog Signal must be present.
CB.CFG must be in the directory specified by the
env-Variable "CBDIREC" or in present directory.

در بالا، خصوصیت کپی رایت حذف شده است. دلیل این امر این است که این برنامه برای استفاده در سطح داخلی یک شرکت استفاده می‌شود.


Functional Comments: کامنت نویسی در سطح کاربردی به این معنی نیست که شما اتفاقاتی را که در یک متد یا کلاس یا هر بخشی روی می‌دهد، خط به خط توضیح دهید؛ بلکه چرخه‌ی کاری آن شی را هم توضیح بدهید کفایت می‌کند. این مورد می‌تواند شامل این موارد باشد:
  • توضیحی در مورد باگ‌های این قسمت
  • یادداشت گذاری برای دیگر افراد تیم
  • احتمالاتی که برای بهبود ویژگی‌ها و کارایی کد وجود دارد.


Explanatory Comment: کامنت گذاری توصیفی در سطح کدنویسی رخ می‌دهد و شامل توضیح در مورد کارکرد یک شیء و توضیح کدهای شیء مربوطه می‌گردد. برای قرار دادن کامنت الزامی نیست که کدها را خط به خط توضیح دهید یا اینکه خطوط ساده را هم تشریح کنید؛ بلکه کامنت شما همینقدر که بتواند نحوه‌ی کارکرد هر چند خط کد مرتبط به هم را هم توضیح دهد، کافی است. این توضیح‌ها بیشتر شامل موارد زیر می‌شوند:

  • کدهای آغازین
  • کدهای خروجی
  • توضیح کوتاه از آنچه که این شیء ، متد یا ... انجام می‌دهد. 
  • حلقه‌های طولانی یا پیچیده
  • کدهای منطقی عجیب و پیچیده
  • Regular Expression

کدهای آغازین شروع خوبی برای تمرین خواهند بود. به عنوان نمونه اینکه توضیحی در مورد ورودی و خروجی یک متد بدهید که آرگومان‌های ورودی چه چیزهایی هستند و چه کاربری داردند و در آغاز برنامه، برنامه چگونه آماده سازی و اجرا می‌شود. مقادیر پیش فرض چه چیزهایی هستند و پروژه چگونه تنظیم و مقداردهی می‌شود.

کدهای خروجی هم به همین منوال است. خروجی‌های نرمال و غیرنرمال آن چیست؟ کدهای خطایی که ممکن است برگرداند و ... که باید به درستی توضیح داده شوند.

توضیح اشیاء و متدها و ... شامل مواردی چون: هدف از ایجاد آن، آرگومان هایی که به آن پاس می‌شوند و خروجی که می‌دهد و اینکه قالب یا فرمت آن‌ها چگونه است و چه محدودیت‌هایی در مقادیر قابل انتظار وجود دارند. ذکر محدودیت‌ها، مورد بسیاری مهمی است و دلیل بسیاری از باگ‌ها، عدم توجه یا اطلاع نداشتن از وجود این محدودیت هاست. مثلا محدوده‌ی خاصی برای آرگومان‌های ورودی وجود دارد؟ چه اتفاقی می‌افتد اگر به یک بافر 128 کاراکتری، 1024 کاراکتر را ارسال کنیم؟

کدهای منطقی عجیب، یکی از حیاتی‌ترین بخش‌های کامنت گذاری برای نگه داری یک برنامه در آینده است. به عنوان نمونه استفاده از عبارات با قاعده، اغلب اوقات باعث سردرگمی کاربران شده است. پس توضیح دادن در مورد این نوع کدها، توصیه زیادی می‌شود. اگر عبارات با قاعده شما طولانی هستند، سعی کنید از هم جدایشان کنید یا خطوط آن را بشکنید و هر خط آن را توضیح دهید.

سیستم کامنت گذاری
هر زبانی از یک سیستم خاص برای کامنت گذاری استفاده می‌کند. به عنوان مثال پرل از سیستم (POD (Plain Old Documentation استفاده می‌کند یا برای Java سیستم JavaDoc یا برای PHP از سیستم PHPDoc  (+ ) که پیاده سازی از JavaDoc می‌باشد استفاده می‌کنند. این سیستم برای سی شارپ استفاده از قالب XML است. کد زیر نمونه‌ای از استفاده از این سیستم است:
// XMLsample.cs
// compile with: /doc:XMLsample.xml
using System;
/// <summary>
/// Class level summary documentation goes here.</summary>
/// <remarks>
/// Longer comments can be associated with a type or member
/// through the remarks tag</remarks>
public class SomeClass
{
    /// <summary>
    /// Store for the name property</summary>
    private string myName = null;

    /// <summary>
    /// The class constructor. </summary>
    public SomeClass()
    {
        // TODO: Add Constructor Logic here
    }

    /// <summary>
    /// Name property </summary>
    /// <value>
    /// A value tag is used to describe the property value</value>
    public string Name
    {
        get
        {
            if (myName == null)
            {
                throw new Exception("Name is null");
            }
            return myName;
        }
    }

    /// <summary>
    /// Description for SomeMethod.</summary>
    /// <param name="s"> Parameter description for s goes here</param>
    /// <seealso cref="String">
    /// You can use the cref attribute on any tag to reference a type or member
    /// and the compiler will check that the reference exists. </seealso>
    public void SomeMethod(string s)
    {
    }
}

دستورات سیستم کامنت گذاری سی شارپ

در سایت جاری، دو مقاله زیر اطلاعاتی در رابطه با نحوه‌ی کامنت گذاری ارئه داده‌اند.
- در مقاله «زیباتر کد بنویسیم» چند مورد آن به این موضوع اختصاص دارد.
- مقاله «وادار کردن خود به کامنت نوشتن» گزینه‌ی کامنت گذاری اجباری در ویژوال استودیو را معرفی می‌کند.
نظرات مطالب
React 16x - قسمت 10 - ترکیب کامپوننت‌ها - بخش 4 - یک تمرین
یک نکته تکمیلی:
یکی از مشکلات استفاده از JSON.parse(JSON.stringify(originalObject)) برای کپی کردن آبجکت‌ها این است که از آبجکت‌های circular پشتیبانی نمیکند؛ به عنوان مثال کد ساختار زیر را در نظر بگیرید:
const a = { x: 20, date: new Date() };
a.c = a;
استفاده از JSON.parse... خطای زیر را صادر خواهد کرد:
Uncaught TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'Object'
    --- property 'c' closes the circle
    at JSON.stringify (<anonymous>)
    at <anonymous>:1:17
یکی دیگر از مشکلات این است که برای پراپرتی‌هایی از نوع Date به صورت خودکار Date.prototype.toJSON صدا زده خواهد شد:
const a = { x: 20, date: new Date() };
JSON.parse(JSON.stringify(a))
{x: 20, date: '2023-01-04T15:17:02.957Z'}
برای رفع این دست از مشکلات میتوانید از تابع توکار structuredClone استفاده کنید:
structuredClone(a)
// {x: 20, date: Wed Jan 04 2023 15:17:02 GMT+0000 (Greenwich Mean Time), c: {…}}
البته این تابع یکسری مشکلات هم دارد: توابع، کلاس‌ها، DOM قابل clone نیستند. 
اشتراک‌ها
انتقال WebAssembly به سرور یا WASI

Bringing WebAssembly to the .NET Mainstream - Steve Sanderson, Microsoft

Many developers still consider WebAssembly to be a leading-edge, niche technology tied to low-level systems programming languages. However, C# and .NET (open-source, cross-platform technologies used by nearly one-third of all professional developers [1]) have run on WebAssembly since 2017. Blazor WebAssembly brought .NET into the browser on open standards, and is now one of the fastest-growing parts of .NET across enterprises, startups, and hobbyists. Next, with WASI we could let you run .NET in even more places, introducing cloud-native tools and techniques to a wider segment of the global developer community. This is a technical talk showing how we bring .NET to WebAssembly. Steve will demonstrate how it runs both interpreted and AOT-compiled, how an IDE debugger can attach, performance tradeoffs, and how a move from Emscripten to WASI SDK lets it run in Wasmtime/Wasmer or higher-level runtimes like wasmCloud. Secondly, you'll hear lessons learned from Blazor as an open-source project - challenges and misconceptions faced bringing WebAssembly beyond early adopters. [1] StackOverflow survey 2021 

انتقال WebAssembly به سرور یا WASI
بازخوردهای پروژه‌ها
NetSqlAzMan
NetSqlAzMan is the .NET Sql Authorization Manager short form and is an applicative authorization manager, that is, given an application user, what this user is authorized to do within that application.

 is for all  developers that need to manage loosely-coupled applicative authorizations, that is, weakly coupled with source code, in a light and fast way having all these authorizations in a relational database such as  (2000/MSDE/2005/2008/2012/Express/Compact).  
  • NetSqlAzMan allows you to change User Authorizations without recompile your application ! 
  • NetSqlAzMan supports AOP (Aspect Oriented Programming 
اشتراک‌ها
Entity FrameWork DbContext وDependency Injection و DbContextScope

یکی از متداول‌ترین الگوهای امروزی برای رفع وابستگی به یک سرویس در یک Object وابسته به ان سرویس الگوی Dependency Injection می‌باشد . در این الگو , وابستگی به سایر کلاس‌ها , به صورت اتوماتیک به داخل سرویس مورد نظر تزریق می‌شود و نیاز به نمونه گیری و ساخت Object از ان وابستگی به صورت Explicit نیست . این الگو در مهندسی نرم افزار فوایدیی (Refactoring , کنترل LifeTime اشیاء , ...) دارد که مرتبط با موضوع این مقاله نیست , اما نحوه صحیح نمونه گیریی از DbContext با الگوی Dependency Injection در انواع برنامه‌ها اعم از وب یا دسکتاپ موضوع اصلی این مقاله می‌باشد. 

Entity FrameWork DbContext وDependency Injection و DbContextScope
مطالب
Roslyn #1
معرفی Roslyn

سکوی کامپایلر دات نت یا Roslyn (با تلفظ «رازلین») بازنویسی مجدد کامپایلرهای VB.NET و #C توسط همین زبان‌ها است. این سکوی کامپایلر به همراه یک سری کتابخانه و اسمبلی ارائه می‌شود که امکان آنالیز زبان‌های مدیریت شده را به صورت مستقل و یا یکپارچه‌ی با ویژوال استودیو، فراهم می‌کنند. برای نمونه در VS.NET 2015 تمام سرویس‌های زبان‌های موجود، با Roslyn API جایگزین و بازنویسی شده‌اند. نمونه‌هایی از این سرویس‌های زبان‌ها، شامل  Intellisense و مرور کدها مانند go to references and definitions، به همراه امکانات Refactoring می‌شوند. به علاوه به کمک Roslyn می‌توان یک کامپایلر و ابزارهای مرتبط با آن، مانند FxCop را تولید کرد و یا در نهایت یک فایل اسمبلی نهایی را از آن تحویل گرفت.


چرا مایکروسافت Roslyn را تولید کرد؟

پیش از پروژه‌ی Roslyn، کامپایلرهای VB.NET و #C با زبان ++C نوشته شده بودند؛ از این جهت که در اواخر دهه‌ی 90 که کار تولید سکوی دات نت در حال انجام بود، هنوز امکانات کافی برای نوشتن این کامپایلرها با زبان‌های مدیریت شده وجود نداشت و همچنین زبان محبوب کامپایلر نویسی در آن دوران نیز ++C بود. این انتخاب در دراز مدت مشکلاتی مانند کاهش انعطاف پذیری و productivity تیم کامپایلر نویس را با افزایش تعداد سطرهای کامپایلر نوشته شده به همراه داشت و افزودن ویژگی‌های جدید را به زبان‌های VB.NET و #C سخت‌تر و سخت‌تر کرده بود. همچنین در اینجا برنامه نویس‌های تیم کامپایلر مدام مجبور بودند که بین زبان‌های مدیریت شده و مدیریت نشده سوئیچ کنند و امکان استفاده‌ی همزمان از زبان‌هایی را که در حال توسعه‌ی آن هستند، نداشتند.
این مسایل سبب شدند تا در طی بیش از یک دهه، چندین نوع کامپایلر از صفر نوشته شوند:
- کامپایلرهای خط فرمانی مانند csc.exe و vbc.exe
- کامپایلر پشت صحنه‌ی ویژوال استودیو (برای مثال کشیدن یک خط قرمز زیر مشکلات دستوری موجود)
- کامپایلر snippet‌ها در immediate window ویژوال استودیو

هر کدام از این کامپایلرها هم برای حل مسایلی خاص طراحی شده‌اند. کامپایلرهای خط فرمانی، با چندین فایل ورودی، به همراه ارائه‌ی تعدادی زیادی خطا و اخطار کار می‌کنند. کامپایلر پشت صحنه‌ی ویژوال استودیوهای تا پیش از نسخه‌ی 2015، تنها با یک تک فایل در حال استفاده، کار می‌کند و همچنین باید به خطاهای رخ داده نیز مقاوم باشد و بیش از اندازه گزارش خطا ندهد. برای مثال زمانیکه کاربر در حالت تایپ یک سطر است، بدیهی است تا اتمام کار، این سطر فاقد ارزش دستوری صحیحی است و کامپایلر باید به این مساله دقت داشته باشد و یا کامپایلر snippet‌ها تنها جهت ارزیابی یک تک سطر از دستورات وارد شده، طراحی شده‌است.

با توجه به این مسایل، مایکروسافت از بازنویسی سکوی کامپایلر دات نت این اهداف را دنبال می‌کند:
- بالا بردن سرعت افزودن قابلیت‌های جدید به زبان‌های موجود
- سبک کردن حجم کاری کامپایلر نویسی و کاهش تعداد آن‌ها به یک مورد
- بالا بردن دسترسی پذیری به API کامپایلرها
برای مثال اکنون برنامه نویس‌ها بجای اینکه یک فایل cs را به کامپایلر csc.exe ارائه کنند و یک خروجی باینری دریافت کنند، امکان دسترسی به syntax trees، semantic analysis و تمام مسایل پشت صحنه‌ی یک کامپایلر را دارند.
- ساده سازی تولید افزونه‌های مرتبط با زبان‌های مدیریت شده.
اکنون برای تولید یک آنالیز کننده‌ی سفارشی، نیازی نیست هر توسعه دهنده‌ای شروع به نوشتن امکانات پایه‌ای یک کامپایلر کند. این امکانات به صورت یک API عمومی در دسترس برنامه نویس‌ها قرار گرفته‌اند.
- آموزش مسایل درونی یک کامپایلر و همچنین ایجاد اکوسیستمی از برنامه نویس‌های علاقمند در اطراف آن.
همانطور که اطلاع دارید، Roslyn به صورت سورس باز در GitHub در دسترس عموم است.


تفاوت Roslyn با کامپایلرهای سنتی

اکثر کامپایلرهای موجود به صورت یک جعبه‌ی سیاه عمل می‌کنند. به این معنا که تعدادی فایل ورودی را دریافت کرده و در نهایت یک خروجی باینری را تولید می‌کنند. اینکه در این میان چه اتفاقاتی رخ می‌دهد، از دید استفاده کننده مخفی است.


نمونه‌ای از این کامپایلرهای جعبه سیاه را در تصویر فوق مشاهده می‌کنید. در اینجا شاید این سؤال مطرح شود که در داخل جعبه‌ی سیاه کامپایلر سی‌شارپ، چه اتفاقاتی رخ می‌دهد؟


خلاصه‌ی مراحل رخ داده در کامپایلر سی‌شارپ را در تصویر فوق ملاحظه می‌کنید. در اینجا ابتدا کار parse اطلاعات متنی دریافتی شروع می‌شود و از روی آن syntax tree تولید می‌شود. در مرحله‌ی بعد مواردی مانند ارجاعاتی به mscorlib و امثال آن پردازش می‌شوند. در مرحله‌ی binder کار پردازش حوزه‌ی دید متغیرها، اشیاء و اتصال آن‌ها به هم انجام می‌شود. در مرحله‌ی آخر، کار تولید کدهای IL و اسمبلی باینری نهایی صورت می‌گیرد.
با معرفی Roslyn، این جعبه‌ی سیاه، به صورت یک API عمومی در دسترس برنامه نویس‌ها قرار گرفته‌است:


همانطور که مشاهده می‌کنید، هر مرحله‌ی کامپایل جعبه‌ی سیاه، به یک API عمومی Roslyn نگاشت شده‌است. برای مثال Parser به Syntax tree API نگاشت شده‌است. به علاوه این API صرفا به موارد فوق خلاصه نمی‌شود و همانطور که پیشتر نیز ذکر شد، برای اینکه بتواند جایگزین سه نوع کامپایلر موجود شود، به همراه Workspace API نیز می‌باشد:


Roslyn امکان کار با یک Solution و فایل‌های آن را دارد و شامل سرویس‌های زبان‌های مورد نیاز در ویژوال استودیو نیز می‌شود. برفراز Workspace API، یک مجموعه API دیگر به نام Diagnostics API تدارک دیده شده‌است تا برنامه نویس‌ها بتوانند امکانات Refactoring جانبی را توسعه داده و یا در جهت بهبود کیفیت کدهای نوشته شده، اخطارهایی را به برنامه نویس‌ها تحت عنوان Code fixes و آنالیز کننده‌ها، ارائه دهند.