مطالب
قابلیت چند زبانه و Localization در AngularJs- بخش دوم: بررسی اجمالی قابلیت های ماژول angular-translate
در بخش قبلی به معرفی ماژول angular-tanslate پرداختیم. در این بخش قصد داریم تا به بررسی مفهومی قابلیت‌های موجود در این ماژول بپردازیم.
شکل زیر یک شمای کلی را از قابلیت‌های angular-translate، نمایش می‌دهد. همانطور که ملاحظه می‌کنید در مواردی نظیر ذخیره سازی زبان‌ها، بارگذاری ریسورس‌های زبان‌ها و گرامرهای استفاده در DOM راهکارهای گوناگونی دارد.

angular-translate دایرکتیو و فیلتر هایی را به صورت کامپوننت عرضه کرده است که شما می‌توانید به وسیله‌ی آنها پروژه خود را به زبان‌های گوناگون localize کنید. آنچه که در تصویر فوق مشاهده می‌کنید در حقیقت ساختار ماژول angular-translate را نمایش می‌دهد. به این صورت که در اولین لایه دایرکتیو translate قرار گرفته است.

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

در سطح بعدی لایه Interpolator قرار گرفته است که وظیفه تغییر DOM‌ها را بر عهده دارد. این فرآیند متغیرهایی را که در ریسورس قرار داده‌ایم، درایه به درایه در view و در مکان‌های هم نام قرار می‌دهد. این فرآیند به وسیله راهکار‌های گوناگونی از قبیل Message Format و یا Angular Core Interpolation Service امکان پذیر است.

جعبه خاکستری رنگ بخش missing translation handler را نشان می‌دهد. این handlerها زمانی فراخوانی می‌گردند که translator به دنبال یک key می‌گردد که تعریف نشده باشد. angular-translate خود شامل یک logging service می‌باشد که به صورت extension باید آن را به پروژه خود اضافه نمایید که در بخش‌های بعدی در مورد آن مفصل‌تر بحث می‌کنیم.

بخش asynchronous loader شما را قادر می‌سازد که داده‌های زبان‌های متفاوت را به صورت غیر هم زمان بارگذاری نمایید. angular-translate از ماژول‌های asynchronous loader پشتیبانی می‌کند. روش معرفی شده در سایت مرجع در مورد بارگذاری غیر همزمان urlLoader و staticFilesLoader هستند که در بخش‌های بعدی به آن خواهیم پرداخت.

angular-translate برای ذخیره سازی داده‌های بازگذاری شده و نگه داشتن زبان سایت در صورت reload شدن صفحه راهکارهای متفاوتی را ارائه نموده است. این قابلیت در ابتدا چک می‌کند که ریسورس‌های زبان درون یک local storage قرار گرفته‌اند یا خیر. این عملیات طی یک فرآیند جستجوی key-value صورت می‌گیرد و در نهایت فایل‌های ریسورس زبان مورد نظر که درون کوکی یا localStorage ذخیره شده‌اند بارگذاری می‌شوند. angular-translate به صورت توکار دارای دو راهکار localStorage و cookieStorage برای ذخیره سازی ریسورس‌ها می‌باشد.

در بخش بعدی در مورد نحوه‌ی ذخیره سازی داده‌ها به دو روش cookieStorage و localStorage بیشتر صحبت خواهیم کرد.

مطالب
مدیریت Instance در WCF
نحوه پیاده سازی و مدیریت Instance در پروژه‌های مبتنی بر WCF

نکته : آشنایی اولیه با مفاهیم WCF جهت درک صحیح مطالب الزامی است.

تشریح مسئله :  در صورتی که نیاز باشد که نمونه ساخته شده از سرویس (سمت سرور) به صورت Singleton  باشد بهترین روش برای پیاده سازی به چه صورت است.

برای شروع ابتدا مثال زیر را پیاده سازی می‌کنیم.
یک Contract به صورت زیر تعریف می‌کنیم:
[ServiceContract(SessionMode=SessionMode.Allowed)]
    public interface IMyService
    {
        [OperationContract]
        int GetData();             
    }

حالا یک سرویس برای پیاده سازی Interface بالا می‌نویسیم.
[ServiceBehavior( InstanceContextMode = InstanceContextMode.PerCall )]
    public class PerCallService : IMyService
    {
        int count;
        public int GetData()
        {
            return ++count;
        }
    }
همانطور که از نام سرویس مشخص است از این سرویس به ازای هر فراخوانی یک نمونه سمت سرور ساخته می‌شود.
حالا برای مشاهده نتیجه یک پروژه ConsoleApplication ایجاد کنید و سرویس مورد نظر را از روش AddServiceReference به پروژه اضافه کرده در فایل Program کد‌های زیر را کپی کنید.
 static void Main( string[] args )
        {
            Console.WriteLine( "PerCall Service" );

            MyPerCallService.MyServiceClient client = new MyPerCallService.MyServiceClient();
            int count = 0;
            for ( int i = 0 ; i < 5 ; i++ )
            {
                count = client.GetData();              
            }          
            Console.WriteLine( count );
            Console.ReadLine();         
        }
