مطالب
ارتقاء به Angular 6: بررسی تغییرات RxJS
پس از ارتقاء Angular CLI و ساختار پروژه‌ی قبلی خود به نگارش 6، اولین موردی را که مشاهده خواهید کرد، این است: برنامه دیگر کامپایل نمی‌شود! اولین دلیل آن عدم استفاده‌ی از HttpClient معرفی شده‌ی در نگارش 4.3 است و دومین دلیل مهم آن، تغییرات بنیادین RxJS است که خلاصه‌ی کاربردی آن‌را در این مطلب بررسی خواهیم کرد.


RxJS اکنون جزئی از پروژه‌های گوگل است

توسعه دهنده‌ی اصلی RxJS یا همان Ben Lesh اکنون به گوگل پیوسته‌است و جزو تیم Angular است. بنابراین در آینده شاهد یکپارچگی بهتر این دو با هم خواهیم بود. البته RxJS هنوز هم به عنوان یک پروژه‌ی مستقل از Angular مدیریت خواهد شد.


آشنایی با تغییرات RxJS 5.5 جهت مهاجرت به RxJS 6.0 ضروری است

در مطلب «کاهش حجم قابل ملاحظه‌ی برنامه‌های Angular با استفاده از RxJS 5.5» با pipe-able operators آشنا شدیم و این موارد پایه‌های مهاجرت به RxJS 6.0 هستند. بنابراین پیش از مطالعه‌ی ادامه‌ی بحث نیاز است این مطلب را به خوبی مطالعه و بررسی کنید.


تغییر رفتار خطاهای مدیریت نشده در RxJS 6.0

تا پیش از RxJS 6.0 اگر خطای مدیریت نشده‌ای رخ می‌داد، این خطا به صورت synchronous به فراخوان صادر می‌شد. این رفتار در نگارش 6 تغییر کرده و صدور آن اینبار asynchronous شده‌است.
برای مثال یک چنین کدی تا پیش از RxJS 6.0 کار می‌کرد:
try {
    source$.subscribe(nextFn, undefined, completeFn);
} catch (err) {
    handleError(err);
}
از این جهت که دومین پارامتر در اینجا، متدی است که کار مدیریت خطا را انجام می‌دهد و چون ذکر نشده‌است، خطای رخ داده‌ی حاصل، به صورت همزمان به فراخوان صادر شده‌است و try/catch نیز در اینجا کار می‌کند. اما این مثال دیگر در نگارش 6 کار نخواهد کرد و صدور خطای مدیریت نشده، دیگر همزمان نیست و قسمت catch این قطعه کد دیگر هیچگاه فراخوانی نمی‌شود. البته این رفتار طبیعی است که می‌بایستی از نگارش‌های پیشین، با Observable هایی که عموما async هستند، وجود می‌داشت و اکنون اصلاح شده‌است.
برای اصلاح این کد در نگارش 6، همان پارامتر دوم متد را مقدار دهی کنید و try/catch را در صورت وجود حذف نمائید.


تغییرات مهم importها در RxJS 6.0

همانطور که در مطلب «کاهش حجم قابل ملاحظه‌ی برنامه‌های Angular با استفاده از RxJS 5.5» نیز بررسی کردیم، تا نگارش 5 این کتابخانه، importها به صورت زیر بودند:
 import 'rxjs/add/operator/map';
و پس از RxJS 5.5 امکان import آن‌ها با روش مخصوص ES 6 میسر شده‌است:
 import { map } from 'rxjs/operators';
