مطالب
تبدیل زیرنویس‌های خاص پلورال‌سایت به فرمت SRT - قسمت دوم
قسمت اول این مطلب را در اینجا می‌توانید مطالعه کنید. از سه سال قبل تا به این تاریخ، فرمت زیرنویس‌های این سایت به صورت JSON تغییر پیدا کرده‌است و یک چنین ساختار جدیدی را دارد:
{
    "userIsAuthorizedForCourseTranscripts": false,
    "modules": [
        {
            "title": "Course Overview",
            "clips": [
                {
                    "title": "Course Overview",
                    "playerParameters": "author=scott-allen&name=aspdotnet-core-1-0-fundamentals-m0&mode=live&clip=0&course=aspdotnet-core-1-0-fundamentals",
                    "transcripts": [ ]
                }
            ]
        },
        {
            "title": "Building Your First ASP.NET Core Application",
            "clips": [
                {
                    "title": "Introduction",
                    "playerParameters": "author=scott-allen&name=aspdotnet-core-1-0-fundamentals-m1&mode=live&clip=0&course=aspdotnet-core-1-0-fundamentals",
                    "transcripts": [
                        {
                            "displayTime": 0.0,
                            "text": "Hi! This is Scott, and this course will help you build your first application with ASP.NET Core."
                        },
                        {
                            "displayTime": 7.0,
                            "text": "In this course, we'll be using Visual Studio and the new ASP.NET Framework to build a web application that"
                        }
                    ]
                }
            ]
        }
    ]
}
که اگر بخواهیم کلاس‌های معادل آن‌را تشکیل دهیم، به ساختار زیر خواهیم رسید:
public class PluralsightCourse
{
    public bool UserIsAuthorizedForCourseTranscripts { get; set; }
    public PluralsightCourseItems[] Modules { get; set; }
}
public class PluralsightCourseItems
{
    public string Title { get; set; }
    public PluralsightCourseClip[] Clips { get; set; }
}
public class PluralsightCourseClip
{
    public string Title { get; set; }
    public string PlayerParameters { get; set; }
    public PluralsightCourseClipTranscript[] Transcripts { get; set; }
}
public class PluralsightCourseClipTranscript
{
    public float DisplayTime { get; set; }
    public string Text { get; set; }
}
و بعد از تشکیل این ساختار که توسط منوی edit و گزینه‌ی paste special ویژوال استودیو تشکیل شده‌است:


بارگذاری آن توسط کتابخانه‌ی JSON.NET به صورت ذیل خواهد بود:
public static PluralsightCourse ProcessJsonFile(string jsonData)
{
    return JsonConvert.DeserializeObject<PluralsightCourse>(jsonData);
}
و پس از آن اگر حلقه‌ای را بر روی ماژول‌ها و سپس آیتم‌های هر ماژول تشکیل دهیم، می‌توان فرمت آن‌را به فرمت استاندارد srt که قابلیت پخش در اکثر برنامه‌های video player را دارد (مانند kmplayer)، تبدیل کرد.


کدهای کامل این برنامه را از اینجا می‌توانید دریافت کنید:
PluralsightJsonTranscripts.V1.0.7z
اشتراک‌ها
سری کار با IdentityServer 5

- Creating an IdentityServer 5 Project
- Adding JWT Bearer Authentication to an ASP.NET Core 5 API
- Adding Policy-Based Authorisation to an ASP.NET Core 5 API
- Authenticating a .NET 5 Console Application using IdentityServer 5
- Adding API Resources to IdentityServer 5
- Containerising a PostgreSQL 13 Database
- Adding Entity Framework Core 5 to IdentityServer 5
- Adding an OAuth 2.0 Security Scheme to an ASP.NET Core 5 API
- Adding ASP.NET Core 5 Identity to IdentityServer 5
- Seeding an ASP.NET Core 5 Identity Database with Users
- Authenticating an ASP.NET Core 5 Web Application using IdentityServer 5
- Authenticating an Angular 11 Single-Page Application using IdentityServer 5
- Authenticating a Flutter Android Application using IdentityServer 5
- Containerising an IdentityServer 5 Project
- Containerising an IdentityServer 5 Project with API Resources and Clients
 

سری کار با IdentityServer 5
مطالب
معرفی و راهنمایی جهت انتخاب پلتفرم‌های توسعه‌ی رابط کاربری جدید مایکروسافت
اگر به تکنولوژی‌های شرکت مایکروسافت علاقمند باشید و اخبار آن را دنبال کرده باشید قطعا در جریان هستید که علاوه بر تکنولوژی‌های قدیمی (WPF, UWP, Xamarin) تکنولوژی‌های جدیدی (Project Reunion, Maui, WinUI, Uno, Xaml Island) نیز بصورت همزمان در حال توسعه هستند. اکثر این تکنولوژی‌ها شبیه و نزدیک به هم هستند و برای کسی که تازه کار باشد ممکن است دچار سردرگمی شود و چون بصورت همزمان در حال توسعه می‌باشند ممکن سوالاتی برای شما پیش بیاید. در این مطلب هر کدام از این تکنولوژی‌ها را معرفی کرده و در انتخاب صحیح به شما کمک خواهیم کرد.