بعد از اجرا خروجی به صورت زیر است:

بعد از 5 بار فراخوانی متد GetData باز خروجی دارای مقدار 1 است. یعنی به ازای هر بار فراخوانی متد GetData یک نمونه از سرویس مورد نظر ساخته می‌شود.این عمل توسط خصوصیت InstanceContextMode که از نوع PerCall است به سرویس اعمال میشود.

حالا یک سرویس دیگر به صورت زیر ایجاد کنید.

 [ServiceBehavior( InstanceContextMode = InstanceContextMode.Single )]
    public class SingleService : IMyService
    {
        int count;
        public int GetData()
        {
            return ++count;
        }
    }
تنها تفاوت این سرویس با سرویس قبلی در این است که InstanceContextMode این سرویس  به صورت Single معرفی شده است. یعنی به ازای n فراخوانی فقط یک نمونه از کلاس ساخته می‌شود. این سرویس رو هم مثل روش قبلی به Client Application اضافه کنید.
کد کلاس Program رو به صورت زیر تغییر دهید.

static void Main( string[] args )
        {
            Console.WriteLine( "Single Service" );

            MySingleService.MyServiceClient client = new MySingleService.MyServiceClient();
            int count = 0;
            for ( int i = 0 ; i < 5 ; i++ )
            {
                count = client.GetData();              
            }          
            Console.WriteLine("Result is : {0}", count );
            Console.ReadLine();         
        }
که بعد از اجرا خروجی به صورت زیر است.

به ازای 5 بار فراخوانی سرویس متغیر Count سمت سرور مقدار قبلی خود را حفظ کرده است.

مطالب
مدیریت مرکزی شماره نگارش‌های بسته‌های NuGet در پروژه‌های NET Core.
عموما برنامه‌های بزرگ NET.، به چندین زیر پروژه شکسته می‌شوند تا مدیریت آن‌ها ساده‌تر شود. مهم‌ترین مشکلی که در این حالت پس از مدتی بروز می‌کند، هماهنگ نگه داشتن شماره نگارش‌های ارجاعات NuGet این پروژه‌ها است و همچنین به روز رسانی مکرر و هر باره‌ی تمام این فایل‌های csproj. به همین جهت ایده‌ی مدیریت مرکزی شماره نگارش‌های ارجاعات پروژه‌های NuGet قرار است به نگارش بعدی آن اضافه شود که البته هم اکنون نیز قسمتی از آن در NET Core SDK 3.1.300. به بعد، قابل استفاده‌است که جزئیات آن‌را در ادامه مرور می‌کنیم.


ایجاد فایل جدید Directory.Packages.props

زمانیکه قرار است شماره نگارش‌های بسته‌های NuGet مختلف مورد استفاده‌ی در برنامه، به صورت مرکزی مدیریت شوند، نیاز به یک مخزن ثبت آن‌ها نیز می‌باشد. به همین جهت یک فایل جدید را به نام Directory.Packages.props در کنار فایل sln پروژه‌ی خود ایجاد کنید (در ریشه‌ی اصلی پروژه)؛ با این محتوای فرضی:
<Project>
  <ItemGroup>
    <PackageVersion Include="Microsoft.Extensions.Localization.Abstractions" Version="3.1.8" />
    <PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.8" />
  </ItemGroup>
</Project>
برای تشکیل این فایل، فایل‌های csproj مختلف موجود در solution جاری را یافته و سپس PackageReference‌های آن‌ها را به فایل props فوق کپی کنید؛ با یک تفاوت مهم: بجای PackageReference اینبار از نام PackageVersion استفاده می‌شود.


تغییرات مورد نیاز در فایل‌های پروژه‌های موجود

در ادامه مجددا به تمام فایل‌های csproj خود مراجعه کرده و ویژگی Version را از آن‌ها حذف کنید؛ مانند:
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Localization.Abstractions" />
    <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
  </ItemGroup>
</Project>
 از این پس دیگر هیچکدام از فایل‌های پروژه‌ی شما نباید به همراه قید صریح شماره نگارش بسته‌های مورد استفاده باشند؛ در غیر اینصورت در حین Build پروژه، خطای زیر را دریافت خواهید کرد:
error NU1008: Projects that use central package version management should not define the version on the PackageReference items

همچنین اگر دقت کرده باشید، ویژگی جدید ManagePackageVersionsCentrally نیز به این فایل پروژه و سایر فایل‌های پروژه نیز باید اضافه شود. حالت پیش‌فرض آن false است.

