مطالب
Performance در AngularJS 1.x قدم ششم
موضوع این مقاله استفاده مستقیم از توابع و عملیات محاسباتی برای Binding در View می‌باشد که در پروژه‌های بزرگ که حجم المنت‌ها در صفحه زیاد است عملکردی منفی در Performance دارد که قابل چشم پوشی نیست. برای اینکه این مورد ملموس باشد بنده مثالی را آماده کرده‌ام که هدف آن بیشتر درک درست شما از این موضوع است.
کد زیر را مشاهده کنید:
<input type="text" ng-model="newItemTitle">
<button type="button" ng-click="add()">افزودن</button>
<ul>
     <li ng-repeat="item in items">{{item.title}}</li>
</ul>
<div ng-show="showMSG()">شما بیش از ۱۰ استان ثبت کرده اید</div>
و قسمت Controller:
$scope.newItemTitle='';           

$scope.add=function(){
     $scope.items.push({
          title:$scope.newItemTitle
     });
}

$scope.items=[
     {title:'اردبیل'},
     {title:'تهران'},
     {title:'اصفهان'},
     {title:'شیراز'},
     {title:'مشهد'},
];  

$scope.showMSG=function(){
     return $scope.items.length>10;
}
 همانطور که مشاهده میکنید این کد یک مثال ساده است که شامل لیست استانها و قسمتی برای افزودن استان جدید و در قسمت پایینتر در صورتی که بیش از ۱۰ استان ثبت شده باشد به کاربر پیغامی نمایش می‌دهیم.

سوال اول، مشکل کجاست؟
این کد کاملا صحیح است، اما بهینه نیست. مشکل اصلی در View است که مستقیما تابع showMSG را صدا میزند. صدا زدن مستقیم توابع از View در قسمت‌هایی که Bind شده‌اند، در Performance نتیجه منفی دارند. منظور از صدا زدن مستقیم توابع در قسمت‌های Bind روش‌های زیر است:
ng-show="showMSG()"
ng-if="showMSG()"
ng-hide="showMSG()==false"
ng-class="{'red',getResult()}"
ng-style="{'width':getWidth()}"
سوال دوم، چرا Performance را کاهش میدهد؟
AngularJS برای اینکه بتواند تکلیف ng-show هایی را که در div نوشته شده‌است، مشخص کند، مجبور است تابع showMSG را صدا بزند. تا این قسمت هیچ مشکلی نیست. اما وقتی که AngularJS می‌خواهد در زمان‌های بعدی هم متوجه تغییرات بشود مجبود هست دوباره تابع showMSG را صدا بزند و این کار تکرار می‌شود و در مواقعی که تغییرات انجام شده هیچ ارتباطی با این Binding ندارند باز هم اجرا می‌شود و این تداوم در اجرا که اکثرا لازم نیستند باعث کاهش Performance می‌شود. حالا فرض کنید در پروژه‌ای بزرگ در بیشتر قسمت‌های صفحه از این روش استفاده کرده اید و پروژه با داده‌های حجیم کار میکند.

سوال سوم، راهکار چیست؟ 
راهکار این موضوع خیلی ساده است؛ اما در بهبود کارآیی پروژه، خیلی تاثیر مثبتی دارد. به طور کلی سعی کنید در ‌Binding‌های View از متغییر استفاده کنید و هیچ تابعی و یا عملیات محاسباتی را در Binding قرار ندهید . منظور از عملیات محاسباتی در Binding روش زیر است:
<div ng-show="items.length>10">شما بیش از ۱۰ استان ثبت کرده اید</div>
حتی این روش هم مناسب نیست. روشی که می‌توان برای حل این مشکل در نظر گرفت به شرح زیر است:
$scope.maxItem=false';           

$scope.add=function(){
     $scope.items.push({
          title:$scope.newItemTitle
     });
     $scope.maxItem=$scope.items.length>10;
}

<div ng-show="maxItem">شما بیش از ۱۰ استان ثبت کرده اید</div>
این مشکل با متفیر maxItem و انتقال منطق به تابع add حل می‌شود.
نتیجه گیری کلی، در پروژه‌هایی که با داده‌های حجیم کار میکنند، هیچ وقت از توابع و عملیات محاسباتی در View استفاده نکنید. 
نظرات اشتراک‌ها
FireFox 18 و مصرف بالای CPU
فایرفاکس 18.0.2 تازه منتشر شده. به نظر این مشکل رو برطرف کردن.
مطالب
رفع مشکل postBack در Master Page و دریافت خطای Operation is not valid due to the current state of the object
با این خطا هنگامی مواجه شدم که در Master Page  یک TextBox و یک دکمه قرار داده بودم و در رویداد دکمه به یک صفحه دیگر انتقال پیدا می‌کردم. کد زیر:
protected void imgBtnSearch_Click(object sender, ImageClickEventArgs e)
        {
            if (TxtbSearch.Text != string.Empty)
            {
                Response.Redirect("/Exhibition/ShowSearch.aspx?title=" + 
                      Sanitizer.GetSafeHtmlFragment(TxtbSearch.Text) + "&b=true", false);
            }
        }
این کد در ماشین خودم کار می‌کرد و مشکلی نداشت. وقتی پروژه را به سرور انتقال می‌دادم و بر روی IIS 6 تست می‌کردم خطای 404 دریافت می‌کردم. ضمن اینکه به صفحه خواسته شده انتقال پیدا نمی‌کردم، و همه چیز کاملا گیج کننده بود. وقتی صفحه را از خود سرور باز و رویداد فوق را اجرا می‌کردم خطای Operation is not valid due to the current state of the object دریافت می‌کردم به همراه کد زیر در Track trace به شرح زیر:
at System.Web.HttpValueCollection.ThrowIfMaxHttpCollectionKeysExceeded()
at System.Web.HttpValueCollection.FillFromEncodedBytes(Byte[] bytes, Encoding encoding)
at System.Web.HttpRequest.FillInFormCollection()
با افزودن کد زیر در Web.config مشکل برطرف گردید.
<appSettings>
    <add key="aspnet:MaxHttpCollectionKeys" value="2001" />
  </appSettings>