هر چند نگارش 5.5 بهبودهای قابل ملاحظه‌ای و مزایایی مانند حذف ساده‌تر کدهای مرده، عدم تعریف عملگرها به صورت استاتیک و همچنین سازگاری بهتر با ابزارهایی مانند TSLint را به همراه دارد، اما باز هم دست آخر به تعداد زیادی import مانند کدهای زیر می‌رسیدیم:
import { timer } from 'rxjs/observable/timer';  
import { of } from 'rxjs/observable/of';
import { from } from 'rxjs/observable/from';
import { range } from 'rxjs/observable/range';
این مشکل در RxJS 6.0 برطرف شده‌است و در ماژول‌های مختلف برنامه حداکثر به دو سطر خلاصه شده‌ی زیر نیاز خواهیم داشت:
import { interval, of } from 'rxjs';  
import { filter, mergeMap, scan } from 'rxjs/operators';
در نگارش 6، تمام «نوع‌ها» مانند Observable و Subject و «متدهای ایجاد» مانند timer و interval از مسیر rxjs دریافت می‌شوند و تمام «عملگرها» مانند map و filter از مسیر rxjs/operators اضافه خواهند شد و ... همین!
البته RxJS 6.0 در کل به همراه 4 گروه کلی importها است که در زیر مشاهده می‌کنید (در اینجا مواردی که کمتر در برنامه‌های Angular به صورت مستقیم استفاده می‌شوند مانند ajax آن و یا webSocket هم قابل مشاهده هستند):
rxjs
rxjs/operators
rxjs/testing
rxjs/webSocket
rxjs/ajax


مواردی که از RxJS 6.0 حذف شده‌اند

برای کاهش حجم کتابخانه‌ی RxJS و همچنین جلوگیری از بکارگیری متدهایی که نمی‌بایستی خارج از کدهای اصلی خود RxJS استفاده شوند، تعداد زیادی از متدهای قدیمی آن و روش‌های کار پیشین با RxJS حذف شده‌اند. برای مثال شما در RxJS 5.5 می‌توانید برای کار با عملگر of، یا آن‌را از مسیر rxjs/add/observable/of دریافت کنید (همان روش وصله کردن تا پیش از RxJS 5.5) و یا آن‌را از مسیر rxjs/observable/of به روش مخصوص ES 6.0 به برنامه اضافه کنید و یا حتی امکان دریافت آن از مسیر rxjs/observable/fromArray نیز میسر است.
در RxJS 6.0 تمام این‌ها حذف شده‌اند و فقط روش زیر باقی مانده‌است:
 import { of } from 'rxjs';
به این ترتیب نه فقط حجم این کتابخانه کاهش یافته‌است، بلکه با کاهش سطح API آن، یادگیری آن نیز ساده‌تر شده‌است.


معرفی بسته‌ی rxjs-compat

در مطلب «ارتقاء به Angular 6: بررسی تغییرات Angular CLI» روش ارتقاء وابستگی‌های پروژه به نگارش 6 را بررسی کردیم. یکی از مراحل آن اجرای دستور زیر بود:
 ng update rxjs
این مورد صرفا وابستگی rxjs ذکر شده‌ی در فایل package.json را به آخرین نگارش آن به روز رسانی و همچنین نصب می‌کند.

پس از آن اگر پروژه را کامپایل کنید، پر خواهد بود از خطاهای rxjs، مانند:
 ERROR in node_modules/ng2-slim-loading-bar/src/slim-loading-bar.service.d.ts(1,10):
error TS2305: Module '"/node_modules/rxjs/Observable"' has no exported member 'Observable'.
این مشکل با بسته‌های ثالثی وجود دارند که هنوز از نگارش‌های قبلی RxJS استفاده می‌کنند و همانطور که عنوان شد، RxJS 6.0 شامل حذفیات و نقل و انتقالات بسیاری است. به همین جهت هیچکدام از کتابخانه‌های ثالث مبتنی بر نگارش‌های پیشین RxJS دیگر کار نکرده و کامپایل نخواهند شد.
برای رفع این مشکل و ارائه‌ی راه‌حلی کوتاه مدت، بسته‌ای به نام rxjs-compat ارائه شده‌است که سبب هدایت تعاریف قدیمی به تعاریف جدید می‌شود و به این ترتیب کدهای کتابخانه‌ی ثالث، بدون مشکل با نگارش 6 نیز قابل استفاده خواهند بود.
برای نصب آن نیاز است دستور زیر را صادر کنید:
 npm i rxjs-compat --save
