نظرات نظرسنجی‌ها
برای توسعه برنامه‌های مبتنی بر NET Core. از چه محیطی استفاده می‌کنید؟
یه مدت روی اوبونتو از vsCode استفاده کردم. خیلی خوبه و سبک و راضی کننده ست. منتها مشکل اصلی من دیباگ کردن پروژه‌های docker base بود. راه حل هایی توی نت بود. منتها ساده نبودن و به همین خاطر فعلا بیخیال شدم و روی ویندوز با  2017 vs کار میکنم. اگر بشه به راحتی از داکر استفاده کرد برمیگردم روی vsCode
نظرسنجی‌ها
به روز رسانی‌های برنامه‌های خود را چگونه ارائه می‌کنید؟
به روز رسانی خودکار برنامه توسط خود آن (self-update) با بررسی اطلاعات آخرین به روز رسانی، از وب‌سایت ما.
کاربر نگارش‌های جدید دریافتی را (از طریق ایمیل و یا وب سایت ما) بر روی نگارش‌های فعلی کپی می‌کند.
کاربر یک برنامه‌‌ی به روز رسانی نصاب مانند را اجرا می‌کند.
کاربران به علت پیچیدگی برنامه نمی‌توانند برنامه را به روز رسانی کنند؛ ما برای آن‌ها اینکار را انجام می‌دهیم.
از 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. 

نگارش نهایی SQL Server 2016 منتشر شد
مطالب
آشنایی با Feature Toggle - بخش اول
فرض کنید میخواهید برای بخش‌هایی از نرم افزاری که طراحی کرده‌اید ، امکانی را در نظر بگیرید که بتوانید زمانیکه نرم افزار در حال استفاده‌است، قابلیت‌هایی از آن‌را فعال یا غیرفعال نمایید؛ بدون اینکه نرم افزار از دسترس خارج شود. Feature Toggle که تحت عنوان Feature Flag هم شناخته می‌شود همین امکان را برای ما به ارمغان می‌آورد و ما را قادر می‌سازد تا قابلیت‌هایی را از نرم افزار، فعال یا غیرفعال کنیم، بدون اینکه نیاز باشد نرم افزار از دسترس مشتریان خارج شود و یا نیاز باشد نسخه‌ی جدیدی از نرم افزار  منتشر شود. برای مثال قابلیت ثبت نام کاربران را در بازه‌های خاصی غیرفعال کنیم و یا فرض کنید قابلیت جدیدی به نرم افزار اضافه کرده‌اید و میخواهید بعد از پابلیش، در یک بازه زمانی که نرم افزار شما بازدید کننده‌های کمتری دارد، آن‌را موقتا فعال کنید، نتیجه خروجی را ببینید و سپس آن را غیر فعال نمایید. در ادامه این مقاله سعی خواهیم کرد ابتدا با یک مثال ساده با این قابلیت آشنا شویم و سپس به معرفی یکی از کتابخانه‌های محبوب در این زمینه بپردازیم.
Feature Toggle چیزی بیشتر از یک دستور IF نیست، اگر شرط مورد نظر برقرار بود، کد را اجرا میکند، در غیر اینصورت از اجرای آن بخش صرف نظر میکند.
IF (currentYear<2023){
alert('Wear a mask!');
}
در قطعه کد فوق، سال جاری را چک کرده‌ایم و گفته‌ایم اگر سال جاری کمتر از سال 2023 بود، به بازدید کننده یک پیغام را نمایش دهیم. حال فرض کنید بیماری کرونا، پیش از سال 2023 از بین برود، ولی طبق این شرط همچنان پیغام به کاربران نمایش داده میشود. میتوانیم فعال و غیر فعال بودن نمایش این پیغام را یا از دیتابیس و یا از فایل appsetting.json  بخوانیم که در این حالت  به صورت زیر می‌باشد :
var showCoronaAlert=_cofiguration.GetValue<bool>("Features:showCoronaAlert"); // or read this from Database
If(showCoronaAlert){
alert(Wear a amask!);
}
در این روش بجای اینکه تاریخ را چک کنیم و بر اساس آن تصمیم بگیریم که آیا پیغامی نمایش داده شود یا نه، وضعیت نمایش آن را از فایل تنظیمات و یا دیتابیس خوانده‌ایم. در این حالت دیگر نیازی به تغییر و انتشار نسخه‌ی جدیدی از نرم افزار نیست و فقط کافی‌است مقدار مربوط به نمایش پیغام را در دیتابیس و یا فایل تنظیمات، به روزسانی نماییم.

 کتابخانه  Microsoft.FeatureManagement