منابع:
Code Project
stack overflow
مطالب
توسعه برنامه‌های Cross Platform با Xamarin Forms & Bit Framework - قسمت سیزدهم
در این قسمت قصد داریم به بررسی نحوه‌ی بهبود Performance در پروژه‌های Xamarin Forms نگاهی بیاندازیم. صد البته امکان پوشش دادن تمامی نکات وجود ندارد و در این قسمت سعی بر پوشش دادن مهم‌ترین آنها را داریم.
توجه داشته باشید که در قسمت نهم به "x:DataType" و در قسمت چهارم به "مواردی مهم در زمینه‌ی بهبود عملکرد پروژه‌های Xamarin در Android" پرداخته بودیم که آن نکات در بهبود سرعت برنامه‌ها تاثیر گذارند. همان طور که در قسمت چهارم گفته شد، همیشه سرعت برنامه را در Release mode تست کنید.

در Xamarin Forms هر کنترل (برای مثال Entry و Button) در زمان اجرا به یک کنترل Native معادل خود تبدیل می‌شود. مشکلی که وجود دارد این است که وقتی از روی Button مربوط به Xamarin Forms، یک Button در Android و ... ساخته می‌شود، آن Button بر روی یک Container قرار می‌گیرد. در واقع به ازای هر کنترل Xamarin Forms، دو کنترل Native ساخته می‌شود(!) و تعداد کنترل‌های بیشتر در برنامه یعنی کندی بیشتر.
وظیفه تبدیل Xamarin forms control به یک Native control بر عهده ‌Renderer هاست. البته اینکه هر Xamarin Forms control به دو Native control تبدیل شود در ذیل بحث Fast Renderers در حال بهبود یافتن است. Fast Renderer یک Renderer است که به ازای هر Xamarin forms control، فقط یک کنترل Native را می‌سازد. راهنمای فعال سازی Fast Renderers را می‌توانید بخوانید و در برنامه‌هایتان اعمال کنید؛ ولی در پروژه‌های مبتنی بر Bit مانند XamApp، این مهم به صورت خودکار فعال می‌شود و نیازی به اقدام جداگانه‌ای نیست.

مورد بعدی در مورد Layout‌های Xamarin Forms است (Grid,StackLayout,FlexLayout و...) در صورتیکه قصد تعریف کردن مواردی چون Tap Gesture و Background را بر روی Layout خود ندارید و از Layout خود فقط انتظار Layout بودن را دارید، می‌توانید آنها را سریع‌تر سازید. مثال قسمت قبل را که برای نمایش هر Product در List View از Flex Layout استفاده می‌کرد، به‌خاطر بیاورید. ما آن Flex را استفاده کردیم تا نام Product، بیست و پنج درصد فضای هر ردیف از List View را بگیرد و ... به آن Flex Layout رنگی داده نشد یا هر چیزی از این قبیل. برای بهبود عملکرد آن List View می‌توانیم از Flex Layout به شکل زیر استفاده کنیم:
<sfListView:SfListView.ItemTemplate>
                <DataTemplate>
                    <FlexLayout
                        x:DataType="model:Product"
                        CompressedLayout.IsHeadless="True"
                        Direction="Row">
                        <Label
                            FlexLayout.Basis="40%"
                            Text="{Binding Name}"
                            VerticalTextAlignment="Center" /> ...
با اضافه کردن CompressedLayout.IsHeadless=True دیگر کنترل Native ای برای آن Flex Layout ساخته نمی‌شود و کنترل Native کمتر یعنی سرعت بیشتر برنامه.
برای این امکان، ذکر دو نکته الزامی است:
۱- استفاده از CompressedLayout.IsHeadless باعث می‌شود تعدادی از امکانات Layout مانند Background Color دیگر کار نکنند. فعال سازی آن فقط در DataTemplate‌های ListView توصیه می‌شود که مثلا 20 عدد Product در مثال قسمت قبل، منجر به ساخته شدن 20 عدد Flex Layout می‌شوند و اگر کاری کنیم که کنترل Native معادل آن ساخته نشود، لااقل 20 بار سود کرده‌ایم! استفاده کردن از CompressLayout در همه جای برنامه، ایده جالبی نیست.
۲- CompressedLayout فقط در Android و iOS اعمال می‌شود و تست کردن آن در UWP عملا فایده‌ای ندارد.

نکته مهم بعدی، بحث نمایش عکس است. در Xamarin Forms یک عکس می‌تواند در رزولوشن‌های مختلف با کمک Drawable در Android و Asset Catalog Image Sets در iOS و ... باشد. همچنین می‌توان عکس را از یک Url گرفت و یا به شکل Embedded در پروژه‌ی مشترک بین سه پلتفرم باشد. می‌توان علاوه بر PNG و JPG از WebP ،SVG و GIF نیز استفاده نمود. اما آنچه که مهم است این است که بعد از یادگیری اصول اولیه نمایش عکس در Xamarin Forms، حتما حتما از FF Image Loading برای نمایش عکس‌ها استفاده شود.
استفاده از FF Image Loading دارای مزایایی چون پشتیبانی از WebP | SVG است. همچنین این کتابخانه فایل‌ها را نیز Cache می‌کند (هم در صورتیکه Url باشند و قرار باشند از طریق اینترنت دریافت شوند و هم Bitmap حاصل از Render کردن آن عکس برای آن Device خاص همانند GlideX در Android). امکان گرد کردن عکس، یا سیاه و سفید نمودن آن و کوهی از امکانات دیگر، استفاده‌ی از این کتابخانه را الزامی می‌کند!
برای نمایش لوگوی Bit در برنامه برای مثال، ابتدا Package مربوطه را در پروژه XamApp نصب می‌کنیم. سپس آن را در Android ،iOS و UWP راه اندازی می‌کنیم و در Android مقدار enableFastRenderer را True می‌دهیم. سپس در Xaml داریم:
        <ffimageloading:CachedImage
            CacheType="All"
            DownsampleToViewSize="true"
            HeightRequest="100"
            HorizontalOptions="Center"
            Source="https://avatars2.githubusercontent.com/u/22663390?s=100"
            VerticalOptions="Center"
            WidthRequest="100" />