اکنون اگر برنامه را مجددا کامپایل کنید، تمام خطاهای مرتبط با کتابخانه‌های ثالث مورد استفاده برطرف شده‌اند.

البته دقت داشته باشید از rxjs-compat به عنوان یک راه حل موقت باید استفاده کرد و نیاز است ابتدا کدهای خود را به روش pipe-able operators بازنویسی کنید و مسیرهای importها را اصلاح کنید و در آخر بسته‌های جدید وابستگی‌های ثالث را که از RxJS6 استفاده می‌کنند، نصب نمائید. در نهایت rxjs-compat را حذف کنید.


خودکار سازی اصلاح importها در برنامه‌های پیشین، جهت مهاجرت به RxJS 6.0

با توجه به این تغییرات و حذف و اضافه شدن‌ها در نگارش 6، تقریبا دیگر هیچکدام از importهای قبلی شما کار نمی‌کنند! و اصلاح آن‌ها نیاز به زمان زیادی خواهد داشت. به همین جهت تیم RxJS ابزاری را طراحی کرده‌اند که با اجرای آن بر روی پروژه، به صورت خودکار تمام importهای قبلی را به نگارش جدید تبدیل می‌کند. برای اینکار ابتدا ابزار rxjs-tslint را نصب کنید:
 npm i -g rxjs-tslint
در ادامه فایل tslint.json پروژه خود را گشوده و مداخل زیر را به آن اضافه و ویرایش نمائید:
{
  "rulesDirectory": [
    "node_modules/rxjs-tslint"
  ],
  "rules": {
    "rxjs-collapse-imports": true,
    "rxjs-pipeable-operators-only": true,
    "rxjs-no-static-observable-methods": true,
    "rxjs-proper-imports": true
  }
}
سپس به ریشه‌ی پروژه‌ی خود وارد شده و دستور زیر را اجرا کنید:
 rxjs-5-to-6-migrate -p src/tsconfig.app.json
کیفیت کار این ابزار تا حدی است که تیم‌های داخلی گوگل از آن برای ارتقاء کدهای پیشین استفاده می‌کنند و بر روی پروژه‌های واقعی آزمایش شده‌است.
البته توصیه شده‌است این ابزار را بیش از یکبار نیاز است اجرا کنید.


خلاصه‌ی روش مهاجرت به RxJS 6x

ابتدا آخرین نگارش rxjs را نصب کنید:
 ng update rxjs
سپس rxjs-compat را جهت رفع کمبودهای کتابخانه‌های ثالث مورد استفاده نصب نمائید:
 npm i rxjs-compat --save
پس از آن ابزار rxjs-tslint را نصب و اجرا کنید:
npm i -g rxjs-tslint
rxjs-5-to-6-migrate -p src/tsconfig.app.json
و در آخر ارتقاء به روش pipe-able را باید مدنظر داشته باشید.


یافتن معادل‌های جدید دستورات قدیمی

در حین تبدیل کدهای قدیمی به جدید نیاز خواهید داشت تا معادل‌ها را بیابید. برای این منظور به مستندات رسمی این مهاجرت مراجعه کنید:
https://github.com/ReactiveX/rxjs/blob/master/MIGRATION.md
برای مثال در اینجا مشاهده خواهید کرد که معادل Observable.throw حذف شده، اکنون throwError است و همینطور برای مابقی.


یک مثال واقعی تغییر یافته

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

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

ابتدا نیاز است در سایت bintray ثبت نام کنید و با حساب جدید وارد شوید و گزینه‌ی maven را انتخاب کنید.

سپس روی گزینه‌ی Add New Package کلیک کنید تا یک پکیج جدید را ایجاد کنیم.

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

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


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

