مطالب
آشنایی با CLR: قسمت چهاردهم
در ادامه قسمت قبلی روش‌های زیادی جهت اضافه شدن یک ماژول به یک اسمبلی وجود دارند. اگر شما از کامپایلر سی‌شارپ برای ساخت یک فایل PE با جدول مانیفست استفاده می‌کنید، می‌توانید از سوئیچ AddModule/ استفاده کنید. برای اینکه بدانیم چگونه می‌توان یک اسمبلی چند فایله ساخت بیاید فرض کنیم که دو فایل سورس کد با مشخصات زیر داریم:
RUT.cs: این سورس شامل کدهایی است که به ندرت در برنامه استفاده می‌شود.
FUT.cs: این سورس شامل کدهایی است که به طور مکرر مورد استفاده قرار می‌گیرد.

ابتدا به صورت زیر کد سورسی را که به ندرت استفاده می‌شود، به عنوان یک ماژول جداگانه کامپایل می‌کنم:
csc /t:module RUT.cs
اجرای این خط سبب ایجاد یک فایل به نام RUT.netmodule می‌گردد که یک DLL استاندارد است؛ ولی CLR به تنهایی توانایی بارگیری آن را ندارد. دفعه‌ی بعد سورس کدی را که مکرر استفاده می‌شود، به صورت یک ماژول کامپایل می‌کنیم و از آنجائیکه این ماژول استفاده‌ی زیادی دارد، آن را نگهدارنده‌ی جدول مانیفست معرفی می‌کنیم و به این دلیل که این ماژول نماینده‌ی کل اسمبلی است، نام خروجی آن را به جای FUT.dll به MultiFileLibrary.dll تغییر می‌دهیم:
csc /out:MultiFileLibrary.dll /t:library /addmodule:RUT.netmodule FUT.cs
خط بالا به علت سوئیچ t:library\ فایل MultiFileLibrary.dll را ایجاد می‌کند. این فایل شامل جدول متادیتای مانیفست می‌شود و سوئیچ به آن می‌گوید که باید ماژول RUT.netmodule را جزئی از اسمبلی بداند. این سوئیچ به کامپایلر اعلام می‌کند که ارجاع این فایل در جدول FileDef  و ExportedTypesDef ثبت شود.
بعد از اتمام عملیات کامپایل، مطابق شکل زیر دو فایل ایجاد می‌شود که فایل سمت راست شامل جدول مانیفست است. فایل RUT.netmodule شامل کد IL و جداول متادیتاهای مربوط به خواص و رویدادها و مواردی از این قبیل است که در این ماژول یافت می‌شود. فایل بعدی MultiFileLibrary.dll هست که شامل کد IL کد FUT.CS می‌شوذ بعلاوه جداول متادیتا مثل ماژول قبلی و جدول متادیتای مانیفست که باعث می‌شود به عنوان یک اسمبلی شناخته شود.



البته توجه داشته باشید که جدول مانیفست ارجاعی به نوع‌های عمومی استخراج شده داخل فایل خودش ندارد، زیرا که در جداول اختصاصی خودش موجود است و در ذخیره سازی صرفه جویی می‌گردد.
بعد از اینکه MultiFileLibrary.dll ساخته شد، به منظور آزمایش کردن جداول متادیتا می‌توانید از ابزار ILDasm.exe استفاده کنید تا ارجاع به فایل RUT.netmodule به شما ثابت شود. آنچه در زیر می‌بینید نمایی از جداول FileDef و ExportedTypesDef است:
File #1 (26000001)
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Token: 0x26000001
Name : RUT.netmodule
HashValue Blob : e6 e6 df 62 2c a1 2c 59 97 65 0f 21 44 10 15 96 f2 7e db c2
Flags : [ContainsMetaData] (00000000)


ExportedType #1 (27000001)
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Token: 0x27000001
Name: ARarelyUsedType
Implementation token: 0x26000001
TypeDef token: 0x02000002
Flags : [Public] [AutoLayout] [Class] [Sealed] [AnsiClass]
[BeforeFieldInit](00100101)
 