ساخت برنامه با WPF
به کمک تکنولوژی WPF میتوانیم نرم افزارهای دسکتاپ را توسعه دهیم. WPF همچنان پشتیبانی میشود و در سال‌های اخیر بصورت متن باز نیز منتشر شده‌است. اگر نیاز دارید که برنامه شما در ویندوز‌های 7 تا ویندوز 11 اجرا شود، میتوانید از WPF استفاده کنید. لازم به ذکر است که برنامه‌های WPF به عنوان Win32 یا Desktop نیز شناخته میشوند.

ساخت برنامه با UWP
UWP بعد از WPF و با انتشار ویندوز 10 معرفی شد. علت انتشار، هماهنگی برنامه‌ها با سیستم عامل ویندوز 10 و امنیت بیشتر بود. به‌طور فنی برنامه‌ای که بصورت UWP ساخته میشود، همان WPF است؛ با این تفاوت که داخل SandBox اجرا میشود و با محیط خارج ارتباطی ندارد. بدلیل مسائل امنیتی، بسیاری از کارهای ساده و مهم در UWP غیرممکن (البته راه حل‌هایی نیز وجود دارد) می‌باشد و نیاز به دسترسی کاربر دارد. به عنوان مثال، API‌های system.Io.File یا Process قابل استفاده نمی‌باشند.
نرم افزارهایی که با UWP ساخته میشوند فقط بر روی ویندوز 10 به بالا قابلیت اجرایی دارند و توزیع آن از طریق استور مایکروسافت امکان پذیر است. در صورت نیاز به توزیع دستی (فایل نصبی)، توسعه دهنده باید فایل نصبی را بصورت دیجیتال، امضاء کند که دردسر‌های خودش را دارد.

ساخت برنامه با Xamarin
اگر نیاز دارید که برای سیستم عامل اندروید و مک برنامه بنویسید، زامارین میتواند به شما کمک کند.

ساخت برنامه با WinUI
بعد از معرفی UWP نیاز به یک فریمورک رابط کاربری قوی جهت جذب کاربران به سمت UWP احساس شد. در نتیجه مایکروسافت فریمورک WinUI را ایجاد کرد. WinUI در 2 نسخه در حال توسعه می‌باشد:

WinUI 2.X
این نسخه از WinUI فقط قابلیت استفاده در برنامه‌های مبتنی بر UWP را دارد. اخیرا نسخه 2.6 آن منتشر شده که شامل تغییرات بصری عظیمی می‌باشد. لازم به ذکر است که ویندوز 11 که اخیرا معرفی شد، بر پایه WinUI 2.6 ایجاد شده است.

WinUI 3.X
این نسخه از WinUI قابلیت استفاده در پلتفرم‌های دیگر را محیا می‌کند و هم اکنون بصورت پیش نمایش است و بر پایه WinUI 2.5 می‌باشد. در 3 ماهه آخر سال 2021 تمامی استایل‌ها بر پایه نسخه 2.6 خواهد بود.
 

پلتفرم Uno
پلتفرم اونو توسط مایکروسافت ایجاد نشده، اما توسط آن پشتیبانی میشود. شما به کمک پلتفرم اونو میتوانید به کمک WinUI 3، برنامه‌های خود را در ویندوز 7 (به کمک موتور رندر Skia ) تا ویندوز 11، لینوکس (به کمک Skia)، مک و حتی موبایل اجرا کنید.

پلتفرم Maui
مائویی در واقع نسل بعدی زامارین می‌باشد و بصورت تک پروژه‌ای ایجاد شده‌است. در زامارین شما برای هر پلتفرم (ویندوز، اندروید، مک و...) یک پروژه جداگانه داشتید، اما در مائویی فقط یک پروژه واحد وجود دارد. پس اگر نیاز دارید که برای گوشی‌های همراه برنامه نویسی کنید، میتوانید از مائویی استفاده کنید. لازم به ذکر است به کمک مائویی میتوانید برای لینوکس و مک هم برنامه ایجاد کنید. اما بدلیل وجود WinUI در سایر پلتفرم‌ها، بهتر است از مائویی فقط برای ایجاد برنامه‌های موبایل استفاده کنید.
 

پلتفرم Project Reunion
اخیرا نام این پروژه به Windows App SDK تغییر یافته‌است. به کمک این پروژه میتوانید از WinUI 3 در برنامه‌های WPF و سایر تکنولوژی‌های Desktop استفاده کنید و کل برنامه خود را مدرن کنید. لازم به ذکر است که برنامه‌های ساخته شده توسط Reunion فقط در ویندوز 10 به بالا اجرا میشوند. در حال حاضر جهت اجرای برنامه نیاز هست که برنامه بصورت MSIX پکیج بشود. در نسخه 1.0 که تا چند ماه آینده منتشر خواهد شد، نیازی به پکیج کردن نخواهد بود.