یک نکته: می‌توان ویژگی ManagePackageVersionsCentrally را نیز به صورت سراسری به فایل Directory.Packages.props اضافه کرد تا به صورت خودکار به تمام فایل‌های csproj موجود، اعمال شود:
<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
  </PropertyGroup>
  <ItemGroup>
    <PackageVersion Include="Microsoft.Extensions.Localization.Abstractions" Version="3.1.8" />
    <PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.8" />
  </ItemGroup>
</Project>


نحوه‌ی افزودن بسته‌های جدید

قابلیتی که تا اینجا معرفی شد، در NET Core SDK 3.1.300. به بعد قابل دسترسی و استفاده‌است (و پس از این تغییرات، برنامه بدون مشکل کامپایل می‌شود)؛ اما هنوز NET Core CLI. برای افزودن خودکار بسته‌های جدید NuGet به این سیستم، به روز رسانی نشده‌است. یعنی فعلا اگر خواستید بسته‌ی جدیدی را اضافه کنید باید ابتدا به صورت دستی PackageVersion آن‌را در فایل Directory.Packages.props ثبت کنید و سپس PackageReference بدون شماره‌ی نگارش را نیز به پروژه‌ی مدنظر خود به صورت دستی اضافه کنید.



برای مطالعه بیشتر
مستندات رسمی آن
وضعیت پیاده سازی آن
مطالب
تهیه آزمون واحد جهت کار با محتوای فایل‌ها

یکی از شروط تهیه‌ آزمون‌های واحد، خارج نشدن از مرزهای سیستم در حین بررسی آزمون‌های مورد نظر است؛ تا بتوان تمام آزمون‌ها را با سرعت بسیار بالایی، بدون نگرانی از در دسترس نبودن منابع خارجی، درست در لحظه انجام آزمون‌ها، به پایان رساند. اگر این خروج صورت گیرد، بجای unit tests با integration tests سر و کار خواهیم داشت. در این میان، کار با فایل‌ها نیز مصداق بارز خروج از مرزهای سیستم است.
برای حل این مشکل راه حل‌های زیادی توصیه شده‌اند؛ منجمله تهیه یک اینترفیس محصور کننده فضای نام System.IO و سپس استفاده از فریم ورک‌های mocking و امثال آن. یک نمونه از پیاده سازی آن‌را اینجا می‌توانید پیدا کنید : (+)
اما راه حل ساده‌تری نیز برای این مساله وجود دارد و آن هم افزودن فایل‌های مورد نظر به پروژه آزمون واحد جاری و سپس مراجعه به خواص فایل‌ها و تغییر Build Action آن‌‌ها به Embedded Resource می‌باشد. به این صورت پس از کامپایل پروژه، فایلهای ما در قسمت منابع اسمبلی جاری قرار گرفته و به کمک متد زیر قابل دسترسی خواهند بود:
using System.IO;
using System.Reflection;

public class UtHelper
{
public static string GetInputFile(string filename)
{
var thisAssembly = Assembly.GetExecutingAssembly();
var stream = thisAssembly.GetManifestResourceStream(filename);
return new StreamReader(stream).ReadToEnd();
}
}

نکته‌ای را که اینجا باید به آن دقت داشت، filename متد GetInputFile است. چون این فایل دیگر به صورت متداول از فایل سیستم خوانده نخواهد شد، نام واقعی آن به صورت namespace.filename می‌باشد (همان نام منبع اسمبلی جاری).
اگر جهت یافتن این نام با مشکل مواجه شدید، تنها کافی است اسمبلی آزمون واحد را با برنامه Reflector یا ابزارهای مشابه گشوده و نام منابع آن‌را بررسی کنید.