همانطور که در بالا می‌بینید فایل RUT.netmodule با شناسه‌ی (توکن) 0x26000001 به عنوان بخشی از اسمبلی شناخته می‌شود و به نوع کد IL آن اشاره می‌کند.

قابل توجه افراد کنجکاو: توکن‌های جداول متا، مقادیر 4 بایتی است که بایت پر ارزش آن اشاره می‌کند که برای یافتن آن باید به چه جدولی ارجاع کرد. مقادیر زیر این نکته را روشن می‌کند که هر کد ابتدایی به چه جدولی اشاره می‌کند:
 0x01
 TypeRef
 0x02
 TypeDef
 0x23
 AssemblyRef
 0x26
 File
file definition

 0x27
 ExportedType
برای دیدن لیست کاملی از این کدها فایل Corhdr.h را که به همراه فریم ورک دات نت نصب می‌شود، مطالعه فرمایید. سه بایت باقیمانده هم بر اساس جدولی که به آن ارجاع شده است مشخص می‌گردد؛ مثلا در مثال بالا کد 0x26000001  به اولین سطر جدول File اشاره می‌کند. برای اکثر جدول‌ها شماره گذاری سطرها از عدد 1 آغاز می‌شود نه صفر یا برای برای جداول TypeDef عموما از عدد 2 آغاز می‌شود. 

برای اجرای اسمبلی، کامپایلر نیاز دارد که همه‌ی فایل‌های اسمبلی، نصب شده و قابل دسترس باشند و در صورتیکه شما فایل RUT.netmodule را حذف کنید کامپایلر سی شارپ خطای زیر را صادر می‌کند:
fatal error CS0009: Metadata file 'C:\ MultiFileLibrary.dll' could not be opened—'Error importing module 'RUT.netmodule' of assembly 'C:\ MultiFileLibrary.dll'—The system cannot find the file specified'

و این خطا بدین معنی است که برای ساخت اسمبلی باید تمامی فایل‌ها حاضر و مهیا باشند. هر کد کلاینتی که اجرا می‌شود آن متد را صدا می‌زنند. موقعی که یک متد برای اولین بار فراخوانی می‌شود، CLR عملیات شناسایی جهت شناسایی ارجاعات آن در پارامترها، نوع خروجی متد و متغیرهای محلی آن اجرا می‌کند. سپس تلاش می‌کند تا فایل اسمبلی ارجاع شده را که شامل مانیفست هست، بار کند. اگر نوعی که لازم داریم در همین فایل متد وجود داشته باشد، اجرای عملیات را به سمت آن آغاز می‌کند ولی اگر جدول مانیفست ارجاع را به فایل دیگری بدهد، آن فایل در حافظه بار شده و سپس آن نوع را در دسترس قرار می‌دهد. 
خطوط بالا این نکته را روشن می‌کند که فایل‌های اسمبلی را تنها موقعی در حافظه بار میکند که ارجاعی از نوع موجود در آن صدا زده شده باشد؛ یعنی اینکه در زمان اجرای برنامه، لازم نیست که همه‌ی فایل‌ها حاضر و مهیا باشند.
اشتراک‌ها
NET 8 Preview 5. منتشر شد

We’re excited to share all the new features and improvements in .NET 8 Preview 5! This release is a follow-up to the Preview 4 release. You’ll continue to see many more features show up with these monthly releases. .NET 6 and 7 users will want to follow this release closely since we have focused on making it a straightforward upgrade path. 

NET 8 Preview 5. منتشر شد
اشتراک‌ها
NET 5.0 Preview 6. منتشر شد

Today, we’re releasing .NET 5.0 Preview 6. It contains a small set of new features and performance improvements. The .NET 5.0 Preview 4 post covers what we are planning to deliver with .NET 5.0. Most of the features are now in the product, but some are not yet in their final state. We expect that the release will be feature-complete with Preview 8. 