پلتفرم Xaml Island
این پلتفرم در واقع پلی است که میتوانید از کنترل‌های UWP یا WinUI در برنامه‌های دسکتاپ (WPF) استفاده کنید. تفاوت این پلتفرم با Reunion در این است که شما فقط میتوانید بخشی از برنامه خود را مدرن کنید و قسمت‌های مدرن شده در ویندوز‌های پایین‌تر از ویندوز 10، کار نخواهند کرد. اما در Reunion تمام بخش‌های برنامه شما مدرن خواهد شد.

سخن آخر اینکه اگر نیاز به برنامه‌های موبایل دارید، بهتر است از مائویی استفاده کنید بدلیل اینکه:
  • نسل بعدی زامارین است
  • از دات نت 6 به بالا استفاده می‌کند
  • روان، سریع و انعطاف پذیر است
  • خطاهای بسیار کمتری دارد
  • مخصوص موبایل طراحی شده است
  • تجربه بیشتری نسبت به سایر پلتفرم‌ها دارد

اگر نیاز به اجرای برنامه بصورت کراس پلتفرم دارید (ویندوز/لینوکس/مک) بهتر است از Uno استفاده کنید بدلیل اینکه:
  • مخصوص کراس پلتفرم طراحی شده
  • از WinUI 3 استفاده می‌کند
  • برای ویندوز 10 به بالا از تکنولوژی UWP و برای ویندوز 7 و لینوکس از Skia استفاده می‌کند

اگر نیاز دارید برنامه شما فقط در ویندوز 10 به بالا اجرا شود بهتر است از Project Reunion استفاده کنید بدلیل اینکه:
  • از WinUI 3 استفاده می‌کند
  • تمام ویژگی‌های UWP را دارد
  • محدودیت‌های UWP را ندارد
  • بصورت Full Trust اجرا میشود
  • پیچیدگی‌های UWP را ندارد
  • از پلتفرم WPF برای اجرا استفاده می‌کند

اگر نیاز دارید که برنامه شما در ویندوز 7 به بالا اجرا شود و در ویندوز 10 ظاهر مدرن‌تری به خود بگیرد بهتر است از Xaml Island استفاده کنید بدلیل اینکه:
  • فقط بخشی از برنامه را مدرن می‌کند
  • قسمت‌های مدرن شده در نسخه‌های قبل ویندوز 10 اجرا نمیشود

مطالب
استفاده از Awesomium.NET در برنامه‌های وب
برای تهیه تصاویر سایت‌های معرفی شده در قسمت اشتراک‌های سایت، پیشتر از کنترل WebBrowser دات نت که در پشت صحنه از امکانات IE کمک می‌گیرد، استفاده می‌کردم. بسیار ناپایدار است؛ به روز رسانی مشکلی داشته و وابسته است به سیستم عامل جاری سیستم. برای مثال مرتبا برای تهیه تصاویر بند انگشتی (Thumbnails) سایت‌های تهیه شده با بوت استرپ کرش می‌کرد و این کرش چون از نوع unmaged code است، عملا پروسه IIS وب سایت را از کار می‌انداخت و در این حالت سایت تا ری‌استارت بعدی IIS در دسترس نبود. برای حل این مشکل و بهبود کیفیت تصاویر تهیه شده، از پروژه Awesomium که در حقیقت مرورگر کروم را جهت استفاده در انواع و اقسام زبان‌های برنامه نویسی محصور می‌کند، کمک گرفته شد؛ که شرح آن‌را در ادامه ملاحظه خواهید کرد.


دریافت و نصب Awesomium

پروژه Awesomium دارای یک SDK است که از اینجا قابل دریافت می‌باشد. بعد از نصب آن در مسیر Awesomium SDK\1.7.3.0\wrappers\Awesomium.NET\Assemblies\Packed می‌توانید محصور کننده‌ی دات نتی آن‌را مشاهده کنید. منظور از Packed در اینجا، استفاده از DLLهای فشرده شده‌ی native آن است که در مسیر Awesomium SDK\1.7.3.0\build\bin\packed کپی شده‌اند. بنابراین برای توزیع این نوع برنامه‌ها نیاز است اسمبلی دات نتی Awesomium.Core.dll به همراه دو فایل بومی icudt.dll و awesomium.dll ارائه شوند.


تهیه تصاویر سایت‌ها به کمک Awesomium.NET