کتابخانه  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
}

همان مثال بالا را  در بخش FeatureManagement  اضافه کرده‌ایم  و مقدار true را به معنی فعال بودن، برای آن در نظر گرفته‌ایم. این حالت، ساده‌ترین روش ثبت یک قابلیت با استفاده از این کتابخانه می‌باشد. برای بررسی وضعیت هر کدام از قابلیت‌ها باید اینترفیس  IFeatureManager   را به کلاس مربوطه تزریق نماییم و سپس بر اساس نام قابلیت، وضعیت آن را بررسی نماییم:
 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();
        }
    }
اگر نیاز هست از اسم دیگری برای بخش (section)

فعال سازی بر اساس تاریخ (TimeWindowsFilter)
یکی از قابلیت‌های این کتابخانه، فعال سازی بر اساس بازه زمانی هست. اگر نیاز دارید یک قابلیت در یک بازه‌ی خاص فعال شود، میتوانید از این قابلیت استفاده کنید. برای فعال سازی این امکان، باید فیلتر TimeWindowFilter را که به صورت توکار به همراه کتابخانه وجود دارد، به صورت زیر در متد configureServices ثبت نماییم:
public void ConfigureServices(IServiceCollection services)
{ 
    services.AddFeatureManagement().AddFeatureFilter<TimeWindowFilter>();
}

و سپس یک Feature را در بخش FeatureManagement همانند زیر تعریف میکنیم که توسط آن مشخص کرده‌ایم این قابلیت در بازه‌ی زمانی بین دو تاریخ تعریف شده، فعال باشد :
 "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"
          }
        }
      ]
    }
  }
و نحوه‌ی بررسی فعال بودن آن، همانند روش قبل می‌باشد و فقط کافیست اسم Feature را به متد IsEnabledAsync بدهیم:
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));
        }
    }

کلاس BrowserFilter :
  public class BrowserFilterSettings
    {
        public string[] AllowedBrowsers { get; set; }
    }
بعد از پیاده سازی فیلتر فوق نیاز هست فیلتر سفارشی را که در بالا نوشتیم، در متد ConfigureServices ثبت نماییم. با توجه به اینکه برای تشخیص نوع مروگر کاربر نیاز هست  هدر درخواست را بررسی کنیم، پس نیاز هست IHttpContextAccessor را هم ثبت نماییم:
public void ConfigureServices(IServiceCollection services)
        {
            services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddFeatureManagement()
                .AddFeatureFilter<BrowserFilter>();
        }
و برای بررسی فعال بودن قابلیت مورد نظر فقط کافیست مانند قبل، اسم قابلیت مورد نظر را به صورت زیر بررسی کنیم :
if(await _featureManager.IsEnabledAsync("ChatV2")){
// do something 
}

* از دیگر قابلیت‌های این کتابخانه، فعال و غیر فعال کردن کنترلر و اکشن متدها بر اساس وضعیت Feature‌ها می‌باشد که در بخش دوم این مقاله به توضیح این موارد خواهیم پرداخت.
مطالب
مقدمه ای بر Docker، قسمت پنجم
  در قسمت‌های قبل با کلیات مفاهیم داکر آشنا شدیم. اما بنا داریم در این قسمت با اصول اولیه‌ی تهیه‌ی 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 جهت مدیریت و اجرای این برنامه میباشد که حاوی ساختار زیر است:
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
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 کردن:
 docker-compose build
برای اجرا کردن:
 docker-compose up
برای حذف کردن:
 docker-compose down
برای stop کردن موقتی:
 docker-compose stop
برای start کردن مجدد:
 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!`))
 بعد از اجرا کردن docker-compose، به راحتی سرویس‌های ما از طریق پورت 8181 و 8182 قابلیت فراخوانی را دارند. 

نکته: 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» قابل دریافت میباشد.
نظرات مطالب
نوروز مبارک!
سال خوبی داشته باشید.
نظرات مطالب
نحوه‌ی صحیح فراخوانی SQL Aggregate Functions حین استفاده از LINQ - قسمت دوم
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 یا حتی استفاده از آن‌ها به عنوان مرجع بی‌نظیر است.