NET 5.0 Preview 6. منتشر شد
مطالب
قسمت اول - ساخت گزارش در محیط Telerik Reporting
یکی از ضروریات نرم افزارها وجود گزارشات مختلف در قالب لیست‌ها ، نمودارها و ... در آنها می‌باشد.یک نرم افزار خوب باید توانایی ارائه گزارشات خوب و زیبا را نیز داشته باشد.گزارشات در حقیقت نمایشی از داده‌ها هستند که عموما به چاپ می‌رسند. مورد دیگری که در خصوص گزارشات حائز اهمیت می‌باشد ، تبدیل آنها به فرمت‌های مختلف جهت حمل و جابه جایی آسان از سیستمی به سیستم دیگر می‌باشد. برای مثال تبدیل گزارشات به قالب Pdf مزایایی بسیاری از نظر قابل حمل بودن در پی خواهد داشت. در برنامه نویسی دات نت گزارشات را می‌توان توسط دستورات چاپ در دات تهیه ، نمایش و چاپ نمود. اما تهیه گزارش توسط دستورات دات نت کاری مشکل و طاقت فرسا می‌باشد. همچنین امکان تبدیل این گزارشات به فرمت‌های دیگر نظیر Pdf ، به راحتی انجام نمی‌شود و باید از کلاس‌ها و ابزارهای جانبی که برای این کار تهیه شده اند استفاده نمود . از این رو ابزارهای مختلفی در جهت تهیه گزارشات به وجود آمدند.ابزارهایی نظیر :

• Crystal Report
• Stimul Report
• Telerik Reporting
• … 

در ادامه این سری آموزش‌ها قصد داریم Telerik Reporting و نحوه تهیه گزارش با آن را مورد بررسی قرار دهیم. این ابزار امکانات بسیاری در خصوص تهیه گزارش برنامه‌های دات نتی نظیر Windows Form ، Asp.net و ... در اختیار ما قرار می‌دهد.در ادامه و برای شروع ، ساخت یک گزارش ساده در این محیط را بررسی میکنیم.

 
 نکته : گزارشاتی که توسط Telerik Reporting تهیه می‌شوند به وسیله کدهای C# جنریت می‌شوند.بنابراین همیشه توصیه می‌شود گزارشات خود را درون یک یا چند پروژه Class Library قرار دهیم و از این پس ، این گزارشات از درون پروژه‌های دیگر (ویندوزی ، وب و ...) در دسترس هستند.کافی ست پروژه Class Library را به عنوان Reference به پروژه مورد نظر خود اضافه کنیم..  برای شروع می‌توان یک پروژه جدید  از نوع Class Library  ایجاد کرد.پس از آن روی نام پروژه راست کلیک کنید و گزینه Telerik Report را انتخاب نمایید.پس از تعیین نام گزارش کلید Ok را کلیک نمایید.

انتخاب گزینه Telerik Reporting از پنجره New Item