پس از نصب Awesomium اگر به مسیر Documents\Awesomium SDK Samples\1.7.3.0\Awesomium.NET\Samples\Core\CSharp\BasicSample مراجعه کنید، مثالی را در مورد تهیه تصاویر سایت‌ها به کمک Awesomium.NET، مشاهده خواهید کرد. خلاصه‌ی آن چند سطر ذیل است:
            try
            {
                using (WebSession mywebsession = WebCore.CreateWebSession(
new WebPreferences() { CustomCSS = "::-webkit-scrollbar { visibility: hidden; }" }))
                {
                    using (var view = WebCore.CreateWebView(1240, 1000, mywebsession))
                    {
                        view.Source = new Uri("https://site.com/");

                        bool finishedLoading = false;
                        view.LoadingFrameComplete += (s, e) =>
                        {
                            if (e.IsMainFrame)
                                finishedLoading = true;
                        };

                        while (!finishedLoading)
                        {
                            Thread.Sleep(100);
                            WebCore.Update();
                        }

                        using (var surface = (BitmapSurface)view.Surface)
                        {
                            surface.SaveToJPEG("result.jpg");
                        }
                    }
                }
            }
            finally
            {
                WebCore.Shutdown();
            }
کار با ایجاد یک WebSession شروع می‌شود. سپس با مقدار دهی CustomCSS، اسکرول بار صفحات را جهت تهیه تصاویری بهتر مخفی می‌کنیم. سپس یک WebView آغاز شده و منبع آن به Url مدنظر تنظیم می‌شود. در ادامه باید اندکی صبر کنیم تا بارگذاری سایت خاتمه یافته و نهایتا می‌توانیم سطح این View را به صورت یک تصویر ذخیره کنیم.


مشکل! این روش در برنامه‌های ASP.NET کار نمی‌کند!

مثال همراه آن یک مثال کنسول ویندوزی است و به خوبی کار می‌کند؛ اما در برنامه‌های وب پس از چند روز سعی و خطا مشخص شد که:
الف) WebCore.Shutdown فقط باید در پایان کار یک برنامه فراخوانی شود. یعنی اصلا نیازی نیست تا در برنامه‌های وب فراخوانی شود.
 System.InvalidOperationException: You are attempting to re-initialize the WebCore.
The WebCore must only be initialized once per process and must be shut down only when the process exits.
ب) Awesomium فقط در یک ترد کار می‌کند. به این معنا که اگر کدهای فوق را در یک صفحه‌ی وب فراخوانی کنید، بار اول کار خواهد کرد. بار دوم برنامه کرش می‌کند؛ با این پیغام خطا:
 System.AccessViolationException: Attempted to read or write protected memory.
This is often an indication that other memory is corrupt. at Awesomium.Core.NativeMethods.WebCore_CreateWebView_1(HandleRef jarg1, Int32 jarg2, Int32 jarg3, HandleRef jarg4)
چون هر صفحه‌ی وب در یک ترد مجزا اجرا می‌شود، عملا استفاده‌ی مستقیم از Awesomium در آن ممکن نیست.
خطای فوق هم از آن نوع خطاهایی است که پروسه‌ی IIS را درجا خاموش می‌کند.


استفاده از Awesomium در یک ترد پس زمینه

راه حلی که نهایتا پاسخ داد و به خوبی و پایدار کار می‌کند، شامل ایجاد یک ترد مجزای Awesomium در زمان آغاز برنامه‌ی وب و زنده نگه داشتن آن تا زمان پایان کار برنامه است.
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Threading;
using System.Web;
using Awesomium.Core;

namespace AwesomiumWebModule
{
    public class AwesomiumModule : IHttpModule
    {
        private static readonly Thread WorkerThread = new Thread(awesomiumWorker);
        private static readonly ConcurrentQueue<AwesomiumRequest> TaskQueue = new ConcurrentQueue<AwesomiumRequest>();
        private static bool _isRunning = true;

        static AwesomiumModule()
        {
            WorkerThread.Start();
        }       

        private static void awesomiumWorker()
        {
            while (_isRunning)
            {
                if (TaskQueue.Count != 0)
                {
                    AwesomiumRequest outRequest;
                    if (TaskQueue.TryDequeue(out outRequest))
                    {
                        var img = AwesomiumThumbnail.FetchWebPageThumbnail(outRequest);
                        File.WriteAllBytes(outRequest.SavePath, img);
                        Thread.Sleep(500);
                    }
                }
                Thread.Sleep(5);
            }
        }

        public void Dispose()
        {
            _isRunning = false;
            WebCore.Shutdown();
        }

        public void Init(HttpApplication context)
        {
            context.EndRequest += endRequest;
        }

        static void endRequest(object sender, EventArgs e)
        {
            var url = HttpContext.Current.Items[Constants.AwesomiumRequest] as AwesomiumRequest;
            if (url!=null)
            {
                TaskQueue.Enqueue(url);
            }
        }
    }
}
در اینجا اگر در برنامه‌های وب فرم، از طریق HttpContext.Current.Items.Add و یا در برنامه‌های MVC به کمک this.HttpContext.Items.Add یک آیتم جدید، با کلید Constants.AwesomiumRequest و از نوع کلاس AwesomiumRequest دریافت گردد، مقدار آن به یک ConcurrentQueue اضافه خواهد شد. این صف در یک ترد مجزا مدام در حال بررسی است. اگر مقداری به آن اضافه شده‌است، از صف خارج شده و پردازش خواهد شد.
نمونه‌ی استفاده از آن، در سمت یک برنامه‌ی وب نیز به صورت زیر است. ابتدا ماژول تهیه شده باید در برنامه ثبت شود:
<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
    <httpModules>
      <add name="AwesomiumWebModule" type="AwesomiumWebModule.AwesomiumModule"/>
    </httpModules>
  </system.web>

  <system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
    <modules>
      <add name="AwesomiumWebModule" type="AwesomiumWebModule.AwesomiumModule"/>
    </modules>
  </system.webServer>
