در قسمت قبلی به اصل وجودی CLR پرداختیم. در این قسمت تا حدودی به بررسی ماژول مدیریت شده managed module که از زبانهای دیگر، کامپایل شده و به زبان میانی تبدیل گشته است صحبت میکنیم.
یک ماژول مدیریت شده شامل بخشهای زیر است:
نام بخش | توضیح |
هدر PE32 یا PE32+ | CLR باید بداند که برنامهی نوشته شده قرار است روی چه پلتفرمی و
با چه معماری، اجرا گردد. این برنامه یک برنامهی 32 بیتی است یا 64
بیتی. همچنین این هدر اشاره میکند که نوع فایل از چه نوعی است؛ GUI,CUI یا
DLL. به علاوه تاریخ ایجاد یا کامپایل فایل هم در آن ذکر شده است. در صورتیکه
این فایل شامل کدهای بومی native CPU هم باشد، اطلاعاتی در مورد این نوع
کدها نیز در این هدر ذکر میشود و اگر ماژول ارائه شده تنها شامل کد IL باشد،
قسمت بزرگی از اطلاعات این هدر در نظر گرفته نمیشود. |
CLR Header | اطلاعاتی را در مورد CLR ارائه میکند. اینکه برای
اجرا به چه ورژنی از CLR نیاز دارد. منابع مورد استفاده. آدرس و اندازه جداول
و فایلهای متادیتا و جزئیات دیگر. |
metadata | هر کد یا ماژول مدیریت شدهای، شامل جداول متادیتا است که این جداول
بر دو نوع هستند. اول جداولی که نوعها و اعضای تعریف شده در کد را توصیف
میکنند و دومی جداولی که نوعها و اعضایی را که در کد به آن ارجاع شده است،
توصیف میکنند. |
IL Code | اینجا محل قرار گیری کدهای میانی تبدیل شده است که در زمان اجرا، CLR آنها را به کدهای بومی تبدیل میکند. |
کامپایلرهایی که بر اساس CLR کار میکنند، وظیفه دارند جداول متادیتاها را به طور کامل ساخته و داخل فایل نهایی embed کنند. متادیتاها مجموعهی کاملی از فناوریهای قدیمی چون فایلهای COM یا Component Object Model و همچنین IDL یا Interface Definition (Description) Language هستند. گفتیم که متادیتاها همیشه داخل فایل IL که ممکن است DLL باشد یا EXE، ترکیب یا Embed شدهاند و جدایی آنها غیر ممکن است. در واقع کامپایلر در یک زمان، هم کد IL و هم متادیتاها را تولید کرده و آنها را به صورت یک نتیجهی واحد در میآورد.
متادیتاها استفادههای زیادی دارند که در زیر به تعدادی از آنان اشاره میکنیم:
- موقع کامپایل نیاز به هدرهای C و ++C از بین میرود؛ چرا که فایل نهایی شامل تمامی اطلاعات ارجاع شده میباشد. کامپایلرها میتوانند مستقیما اطلاعات را از داخل متادیتاها بخوانند.
- ویژوال استودیو از آنها برای کدنویسی راحتتر بهره میگیرد. با استفاده از قابلیت IntelliSense، متادیتاها به شما خواهند گفت چه متدهایی، چه پراپرتیهایی، چه رویدادهایی و ... در دسترس شماست و هر متد انتظار چه پارامترهایی را از شما دارد.
- CLR Code Verification از متادیتا برای اینکه اطمینان کسب کند که کدها تنها عملیات type Safe را انجام میدهند، استفاده میکند.
- متادیتاها به فیلد یک شیء اجازه میدهند که خود را به داخل بلوکهای حافظ انتقال داده و بعد از ارسال به یک ماشین دیگر، همان شیء را با همان وضعیت، ایجاد نماید.
- متادیتاها به GC اجازه میدهند که طول عمر یک شیء را رصد کند. GC برای هر شیء موجود میتواند نوع هر شیء را تشخیص داده و از طریق متادیتاها میتواند تشخیص دهد که فیلدهای یک شیء به اشیاء دیگری هم متصل هستند.
در آینده بیشتر در مورد متادیتاها صحبت خواهیم کرد.
معرفی Blazor Hybrid
- در Blazor Web Assembly که UI با HTML / CSS زده میشود، کدهای C# .NET ای با کمک Web Assembly و داخل خود مرورگر اجرا میشوند. با کمک Blazor Web Assembly میتوان محصولات PWA و SPA ایجاد نمود.
- در Blazor Server که UI با HTML / CSS زده میشود، کدها در سرور اجرا و به وسیلهی Web Sockets، تعاملات UI ای از Browser به سرور ارسال و تغییرات UI ای از سرور به Browser ارسال میشوند. با کمک Blazor Server میتوان محصولات SPA ایجاد نمود.
- Blazor Native Mobile Apps که در این روش از کامپوننتهای Native موبایل استفاده میشود؛ نه عناصر HTML مانند h1 و div. با کمک Blazor Native Mobile Apps میتوان برنامههای Native موبایل برای Android / iOS و برنامههای Desktop برای Windows ایجاد نمود.
- Blazor Hybrid که در این روش UI با HTML / CSS بوده، ولی اجرای کدهای C# .NET داخل خود سیستم عامل و به صورت Native است. با کمک Blazor Hybrid میتوان برنامههای موبایل برای Android / iOS و برنامههای Desktop برای Windows ایجاد نمود.
برای شروع کار با Backload ابتدا به قسمت Nutget میرویم که در مسیر زیر است :
Backload. A Proffesional Full Featured Asp.Net FileUpload Controller *
پس از نصب دو مورد بالا ، موارد زیر را که در دو عکس پایین میبینید، به پروژهی شما اضافه خواهند شد:
*نکاتی که باید بدانید:
عکس هایی که شما آپلود میکنید در پوشهی Files موجود در ریشهی پروژهی شما قرار میگیرند این پوشه بوسیلهی خود ابزار Backload ساخته میشود.
چنانچه بخواهید در پوشهی Files پوشهای ایجاد کنید، ابتدا View آنرا باز کنید. این View در پروژه، در مسیر Views/ BackloadDemo/Index قرار دارد .
در داخل تگ form یک Hidden Field با نام objectContext اضافه میکنید. Value ایی که شما به این Hidden Field نسبت میدهید، نام پوشهی شما در پوشهی Files خواهد بود. مانند تصویر زیر: در اینجا پوشهای با نام 2014-02 در پوشهی Files وقتی که فایلی را باFile Upload آپلود میکنیم، ایجاد میشود.
چنانچه بخواهید در پوشهای که خودتان ایجاد کردید (که در این مثال 2014-02 میباشد) پوشههای متعدد دیگری هم داشته باشید Hidden Field ای با نام uploadContext ایجاد میکنید؛ مانند تصویر زیر :
اکنون اگر فایل جدیدی را آپلود کنید در مسیر
ذخیره میشود . یعنی بین نام هر پوشه از سمی کولن ; در Value استفاده میکنید.
تا اینجا ما میتوانیم بوسیلهی ابزار Backload عکسها را آپلود ، حذف و مسیر آپلود عکسها را تغییر دهیم.اگر توجه کرده باشید دفعات بعد که پروژه را اجرا میکنید عکسهای موجود در پوشه، در گرید ویو File Upload به شما نمایش داده خواهد شد. حال اگر بخوایم عکسهای موجود در پوشهی دیگری را نمایش دهیم باید چه کار کنیم؟!
گاهی اوقات نیاز داریم که محتویات پوشهای خاص را در گرید ویو File Upload مان نمایش دهیم. برای این کار شما باید کنترلر FileUploadController که در فایل ضمیمه در آموزش هست را در پوشهی Controller پروژهی خود کپی کنید .اگر شما این کنترلر را باز کنید مواردی مانند کلمه کلیدی Task و async را مشاهده خواهید کرد. این موارد در .Net Framework 4 شناسایی نمیشود. برای همین در ابتدای آموزش تاکید کردم که .Net Framework 4.5 و یا بالاتر را برای پروژهی خود انتخاب کنید .
در تابع Handler_GetFilesRequestStarted در این کنترلر باید مشخص کنید که فایلهای موجود در کدام مسیر را برای شما نمایش دهد؛ آن هم با استفاده از دستور زیر :
اکنون قبل از آنکه پروژه را اجرا کنید فایل Backload.Demo.js که در مسیر Scripts/Fileupload هست را باز کنید و url موجود در آنرا مانند عکس زیر تغیییر دهید :
حالا پروژه را اجرا کنید. خواهید دید تمامی فایلهای موجود در مسیری را که شما مشخص کردهاید، برایتان نمایش خواهد داد.
چنانچه بخواهید تعداد مثلا 5 فایل برای شما در گرید ویو مربوط به FileUpload نمایش داده شود، به تابع handler_GetFilesRequestFinished میروید. متغیر limit مشخص میکند که 5 فایل نمایش داده شود. میتوانید این عدد را به دلخواه خود تغییر دهید.
نکتهی بسیار مهم دیگری که باید به آن توجه شود مربوط به Hidden Field نام پوشهها میباشد. بار دیگر پروژه را اجرا کنید. با استفاده از ابزاری مثل FireBug کدهای html صفحهی خود را ببینید. Hidden Field ایی با نام objectContext را پیدا کنید و Value آنرا به test تغییر دهید. فایلی را آپلود کنید حالا به پوشهی Files موجود در ریشهی پروژه بروید. میبینید که پوشهای با نام testایجاد شده و فایلی هم که آپلود کردید در آن قرار دارد که این یک اشکال است. برای اینکه جلوی این گونه کارها را بگیریم به تابع handler_StoreFileRequestStartedAsync میرویم و کد زیر را مینویسیم :
دستور e.Context.PipelineControl.ExecutePipeline = false; باعث میشود که اجرای تابع متوقف شود.
فایل ضمیمه :FileUploadController-462d551688cf48c68cb55343ac5464f3.zip
برای مشاهده مثالهای دیگری دربارهی Backload به این لینک بروید.
موفق باشید.
این نوشتار اولین آموزش من در این سایت میباشد و جا دارد از دوست خوبم "محبوبه قربانی" که باعث شد من با MVC آشنا شوم تشکر کنم.
- فایل اجرایی تک فایلی تولید شده در اصل یک فایل zip خود باز شونده بود که در یک مکان موقتی به صورت خودکار باز و اجرا میشد. این حالت با آنتیویروسها و یا سیستمهایی که قسمتهای اصلی آنها جهت کاربران عادی قفل شدهاند، مشکلاتی را ایجاد میکرد.
- حجم فایل نهایی تولید شده قابل توجه بود. برای نمونه یک برنامهی کنسول Hello world آن حدود 70 مگابایت میشد. البته باید درنظر داشت که یک چنین خروجی به همراه یک NET Core runtime. کامل نیز میشد.
از آن زمان تغییرات تدریجی مفیدی در این زمینه رخ دادهاند که خلاصهای از آنها را تا دات نت 6 در ادامه مرور میکنیم.
اصول تولید برنامههای اجرایی تک فایلی دات نت
فرض کنید برنامهی کنسول ما از این سه سطر تشکیل شدهاست:
using System; Console.WriteLine("Hello, World!"); Console.ReadLine();
dotnet publish -p:PublishSingleFile=true -r win-x64 -c Release --self-contained true
پس از اجرای دستور فوق، اگر به مکان C:\MyProject\bin\Release\net6.0\win-x64\publish مراجعه کنیم، به یک فایل exe حدود 62 مگابایتی خواهیم رسید که کمی کم حجمتر از نمونهی NET Core 3x. آن است! البته همانطور که عنوان شد این خروجی به همراه runtime متناظری نیز هست. اگر بخواهیم این runtime را از آن حذف کنیم میتوان به صورت زیر عمل کرد:
dotnet publish -p:PublishSingleFile=true -r win-x64 -c Release --self-contained false
یک نکته: میتوان سوئیچهای فوق را به فایل csproj نیز به صورت زیر اضافه کرد:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net6.0</TargetFramework> <PublishSingleFile>true</PublishSingleFile> <SelfContained>true</SelfContained> <RuntimeIdentifier>win-x64</RuntimeIdentifier> <PublishReadyToRun>true</PublishReadyToRun> </PropertyGroup> </Project>
تک فایلهای اجرایی دات نت 6 دیگر فایلهای zip خود باز شونده نیستند
همانطور که عنوان شد، تک فایلهای اجرایی تولید شدهی در نگارشهای پیشین دات نت، چیزی بجز یک فایل zip خود بازشونده که همه چیز داخل آن قرار گرفته بودند، نبودند. این حالت دیگر در دات نت 6 صادق نیست و اینبار خروجی نهایی در حافظه بارگذاری میشود و نیاز به باز شدن آن در مکانهای temp برطرف شدهاست. تا زمان دات نت 5، این قابلیت فقط برای خروجیهای لینوکس تدارک دیده شده بود، اما با ارائهی دات نت 6، خروجیهای ویندوز و مک هم فایلهای اجرایی واقعی هستند.
فعالسازی IL Trimming
به صورت پیشفرض با اجرای دستورات تولید تک فایلهای اجرایی برنامههای دات نت، تمام وابستگیهای استفاده شده بدون هیچگونه بهینه سازی در کنار هم قرار میگیرند. با فعالسازی قابلیت IL Trimming میتوان وابستگیهایی را که برنامه از آنها استفاده نمیکند، از خروجی نهایی حذف کرد که در نتیجهی آن، شاهد کاهش حجم قابل ملاحظهی فایل تولیدی نهایی خواهیم بود. برای اینکار میتوان سوئیچ PublishTrimmed را فعالسازی کرد:
dotnet publish -p:PublishSingleFile=true -r win-x64 -c Release --self-contained true -p:PublishTrimmed=true
باید دقت داشت که این حجم نهایی، یک فایل اجرایی واقعی بدون نیاز به نصب هیچ نوع runtime ای است و کاملا متکی به خود است.
فعالسازی فشرده سازی
به همراه دات نت 6، امکان فشرده سازی خودکار این خروجی نهایی تک فایلی، جهت کاهش هرچه بیشتر حجم آن نیز میسر شدهاست. برای اینکار میتوان سوئیچ EnableCompressionInSingleFile را فعالسازی کرد:
dotnet publish -p:PublishSingleFile=true -r win-x64 -c Release --self-contained true -p:EnableCompressionInSingleFile=true
خطا هنگام اجرا در IIS/7.5 کلیه آدرس ها نیاز به دریافت پارامتر ارسالی دارند
وجود , اضافی در حین معرفی خواص در زبان #C کاملا مجازه و به هیچ چیزی هم تفسیر نمیشه. اگر این رو حذف کردید و بعد برنامه رو کامپایل و به سرور ارسال کردید، یعنی فایلهای bin روی سرور شما قدیمی بودن یا هماهنگ نشده بودند. معنای دیگری نداره.
اگر در فایلهای Razor برنامههای ASP.NET Core 2.0 میخواهید از قابلیتهای C# 7.1 استفاده کنید، نیاز است تنظیم LangVersion ذیل را به فایل csproj اضافه نمائید:
<PropertyGroup> <TargetFramework>netcoreapp2.0</TargetFramework> <LangVersion>latest</LangVersion> </PropertyGroup>
C# Literals & C# 7.0 Binary Literals and Digit Separators
C#7: Binary Literals and Numeric Literal Digit Separators
پیش از ارائه نهایی مطلب، تمام کدهای آن با VS 2017 RTM آزمایش و بررسی شوند.
Generalized Async Return Types in C# 7.0
C#7: Better Performance with Ref Locals, and Ref and Async Returns
Asynchronous Programming in C# using Async Await – Best Practices
پیش از ارائه نهایی مطلب، تمام کدهای آن با VS 2017 RTM آزمایش و بررسی شوند.