در این حالت فایل گزارش به پروژه افزوده می‌شود. در ادامه می‌توانید توسط ویزاردی که نمایش داده می‌شود کارهای عمومی مربوط به پیاده سازی گزارش (انتخاب منبع داده(Data Source) ، ساخت Query جهت بارگذاری اطلاعات ، فیلدهایی که باید نمایش داده شوند ، گروه بندی داده‌ها و ...) را توسط این ویزارد انجام دهید. برای اینکار در پنجره ای که نمایش داده می‌شود بر روی کلید Next کلیک نمایید.
جهت ایجاد یک گزارش جدید در پنجره  Report Choose Page گزینه New Report را انتخاب نموده و کلید Next را کلیک نمایید.
جهت انتخاب منبع داده گزارش در پنجره Choose Data Source گزینه Add New Data Source را انتخاب نمایید.در این حالت می‌توانید گزینه‌های متفاوتی را به عنوان منبع داده گزارش خود انتخاب نمایید. گزینه‌های نمایش داده شده به شرح ذیل است:
• Sql Data Source : جهت اتصال مستقیم به بانک اطلاعات Microsoft Sql Server
• Object Data Source :  جهت اتصال به کلاس‌های لایه Business و بارگذاری داده از این کلاس ها
• Entity Data Source : جهت اتصال به  Entity Framework
• Open Access Data Source : جهت اتصال به Open Access ORM ساخت شرکت Telerik
• Cube Data Source : جهت اتصال و نمایش داده‌های تحلیل شده
  در ادامه برای اینکه بتوان مستقیما به Sql Server وصل شد و Query‌های مربوط به گزارش را روی آن اجرا نمود؛ می‌توان گزینه Sql Data Source را انتخاب نمود و بر روی کلید Ok کلیک کرد.سپس در پنجره Choose Your Data Connection گزینه New Connection را کلیک کنید و یک اتصال به بانک مورد نظر خود ایجاد کنید.پس ایجاد و تست Connection ساخته شده روی Next  کلیک کنید.در پنجره Save the connection string می‌توان نامی را جهت Connection string انتخاب کرد تا Connection string با همان نام در فایل Config پروژه ذخیره شود.در ادامه کلید Next را کلیک کرده و وارد مرحله بعد شوید. در پنجره Configure Data Source Command گزینه Query Builder را جهت ساخت Query مورد نظر برای بارگذاری داده‌ها انتخاب نمایید.

انتخاب جداول جهت ساخت Query


پنجره ساخت Query

پس از ساخت Query مورد نظر کلید Ok را کلیک نمایید. در پنجره Configure Data Source Command کوئری ساخته شده به شما نمایش داده می‌شود.کلید Next را کلیک کنید. 

سپس وارد مرحله Preview Data Source Result می‌شوید که در آن قادر خواهید بود پیش نمایشی از داده هایی که بعدا توسط Query ساخته شده بارگذاری خواهند شد را مشاهده نمایید. Next را کلیک نموده تا وارد مرحله بعد شوید.مرحله بعد Standard Report Type می‌باشد که در این مرحله شما می‌توانید نوع گزارش خود را انتخاب نمایید و کلید Next را فشار دهید.در بخش Design Data Layout چند فیلد را از بخش سمت چپ (Available Fields) انتخاب نموده و کلید Details را کلیک نمایید.فیلدهای انتخاب شده به بخش Details گزارش اضافه خواهند شد.در ادامه Next را کلیک کنید تا وارد بخش Choose Report Layout شوید.شما می‌توانید در این بخش یک حالت نمایشی را برای گزارش خود انتخاب نمایید و Next را کلیک نمایید.در بخش Choose Report Style یک قالب بندی جهت گزارش خود انتخاب نمایید.در ادامه Next و سپس Finish را کلیک نمایید.کدهای گزارش Generate شده می‌توان در قسمت Designer گزارش را مشاهده نمود. 

در این حالت کارهای زیر توسط Wizard به صورت اتوماتیک انجام خواهد شد:
• بایند شدن اتوماتیک فیلدهای گزارش به ستوان‌های مرتبط
• اعمال قالب بندی انتخاب شده برای صفحه و سر ستونها
• افزودن تاریخ و شماره صفحه به پایین گزارش
در ادامه پروژه را Rebuild کرده و گزینه Preview را در Designer جهت نمایش ، پیش نمایش گزارش کلیک نمایید.

نکته : در هر برنامه‌ی گزارش سازی بخش Designer گزارش به 4 بخش کلی تقسیم می‌شود:
•  Report Header: مواردی که در این بخش از گزارش قرار میگیرند در بالای صفحه اول گزارش نمایش داده می‌شوند.
•  Page Header: مواردی که در این بخش از گزارش قرار میگیرند در بالای همه صفحات گزارش قرار گرفته و تکرار می‌شوند.
•  Details: داده‌های اصلی گزارش که شامل جزئیات و بخش اصلی گزارش می‌باشند و سطر به سطر نیز تکرار می‌شوند در این بخش قرار می‌گیرند.
•  Page Footer: مواردی که در این بخش از گزارش قرار میگیرند در پایین همه صفحات نمایش داده می‌شوند.
•  Report Footer:مواردی که در این بخش قرار می‌گیرند در پایین صفحه آخر گزارش نمایش داده می‌شوند.  