</configuration>
سپس باید تنها مدیریت  HttpContext.Current.Items در سمت برنامه صورت گیرد:
        protected void btnStart_Click(object sender, EventArgs e)
        {
            var host = new Uri(txtUrl.Text).Host;
            HttpContext.Current.Items.Add(Constants.AwesomiumRequest, new AwesomiumRequest
            {
                Url = txtUrl.Text,
                SavePath = Path.Combine(HttpRuntime.AppDomainAppPath, "App_Data\\Thumbnails\\" + host + ".jpg"),
                TempDir = Path.Combine(HttpRuntime.AppDomainAppPath, "App_Data\\Temp")
            });
            lblInfo.Text = "Please wait. Your request will be served shortly.";
        }
در اینجا کاربر درخواست خود را در صف قرار می‌دهد. پس از مدتی کار آن در WorkerThread ماژول تهیه شده انجام گردیده و تصویر نهایی تهیه می‌شود.
Url، آدرس وب سایتی است که می‌خواهید تصویر آن تهیه شود. SavePath مسیر کامل فایل jpg نهایی است که قرار است دریافت و ذخیره گردد. TempDir محل ذخیره سازی فایل‌های موقتی Awesomium است. Awesomium یک سری کوکی، تصاویر و فایل‌های هر سایت را به این ترتیب کش کرده و در دفعات بعدی سریعتر عمل می‌کند.

پروژه‌ی کامل آن‌را از اینجا می‌توانید دریافت کنید:
AwesomiumWebApplication_V1.0.zip
 
مطالب
تولید و ارسال خودکار بسته‌های NuGet پروژه‌های NET Core. به کمک AppVeyor
اگر پروژه‌ی شما به همراه توزیع بسته‌های نیوگت است، پس از مدتی، از build و آپلود دستی بسته‌های نیوگت آن‌ها خسته خواهید شد. همچنین این سؤال هم برای مصرف کنندگان بسته‌ی نیوگت شما همواره وجود خواهد داشت: «آیا بسته‌ی نهایی را که آپلود کرده، دقیقا بر اساس سورس کد موجود در مخزن کد عمومی آن تهیه شده‌است؟»
برای رفع این مشکلات، از روش‌های توسعه‌ی به همراه ابزارهای یکپارچگی مداوم استفاده می‌شود. برای نمونه، AppVeyor یکی از سرویس‌های ابری یکپارچگی مداوم (Continuous Integration و یا به اختصار CI) است. به کمک آن می‌توان یک image از ویندوز سرور را به همراه ابزارهای build، آزمایش و توزیع برنامه‌های NET. در اختیار داشت. این سرویس، مخزن کد شما را مونیتور کرده و هر زمانیکه تغییری را در آن ایجاد کردید، آن‌ها را به صورت خودکار build و در صورت موفقیت آمیز بودن این عملیات، بسته‌ی نیوگت متناظری را به سایت nuget.org ارسال می‌کند. بنابراین پس از یکپارچه کردن مخزن کد خود با این نوع سرویس‌های یکپارچگی مداوم، دیگر حتی نیازی به build دستی آن نیز نخواهید داشت. همینقدر که کدی را به مخزن کد تحت نظر، commit کنید، مابقی مراحل آن خودکار است.
به همین جهت در این مطلب قصد داریم نحوه‌ی اتصال یک مخزن کد GitHub را به سرویس یکپارچگی مداوم AppVeyor، جهت تولید خودکار بسته‌های Nuget، بررسی کنیم.




معرفی سرویس ابری AppVeyor

AppVeyor یک راه حل یکپارچگی مداوم چند سکویی است که استفاده‌ی از آن برای پروژه‌های سورس باز رایگان است و سازگاری فوق العاده‌ای را با محصولات مایکروسافت دارد. برای ورود به آن می‌توان از اکانت‌های GitHub ،BitBucket و VSTS (Visual Studio Team Services) استفاده کرد.
گردش کاری متداول یکپارچگی مداوم AppVeyor به این صورت است:
الف) با اکانت GitHub خود به آن وارد شوید.
ب) یک مخزن کد GitHub خود را به آن Import کنید.
ج) به مخزن کد GitHub خود یک فایل yml. تنظیمات مخصوص AppVeyor را اضافه کنید.
د) نظاره‌گر Build و توزیع خودکار پروژه‌ی خود باشید.


ایجاد اکانت و اتصال به مخزن کد GitHub

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


پس از ورود موفق، گزینه‌ی new project را انتخاب کنید:


در ادامه مخزن کد GitHub و نوع عمومی آن‌را انتخاب می‌کنیم تا AppVeyor بتواند پروژه‌های آن‌را Import کند و همچنین به آن‌ها web hookهایی را اضافه کند تا با اعمال تغییراتی در سمت GitHub، کار اطلاع رسانی آن‌ها به AppVeyor به صورت خودکار صورت گیرد:


پس از آن لیست مخزن‌های کد شما در همینجا ارائه می‌شود تا بتوانید یک یا چند مورد را انتخاب کنید:


انجام تنظیمات عمومی مخزن کد

در صفحه‌ی بعدی، برگه‌ی settings و سپس از منوی کنار صفحه‌ی آن، گزینه‌ی ‌General را انتخاب کنید:


در اینجا اگر پروژه‌ی شما از نوع NET Core. است، گزینه‌ی NET Core .csproj patching. را انتخاب نمائید:


سپس در پایین صفحه بر روی دکمه‌ی Save کلیک کنید.


انتخاب و تنظیم محیط Build

در ادامه در برگه‌ی settings و سپس از منوی کنار صفحه‌ی آن، گزینه‌ی Environment را انتخاب کنید:


در این صفحه، worker image را بر روی VS 2017 قرار دهید و همچنین در قسمت Cached directories and files، مسیر C:\Users\appveyor\.dnx را جهت کش کردن عملیات Build و بالا بردن سرعت آن، مقدار دهی کنید. سپس در پایین صفحه بر روی دکمه‌ی Save کلیک نمائید.

اکنون بر روی گزینه‌ی Build در منوی سمت چپ صفحه کلیک کنید. در اینجا سه حالت msbuild ،script و off را می‌توان انتخاب کرد.
- در حالت msbuild، که ساده‌ترین حالت ممکن است، فایل sln. مخزن کد، یافت شده و بر اساس آن به صورت خودکار تمام پروژه‌های این solution یکی پس از دیگری build خواهند شد. این مورد برای برنامه‌های Full .NET Framework شاید گزینه‌ی مناسبی باشد.
- حالت script برای پروژه‌های NET Core. مناسب‌تر است و در این حالت می‌توان کنترل بیشتری را بر روی build داشت. به علاوه این روش بر روی لینوکس هم کار می‌کند؛ زیرا در آنجا دسترسی به msbuild نداریم.
- حالت off به معنای خاموش کردن عملیات build است.

در اینجا گزینه‌ی cmd را جهت ورود build script انتخاب می‌کنیم:


سپس دستورات ذیل را جهت ورود به پوشه‌ی پروژه‌ی کتابخانه (جائیکه فایل csproj آن قرار دارد)، بازیابی وابستگی‌های پروژه و سپس تولید بسته‌ی نیوگتی از آن، وارد می‌کنیم:
cd ./src/DNTPersianUtils.Core
dotnet restore
dotnet pack -c release
cd ../..
در ادامه در پایین صفحه بر روی دکمه‌ی Save کلیک نمائید.
ذکر  ../.. cd  در انتهای این دستورات ضروری است. در غیر اینصورت cd بعدی در تنظیماتی دیگر، داخل همین پوشه انجام می‌شود.


تنظیم اجرای خودکار آزمون‌های واحد


در همین صفحه، گزینه‌های settings -> tests -> script -> cmd را انتخاب و سپس دستورات زیر را وارد کرده و آن‌را ذخیره کنید:
cd ./src/DNTPersianUtils.Core.Tests
dotnet restore
dotnet test
cd ../..
به این ترتیب به صورت خودکار آزمون‌های واحد موجود در پروژه‌ی انتخابی، توسط NET Core CLI. اجرا خواهند شد.


تنظیم اطلاع رسانی خودکار از اجرای عملیات


در برگه‌ی settings -> notifications مطابق تنظیمات فوق می‌توان نوع email را جهت اطلاع رسانی شکست انجام عملیات یکپارچگی مداوم، انتخاب کرد.


آزمایش Build خودکار

برای آزمایش تنظیماتی که انجام دادیم، به برگه‌ی latest build مراجعه کرده و بر روی دکمه‌ی new build کلیک کنید تا اسکریپت‌های build و test فوق اجرا شوند. بدیهی است اجرای بعدی این اسکریپت‌ها خودکار بوده و به ازای هر commit به GitHub، بدون نیاز به مراجعه‌ی مستقیم به appveyor صورت می‌گیرند.



اضافه کردن نماد AppVeyor به پروژه

در تنظیمات برگه‌ی Settings، گزینه‌ی AppVeyor badge نیز در منوی سمت چپ صفحه، وجود دارد:


در اینجا همان کدهای mark down آن‌را انتخاب کرده و به ابتدای فایل readme پروژه‌ی خود اضافه کنید. برای نمونه نماد فعلی (تصویر فوق)، build failing را نمایش می‌دهد؛ چون سه آزمون واحد آن مشکل دارند و باید اصلاح شوند.
پس از رفع مشکلات پروژه و commit آن‌ها، build و اجرای خودکار آزمون‌های واحد آن توسط AppVeyor صورت گرفته و اینبار این نماد به صورت زیر تغییر می‌کند:



ارسال خودکار بسته‌ی نیوگت تولید شده به سایت nuget.org

برای ارسال خودکار حاصل Build، به سایت نیوگت، نیاز است یک API Key داشته باشیم. به همین جهت به صفحه‌ی مخصوص آن در سایت nuget پس از ورود به سایت آن، مراجعه کرده و یک کلید API جدید را صرفا برای این پروژه تولید کنید (در قسمت Available Packages بسته‌ی پیشینی را که دستی آپلود کرده بودید انتخاب کنید).
پس از کپی کردن کلید تولید شده‌ی در سایت nuget، به قسمت settings -> deployment مراجعه کرده و یک تامین کننده‌ی جدید از نوع nuget را اضافه کنید:


در اینجا API Key را ذکر خواهیم کرد. سپس در پایین صفحه بر روی دکمه‌ی Save کلیک کنید.

همچنین نیاز است مشخص کنیم که بسته‌های nupkg تولید شده در چه مسیری قرار دارند. به همین جهت در قسمت settings -> artifacts مسیر پوشه‌ی bin نهایی را ذکر می‌کنیم:


این مورد را نیز با کلیک بر روی دکمه‌ی Save ذخیره کنید.

اکنون اگر نگارش جدیدی را به GitHub ارسال کنیم (تغییر VersionPrefix در فایل csproj و سپس commit آن)، پس از Build پروژه، بسته‌ی نیوگت آن نیز به صورت خودکار تولید شده و به سایت nuget.org ارسال می‌شود. لاگ آن‌را در پایین صفحه‌ی برگه‌ی latest build می‌توانید مشاهده کنید.



ساده سازی مراحل تنظیمات AppVeyor

در صفحه‌ی settings‌، در منوی سمت چپ آن، گزینه‌ی export YAML نیز وجود دارد. در اینجا می‌توان تمام تنظیمات انجام شده‌ی فوق را با فرمت yml. دریافت کرد و سپس این فایل را به ریشه‌ی مخزن کد خود افزود. با وجود این فایل، دیگر نیازی به طی کردن دستی هیچکدام از مراحل فوق نیست.
برای نمونه فایل appveyor.yml نهایی مطابق با توضیحات این مطلب، چنین محتوایی را دارد:
version: 1.0.{build}
image: Visual Studio 2017
dotnet_csproj:
  patch: true
  file: '**\*.csproj'
  version: '{version}'
  package_version: '{version}'
  assembly_version: '{version}'
  file_version: '{version}'
  informational_version: '{version}'
cache: C:\Users\appveyor\.dnx
build_script:
- cmd: >-
    cd ./src/DNTPersianUtils.Core

    dotnet restore

    dotnet pack -c release

    cd ../..
test_script:
- cmd: >-
    cd ./src/DNTPersianUtils.Core.Tests

    dotnet restore

    dotnet test

    cd ../..