پایان
مطالب
تکنیک‌های ایجاد سایت‌های چند زبانه
امروزه چند زبانه بودن سایت‌ها، از اهمیت بالایی برخوردار شده است و هر سایتی که نیاز داشته باشد در سایر نقاط جهان شناخته شود و کاربران مناطق مختلف، به راحتی از آن استفاده کنند، سایت‌های خود را بر پایه‌ی چندین زبان ایجاد می‌کنند. در این نوشتار سعی داریم بر این موضوع بررسی اجمالی داشته باشیم و نکات زیر را بررسی نماییم.

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

طراحی مدل دیتابیس

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

مزایا:

  1. پیاده سازی آسان

معایب:

  1. در این روش با زیاد شدن هر زبان، تعداد ستون‌ها افزایش می‌یابد که باعث می‌شود طراحی مناسبی نداشته باشد.
  2. در ضمن این مورد باید توسط برنامه نویس مرتبا اضافه گردد یا اینکه برنامه نویس این امکان را در سیستم قرار دهد که مدیر سایت بتواند در پشت صحنه کوئری افزودن ستون را ایجاد کند که باید جدول مرتبا مورد alter گرفتن قرار بگیرد.
  3. ممکن است همیشه برای هر زبانی مطلبی قرار نگیرد و این مورد باعث می‌شود بی جهت فضایی برای آن در نظر گرفته شود.

پی نوشت: با اینکه امروزه بحث فیلدهای sparse Column وجود دارد ولی این فیلد‌ها در هر شرایطی مورد استفاده قرار نمی‌گیرند وبیشتر متعلق به زمانی است که می‌دانیم آن فیلد به شدت کم مورد استفاده قرار می‌گیرد.