سوال: چگونه این فایل را در SonaType آپلود کنیم؟ 
گام اول: ابتدا باید در سایت ثبت نام کنید. پس به این صفحه رفته و ثبت نام کنید. سپس در یک مرحله‌ی غیرمنطقی باید یک issue توسط سیستم JIRA ایجاد کنید. برای همین گزینه‌ی Creare را در بالای صفحه بزنید. اطلاعات زیر را به ترتیب پر کنید:
Project: Community Support - Open Source Project Repository Hosting

Issue Type: New Project

Summary: مثلا نام پروژه خودتان را بنویسید

یک نام پکیج که سعی کنید کتابخانه‌های هم خانواده این اشتراک را داشته باشند که در یک گروه قرار بگیرند
Group Id: AndroidBreadCrumb.Plus

آدرس جایی که پروژه قرار دارد
Project URL: https://github.com/yeganehaym/AndroidBreadCrumb

//آدرس سیستم کنترل نسخه
SCM url: https://github.com/yeganehaym/AndroidBreadCrumb
بقیه‌ی موارد الزامی نیست. کادر را تایید کنید. در این مرحله باید مدتی منتظر بمانید تا این مخزن را برای شما تایید کنند که طبق مستندات حدود یک هفته‌ای طول می‌کشد. بعد از اینکار باید نام کاربری اکانت خود را در پروفایل سایت Bintray  در برگه‌ی Accounts  قسمت sonatype oss account وارد کنید و پروفایل را آپدیت کنید.

فعال سازی امضای خودکار در Bintray

همانطور که در ابتدای مقاله گفتیم، می‌خواهیم کتابخانه‌ی خود را از طریق jcenter به maven ارسال کنیم. برای همین نیاز داریم که ابتدا کتابخانه‌ی خود را امضا کنیم. برای اینکار باید از طریق GPG یک کلید بسازیم. ساخت کلید به این شیوه، قبلا در مقاله‌ی «ساخت کلیدهای امنیتی با GnuPG» توضیح داده شد و از تکرار آن خودداری می‌کنیم. تنها به ذکر این نکته بسنده می‌کنیم که شما باید یک کلید ساخته و آن را به سرور کلیدها ارسال کنید و سپس کلید متنی عمومی و خصوصی آن را در پروفایل bintray برگه‌ی GPG Signing درج کنید.


به عنوان آخرین کار باید امضای خودکار را فعال کنید. بنابراین نیاز است که به صفحه‌ی اصلی رفته و بر روی maven کلیک کنید و گزینه‌ی Edit را انتخاب کنید. در صفحه‌ی باز شده، تیک GPG sign uploaded files automatically را بزنید.

این تنظیم از این پس بر روی تمامی کتابخانه‌ها اعمال می‌شود.


سوال : چگونه پروژه‌ی اندرویدی خودم را کامپایل کنم؟


فایل  build.gradle پروژه را باز کنید و پلاگین bintray را به آن معرفی کنید:
 dependencies {
        classpath 'com.android.tools.build:gradle:1.2.2'
        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2'
        classpath 'com.github.dcendents:android-maven-plugin:1.2'
    }
بسیار مهم است که نسخه‌ی gradle build tools از نسخه‌ی 1.1.2 به بعد باشد. چون که در نسخه‌های پایین‌تر، یک باگ بسیار حیاتی یافت شده، که از این نسخه به بعد رفع گردیده است. حال فایل local.properties را باز کنید و اطلاعات زیر را وارد کنید:
bintray.user=YOUR_BINTRAY_USERNAME
bintray.apikey=YOUR_BINTRAY_API_KEY
bintray.gpg.password=YOUR_GPG_PASSWORD
نام کاربری که برای اکانت bintray انتخاب کردید را بنویسید. برای ApiKey در قسمت Edit Profile برگه‌ی Api Key در خط دوم می‌توانید آن را ببینید و کلمه‌ی عبور GPG هم همان عبارتی است که در انتهای ساخت کلید دوبار از شما پرسیده شده است.  (در صورتی که اقدامات لازم برای mavenCentral را انجام داده اید خط سوم را  وارد کنید)