مطالب
آشنایی با CLR: قسمت بیستم
در قسمت قبلی با نحوه انتشار برنامه‌ها آشنا شدیم. در این قسمت نحوه پیکربندی یا تغییر پیکربندی برنامه را مشخص می‌کنیم.
کاربر یا مدیر سیستم بهتر از هر کسی می‌تواند جنبه‌های‌های مختلف اجرای برنامه را مشخص کند. به عنوان نمونه ممکن است مدیر سیستم بخواهد فایل‌های یک برنامه را سمت هارد دیسک سیستم کاربر انتقال دهد یا اطلاعات مانیفست یک اسمبلی را رونویسی کند و مباحث نسخه بندی که در آینده در مورد آن صحبت می‌کنیم.
با ارائه یک فایل پیکربندی در شاخه برنامه می‌توان به مدیر سسیتم  اجازه داد تا کنترل بیشتر بر روی برنامه داشته باشد. ناشر برنامه می‌تواند این فایل را همراه دیگر فایل‌های برنامه پکیج کند تا در شاخه برنامه نصب شود تا بعدا مدیر یا کاربر سیستم بتوانند آن را تغییر و ویرایش کنند. CLR هم محتوای این فایل را تفسیر کرده و قوانین بارگیری اسمبلی‌ها و ... را تغییر می‌دهد. این فایل پیکربندی می‌تواند به صورت XML هم ارائه شود. مزیت قرار دادن یک فایل جداگانه نسبت به رجیستری این مزیت را دارد که هم قابل جابجایی و پشتیبانی گیری است و هم اینکه تغییر آن ساده‌تر است.
البته در آینده بیشتر در مورد این فایل صحبت می‌کنیم ولی در حال حاضر بهتر است اندکی طعم آن را بچشیم. فرض را بر این می‌گذاریم که ناشر می‌خواهد فایل‌های اسمبلی MultiFileLibrary را در دایرکتوری جداگانه‌ای قرار دهد و چیزی شبیه به ساختار زیر را در نظر دارد:
AppDir directory (contains the application’s assembly files)
Program.exe
Program.exe.config (discussed below)


AuxFiles subdirectory (contains MultiFileLibrary’s assembly files)
MultiFileLibrary.dll
FUT.netmodule
RUT.netmodule

حال با تنظیم بالا به دلیل اینکه CLR انتظار دارد این اسمبلی را در دایرکتوری برنامه بیابد و با این جابجایی قادر به انجام این کار نیست، استثنای زیر را صادر می‌کند:
System.IO.FileNotFoundException
برای حل این مشکل، ناشر یک فایل XML را ایجاد کرده و در مسیر دایرکتوری برنامه قرار می‌دهد. این فایل باید همنام اسمبلی اصلی برنامه با پسوند config. باشد. به عنوان مثال، نام فایل می‌شود: Program.exe.config و فایل پیکربندی هم چیزی شبیه فایل زیر می‌شود:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas­microsoft­com:asm.v1">
<probing privatePath="AuxFiles" />
</assemblyBinding>
</runtime>
</configuration>
حالا هر موقع CLR در جست و جوی یک اسمبلی باشد که نتواند آن را در دایرکتوری مربوطه بیابد مسیر Auxfiles را هم بررسی خواهد کرد. با قرار دادن کارکتر « , » هم می‌توان برای خصوصیت PrivatePath، دایرکتوری‌های زیادتری را معرفی کرد. البته مسیردهی این خصوصیت باید به طور نسبی باشد نه مطلق یا اینکه یک مسیر نسبی خارج از دایرکتوری برنامه. ایده اصلی اینکار این است که برنامه کنترل بیشتری روی دایرکتوری خود و دایرکتوری‌های زیرمجموعه داشته باشد نه خارج از آن.

نحوه عملکرد اسکن CLR برای بارگزاری اسمبلی ها
موقعی که CLR قصد بارگزاری اسمبلی‌های خنثی را دارد، شاخه‌های زیر را به طور خودکار اسکن خواهد نمود ( مسیرهای FirstPrivatePath و SecondPrivatePath توسط فایل پیکربندی مشخص شده است)
AppDir\AsmName.dll
AppDir\AsmName\AsmName.dll
AppDir\firstPrivatePath\AsmName.dll
AppDir\firstPrivatePath\AsmName\AsmName.dll
AppDir\secondPrivatePath\AsmName.dll
AppDir\secondPrivatePath\AsmName\AsmName.dll
...

این نکته ضروری است که اگر اسمبلی شما در یک دایرکتوری همنام خودش (در مثال ما MultiFileLibrary) قرار بگیرد، نیازی نیست این مسیر را در فایل پیکربندی ذکر کنید؛ زیرا CLR در صورت نیافتن دایرکتوری با این نام را اسکن خواهد نمود. بعد از آن اگر به هر نحوی CLR نتواند اسمبلی را در هیچ کدام از دایرکتوری‌های گفته شده بیابد، با همان قوانین گفته شده اینبار به دنبال فایلی با پسوند exe خواهد بود و اگر باز هم جست و جوی آن نتیجه‌ای را در بر نداشته باشد، استثنای زیر را صادر می‌کند:
 FileNotFoundException