artifacts:
- path: ./src/DNTPersianUtils.Core/bin/release/*.nupkg
  name: NuGet
deploy:
- provider: NuGet
  api_key:
    secure: xyz
  skip_symbols: true
notifications:
- provider: Email
  to:
  - me@yahoo.com
  on_build_success: false
  on_build_failure: true
  on_build_status_changed: true
بنابراین بجای طی مراحل عنوان شده‌ی در این بحث می‌توانید یک فایل appveyor.yml را با محتوای فوق (پس از اصلاح مسیرها و نام‌ها) در ریشه‌ی پروژه‌ی خود قرار دهید و ... صرفا مخزن کد آن‌را در appveyor ثبت و import کنید. مابقی مراحل یکپارچگی مداوم آن خودکار است و نیاز به تنظیم دیگری ندارد. فقط برای آزمایش آن به برگه‌ی Latest build مراجعه کرده و یک build جدید را شروع کنید تا مطمئن شوید همه چیز به درستی کار می‌کند.
یک نکته: api_key ذکر شده‌ی در اینجا در قسمت secure، رمزنگاری شده‌است. برای تولید آن می‌توانید از مسیر https://ci.appveyor.com/tools/encrypt استفاده کنید. به این صورت مشکلی با عمومی کردن فایل appveyor.yml خود در GitHub نخواهید داشت.
اشتراک‌ها
خالق پایتون به مایکروسافت پیوست

Creator of Python, Guido van Rossum, has joined Microsoft as a Distinguished Engineer in the Developer Division. His stated aim is to make Python better. We can't wait to find out what that results in.  

خالق پایتون به مایکروسافت پیوست
مطالب
ارسال ایمیل در ASP.NET Core
فضای نام System.Net.Mail در NET Core 1.2. که پیاده سازی netstandard2.0 است، ارائه خواهد شد. بنابراین فعلا (در زمان NET Core 1.1.) راه حل توکار و رسمی برای ارسال ایمیل در برنامه‌های مبتنی بر NET Core. وجود ندارد. اما می‌توان کتابخانه‌ی ثالثی را به نام MailKit، به عنوان راه‌حلی که .NET 4.0, .NET 4.5, .NET Core, Xamarin.Android, و Xamarin.iOS را پشتیبانی می‌کند، درنظر گرفت و توانمندی‌ها و پروتکل‌های پشتیبانی شده‌ی توسط آن، از System.Net.Mail توکار نیز بسیار بیشتر است.


افزودن وابستگی‌های MailKit به برنامه

برای شروع به استفاده‌ی از MailKit، می‌توان بسته‌ی نیوگت آن‌را به فایل project.json برنامه معرفی کرد:
{
    "dependencies": {
        "MailKit": "1.10.0"
    }
}


استفاده از MailKit جهت تکمیل وابستگی‌های ASP.NET Core Identity

قسمتی از ASP.NET Core Identity، شامل ارسال ایمیل‌های «ایمیل خود را تائید کنید» است که آن‌را می‌توان توسط MailKit به نحو ذیل تکمیل کرد:
using System.Threading.Tasks;
using ASPNETCoreIdentitySample.Services.Contracts.Identity;
using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;
 
namespace ASPNETCoreIdentitySample.Services.Identity
{
    public class AuthMessageSender : IEmailSender, ISmsSender
    {
        public async Task SendEmailAsync(string email, string subject, string message)
        {
            var emailMessage = new MimeMessage();
 
            emailMessage.From.Add(new MailboxAddress("DNT", "do-not-reply@dotnettips.info"));
            emailMessage.To.Add(new MailboxAddress("", email));
            emailMessage.Subject = subject;
            emailMessage.Body = new TextPart(TextFormat.Html)
            {
                Text = message
            };
 
            using (var client = new SmtpClient())
            {
                client.LocalDomain = "dotnettips.info";
                await client.ConnectAsync("smtp.relay.uri", 25, SecureSocketOptions.None).ConfigureAwait(false);
                await client.SendAsync(emailMessage).ConfigureAwait(false);
                await client.DisconnectAsync(true).ConfigureAwait(false);
            }
        }
 
        public Task SendSmsAsync(string number, string message)
        {
            // Plug in your SMS service here to send a text message.
            return Task.FromResult(0);
        }
    }
}
در اینجا MimeMessage بیانگر محتوا و تنظیمات ایمیلی است که قرار است ارسال شود. ابتدا قسمت‌های From و To آن تنظیم می‌شوند تا مشخص باشد که ایمیل ارسالی از کجا ارسال شده و قرار است به چه آدرسی ارسال شود. در ادامه موضوع و عنوان ایمیل تنظیم شده‌است. سپس متن ایمیل، به خاصیت Body شیء MimeMessage انتساب داده خواهد شد. فرمت ایمیل ارسالی را نیز می‌توان در اینجا تنظیم کرد. برای مثال TextFormat.Html جهت ارسال پیام‌هایی حاوی تگ‌های HTML مناسب است و اگر قرار است صرفا متن ارسال شود، می‌توان TextFormat.Plain را انتخاب کرد.
در آخر، این پیام به SmtpClient جهت ارسال نهایی، فرستاده می‌شود. این SmtpClient هرچند هم نام مشابه آن در System.Net.Mail است اما با آن یکی نیست و متعلق است به MailKit. در اینجا ابتدا LocalDomain تنظیم شده‌است. تنظیم این مورد اختیاری بوده و صرفا به SMTP سرور دریافت کننده‌ی ایمیل‌ها، مرتبط است که آیا قید آن‌را اجباری کرده‌است یا خیر. تنظیمات اصلی SMTP Server در متد ConnectAsync ذکر می‌شوند که شامل مقادیر host ،port و پروتکل ارسالی هستند.


ارسال ایمیل به SMTP pickup folder

روشی که تا به اینجا بررسی شد، جهت ارسال ایمیل‌ها به یک SMTP Server واقعی کاربرد دارد. اما در حین توسعه‌ی محلی برنامه می‌توان ایمیل‌ها را در داخل یک پوشه‌ی موقتی ذخیره و آن‌ها را توسط برنامه‌ی Outlook (و یا حتی مرورگر Firefox) بررسی و بازبینی کامل کرد.
در این حالت تنها کاری را که باید انجام داد، جایگزین کردن قسمت ارسال ایمیل واقعی توسط SmtpClient در کدهای فوق، با قطعه کد ذیل است:
using (var stream = new FileStream($@"c:\smtppickup\email-{Guid.NewGuid().ToString("N")}.eml", FileMode.CreateNew))
{
   emailMessage.WriteTo(stream);
}
تولید فایل‌های eml جهت «شبیه سازی ارسال ایمیل در ASP.Net» بسیار مفید هستند.


FAQ و منبع تکمیلی
اشتراک‌ها
بازی Arrow hero
A minimalist game where your goal is to match your inputs with an unstoppable continuous overwelming flow of arrows.  Play
بازی Arrow hero