در مرحله‌ی بعدی خطوط زیر را بعد از 'Apply Plugin 'com.android.library اضافه کنید و اطلاعاتی که در bintray وارد کرده‌اید را در اینجا وارد کنید:
apply plugin: 'com.android.library'

ext {
    bintrayRepo = 'maven'
    bintrayName = 'AndroidBreadCrumb'

    publishedGroupId = 'com.plus'
    libraryName = 'AndroidBreadCrumb'
    artifact = 'AndroidBreadCrumb'

    libraryDescription = 'create breadcrumb on android to show a path to user and let user to jump on them'

    siteUrl = 'https://github.com/yeganehaym/AndroidBreadCrumb'
    gitUrl = 'https://github.com/yeganehaym/AndroidBreadCrumb'

    libraryVersion = '1.0'

    developerId = 'yeganehaym'
    developerName = 'ali yeganeh.m'
    developerEmail = 'yeganehaym@gmail.com'

    licenseName = 'The Apache Software License, Version 2.0'
    licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
    allLicenses = ["Apache-2.0"]
}
بعد از آن هم در انتهای فایل گریدل ماژول، دو خط زیر را که شامل اسکریپت‌هایی برای راحتی کار است، معرفی کنید:
apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle'
apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/bintrayv1.gradle'
با اطلاعاتی که بالا تعریف کردیم، کاربر باید شناسه‌ای به شکل زیر در گریدل به کار ببرد تا به کتابخانه‌ی ما دسترسی داشته باشد:
compile 'com.plus:AndroidBreadCrumb:1.0'

آپلود فایل‌ها به مخزن
برای آپلود فایل‌های ماژول به مخزن، ابتدا ترمینال اندروید استودیو را باز کنید و گام‌های زیر را به ترتیب انجام بدهید:
گام اول: با ارسال دستور زیر از صحت کدها و منابع مطمئن می‌شویم:
gradlew install
در صورتیکه خطایی نباشد، پیام موفقیت آمیزی را به شما نمایش می‌دهد:
BUILD SUCCESSFUL
حالا باید فایل‌ها را به سمت سرور ارسال کنیم:
gradlew bintrayUpload
در صورتی که عملیات موفقیت آمیز باشد پیام زیر نمایش می‌یابد:
SUCCESSFUL

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



و قسمت فایل‌ها هم دیگر خالی نیست:




با اینکه کتابخانه‌ی ما روی maven قرار گرفت، ولی هنوز نمی‌توان آن را توسط jcenter استفاده کرد و باید bintray maven را با jcenter هماهنگ نماییم. در حال حاضر استفاده از این کتابخانه بدون سینک به شکل زیر است:

گریدل پروژه
     maven{
            url 'https://dl.bintray.com/yeganehaym/maven'
        }

گریدل ماژول

dependencies {
    compile 'com.plus:AndroidbreadCrumb:1.0'
}
آدرس اولی را می‌توانید با نگاه در صفحه‌ی اختصاصی پکیج ببینید که لینک آن در جلوی نام پکیج وجود دارد و قابلیت کپی کردن لینک هم وجود دارد. اگر روی آن کلیک کنید، می‌توانید مسیر را در صفحه‌ی باز شده ببینید. البته راه مستقیم‌تر اینکه به جای yeganehaym در لینک بالا، نام کاربری خودتان را جایگزین کنید.

برای افزودن کتابخانه‌ی خود به سیستم jcenter با کلیک بر روی گزینه‌ی Add to jcenter می‌توانید به تیم jcenter درخواست دهید که آن را تایید کنند که بعد از درخواست حدود سه ساعت طول می‌کشد تا پاسخ شما را بدهند.