برای اسمبلی‌های ماهواره‌ای همان قوانین بالا دنبال می‌شود؛ با این تفاوت که انتظار می‌رود اسمبلی داخل یک زیر دایرکتوری با تگ‌های RFC1766 مطابقت داشته باشد. به عنوان مثال اگر اسمبلی با فرهنگ و منطقه En-US مشخص شده باشد، دایرکتوری‌های زیر اسکن خواهند شد:
C:\AppDir\en­US\AsmName.dll
C:\AppDir\en­US\AsmName\AsmName.dll
C:\AppDir\firstPrivatePath\en­US\AsmName.dll
C:\AppDir\firstPrivatePath\en­US\AsmName\AsmName.dll
C:\AppDir\secondPrivatePath\en­US\AsmName.dll
C:\AppDir\secondPrivatePath\en­US\AsmName\AsmName.dll
C:\AppDir\en­US\AsmName.exe
C:\AppDir\en­US\AsmName\AsmName.exe
C:\AppDir\firstPrivatePath\en­US\AsmName.exe
C:\AppDir\firstPrivatePath\en­US\AsmName\AsmName.exe
C:\AppDir\secondPrivatePath\en­US\AsmName.exe
C:\AppDir\secondPrivatePath\en­US\AsmName\AsmName.exe
C:\AppDir\en\AsmName.dll
C:\AppDir\en\AsmName\AsmName.dll
C:\AppDir\firstPrivatePath\en\AsmName.dll
C:\AppDir\firstPrivatePath\en\AsmName\AsmName.dll
C:\AppDir\secondPrivatePath\en\AsmName.dll
C:\AppDir\secondPrivatePath\en\AsmName\AsmName.dll
C:\AppDir\en\AsmName.exe
C:\AppDir\en\AsmName\AsmName.exe
C:\AppDir\firstPrivatePath\en\AsmName.exe
C:\AppDir\firstPrivatePath\en\AsmName\AsmName.exe
C:\AppDir\secondPrivatePath\en\AsmName.exe
C:\AppDir\secondPrivatePath\en\AsmName\AsmName.exe

نحوه اسکن کردن CLR میتواند به ما بگوید که عمل اسکن می‌تواند گاهی اوقات با زمان زیادی روبرو شود (به خصوص که قابلیت اسکن روی شبکه را هم دارد). برای محدود کردن ناحیه یا نواحی اسکن می‌توانید یک یا چند المان culture را در فایل پیکربندی مشخص کنید. همچنین مایکروسافت ابزاری به نام FUSLogVw.exe را ارائه داده است که می‌تواند نواحی اسکن را در حین اجرای برنامه به ما گزارش دهد.

نام و محل فایل پیکربندی بسته به نوع برنامه می‌تواند متغیر باشد:
برای فایل‌های اجرایی EXE فایل پیکربندی باید در شاخه فایل اجرایی باشد و باید نام فایل پیکربندی همانند فایل exe بوده و یک پسوند config. را به آن اضافه کرد.

برای برنامه‌های وب فرم، فایل web.config موجود است که در ریشه شاخه مجازی وب اپلیکیشن قرار میگیرد و هر زیر دایرکتوری هم می‌تواند یک web.config جداگانه داشته باشد که میتواند از web.config ریشه هم تنظمیاتش را ارث بری کند. برای نمونه آدرس زیر را در نظر بگیرد:
https://www.dntips.ir/newsarchive

یک فایل کانفیگ در ریشه قرار می‌گیرد و یکی هم در زیر شاخه newsArchive  می‌تواند قرار بگیرد.

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

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

موقعیکه برنامه نیاز داشته باشد به اسمبلی نام قوی بایند یا متصل شود، از 4 ویژگی گفته شده‌ی در قسمت قبلی استفاده می‌کند تا آن را در GAC بیابد. اگر اسمبلی درخواستی موجود باشد، زیر دایرکتوری آن برگشت داده خواهد شد؛ ولی اگر آن را نیابد، ابتدا در داخل دایرکتوری برنامه و سپس در مسیرهایی که در فایل پیکربندی ذکر شده‌اند، به دنبال آن خواهد گشت و در نهایت اگر برنامه توسط فایل MSI نصب شده باشد، محل‌های توزیع را از طریق آن جویا خواهد شد و اگر باز به نتیجه‌ای نرسد، اتصال ناموفق گزارش شده و خطای زیر را ایجاد خواهد کرد:
System.IO.FileNotFoundException
هر بار که برنامه اسمبلی را از غیر از مسیر GAC بخواند، ابتدا هش آن اعتبارسنجی می‌شود و اگر هش آن غیرقابل شناسایی باشد، خطای زیر را صادر می‌کند:
System.IO.FileLoadExceptio
یک اسمبلی با نام قوی مزایای زیر را به همراه دارد:
  1. جلوگیری از دستکاری و حفظ امنیت آن
  2. این اسمبلی تنها یکبار از حافظه‌ی فیزیکی استفاده میکند؛ برعکس توزیع خصوصی که برای هر برنامه باید یک فضای دیسکی داشته باشد.
  3. توزیع ساده‌تر برای نسخه‌های آینده فراهم می‌شود که بعدا در مورد آن توضیح می‌دهیم.