ادامه دارد ...
مطالب
آشنایی با Refactoring - قسمت 10

یکی دیگر از روش‌هایی که جهت بهبود کیفیت کدها مورد استفاده قرار می‌گیرد، «طراحی با قراردادها» است؛ به این معنا که «بهتر است» متدهای تعریف شده پیش از استفاده از آرگومان‌های خود، آن‌ها را دقیقا بررسی کنند و به این نوع پیش شرط‌ها، قرارداد هم گفته می‌شود.
نمونه‌ای از آن‌را در قسمت 9 مشاهده کردید که در آن اگر آرگومان‌های متد AddRole، خالی یا نال باشند، یک استثناء صادر می‌شود. این نوع پیغام‌های واضح و دقیق در مورد عدم اعتبار ورودی‌های دریافتی، بهتر است از پیغام‌های کلی و نامفهوم null reference exception که بدون بررسی stack trace و سایر ملاحظات، علت بروز آن‌ها مشخص نمی‌شوند.
در دات نت 4، جهت سهولت این نوع بررسی‌ها، مفهوم Code Contracts ارائه شده است. (این نام هم از این جهت بکارگرفته شده که Design by Contract نام تجاری شرکت ثبت شده‌ای در آمریکا است!)


یک مثال:
متد زیر را در نظر بگیرید. اگر divisor مساوی صفر باشد، استثنای کلی DivideByZeroException صادر می‌شود:

namespace Refactoring.Day10.DesignByContract.Before
{
public class MathMehods
{
public double Divide(int dividend, int divisor)
{
return dividend / divisor;
}
}
}

روش متداول «طراحی با قراردادها» جهت بهبود کیفیت کد فوق پیش از دات نت 4 به صورت زیر است:

using System;

namespace Refactoring.Day10.DesignByContract.After
{
public class MathMehods
{
public double Divide(int dividend, int divisor)
{
if (divisor == 0)
throw new ArgumentException("divisor cannot be zero", "divisor");

return dividend / divisor;
}
}
}

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

در دات نت 4 ، به کمک امکانات مهیای در فضای نام System.Diagnostics.Contracts، این نوع بررسی‌ها نام و امکانات درخور خود را یافته‌اند:

using System.Diagnostics.Contracts;

namespace Refactoring.Day10.DesignByContract.After
{
public class MathMehods
{
public double Divide(int dividend, int divisor)
{
Contract.Requires(divisor != 0, "divisor cannot be zero");

return dividend / divisor;
}
}
}

البته اگر قطعه کد فوق را به همراه divisor=0 اجرا کنید، هیچ پیغام خاصی را مشاهده نخواهید کرد؛ از این لحاظ که نیاز است تا فایل‌های مرتبط با آن‌را از این آدرس دریافت و نصب کنید. این کتابخانه با VS2008 و VS2010 سازگار است. پس از آن، برگه‌ی Code contracts به عنوان یکی از برگه‌های خواص پروژه در دسترس خواهد بود و به کمک آن می‌توان مشخص کرد که برنامه حین رسیدن به این نوع بررسی‌ها چه عکس العملی را باید بروز دهد.

برای مطالعه بیشتر:
مطالب
عبارات باقاعده و نیاز به Timeout

یکبار سعی کنید مثال ساده زیر را اجرا کنید:

using System;
using System.Text.RegularExpressions;

namespace RegexLoop
{
class Program
{
static void Main(string[] args)
{
var emailAddressRegex = new Regex(@"^[A-Za-z0-9]([_\.\-]?[A-Za-z0-9]+)*\@[A-Za-z0-9]([_\.\-]?[A-Za-z0-9]+)*\.[A-Za-z0-9]([_\.\-]?[A-Za-z0-9]+)*$|^$");
if (emailAddressRegex.IsMatch("an.infinite.loop.sample.just_for.test"))
{
Console.WriteLine("Matched!");
}

var input = "The quick brown fox jumps";
var pattern = @"([a-z ]+)*!";
if (Regex.IsMatch(input, pattern))
{
Console.WriteLine("Matched!");
}
}
}
}