پی نوشت دوم : در صورتی که فیلد شما مانند متن مقاله که عموما از نوع داده (varchar(max است استفاده می‌کنید و در صورتی که زبان مورد استفاده قرار نگیرد در خیلی از اوقات بی جهت فیلد‌های Blob ساخته اید که بهینه سازی آن را نیز باید در نظر بگیرید.


در مرحله‌ی بعد برای رفع مشکلات بالا یک جدول از زبان‌ها، مانند جدول زیر را ایجاد می‌کنیم:
 
 ID  کد
 Language  زبان
 ISO  کد دو رقمی آن زبان
 Flag  پرچم آن کشور
بعد از آن هر مقاله برای یک زبان ایجاد خواهد شد؛ چیزی مانند تصویر زیر:

مزایا:

  1. پیاده سازی آسان

معایب:

  1. ایجاد رکوردهای تکراری، هر مقاله برای بعضی از اطلاعاتش که چند زبانه نیستند داده‌های تکراری خواهد داشت.
  2. هر مقاله یک مقاله‌ی جدا شناخته می‌شود و ارتباطی میان آنان نخواهد بود. بدین ترتیب توانایی ایجاد گزارش‌هایی چون هر گروه از مقاله و دسته بندی آن‌ها از بین خواهد رفت. در ضمن مدیر عموما در یک سیستم مدیریتی می‌خواهد تنها یک لینک را به یک مقاله بدهد و سایت بنا به تشخیص در زبان مزبور، یکی از این مقالات را به کاربر نمایش دهد؛ نه اینکه مرتبا مدیر برای هر زبان، لینکی را مهیا کند و در این حالت چنین چیزی ممکن نخواهد بود.
  3. در یک سیستم فروشگاهی همانند تصویر بالا کار هم سخت‌تر می‌شود و هر رکورد، یک محصول جدا شناخته می‌شود و ویرایش‌ها هم برای هر کدام باید جداگانه صورت بگیرد که در عمل این طرح را رد می‌کند.


سومین راه حل این است که سه جدول ایجاد کنیم:

یک. جدول زبان‌ها (که بالاتر ایجاد شده بود)

دو . جدول نام مقاله به همراه اطلاعات پایه و فیلدها بی نیاز به چند زبانه بودن

سه : یک جدول که هر دو ستون آن کدهای کلید دو جدول بالا را دارند و فیلدهای چند زبانه در آن وجود دارند.

جدول پایه

 ID  کد
 Name  نام مقاله
 CreationDate  تاریخ ایجاد
 Writer  نویسنده
 Visibilty  وضعیت نمایش
 جدول مقالات
 LanguageCode کد زبان
 ArticleID  کد مقاله
 CreationDate  تاریخ ایجاد
 Visibility  وضعیت نمایش مقاله
Title
عنوان مقاله
ContentText
متن مقاله

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

مزایا:

  1. گزارش گیری آسان برای هر دسته مقاله با زبان‌های مختلف و ارتباط و یکپارچگی
  2. آسان در افزودن زبان.

معایب:

  1. ایجاد کوئری‌های پیچیده‌تر و جوین دار که به نسبت روش‌های قبلی کوئری‌ها پیچیده‌تر شده اند.
  2. کدنویسی زیادتر.

استفاده از ساختارهای XML یا JSON برای ذخیره سازی اطلاعات چند زبانه مانند ساختارهای زیر:

XML
<Articles>
<Article>
this is english text
</Article>
<Article>
این یک متن فارسی است
</Article>
</Articles>

یا 
<Articles>
<en-us>
this is english text
</en-us>
<fa-ir>
این یک متن فارسی است
</fa-ir>
</Articles>
JSON
"Articles":["en-us':{"title":"this is english text","content":" english content"},"fa-ir":{"title":"متن فارسی","content":"محتوای فارسی"}]
ازSQL Server 2005 به بعد از نوع داده xml پشتیبانی می‌شود و در نسخه‌ی 2016 آن نیز پشتیبانی از Json اضافه شده است که حتی شامل اندیکس‌های اختصاصی هم برای این دو نوع می‌باشد.
از مزایای این روش ذخیره‌ی همه داده‌ها در یک ستون و یک جدول است و نیازی به ستون‌های اضافه یا جداول اضافه نیست ولی معایب این روش استفاده از کوئری‌های پیچیده‌تر جهت ارتباط و خواندن است.

استفاده از بانک‌های اطلاعاتی NO SQL
در این بانک‌ها دیگر درگیر تعداد ستون‌ها و جنس آن‌ها نیستیم و میتوانیم برای هر مقاله یا محصول، هر تعداد زبان و یا فیلد را که می‌خواهیم، در نظر بگیریم و اضافه کنیم. برای آشنایی بیشتر با این نوع بانک‌ها و انواع آن، مقالات مربوط به nosql را در سایت دنبال کنید.

نکاتی که در یک سایت چند زبانه باید به آن‌ها توجه کرد.

یک . زبان آن صفحه را معرفی کنید: این کار هم به موتورهای جست و جو برای ثبت سایت شما کمک می‌کند و هم برای معلولین که از ابزارهای صفحه خوان استفاده می‌کنند، کمک بزرگی است. در این روش، صفحه خوان‌ها و دستگاه‌های خط بریل که زبان صفحه را تشخیص نمی‌دهند با خواندن کد زبان می‌توانند زبان صفحه را تشخیص دهند. با استفاده از خط زیر میتوانید زبان اصلی صفحه‌ی خود را تنظیم نمایید:
<html lang="en">

اگر از XHTML استفاده می‌کنید خاصیت زیر را فراموش نکنید. دریافت W3C Validation بدون آن امکان پذیر نخواهد بود.
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
با تغییر زبان هر صفحه، باید تنظیم زبان آن تغییر یابد:



دو. چند زبانه بودن صفحه: در بالا یاد گرفتیم که چگونه زبان اصلی صفحه را تنظیم کنیم، ولی گاهی اوقات صفحه به غیر از زبان اصلی، شامل زبان‌های دیگر هم می‌شود؛ مثل نقل قول‌ها یا موارد دیگر. برای این‌کار می‌توانید از خصوصیت lang که در اکثر تگ‌ها پشتیبانی می‌شود، استفاده کنید. مثال پایین یک نقل قول فرانسوی است که ما آن را به خصوصیت lang، جهت تایید زبانش مزین کرده‌ایم:
<blockquote lang=”fr”>

<p>Le plus grand faible des hommes, c'est l'amour qu'ils ont de la vie.</p>

</blockquote>

سه. لینک ها : اگر دارید در صفحه‌ای لینک به جایی می‌دهید که متفاوت از زبان شماست، حتما باید زبان صفحه یا سایت مقصد را مشخص کنید. مثلا لینک زیر برای صفحه‌ای است که از یک زبان غیر فرانسوی به یک صفحه‌ی با زبان فرانسوی هدایت می‌شود:
<a href="" hreflang="fr">French</a>

همچنین اگر متن لینک شما هم به زبان فرانسوی باشد خیلی خوب می‌شود که آن را هم بیان کنید و از خاصیت lang و هم hreflang همزمان استفاده کنید:
<a href="" hreflang="fr">Francais</a>

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

پنج. انکودینگ صفحه را مشخص کنید: برای اینکه نحوه‌ی رمزگذاری و رمزگشایی حروف و نمادها مشخص گردد، باید انکودینگ تنظیم شود و حتی برای بعضی از موتورهای جست و جو که ممکن است با وب سایت شما به مشکل بر بخورند. امروزه بیشتر از صفحات یونیکد استفاده می‌شود که سطح وسیعی از کاراکترها را پشتیبانی می‌کند.
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">

HTML5
<meta charset="UTF-8">

شش. اندازه‌ی فونت:
موقعی که یک سایت چند زبانه را طراحی می‌کنید این نکته خیلی مهم هست که بدانید اندازه فونت‌های زبان پیش فرض، برای باقی زبان‌ها مناسب نیستند. به عنوان مثال ممکن است اندازه فونتی برای زبان‌های انگلیسی، فرانسوی و آلمانی مناسب باشد ولی برای زبان‌های فارسی و عربی و چینی و ... مناسب نباشد و خواندن آن سخت شود. به همین جهت یکی از راه‌های حل این مشکل استفاده از قالب css است که وابسته به خصوصیت lang ای است که شما برای صفحه و هر المان یا تگی که از این خصوصیت استفاده می‌کند، تعیین کرده‌اید.
:lang(en) {

font-size: 85%;

font-family: arial, verdana, sans-serif;

}

:lang(zh) {

font-size: 125%;

font-family: helvetica, verdana, sans-serif;

}

خط زیر تعیین میکند که از استایل اول استفاده شود:
<html lang="en">
و خط زیر تعیین می‌کند که از استایل دوم استفاده شود:
<html lang="zh">
البته این کد بالا در مرورگرهای فایرفاکس، اپرا و IE8 به بالا پاسخ می‌دهد. برای سایر مروگرها چون کروم و نسخه‌های پیشین IE باید از شیوه‌ی زیر بهره ببرید:
<body class="english"> or <body class="chinese">

و استایل:
.english {

font-size: 85%;

font-family: arial, verdana, sans-serif;

}

.chinese {

font-size: 125%;

font-family: helvetica, verdana, sans-serif;

}
در این شیوه برای تگ مربوطه یک کلاس با نام آن زبان ایجاد کرده که محتوای آن تنظیمات قلم آن زبان می‌باشد.

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

هشت : زمان را نیز تغییر دهید: یکی از مواردی که در کمتر سایت چند زبانه‌ای به چشم می‌خورد و به نظر بنده می‌تواند بسیار مهم باشد این است که time zone منطقه‌ی هر زبان را بدانید. به عنوان مثال برای مقاله‌ی خود، تاریخ ایجاد را به صورت UTC ذخیره کنید و سپس نمایش را بر اساس زبان یا حتی بهتر و دقیق‌تر از طریق IP کشور مربوطه به دست آورید. برای کاربران ثبت نام شده این تاریخ می‌تواند دقیق‌تر باشد همانند انجمن‌های وی بولتین.


شیوه‌های تشخیص زبان سایت

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

دومین راه، استفاده از IP کاربر مراجعه کننده است تا بر اساس آن زبان مورد نظر را انتخاب کنید.

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

پی نوشت: فراموش نگردد که امکان تغییر زبان همیشه برای کاربر مهیا باشد و طوری نباشد که کاربر در آینده نتواند زبان سایت را تغییر دهد؛ حتی اگر تشخیص خودکار سایت برای زبان فعال باشد.

پی نوشت: در روش‌های بالا بهتر است همان مرتبه‌ی اول اطلاعات را در یک کوکی ذخیره کنید تا مراحل پیگیری راحت‌تر و آسان‌تر شود.


پلاگین‌ها و ابزارهای مدیریت زبان

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

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

پلاگین بعدی International Telephone Input است که  پیاده سازی پلاگین بالا می‌باشد. برای مواردی مفید است که شما نیاز دارید کد تلفنی کشوری را انتخاب کنید.

در مقاله‌های زیر که در سایت جاری است در مورد Globalization و به خصوص استفاده از ریسورس‌ها مطالب خوبی بیان شده است:

قسمت بیست و دوم آموزش MVC که مبحث Globalization را دنبال می‌کند.

قسمت اول از شش قسمت مباحث Globalization  که دنباله‌ی آن را می‌توانید در مقاله‌ی خودش دنبال کنید.

مطالب
ASP.NET MVC #23

اجرای برنامه‌های ASP.NET MVC توسط نگارش‌های متفاوت IIS

تا اینجا برای اجرای برنامه‌های ASP.NET MVC از وب سرور توکار VS.NET استفاده شد که صرفا جهت آزمایش برنامه‌ها طراحی شده است. تا این تاریخ سه رده از وب سرورهای مایکروسافت ارائه شده‌اند که برای نصب ASP.NET MVC می‌توانند مورد استفاده قرار گیرند و هر کدام هم نکته‌های خاص خودشان را دارند که در ادامه به بررسی آن‌ها خواهیم پرداخت.


اجرای برنامه‌های ASP.NET MVC بر روی IIS 5.x ویندوز XP

پس از ایجاد یک دایرکتوری مجازی بر روی پوشه یک برنامه ASP.NET MVC و سعی در اجرای برنامه، بلافاصله پیغام خطای HTTP 403 forbidden مشاهده می‌شود.
اولین کاری که برای رفع این مساله باید صورت گیرد، کلیک راست بر روی نام دایرکتوری مجازی در کنسول IIS، انتخاب گزینه خواص و سپس مراجعه به برگه «ASP.NET» آن است. در اینجا شماره نگارش دات نت فریم ورک مورد استفاده را به 4 تغییر دهید (برای نمونه ASP.NET MVC 3.0 مبتنی بر دات نت فریم ورک 4 است).
بعد از این تغییر، بازهم موفق به اجرای برنامه‌های ASP.NET MVC بر روی IIS 5.x نخواهیم شد؛ چون در آن زمان مفاهیم مسیریابی و Routing که اصل و پایه ASP.NET MVC هستند وجود خارجی نداشتند. این نگارش از IIS به صورت پیش فرض تنها قادر به پردازش درخواست‌های رسیده‌ای که به یک فایل فیزیکی بر روی سرور اشاره می‌کند، می‌باشد (یعنی مشکلی با اجرای برنامه‌های ASP.NET Web forms ندارد).
برای رفع این مشکل، مجددا بر روی نام دایرکتوری مجازی برنامه در کنسول IIS کلیک راست کرده و گزینه خواص را انتخاب کنید. در صفحه ظاهر شده، در برگه «Virtual directory» آن، بر روی دکمه «Configuration» کلیک نمائید. در صفحه باز شده مجددا بر روی دکمه «Add» کلیک کنید.
در صفحه باز شده، مسیر Executable را C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll وارد کرده و Extension را به .* (دات هرچی) تنظیم کنید. همین مقدار تنظیم، برای اجرای برنامه‌های ASP.NET MVC بر روی IIS 5.x ویندوز XP کفایت می‌کند.

کاری که در اینجا انجام شده است، نگاشت تمام درخواست‌های رسیده صرفنظر از پسوند فایل‌ها، به موتور ASP.NET می‌باشد. به صورت پیش فرض در IIS 5.x درخواست‌ها تنها بر اساس پسوند فایل‌ها پردازش می‌شوند. مثلا اگر فایل درخواستی aspx است، درخواست رسیده به aspnet_isapi.dll یاد شده هدایت خواهد شد. اگر پسوند فایل php است به isapi مخصوص آن (در صورت نصب) هدایت می‌گردد و به همین ترتیب برای سایر سیستم‌های دیگر. زمانیکه Extension به «دات هرچی» و Executable به aspnet_isapi.dll دات نت 4 تنظیم می‌شود، دایرکتوری مجازی تنظیم شده تنها جهت سرویس دهی به یک برنامه ASP.NET عمل خواهد کرد و تمام درخواست‌های رسیده به آن، به موتور اجرایی ASP.NET هدایت می‌شوند.

بدیهی است تنظیمات فوق تنها به یک دایرکتوری مجازی اعمال شدند. اگر نیاز باشد تا بر روی تمام سایت‌ها تاثیر گذار شود، اینبار در کنسول IIS 5.x بر روی «Default web site» کلیک راست کرده و گزینه خواص را انتخاب کنید. در صفحه باز شده به برگه «Home directory» مراجعه کرده و مراحل ذکر شده را تکرار کنید.

مشکل! این روش بهینه نیست.
روش فوق خوبه، کار می‌کنه، اما بهینه نیست؛ از این جهت که «نگاشت تمام درخواست‌ها به موتور ASP.NET» یعنی پروسه پردازش درخواست یک فایل تصویری، js یا css هم باید از فیلتر موتور ASP.NET عبور کند که ضروری نیست.
برای رفع این مشکل، توصیه شده است که سیستم مسیریابی ASP.NET MVC را در IIS 5.x «پسوند دار» کنید. به این نحو که با مراجعه به فایل Global.asax.cs، تعاریف مسیریابی را به نحو زیر ویرایش کنید:

public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.Add(
new Route("{controller}.aspx/{action}/{id}", new MvcRouteHandler())
{
Defaults = new RouteValueDictionary(new
{
controller = "Home",
action = "Index",
id = UrlParameter.Optional
})
});



اینبار برای مثال مسیر http://localhost/MyMvcApp/home.aspx/index به علت داشتن پسوند aspx وارد موتور پردازشی ASP.NET خواهد شد. البته در این حالت URL های تمیز ASP.NET MVC را از دست خواهیم داد و مدام باید دقت داشت که مسیرهای کنترلرها حتما باید به aspx ختم شوند. ضمنا با این تنظیم، دیگر نیازی به تغییر تعاریف نگاشت‌ها در کنسول مدیریتی IIS، نخواهد بود.


اجرای برنامه‌های ASP.NET MVC بر روی IIS 6.x ویندوز سرور 2003

تمام نکات عنوان شده جهت IIS 5.x در IIS 6.x نیز صادق هستند. به علاوه برای اجرای برنامه‌های ASP.NET بر روی IIS 6.x باید به دو نکته مهم دیگر نیز دقت داشت:
الف) ASP.NET 4 به صورت پیش فرض در IIS 6.x غیرفعال است که باید با مراجعه به قسمت Web Services Extensions در کنسول مدیریتی IIS، آن‌را از حالت prohibited خارج کرد.
ب) در هر Application pool تنها از یک نگارش دات نت فریم ورک می‌توان استفاده کرد. برای مثال اگر هم اکنون AppPool1 مشغول سرویس دهی به یک سایت ASP.NET 3.5 است، از آن نمی‌توانید جهت اجرای برنامه‌های ASP.NET MVC 3 به بعد استفاده کنید. زیرا برای مثال ASP.NET MVC 3 مبتنی بر دات نت فریم ورک 4 است. به همین جهت حتما نیاز است تا یک Application pool مجزا را برای برنامه‌های دات نت 4 در IIS 6 اضافه نمائید و سپس در تنظیمات سایت، از این Application pool جدید استفاده نمائید.
البته روش صحیح و اصولی کار با IIS از نگارش 6 به بعد هم مطابق شرحی است که عنوان شد. برای دستیابی به بهترین کارآیی و امنیت بیشتر، بهتر است به ازای هر سایت، از یک Application pool مجزا استفاده نمائید.

اطلاعات تکمیلی:
نکات نصب برنامه‌های ASP.NET 4.0 بر روی IIS 6
مروری بر تاریخچه محدودیت حافظه مصرفی برنامه‌های ASP.NET در IIS



اجرای برنامه‌های ASP.NET MVC بر روی IIS 7.x ویندوز 7 و ویندوز سرور 2008

اگر برنامه ASP.NET MVC در IIS 7.x در حالت یکپارچه (integrated mode) اجرا شود، بدون نیاز به هیچگونه تغییری در تنظیمات سرور یا برنامه، بدون مشکل قابل اجرا خواهد بود. بدیهی است در اینجا نیز بهتر است به ازای هر برنامه، یک Application pool مجزا را ایجاد کرد.
اما در حالت classic (که برای برنامه‌های جدید توصیه نمی‌شود) نیاز است همان مراحل IIS 5,x تکرار شود. البته اینبار مسیر زیر را باید طی کرد تا به صفحه افزودن نگاشت‌ها رسید:
Right-click on a web site -> Properties -> Home Directory tab -> click on the Configuration button -> Mappings tab



نکته‌ای مهم در تمام نگارش‌های IIS

ترتیب نصب دات نت فریم ورک 4 و IIS مهم است. اگر ابتدا IIS نصب شود و سپس دات نت فریم ورک 4، به صورت خودکار، کار نگاشت اطلاعات ASP.NET به IIS صورت خواهد گرفت.
اگر ابتدا دات نت فریم ورک 4 نصب شود و سپس IIS، برای مثال دیگر از برگه ASP.NET در IIS 6.x خبری نخواهد بود. برای رفع این مشکل دستور زیر را در خط فرمان اجرا کنید:

C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe /i

به این ترتیب، اطلاعات مرتبط با موتور ASP.NET مجددا به تنظیمات IIS اضافه خواهند شد.


مطالب
آشنایی با Fluent interfaces

تعریف مقدماتی fluent interface در ویکی پدیا به شرح زیر است: (+)

In software engineering, a fluent interface (as first coined by Eric Evans and Martin Fowler) is a way of implementing an object oriented API in a way that aims to provide for more readable code.

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

برای مثال:
using System;

namespace FluentInt
{
public class FluentApiTest
{
private int _val;

public FluentApiTest Number(int val)
{
_val = val;
return this;
}

public FluentApiTest Abs()
{
_val = Math.Abs(_val);
return this;
}

public bool IsEqualTo(int val)
{
return val == _val;
}
}
}
مثالی هم از استفاده‌ی آن به صورت زیر می‌تواند باشد:
if (new FluentApiTest().Number(-10).Abs().IsEqualTo(10))
{
Console.WriteLine("Abs(-10)==10");
}
که در آن توانستیم تمام متدها را زنجیر وار و با خوانایی خوبی شبیه به نوشتن جملات انگلیسی در کنار هم قرار دهیم.
خوب! این مطلبی است که همه جا پیدا می‌کنید و مطلب جدیدی هم نیست. اما موردی را که سخت می‌شود یافت این است که طراحی کلاس فوق ایراد دارد. برای مثال شما می‌توانید ترکیب‌های زیر را هم تشکیل دهید و کار می‌کند؛ یا به عبارتی برنامه کامپایل می‌شود و این خوب نیست:
if(new FluentApiTest().Abs().Number(-10).IsEqualTo(10)) ...
if (new FluentApiTest().Abs().IsEqualTo(10)) ...
می‌شود در کدهای برنامه یک سری throw new exception را هم قرار داد که ... هی! اول باید اون رو فراخوانی کنی بعد این رو!
ولی ... این روش هم صحیح نیست. از ابتدای کار نباید بتوان متد بی‌ربطی را در طول این زنجیره مشاهده کرد. اگر قرار نیست استفاده گردد، نباید هم در intellisense ظاهر شود و پس از آن هم نباید قابل کامپایل باشد.

بنابراین صورت مساله به این ترتیب اصلاح می‌شود:
می‌خواهیم پس از نوشتن FluentApiTest و قرار دادن یک نقطه، در intellisense فقط Number ظاهر شود و نه هیچ متد دیگری. پس از ذکر متد Number فقط متد Abs یا مواردی شبیه به آن مانند Sqrt ظاهر شوند. پس از انتخاب مثلا Abs آنگاه متد IsEqualTo توسط Intellisense قابل دسترسی باشد. در روش اول فوق، به صورت دوستانه همه چیز در دسترس است و هر ترکیب قابل کامپایلی را می‌شود با متدها ساخت که این مورد نظر ما نیست.
اینبار پیاده سازی اولیه به شرح زیر تغییر خواهد کرد:
using System;

namespace FluentInt
{
public class FluentApiTest
{
public MathMethods<FluentApiTest> Number(int val)
{
return new MathMethods<FluentApiTest>(this, val);
}
}

public class MathMethods<TParent>
{
private int _val;
private readonly TParent _parent;

public MathMethods(TParent parent, int val)
{
_val = val;
_parent = parent;
}

public Restrictions<MathMethods<TParent>> Abs()
{
_val = Math.Abs(_val);
return new Restrictions<MathMethods<TParent>>(this, _val);
}
}

public class Restrictions<TParent>
{
private readonly int _val;
private readonly TParent _parent;

public Restrictions(TParent parent, int val)
{
_val = val;
_parent = parent;
}

public bool IsEqualTo(int val)
{
return _val == val;
}
}
}
در اینجا هم به همان کاربرد اولیه می‌رسیم:
if (new FluentApiTest().Number(-10).Abs().IsEqualTo(10))
{
Console.WriteLine("Abs(-10)==10");
}
با این تفاوت که intellisense هربار فقط یک متد مرتبط در طول زنجیره را نمایش می‌دهد و تمام متدها در همان ابتدای کار قابل انتخاب نیستند.
در پیاده سازی کلاس MathMethods از Generics استفاده شده به این جهت که بتوان نوع متد Number را بر همین اساس تعیین کرد تا متدهای کلاس MathMethods در Intellisense (یا به قولی در طول زنجیره مورد نظر) ظاهر شوند. کلاس Restrictions نیز به همین ترتیب معرفی شده است و از آن جهت تعریف نوع متد Abs استفاده کردیم. هر کلاس جدید در طول زنجیره، توسط سازنده خود به وهله‌ای از کلاس قبلی به همراه مقادیر پاس شده دسترسی خواهد داشت. به این ترتیب زنجیره‌ای را تشکیل داده‌ایم که سازمان یافته است و نمی‌توان در آن متدی را بی‌جهت پیش یا پس از دیگری صدا زد و همچنین دیگر نیازی به بررسی نحوه‌ی فراخوانی‌های یک مصرف کننده نیز نخواهد بود زیرا برنامه کامپایل نمی‌شود.
مطالب
شروع به کار با EF Core 1.0 - قسمت 4 - کار با بانک‌های اطلاعاتی از پیش موجود
روش کار پیش فرض با EF Core همان روش Code First است. ابتدا کلاس‌ها و روابط بین آن‌ها را تنظیم می‌کنید. سپس با استفاده از ابزارهای Migrations، بانک اطلاعاتی متناظری تولید خواهد شد. این ابزارها به همراه روشی برای مهندسی معکوس ساختار یک بانک اطلاعاتی از پیش موجود، به روش Code First نیز هستند که در ادامه جزئیات آن‌را بررسی خواهیم کرد. بنابراین اگر به دنبال روش کاری Database first با EF Core هستید، در اینجا نیز امکان آن وجود دارد.


تهیه یک بانک اطلاعاتی نمونه

برای نمایش امکانات کار با روش Database first، نیاز است یک بانک اطلاعاتی را به صورت مستقل و متداولی ایجاد کنیم. به همین جهت اسکریپت SQL ذیل را توسط Management studio اجرا کنید تا بانک اطلاعاتی BloggingCore2016، به همراه دو جدول به هم وابسته، در آن ایجاد شوند:
CREATE DATABASE [BloggingCore2016]
GO

USE [BloggingCore2016]
GO

CREATE TABLE [Blog] (
    [BlogId] int NOT NULL IDENTITY,
    [Url] nvarchar(max) NOT NULL,
    CONSTRAINT [PK_Blog] PRIMARY KEY ([BlogId])
);
GO

CREATE TABLE [Post] (
    [PostId] int NOT NULL IDENTITY,
    [BlogId] int NOT NULL,
    [Content] nvarchar(max),
    [Title] nvarchar(max),
    CONSTRAINT [PK_Post] PRIMARY KEY ([PostId]),
    CONSTRAINT [FK_Post_Blog_BlogId] FOREIGN KEY ([BlogId]) REFERENCES [Blog] ([BlogId]) ON DELETE CASCADE
);
GO

INSERT INTO [Blog] (Url) VALUES 
('https://www.dntips.ir/'), 
('http://blogs.msdn.com/dotnet'), 
('http://blogs.msdn.com/webdev'), 
('http://blogs.msdn.com/visualstudio')
GO



پیشنیازهای مهندسی معکوس ساختار بانک اطلاعاتی در EF Core

در قسمت اول در حین بررسی «برپایی تنظیمات اولیه‌ی EF Core 1.0 در یک برنامه‌ی ASP.NET Core 1.0»، چهار مدخل جدید را به فایل project.json برنامه اضافه کردیم. مدخل جدید Microsoft.EntityFrameworkCore.Tools که به قسمت tools آن اضافه شد، پیشنیاز اصلی کار با EF Core Migrations است. همچنین وجود مدخل Microsoft.EntityFrameworkCore.SqlServer.Design برای تدارک امکانات مهندسی معکوس ساختار یک بانک اطلاعاتی SQL Server ضروری است.


تبدیل ساختار دیتابیس BloggingCore2016 به کدهای معادل EF Core آن

پس از فعال سازی ابزارهای خط فرمان EF Core، به پوشه‌ی اصلی پروژه مراجعه کرده، کلید shift را نگه دارید. سپس کلیک راست کرده و گزینه‌ی Open command window here را انتخاب کنید تا خط فرمان از این پوشه آغاز شود. در ادامه دستور ذیل را صادر کنید:
 dotnet ef dbcontext scaffold "Data Source=(local);Initial Catalog=BloggingCore2016;Integrated Security = true" Microsoft.EntityFrameworkCore.SqlServer -o Entities --context MyDBDataContext --verbose


اجرا این دستور سبب اتصال به رشته‌ی اتصالی ذکر شده که به بانک اطلاعاتی BloggingCore2016 اشاره می‌کند، می‌شود. سپس پروایدر مدنظر ذکر شده‌است. سوئیچ o محل درج فایل‌های نهایی را مشخص می‌کند. برای مثال در اینجا فایل‌های نهایی مهندسی معکوس شده در پوشه‌ی Entities درج می‌شوند (تصویر فوق). همچنین در اینجا امکان ذکر فایل context تولیدی نیز وجود دارد. اگر علاقمند باشید تا تمام ریز جزئیات این عملیات را نیز مشاهده کنید، می‌توانید پارامتر اختیاری verbose را نیز به انتهای دستور اضافه نمائید.

بقیه مراحل کار با این فایل‌های تولید شده، با نکاتی که تاکنون عنوان شده‌اند یکی است. برای مثال اگر می‌خواهید رشته‌ی اتصالی پیش فرض را از این Context تولید شده خارج کنید:
    public partial class MyDBDataContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(@"Data Source=(local);Initial Catalog=BloggingCore2016;Integrated Security = true");
        }