به این ترتیب دیگر نیازی به تعریف یک url به maven نخواهد بود.

برای دیدن این کتابخانه در صفحه jcenter به ترتیب شناسه‌های Group_ID.Artifact.version را دنبال کنید، یعنی برای ما می‌شود:

com/plus/androidbreadcrumb/1.0
نکته اول : این نکته را به یاد داشته باشید که عمل سینک تنها یکبار اتفاق می‌افتد و در زمان‌های بعد، هر تغییری مثل حذف، به روز آوری و ... مستقیما در jcenter بعد از چند دقیقه اعمال می‌شود.

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


ارسال کتابخانه به mavenCentra
 در این مرحله قصد داریم که این کتابخانه را بر روی mavenCentral هم داشته باشیم. اگر قصدش را ندارید از اینجا به بعد را نیازی نیست انجام بدهید و برای اینکار لازم است همه‌ی مراحل بالا انجام گرفته باشد.
قبل از اینکه این عمل ارسال انجام گیرد، باید دو عمل زیر از قبل صورت گرفته باشند:
  1. پکیج شما در jcenter تایید شده باشد.
  2. با مخزن شما در sonatype موافقت شده باشد.

در صورتیکه دو مرحله‌ی بالا صورت گرفته باشند، در صفحه‌ی پکیج اختصاصی، بر روی گزینه‌ی mavenCentral کلیک کنید:

پس از آن باید نام کاربری و کلمه‌ی عبورتان را در SonaType، وارد کنید و گزینه‌ی sync را بفشارید:

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

نظرات مطالب
هزینه استفاده از دات نت فریم ورک چقدر است؟
- هر کسی می‌تونه برای کار خودش مجوز سورس باز انتخاب کنه، و مهم هم نیست که آن کار استاندارد باشد یا نباشد. مثل هزاران کاری که تابحال دیگران انجام دادن.
- در مورد مجوز فقط خواندنی MS-RSL حق با شما است؛ هر چند مثلا ASP.NET MVC3 مجوز MS-PL‌ دارد. ولی ... مهم نیست. مهم این است که سورس آن در دسترس همه است. همین در دسترس بودن سبب شده مونو الان پیاده سازی خوبی رو از ASP.NET MVC 3 ارائه بده:
http://www.mono-project.com/Release_Notes_Mono_2.10#ASP.NET_MVC3_Support
نظرات مطالب
هزینه استفاده از دات نت فریم ورک چقدر است؟
- هر کسی می‌تونه برای کار خودش مجوز سورس باز انتخاب کنه، و مهم هم نیست که آن کار استاندارد باشد یا نباشد. مثل هزاران کاری که تابحال دیگران انجام دادن.
- در مورد مجوز فقط خواندنی MS-RSL حق با شما است؛ هر چند مثلا ASP.NET MVC3 مجوز MS-PL‌ دارد. ولی ... مهم نیست. مهم این است که سورس آن در دسترس همه است. همین در دسترس بودن سبب شده مونو الان پیاده سازی خوبی رو از ASP.NET MVC 3 ارائه بده:
http://www.mono-project.com/Release_Notes_Mono_2.10#ASP.NET_MVC3_Support
اشتراک‌ها
کنفرانس دات نت 2017

سه روز دیگر شروع می‌شود و سه روز ادامه دارد و محتوای کنفرانس از قرار زیر است:

We’ll have presentations on .NET Core and ASP.NET Core, C#, F#, Roslyn, Visual Studio, Xamarin, and much more. 

کنفرانس دات نت 2017
نظرات مطالب
EF Code First #12
ترکیبی است از همین مثال سورس باز فوق و قسمت tracking که در مورد یکی کردن ی و ک ارسالی پیشتر بحث شد. مورد بیشتری ندارد. فقط یک try/catch اضافه شده در زمان save نهایی که DbEntityValidationException  را بررسی می‌کند.