پس از اجرا، برنامه هنگ خواهد کرد یا به عبارتی برنامه در یک حلقه بی‌نهایت قرار می‌گیرد (در هر دو مثال؛ اطلاعات بیشتر و آنالیز کامل در اینجا). بنابراین نیاز به مکانیزمی امنیتی جهت محافظت در برابر این نوع ورودی‌ها وجود خواهد داشت؛ مثلا یک Timeout . اگر تا 2 ثانیه به جواب نرسیدیم، اجرای Regex متوقف شود. تا دات نت 4، چنین timeout ایی پیش بینی نشده؛ اما در دات نت 4 و نیم آرگومانی جهت تعریف حداکثر مدت زمان قابل قبول اجرای یک عبارت باقاعده در نظر گرفته شده است (^) و اگر در طی مدت زمان مشخص شده، کار انجام محاسبات به پایان نرسد، استثنای RegexMatchTimeoutException صادر خواهد شد.
خیلی هم خوب. به این ترتیب کسی نمی‌تونه با یک ورودی ویژه، CPU Usage سیستم رو تا مدت زمان نامحدودی به 100 درصد برساند و عملا استفاده از سیستم رو غیرممکن کنه.
اما تا قبل از دات نت 4 و نیم چکار باید کرد؟ روش کلی حل این مساله به این ترتیب است که باید اجرای Regex را به یک ترد دیگر منتقل کرد؛ اگر مدت اجرای عملیات، از زمان تعیین شده بیشتر گردید، آنگاه می‌شود ترد را Abort کرد و به عملیات خاتمه داد. روش پیاده سازی و نحوه استفاده از آن‌را در ادامه ملاحظه خواهید نمود:

using System;
using System.Text.RegularExpressions;
using System.Threading;

namespace RegexLoop
{
public static class TimedRunner
{
public static R RunWithTimeout<R>(Func<R> proc, TimeSpan duration)
{
using (var waitHandle = new AutoResetEvent(false))
{
var ret = default(R);
var thread = new Thread(() =>
{
ret = proc();
waitHandle.Set();
}) { IsBackground = true };
thread.Start();

bool timedOut = !waitHandle.WaitOne(duration, false);
waitHandle.Close();

if (timedOut)
{
try
{
thread.Abort();
}
catch { }
return default(R);
}
return ret;
}
}
}

class Program
{
static void Main(string[] args)
{
var emailAddressRegex = new Regex(@"^[A-Za-z0-9]([_\.\-]?[A-Za-z0-9]+)*\@[A-Za-z0-9]([_\.\-]?[A-Za-z0-9]+)*\.[A-Za-z0-9]([_\.\-]?[A-Za-z0-9]+)*$|^$");
if (TimedRunner.RunWithTimeout(
() => emailAddressRegex.IsMatch("an.infinite.loop.sample.just_for.test"),
TimeSpan.FromSeconds(2)))
{
Console.WriteLine("Matched!");
}

var input = "The quick brown fox jumps";
var pattern = @"([a-z ]+)*!";
if (TimedRunner.RunWithTimeout(() => Regex.IsMatch(input, pattern), TimeSpan.FromSeconds(2)))
{
Console.WriteLine("Matched!");
}
}
}
}

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

اشتراک‌ها
Visual Studio 2019 RC منتشر شد
Visual Studio 2019 RC منتشر شد
بازخوردهای دوره
آشنایی با مدل برنامه نویسی TAP
با سلام 
من دستور زیر را در پاورشل نیوگت اجرا کردم اما از متدها الحاقی نمی‌تونم استفاده کنم در دات نت 4
PM> Install-Package Microsoft.Bcl.Async 
با تشکر