روش کار دقیقا همانی است که در مطلب «شروع به کار با EF Core 1.0 - قسمت 1 - برپایی تنظیمات اولیه» بررسی شد.


بررسی پارامترهای دیگر ابزار مهندسی معکوس به Code First

اگر دستور dotnet ef dbcontext scaffold --help را صادر کنیم، خروجی راهنمای ذیل را می‌توان مشاهده کرد:
 Usage: dotnet ef dbcontext scaffold [arguments] [options]
Arguments:
  [connection]  The connection string of the database
  [provider] The provider to use. For example, Microsoft.EntityFrameworkCore.SqlServer
Options:
  -a|--data-annotations   Use DataAnnotation attributes to configure the model where possible. If omitted, the output code will use only the fluent API.
  -c|--context <name> Name of the generated DbContext class.
  -f|--force Force scaffolding to overwrite existing files. Otherwise, the code will only proceed if no output files would be overwritten.
  -o|--output-dir <path> Directory of the project where the classes should be output. If omitted, the top-level project directory is used.
  --schema <schema> Selects a schema for which to generate classes.
  -t|--table <schema.table> Selects a table for which to generate classes.
  -e|--environment <environment>  The environment to use. If omitted, "Development" is used.
  -h|--help   Show help information
  -v|--verbose   Enable verbose output