با این حال GAC، یک سیستم امنیتی است که تنها باید توسط مدیر سیستم کنترل شود و هم اینکه توزیع آن‌ها به راحتی توزیع اسمبلی‌های خصوصی نیست. توصیه می‌شود که از اسمبلی‌های نام قوی، زمانی در GAC استفاده کنید که نیاز است توسط چندین برنامه به طور مشترک استفاده شود؛ در غیر این صورت از همان شیوه‌ی توزیع خصوصی استفاده شود. چون در این حالت هم بهترین حالت ایزوله بودن مهیاست، هم نصب آن ساده‌تر است و از آنجا که محل GAC در شاخه system32 است مرتبا از فضای دیسک آن ناحیه کم می‌شود.

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

کنترل مدیریت پیشرفته (پیکربندی)
در قسمت بیستم با ساخت فایل پیکریندی و نحوه تنظیم کردن اسکن اسمبلی‌ها در CLR آشنا شدیم. این بار قصد داریم در مورد المان‌های دیگر این فایل پیکریندی صحبت کنیم. فایل پیکربندی زیر را بررسی می‌کنیم:
 
<?xml version="1.0"?>
  <configuration>
     <runtime>
        <assemblyBinding xmlns="urn:schemas­microsoft­com:asm.v1">
           <probing privatePath="AuxFiles;bin\subdir" />
             <dependentAssembly>
                <assemblyIdentity name="SomeClassLibrary"  publicKeyToken="32ab4ba45e0a69a1" culture="neutral"/>
                <bindingRedirect  oldVersion="1.0.0.0" newVersion="2.0.0.0" />
                <codeBase version="2.0.0.0"  href="http://www.Wintellect.com/SomeClassLibrary.dll" />
             </dependentAssembly>
             <dependentAssembly>
                <assemblyIdentity name="TypeLib"  publicKeyToken="1f2e74e897abbcfe" culture="neutral"/>
                <bindingRedirect   oldVersion="3.0.0.0­3.5.0.0" newVersion="4.0.0.0" />
                <publisherPolicy apply="no" />
             </dependentAssembly> 
         </assemblyBinding>
     </runtime> 
 </configuration>
 Probing  در قسمت بیستم گفتیم که در این المان، مکان‌هایی را که CLR برای پیدا کردن اسمبلی‌های با نام ضعیف، باید اسکن کند، وارد می‌کنیم که هر مسیر با , از هم جدا شده‌است. برای اسمبلی‌های با نام قوی CLR باید داخل GAC را نگاه کند و در URL هایی که از طریق المان CodeBase مشخص کرده‌ایم. اگر المان CodeBase مشخص نشود، CLR برای پیدا کردن اسمبلی‌های با نام قوی، داخل دایرکتوری‌های این المان را اسکن خواهد کرد.
 Dependent Assembly اول
 در اولین فرزند این المان، Assembly Identity یک اسمبلی با مشخصاتی مثل Culture و توکن عمومی معرفی می‌شود و در BindingRedirect به CLR اطلاع می‌دهد موقعی که به دنبال نسخه یک این اسمبلی است، نسخه‌ی دو آن را برای استفاده جایگزین کند.
 Code Base
 این المان می‌گوید که وقتی CLR سعی در پیدا کردن نسخه‌ی 2 اسمبلی را دارد، آن را از طریق آدرس مورد نظر پیدا کند. این المان میتواند برای اسمبلی‌های با نام ضعیف هم کار کند.
  Dependent Assembly دوم  این مورد هم همانند سابق است با این تفاوت که گستره‌ی نسخه 3 تا 3.5 را به نسخه‌ی 4 تغییر میدهد.
Publisher Policy
اگر سازمان تولید کننده این اسمبلی فایلی برای تعیین Policy به همراه اسمبلی ارائه کرده باشد، این المان باعث می‌شود این فایل ندیده گرفته شود (در مورد فایل Policy در آینده صحبت می‌کنیم).
اکنون هر موقع CLR ارجاعی از جدول AssemblyDef را برای بارگذاری یک اسمبلی دریافت کند، ابتدا فایل پیکربندی را بررسی میکند و بر اساس آن اسمبلی مورد نظر را بارگذاری خواهد کرد. در این لحظه اسمبلی مورد نظر در GAC وجود دارد و آن را بار می‌کند؛ یا اگر یافت نشد المان CodeBase را بررسی میکند و اگر این المان تعریف نشده باشد، در ادامه سیاست‌های قبلی، پوشه کاری برنامه و دایرکتوری‌های private را اسکن میکند.

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

نکته : اگر مدیر بخواهد تمام برنامه‌های موجود از این اسمبلی جدید استفاده کنند باید فایل machine.config را ویرایش کند.

