یه مدت روی اوبونتو از vsCode استفاده کردم. خیلی خوبه و سبک و راضی کننده ست. منتها مشکل اصلی من دیباگ کردن پروژههای docker base بود. راه حل هایی توی نت بود. منتها ساده نبودن و به همین خاطر فعلا بیخیال شدم و روی ویندوز با 2017 vs کار میکنم. اگر بشه به راحتی از داکر استفاده کرد برمیگردم روی vsCode
به روز رسانی خودکار برنامه توسط خود آن (self-update) با بررسی اطلاعات آخرین به روز رسانی، از وبسایت ما.
کاربر نگارشهای جدید دریافتی را (از طریق ایمیل و یا وب سایت ما) بر روی نگارشهای فعلی کپی میکند.
کاربر یک برنامهی به روز رسانی نصاب مانند را اجرا میکند.
کاربران به علت پیچیدگی برنامه نمیتوانند برنامه را به روز رسانی کنند؛ ما برای آنها اینکار را انجام میدهیم.
از ClickOnce استفاده میکنیم.
توسط سیستم به روز رسانی App Storeها.
از Docker استفاده میکنیم.
کاربر نگارشهای جدید دریافتی را (از طریق ایمیل و یا وب سایت ما) بر روی نگارشهای فعلی کپی میکند.
کاربر یک برنامهی به روز رسانی نصاب مانند را اجرا میکند.
کاربران به علت پیچیدگی برنامه نمیتوانند برنامه را به روز رسانی کنند؛ ما برای آنها اینکار را انجام میدهیم.
از ClickOnce استفاده میکنیم.
توسط سیستم به روز رسانی App Storeها.
از Docker استفاده میکنیم.
اشتراکها
چگونه یک سیستم عامل بنویسیم ؟
اشتراکها
نگارش نهایی SQL Server 2016 منتشر شد
Today we announced the general availability of SQL Server 2016, the world’s fastest and most price-performant database for HTAP (Hybrid Transactional and Analytical Processing) with updateable, in-memory columnstores and advanced analytics through deep integration with R Services. Software applications can now deploy sophisticated analytics and machine learning models in the database resulting in 100x or more speedup in time to insight, compared to deployments of such models outside of the database.
اشتراکها
آموزش Scratch و Raspberry
فرض کنید میخواهید برای بخشهایی از نرم افزاری که طراحی کردهاید ، امکانی را در نظر بگیرید که بتوانید زمانیکه نرم افزار در حال استفادهاست، قابلیتهایی از آنرا فعال یا غیرفعال نمایید؛ بدون اینکه نرم افزار از دسترس خارج شود. Feature Toggle که تحت عنوان Feature Flag هم شناخته میشود همین امکان را برای ما به ارمغان میآورد و ما را قادر میسازد تا قابلیتهایی را از نرم افزار، فعال یا غیرفعال کنیم، بدون اینکه نیاز باشد نرم افزار از دسترس مشتریان خارج شود و یا نیاز باشد نسخهی جدیدی از نرم افزار منتشر شود. برای مثال قابلیت ثبت نام کاربران را در بازههای خاصی غیرفعال کنیم و یا فرض کنید قابلیت جدیدی به نرم افزار اضافه کردهاید و میخواهید بعد از پابلیش، در یک بازه زمانی که نرم افزار شما بازدید کنندههای کمتری دارد، آنرا موقتا فعال کنید، نتیجه خروجی را ببینید و سپس آن را غیر فعال نمایید. در ادامه این مقاله سعی خواهیم کرد ابتدا با یک مثال ساده با این قابلیت آشنا شویم و سپس به معرفی یکی از کتابخانههای محبوب در این زمینه بپردازیم.
Feature Toggle چیزی بیشتر از یک دستور IF نیست، اگر شرط مورد نظر برقرار بود، کد را اجرا میکند، در غیر اینصورت از اجرای آن بخش صرف نظر میکند.
IF (currentYear<2023){ alert('Wear a mask!'); }
var showCoronaAlert=_cofiguration.GetValue<bool>("Features:showCoronaAlert"); // or read this from Database
If(showCoronaAlert){
alert(Wear a amask!);
}
در این روش بجای اینکه تاریخ را چک کنیم و بر اساس آن تصمیم بگیریم که آیا پیغامی نمایش داده شود یا نه، وضعیت نمایش آن را از فایل تنظیمات و یا دیتابیس خواندهایم. در این حالت دیگر نیازی به تغییر و انتشار نسخهی جدیدی از نرم افزار نیست و فقط کافیاست مقدار مربوط به نمایش پیغام را در دیتابیس و یا فایل تنظیمات، به روزسانی نماییم.
کتابخانه Microsoft.FeatureManagement توسط تیم اژور پیاده سازی و نوشته شدهاست و برای خواندن اطلاعات، از همان IConfiguration استفاده میکند که ما را قادر میسازد تنظیمات را از منابع مختلفی بخوانیم و همچنین قابلیتهای آن فراتر از تنظیم یک مقدار با true/false میباشد که در ادامه با بعضی از آنها آشنا خواهیم شد.
ابتدا نیاز هست این کتابخانه را به صورت زیر نصب نماییم :
Install-Package Microsoft.FeatureManagement
سپس نیاز هست در متد ConfigureService، سرویس مربوطه را اضافه نماییم :
using Microsoft.FeatureManagement; public void ConfigureServices(IServiceCollection services) { services.AddFeatureManagement(); }
این کتابخانه به صورت پیش فرض، اطلاعات featureها را از بخشی (section) تحت عنوان FeatureManagement از فایل appsetting.json میخواند. پس نیاز داریم این بخش را در appsetting.json تعریف نماییم ( لیست تمامی قابلیتهایی را که قصد داریم به صورت داینامیک فعال/غیرفعال کنیم، در این بخش اضافه خواهیم کرد):
"FeatureManagement": { }
اگر تمایل داشتید از اسم دیگری برای بخش تنظیمات، در فایل appsetting. json استفاده نمایید، میتوانید به صورت زیر این کار را انجام دهید :
public void ConfigureServices(IServiceCollection services) { services.AddFeatureManagement(Configuration.GetSection("MyFeatureManagement")) }
در این مقاله از همان اسم پیش فرض استفاده شده است.
افزودن یک قابلیت جدید
"FeatureManagement": { "MaskAlert":true }
public class HomeController : Controller { private readonly IFeatureManager _featureManager; public HomeController(IFeatureManager featureManager) { _featureManager = featureManager; } public async Task<IActionResult> Index() { if(await _featureManager.IsEnabledAsync("MaskAlert")) { // show messeage } return View(); } }
فعال سازی بر اساس تاریخ (TimeWindowsFilter)
یکی از قابلیتهای این کتابخانه، فعال سازی بر اساس بازه زمانی هست. اگر نیاز دارید یک قابلیت در یک بازهی خاص فعال شود، میتوانید از این قابلیت استفاده کنید. برای فعال سازی این امکان، باید فیلتر TimeWindowFilter را که به صورت توکار به همراه کتابخانه وجود دارد، به صورت زیر در متد configureServices ثبت نماییم:
public void ConfigureServices(IServiceCollection services) { services.AddFeatureManagement().AddFeatureFilter<TimeWindowFilter>(); }
"FeatureManagement": { "EmergencyBanner": { "EnabledFor": [ { "Name": "Microsoft.TimeWindow", "Parameters": { "Start": "01 Mar 2021 12:00:00 +00:00", "End": "01 Apr 2021 12:00:00 +00:00" } } ] } }
if(await _featureManager.IsEnabledAsync("EmergencyBanner")){ // show Emergency banner }
پارامترهای Start و End میتوانند به صورت تکی هم استفاده شوند؛ به این معنا که میتوانید فقط پارامتر start را مقدار دهی کنید و در این حالت از تاریخ مورد نظر به بعد، Feature مورد نظر فعال میباشد و یا اگر فقط پارامتر End مقدار دهی شود، Feature مورد نظر فقط تا تاریخ تعیین شده فعال هست و بعد از آن برای همیشه غیرفعال میشود.
در زیر، نمونهای از این حالت تنظیم شدهاست :
"FeatureManagement": { "EmergencyBanner": { "EnabledFor": [ { "Name": "Microsoft.TimeWindow", "Parameters": { "End": "01 Apr 2021 12:00:00 +00:00" } } ] } }
فیلترهای سفارشی
از دیگر مزایای این کتابخانه این هست که محدود به فیلترهای توکار خود آن نیستیم و امکان توسعه و نوشتن فیلترهای سفارشی را به ما میدهد. برای مثال اگر یک قابلیت را در نرم افزار پیاده سازی کردهایم که میخواهیم فقط بر روی مرورگرهای خاصی در دسترس باشد، میتوانیم به صورت زیر این کار را انجام دهیم:
ابتدا در appsetting.json قابلیت (Feature) مورد نظر را به صورت زیر تعریف میکنیم :
"FeatureManagement": { "ChatV2": { "EnabledFor": [ { "Name": "BrowserFilter", "Parameters": { "AllowedBrowsers": [ "Chrome" ] } } ] } }
[FilterAlias("BrowserFilter")] public class BrowserFilter:IFeatureFilter { private readonly IHttpContextAccessor _httpContextAccessor; public BrowserFilter(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor)); } public Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context) { var userAgent = _httpContextAccessor.HttpContext.Request.Headers["User-Agent"].ToString(); var settings = context.Parameters.Get<BrowserFilterSettings>(); return Task.FromResult(settings.AllowedBrowsers.Any(userAgent.Contains)); } }
public class BrowserFilterSettings { public string[] AllowedBrowsers { get; set; } }
IHttpContextAccessor
را هم ثبت نماییم: public void ConfigureServices(IServiceCollection services) { services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>(); services.AddFeatureManagement() .AddFeatureFilter<BrowserFilter>(); }
if(await _featureManager.IsEnabledAsync("ChatV2")){ // do something }
* از دیگر قابلیتهای این کتابخانه، فعال و غیر فعال کردن کنترلر و اکشن متدها بر اساس وضعیت Featureها میباشد که در بخش دوم این مقاله به توضیح این موارد خواهیم پرداخت.
در قسمتهای قبل با کلیات مفاهیم داکر آشنا شدیم. اما بنا داریم در این قسمت با اصول اولیهی تهیهی docker-compose آشنا شده و دستورالعمل اجرای کانتینرهای مختلف را درون یک فایل نوشته و مدیریت نماییم. در واقع، compose ابزاری است برای تعریف و اجرای اپلیکیشنهای multi-container.
با استفاده از YAML، دستورالعملهای سرویسهای مختلف را نوشته و با یک دستور همهی آنها را با هم اجرا مینماییم. از compose در تمامی مراحل production, staging, development, testing و همچنین CI workflow استفاده میشود.
برای استفاده از compose سه عمل زیر باید انجام شود:
1- ساخت و تعریف dockerfile برای هر سرویس.
2- ساخت و تعریف docker-compose.yml. بنابراین هر سرویس میتواند در محیط ایزولهی خود اجرا شود.
3- اجرای دستور docker-compose up.
در قسمتهای قبلی مراحل ساخت و اجرای imageها درون کانتینر و همچنین متصل کردن آنها را به شبکه، بررسی کرده ایم؛ اما در این قسمت میخواهیم با استفاده از docker-compose مدیریت build و اجرای همهی imageها را بر عهده بگیریم.
عملا با این ساختار، قابلیت ایجاد شبکه، volume و غیره را خواهیم داشت. بنابراین با استفاده از این config توانایی توزیع برنامه را فقط با یک فایل YAML، خواهیم داشت.
ایجاد پروژه:
فرض کنید نرم افزار ما از دو سرویس Nodejsی همچنین یک دیتابیس Mongo تشکیل شده است. در نهایت باید به چیزی شبیه به تصویر زیر برسیم:
دایرکتوری root این پروژه از دو پوشه به نامهای nodeapp1 و nodeapp2 تشکیل شده است که داخل هر کدام یک فایل index.js و همچنین package.json و dockerfile وجود دارد؛ همانند مطالب پیشین.
اما چیزی که اینجا اضافه شده است، فایل docker-compose.yml جهت مدیریت و اجرای این برنامه میباشد که حاوی ساختار زیر است:
1) ابتدا یک شبکه از نوع bridge را به نام shared-network میسازیم.
2) برای مشخص کردن سرویسهای این برنامه از services استفاده کرده و آنها را تعریف مینماییم.
3) سرویس nodeapp1 که قرار است تصویری به نام nodeapp1 را ایجاد کند (هدف آن build کردن اولین سرویس میباشد. همانطور که مشخص است context برنامه، اسم پوشهی nodeapp1 درون ریشهی پروژه است. ضمن اینکه نام dockerfile را هم درون آن پوشه بدان اضافه کردهایم).
4) پورت 8181 را بر روی پورت 80 درون این کانتینر هدایت میکنیم.
5) این سرویس، درون شبکهی ایجاد شدهی shared-network قرار میگیرد.
5) سرویس nodeapp2 را هم به همین شکل اضافه میکنیم.
6) سرویس mongo قرار نیست هیچ کدی را build کند و هدف، فقط اجرای mongo درون شبکهی shared-network است که بقیه سرویسها بتوانند بدان وصل شوند.
برای ساخت و اجرا نیز در ریشهی این پروژه، ترمینال خود را باز کرده و دستورات زیر را وارد مینماییم:
برای build کردن:
برای اجرا کردن:
برای حذف کردن:
برای stop کردن موقتی:
برای start کردن مجدد:
و اگر بخواهیم بعد از build کردن، بصورت خودکار نیز اجرا شود، از دستور زیر استفاده میکنیم:
dockerfile هر دو سرویس نیز بصورت ساده همانند مطالب پیشین در نظر گرفته شدهاست:
در صورتیکه بخواهیم نگاهی هم به کدهای نوشته شده بیندازیم، نکتهی جالبی مد نظر قرار میگیرد؛ بطور مثال از آنجائیکه همهی کانتینرهای اجرا شده، درون یک شبکه هستند، برای فراخوانی سرویسهای دیگر کافیست با نامشان صدا زده شوند. بطور مثال در nodeapp1 برای فراخوانی nodeapp2 به راحتی با نام صدا زده شده است و احتیاجی به فراخوانی با ip نیست. کدهای زیر مربوط به فایل index.js در سرویس nodeapp1 میباشند (بدلیل اینکه روی پورت 80 درون کانتینر قرار گرفتهاست، دیگر لازم به وارد نمودن پورت نبودیم؛ در غیر اینصورت بطور مثال باید درخواستی بصورت http://nodeapp2:5000 را ارسال مینمودیم):
بعد از اجرا کردن docker-compose، به راحتی سرویسهای ما از طریق پورت 8181 و 8182 قابلیت فراخوانی را دارند.
نکته: override کردن composeها نیز قابل انجام است. بدین معنا که شما یک نسخه برای build و استفاده در محیط development و نسخههای دیگری بطور مثال برای production خود تعریف مینمایید؛ مثلا روی پروداکشن، environment variablesهای متفاوتی را در نظر میگیرید. YAML زیر را مشاهده کنید:
فرض کنید که قرار است YAML فوق بر روی فایل قبلی، بازنویسی شود؛ با استفاده از دستور زیر:
تمام کدهای فوق از اینجا «node.rar» قابل دریافت میباشد.
با استفاده از YAML، دستورالعملهای سرویسهای مختلف را نوشته و با یک دستور همهی آنها را با هم اجرا مینماییم. از compose در تمامی مراحل production, staging, development, testing و همچنین CI workflow استفاده میشود.
برای استفاده از compose سه عمل زیر باید انجام شود:
1- ساخت و تعریف dockerfile برای هر سرویس.
2- ساخت و تعریف docker-compose.yml. بنابراین هر سرویس میتواند در محیط ایزولهی خود اجرا شود.
3- اجرای دستور docker-compose up.
در قسمتهای قبلی مراحل ساخت و اجرای imageها درون کانتینر و همچنین متصل کردن آنها را به شبکه، بررسی کرده ایم؛ اما در این قسمت میخواهیم با استفاده از docker-compose مدیریت build و اجرای همهی imageها را بر عهده بگیریم.
عملا با این ساختار، قابلیت ایجاد شبکه، volume و غیره را خواهیم داشت. بنابراین با استفاده از این config توانایی توزیع برنامه را فقط با یک فایل YAML، خواهیم داشت.
ایجاد پروژه:
فرض کنید نرم افزار ما از دو سرویس Nodejsی همچنین یک دیتابیس Mongo تشکیل شده است. در نهایت باید به چیزی شبیه به تصویر زیر برسیم:
دایرکتوری root این پروژه از دو پوشه به نامهای nodeapp1 و nodeapp2 تشکیل شده است که داخل هر کدام یک فایل index.js و همچنین package.json و dockerfile وجود دارد؛ همانند مطالب پیشین.
اما چیزی که اینجا اضافه شده است، فایل docker-compose.yml جهت مدیریت و اجرای این برنامه میباشد که حاوی ساختار زیر است:
version: '3' networks: shared-network: services: nodeapp1: image: nodeapp1 build: context: nodeapp1 dockerfile: dockerfile ports: - "8181:80" networks: - shared-network nodeapp2: image: nodeapp2 build: context: nodeapp2 dockerfile: dockerfile ports: - "8182:80" networks: - shared-network mongo: image: mongo ports: - "27017:27017" networks: - shared-network
2) برای مشخص کردن سرویسهای این برنامه از services استفاده کرده و آنها را تعریف مینماییم.
3) سرویس nodeapp1 که قرار است تصویری به نام nodeapp1 را ایجاد کند (هدف آن build کردن اولین سرویس میباشد. همانطور که مشخص است context برنامه، اسم پوشهی nodeapp1 درون ریشهی پروژه است. ضمن اینکه نام dockerfile را هم درون آن پوشه بدان اضافه کردهایم).
4) پورت 8181 را بر روی پورت 80 درون این کانتینر هدایت میکنیم.
5) این سرویس، درون شبکهی ایجاد شدهی shared-network قرار میگیرد.
5) سرویس nodeapp2 را هم به همین شکل اضافه میکنیم.
6) سرویس mongo قرار نیست هیچ کدی را build کند و هدف، فقط اجرای mongo درون شبکهی shared-network است که بقیه سرویسها بتوانند بدان وصل شوند.
برای ساخت و اجرا نیز در ریشهی این پروژه، ترمینال خود را باز کرده و دستورات زیر را وارد مینماییم:
برای build کردن:
docker-compose build
docker-compose up
docker-compose down
docker-compose stop
docker-compose start
و اگر بخواهیم بعد از build کردن، بصورت خودکار نیز اجرا شود، از دستور زیر استفاده میکنیم:
docker-compose run --build
dockerfile هر دو سرویس نیز بصورت ساده همانند مطالب پیشین در نظر گرفته شدهاست:
FROM node COPY . /var/www WORKDIR /var/www RUN npm i EXPOSE 80 ENTRYPOINT node index
در صورتیکه بخواهیم نگاهی هم به کدهای نوشته شده بیندازیم، نکتهی جالبی مد نظر قرار میگیرد؛ بطور مثال از آنجائیکه همهی کانتینرهای اجرا شده، درون یک شبکه هستند، برای فراخوانی سرویسهای دیگر کافیست با نامشان صدا زده شوند. بطور مثال در nodeapp1 برای فراخوانی nodeapp2 به راحتی با نام صدا زده شده است و احتیاجی به فراخوانی با ip نیست. کدهای زیر مربوط به فایل index.js در سرویس nodeapp1 میباشند (بدلیل اینکه روی پورت 80 درون کانتینر قرار گرفتهاست، دیگر لازم به وارد نمودن پورت نبودیم؛ در غیر اینصورت بطور مثال باید درخواستی بصورت http://nodeapp2:5000 را ارسال مینمودیم):
const express = require('express'); const fetch = require('node-fetch'); const app = express(); app.get('/', async (req, res) => { let response = await fetch("http://nodeapp2/"); text = await response.text(); res.send(text); }) app.listen(80, () => console.log(`listening on port 80!`))
نکته: override کردن composeها نیز قابل انجام است. بدین معنا که شما یک نسخه برای build و استفاده در محیط development و نسخههای دیگری بطور مثال برای production خود تعریف مینمایید؛ مثلا روی پروداکشن، environment variablesهای متفاوتی را در نظر میگیرید. YAML زیر را مشاهده کنید:
version: '3' services: nodeapp1: environment: - PRODUCTION: 'true' nodeapp2: environment: - PRODUCTION: 'true'
فرض کنید که قرار است YAML فوق بر روی فایل قبلی، بازنویسی شود؛ با استفاده از دستور زیر:
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up
تمام کدهای فوق از اینجا «node.rar» قابل دریافت میباشد.
نظرات مطالب
نوروز مبارک!
سال خوبی داشته باشید.
LINQPad یک برنامهی نیمه رایگان است. به این معنا که دریافت آن رایگان است، استفاده از آن هیچ محدودیتی ندارد. فقط هنگام نوشتن کوئریها intellisense ظاهر نخواهد شد. این یک مورد رایگان نیست و برای فعال شدن آن باید مقداری هزینه کنید. کیفیت intellisense آن هم قابل مقایسه است با VS.NET و بسیار مطلوب است.
LINQPad برای تست کردن سریع عبارات LINQ فوق العاده است. با استفاده از آن بدون نیاز به VS.NET خیلی سریع و در عرض چند ثانیه میتونید عبارات LINQ خودتون رو نوشته و تست کنید. این LINQ میتونه LINQ to Objects باشه یا LINQ to SQL یا LINQ to Entities و غیره.
خلاصه چیزی شبیه به management studio مخصوص SQL Server را تصور کنید که اینبار بجای SQL نویسی، LINQ مینویسید، حاصل را نمایش میدهد؛ علاوه بر آن خروجی SQL تولیدی و حتی IL نهایی را هم نمایش میدهد که برای دیباگ بسیار مفید است.
به همراه آن یک سری مثال هم وجود دارد که جهت فراگیری LINQ یا حتی استفاده از آنها به عنوان مرجع بینظیر است.
LINQPad برای تست کردن سریع عبارات LINQ فوق العاده است. با استفاده از آن بدون نیاز به VS.NET خیلی سریع و در عرض چند ثانیه میتونید عبارات LINQ خودتون رو نوشته و تست کنید. این LINQ میتونه LINQ to Objects باشه یا LINQ to SQL یا LINQ to Entities و غیره.
خلاصه چیزی شبیه به management studio مخصوص SQL Server را تصور کنید که اینبار بجای SQL نویسی، LINQ مینویسید، حاصل را نمایش میدهد؛ علاوه بر آن خروجی SQL تولیدی و حتی IL نهایی را هم نمایش میدهد که برای دیباگ بسیار مفید است.
به همراه آن یک سری مثال هم وجود دارد که جهت فراگیری LINQ یا حتی استفاده از آنها به عنوان مرجع بینظیر است.