نکات تکمیلی مهمی را که از آن می‌توان استخراج کرد به این شرح هستند:
- حالت پیش فرض تنظیمات روابط مدل‌ها در این روش، حالت استفاده از Fluent API است. اگر می‌خواهید آن‌را به حالت استفاده‌ی از Data Annotations تغییر دهید، پارامتر a- و یا data-annotations-- را در دستور نهایی ذکر کنید.
- حالت پیش فرض تولید فایل‌های نهایی این روش، عدم بازنویسی فایل‌های موجود است. اگر می‌خواهید پس از تغییر بانک اطلاعاتی، مجددا این فایل‌ها را از صفر تولید کنید، پارامتر f- و یا force- را در دستور نهایی ذکر کنید.

بنابراین اگر می‌خواهید هربار فایل‌های نهایی را بازنویسی کنید و همچنین روش کار با Data Annotations را ترجیح می‌دهید، دستور نهایی، شکل زیر را پیدا خواهد کرد:
 dotnet ef dbcontext scaffold "Data Source=(local);Initial Catalog=BloggingCore2016;Integrated Security = true" Microsoft.EntityFrameworkCore.SqlServer -o Entities --context MyDBDataContext --verbose --force --data-annotations


کار با یک بانک اطلاعاتی موجود، با روش مهاجرت‌های Code First