نظرات مطالب
T4MVC : یکی از الزامات مدیریت پروژه‌های ASP.NET MVC
یکی از مشکلاتی که من با این ابزار خوب دارم اینه که بعد از هر تغییر در کنترلر‌ها یا اضافه کردن یک کنترلر جدید حتما بایدrun custom tool   اجرا کنم...می خواستم بدنم آیا راهی نیست که بشه این قضیه خودکار انجام بشه ؟ (مثلا بعد از Build پروژه)
نظرات مطالب
ایجاد یک DbContext مشترک بین entityهای پروژه‌های متفاوت
روش بهتر ! 
ترجیح میدم سوالتون و با پروژهای مشابهی که کار کردم جواب بدم 
چند سال قبل بر روی سیستمی کار می‌کردیم که قرار بود با توجه به درخواست کاربر  دامنه ای رو یک Registerrer خاص ثبت، تمدید، منتقل، حذف و ... کنه 
چون قرار بود سیستم با امکانات اولیه فروخته بشه  و در صورت خرید پلاگین ها، بقیه امکانات اضافه بشه،
این قسمت به این صورت کار شده بود که در زمان انجام هر عملی لیست Registerrer ها می‌اومد که هر کدومشون توسط پلاگینشون‌نصب شده بودند و می‌تونستن کارهای ذکر شدرو انجام بدن
برای پیاده سازی چنین قابلیتی یک interface کلی وجود داشت که وظایف کلی Registerrer ها رو مشخص می‌کرد
بعد هر پلاگینی که اضافه میشد می‌دونستیم چه کارهایی می‌تونه انجام بده و بعدش با رفلکشن و cast کردن کلاس اصلی هر پلاگین به interface ، به متدهای مورد نظر دسترسی داشتیم . 
خوب تا اینجا شاید واقعا به یک سیستم pluggable نرسیدیم که شاید بگیم عیب دات نته 
اجازه بدید یه مثال از php  بزنم 
یه پروژه  php برای pluggable شدن فقط نیاز داره تا یکسری فایل .php رو در مسیر خاصی در روت اصلی قرار بدیم و ادرسشون و فراخوانی کنیم . کار تمومه و به سیستم  pluggable رسیدیم 
که برای کامل شدن این مثال بهتره که plugin‌ها به صورت فایل zip نصب بشن که در نهایت همون کپی کردن فایل‌های .php در جاهای مختلف پروژه می‌تونه باشه
اما تو دات نت یه خورده این کار سخت هست 
پروژه ای که در حال حاضر کار می‌کنم تقریبا یه سیستم pluggableکامل هست البته از دید من 
به این صورته که هر برنامه نویسی برای سیستمش سه پروژه 
UI 
Common  
Business  داره 
به عنوان مثال
Accounting.UI 
Accounting.Common  
Accounting.Business
و پروژه ای دیگر 
Store.UI 
Store.Common  
Store.Business
و ....
که تمام resource‌ها embeded میشن که با build کردن در فایل‌های  dll ذخیره میشن 
در اجرای اولیه ، کل UI  هایی که resource ی به صورت  embeded دارن لیست میشن و در  زمان درخواست هر صفحه از virtualPathProvider  استفاده می‌کنم تا بتونم اون  resource و از dll مربوطه بخونم و به کاربر نمایش بدم 
در ادامه هر پروژه میتونه ساختار یکسانی برای تعریف منوهایی داشته باشه که قراره به منوی اصلی اضافه بشن. 
که در چنین پروژه ای باید یکسری قوانین رو برای ساختار پروژه‌ها برای برنامه نویس‌ها مشخص کنید که طبق اونها پیش برن.
کار تمومه
حالا هر چندتا پروژه‌ی مشابه با ساختار مشخص شده به پوشه‌ی  bin  اضافه بشن، میتونن یه plug in باشن که به سیستم اضافه میشن 
مطالب
Gulp #2
در قسمت قبلی بحث کردیم که گالپ چیست و چه کاربردی دارد و در نهایت آن را بر روی سیستم خود نصب کردیم. در این مقاله و مقالات بعد می‌خواهیم کار خود را با راه اندازی یک workflow برای بوت استرپ، روند شخصی سازی آن را بسیار آسان و لذت بخش‌تر کنیم. امیدوارم که برای ادامه‌ی این بحث هیجان انگیز آماده باشید!

ساخت پروژه گالپ

ابتدا یک پوشه‌ی دلخواه به نام project را درست کنید.سپس خط فرمان خود را به این مسیر تغییر دهید و در نهایت دستور زیر را وارد کنید:
 npm init
این دستور برایمان یک فایل package.json می‌سازد تا هم مشخصات پروژه را مثل نام، ورژن، نام توسعه دهنده، مخزن و ... مشخص کنیم و هم وابستگی‌های آن را، تا توسعه دهندگان دیگر، هنگام استفاده از پروژه، با مشکل مواجه نشوند و فقط با اجرای دستور npm install تمام وابستگی‌های پروژه را نصب کنند.
حتما مشاهده کرده‌اید که این دستور چند سوالی را از شما می‌پرسد. برای نمونه من آنها به این صورت پاسخ می‌دهم و در نهایت از من یک تایید می‌گیرد که yes را می‌زنم.
name: (Gulp-RTLbootstrap-fontawesome) 
version: (1.0.0) 
description: An Awesome workflow
entry point: (index.js) index.html
test command: test
git repository: https://github.com/mmdsharifi/gulp-rtlBootstrap-fontawesome.git
keywords: gulp,rtlbootstrap,persian bootstrap
author: Mohammad Sharifi
license: (ISC) MIT
الان فایل package.json درست شده و چون ما در این پروژه می‌خواهیم از گالپ استفاده کنیم، یکی از وابستگی‌های پروژه‌ی ما گالپ خواهد بود. بدین معنی که اگر بخواهیم پروژه را توسعه دهیم و گالپ نصب نشده باشد، با مشکل مواجه می‌شویم.

نصب گالپ

در خط فرمان دستور زیر را وارد کنید تا گالپ در این پروژه نصب شود.
npm install gulp --save-dev
تفاوتی آن با دستوری که در مقاله‌ی قبلی اجرا کردیم، این است که این دستور فقط گالپ را در مسیر جاری در فولدر node_modules نصب می‌کند و save-dev --      آن را به وابستگی‌های توسعه‌ی پروژه در فایل package.json اضافه می‌کند.
گام بعدی، ساخت فایلی است که گالپ به آن نیاز دارد تا با استفاده از آن، تسک‌ها و کارهایی را که برایش نوشته‌ایم، از آن بخواند و اجرا کند.

ایجاد فایل gulpfile.js

این فایل را یا به صورت دستی ایجاد کنید یا با خط فرمان با دستور ذیل:
touch gulpfile.js
و حالا آن را در ویراشگر مورد علاقه‌ی خود باز کنید. من از ویرایشگر Atom استفاده می‌کنم. اما notepad هم کفایت می‌کند.

نوشتن اولین تسک گالپ

در ویراشگر خط زیر را می‌نویسیم:
var gulp = require('gulp');
 require  به Node می‌گوید که به فولدر node_modules برای پکیج gulp نگاه کند. زمانیکه آن را پیدا کرد، آن را به متغیر gulp انتساب می‌دهیم تا از تابع‌های گالپ بتوانیم استفاده کنیم. حال می‌خواهیم اولین تسک خود را بنویسیم:
gulp.task('task-name', function() {
  // Stuff here
});
گالپ دارای ۴ تابع task,src,dest,watch است که با آنها آشنا خواهیم شد. task یک کار را برای گالپ تعریف می‌کند و سه پارامتر دارد. اولی نام تسک، دومی (اختیاری) وابستگی این تسک (بدین معنا که اول باید این وظیفه اجرا شود، سپس تسک جاری) و در نهایت تابع درون تسک‌ها را می‌نویسیم. برای مثال:
gulp.task('hello', function() {
  console.log('Hello Gulp !');
});
فایل را ذخیره کنید. می‌خواهیم به گالپ بگوییم که این وظیفه را انجام دهد. کافی است gulp hello  را در خط فرمان وارد کنیم. نتیجه به صورت زیر خواهد بود:


 البته که تسک‌هایی که برای گالپ می‌نویسیم، کاراتر از این است؛ برای مثال:
gulp.task('task-name', function () {
  return gulp.src('source-files') // Get source files with gulp.src
    .pipe(aGulpPlugin()) // Sends it through a gulp plugin
    .pipe(gulp.dest('destination')) // Outputs the file in the destination folder
})
با استفاده از متد src به گالپ می‌گوییم که مسیر مبداء فایل‌ها، برای انجام تسک کجا است و dest هم بعد از انجام تسک، فایل‌های خروجی را به مقصد مشخص می‌برد. متد pipe یک تابع ند جی اس است که مطابق مستندات خودش متدی است که تمام جریان‌های قابل خواندن را واکشی می‌کند و به مسیری [که به صورت آرگومان به عنوان مقصد] داده شده، هدایت می‌کند.
شاید در ابتدا نوشتن تسک برایتان کمی پیچیده باشد، اما بعد از ساخت اولین پروژه با گالپ، خواهید دانست که تسک نوشتن برای گالپ کاری بسیار آسان و شیرین است!

مخزن پروژه در گیت هاب : https://github.com/mmdsharifi/gulp-rtlBootstrap-fontawesome 
نام کامیت این قسمت: Init commit

در مقاله بعدی gulp را در کنار bower بکار خواهیم برد. بهتر است مطالعه‌ای در مورد bower نیز انجام دهید. (پیشنهاد: + و + )