فرض کنید می‌خواهید از یک بانک اطلاعاتی از پیش موجود EF 6.x (یا هر بانک اطلاعاتی از پیش موجود دیگری)، به روش پیش فرض EF Core استفاده کنید. برای این منظور:
 - ابتدا جدول migration history قدیمی آن‌را حذف کنید؛ چون ساختار آن با EF Core یکی نیست.
 - سپس با استفاده از دستور dotnet ef dbcontext scaffold فوق، معادل کلاس‌ها، روابط و Context سازگار با EF Core آن‌را تولید کنید.
 - در ادامه رشته‌ی اتصالی پیش فرض آن‌را از کلاس Context تولیدی خارج کرده و از یکی از روش‌های مطرح شده‌ی در مطلب «شروع به کار با EF Core 1.0 - قسمت 1 - برپایی تنظیمات اولیه» استفاده کنید.
 - سپس نیاز است این Context جدید را توسط متد services.AddDbContext به لیست سرویس‌های برنامه اضافه کنید. این مورد نیز در قسمت اول بررسی شده‌است.
 - مرحله‌ی بعد، افزودن جدول __EFMigrationsHistory جدید EF Core، به این بانک اطلاعاتی است. برای این منظور به روش متداول فعال کردن مهاجرت‌ها، دستور ذیل را صادر کنید:
dotnet ef migrations add InitialDatabase
تا اینجا کلاس آغازین مهاجرت‌ها تولید می‌شود. فایل آن‌را گشوده و محتوای متدهای Up و Down آن‌را خالی کنید:
using Microsoft.EntityFrameworkCore.Migrations;

namespace Core1RtmEmptyTest.DataLayer.Migrations
{
    public partial class InitialDatabase : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
        }
    }
}
متدهای up و down را از این جهت خالی می‌کنیم که علاقمند نیستیم تا ساختاری در بانک اطلاعاتی تشکیل شود و یا تغییر کند (چون این ساختار هم اکنون موجود است).
سپس دستور به روز رسانی بانک اطلاعاتی را صادر کنید:
dotnet ef database update
کار این دستور در اینجا با توجه به خالی بودن متدهای up و down، صرفا ساخت جدول مخصوص __EFMigrationsHistory در بانک اطلاعاتی است؛ بدون تغییری در جداول موجود آن.
پس از این مرحله، روش کار، Code first خواهد بود. برای مثال خاصیتی را به کلاسی اضافه می‌کنید و سپس دو دستور ذیل را صادر خواهید کرد که در آن v2 یک نام دلخواه است:
dotnet ef migrations add v2
dotnet ef database update