نظرات مطالب
پشتیبانی از Generic Attributes در C# 11
یک نکته‌ی تکمیلی: بکارگیری گسترده‌ی Generic attributes در ASP.NET Core 8x

ویژگی Generic attributes به C# 11 اضافه شد، اما در آن زمان، تغییری در تعاریف ویژگی‌های مبتنی بر System.Type موجود در ASP.NET Core 7x رخ نداد. اکنون این قابلیت به صورت گسترده‌ای در ASP.NET Core 8x در موارد زیر بکارگرفته شده‌است:
ProducesResponseType<T>
Produces<T>
MiddlewareFilter<T>
ModelBinder<T>
ModelMetadataType<T>
ServiceFilter<T>
TypeFilter<T>
مطالب
محاسبه مجدد میزان مصرف حافظه‌ی برنامه‌های دات نت

اگر به میزان مصرف حافظه‌ اولیه‌ی برنامه‌های دات نت دقت کنیم، نسبت به مثلا یک برنامه‌ی MFC چند برابر به نظر می‌رسند و ... این علت دارد:
زمانیکه یک برنامه‌ی مبتنی بر دات نت اجرا می‌شود، ابتدا JIT compiler شروع به کار کرده و شروع به کامپایل برنامه می‌کند. این بارگزاری هم در همان پروسه‌ی اصلی برنامه انجام می‌شود. به همین جهت میزان مصرف حافظه‌ی برنامه‌های دات نت عموما بالا به نظر می‌رسد.
اکنون سؤال اینجا است که آیا می توان این حافظه‌ای را که دیگر مورد استفاده نیست (و توسط JIT compiler اخذ شده) به سیستم بازگرداند و محاسبه‌ی مجددی را در این مورد انجام داد. پاسخ به این سؤال را در متد ReEvaluateWorkingSet زیر می‌توان مشاهده کرد:


using System;
using System.Diagnostics;

namespace Toolkit
{
public static class Memory
{
public static void ReEvaluateWorkingSet()
{
try
{
Process loProcess = Process.GetCurrentProcess();
//it doesn't matter what you set maxWorkingSet to
//setting it to any value apparently causes the working set to be re-evaluated and excess discarded
loProcess.MaxWorkingSet = (IntPtr)((int)loProcess.MaxWorkingSet + 1);
}
catch
{
//The above code requires Admin privileges.
//So it's important to trap exceptions in case you're running without admin rights.
}
}
}
}

در این متد ابتدا پروسه جاری دریافت شده و سپس MaxWorkingSet به یک عدد دلخواه تنظیم می‌شود. مهم نیست که این عدد چه چیزی باشد، زیرا این تنظیم سبب می‌شود که در پشت صحنه به شکل حساب شده‌ای حافظه‌ای که مورد استفاده نیست به سیستم بازگردانده شود و سپس عددی که در task manager نمایش داده می‌شود، مجددا محاسبه گردد. همچنین باید دقت داشت که این کد تنها با دسترسی مدیریتی قابل اجرا است و به همین دلیل وجود این try/catch ضروری است.

نحوه استفاده از متد ReEvaluateWorkingSet در برنامه‌های WinForms :
فایل Program.cs را یافته و سپس در روال رویداد گردان Idle برنامه، متد ReEvaluateWorkingSet را فراخوانی کنید (مثلا هر زمان که برنامه minimized شد اجرا می‌شود):

//Program.cs
namespace MemUsage
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
//...

Application.Idle += applicationIdle;
}

static void applicationIdle(object sender, EventArgs e)
{
Memory.ReEvaluateWorkingSet();
}
}
}

نحوه استفاده از متد ReEvaluateWorkingSet در برنامه‌های WPF :
فایل App.xaml.cs را یافته و سپس در روال رویدادگردان Deactivated برنامه، متد ReEvaluateWorkingSet را فراخوانی کنید:

//App.xaml.cs

public App()
{
this.Deactivated += appDeactivated;
}

void appDeactivated(object sender, EventArgs e)
{
Memory.ReEvaluateWorkingSet();
}

تاثیر آن هم قابل ملاحظه است (حداقل از لحاظ روانی!). تست کنید!

مطالب
ارتباط بین کامپوننت‌ها در Vue.js - قسمت دوم استفاده از Event Bus
در قسمت قبلی، نحوه ارتباط بین کامپوننت‌های Parent و Child را مورد بررسی قرار دادیم و اینکه چگونه داده‌هایشان را به اشتراک میگذارند؛ اما چند موضوع در روش قبلی مورد بحث می‌باشد:

1)  مدیریت nested componentها برای استفاده از چنین روشی مشکل است.
2) اگر تعداد داده‌های اشتراکی زیاد باشد، مدیریت آنها با استفاده از props گیج کننده می‌باشد.

3) اگر دو کامپوننت مجزا (Sibling Component) قصد به اشتراک گذاری اطلاعاتی را داشتند تکلیف چیست؟ (هر چند با استفاده از یک کامپوننت Parent مشترک مقدور می‌باشد)

4) روش ساده‌تری برای ارتباط کامپوننت‌های Parent و Child  و همچنین Sibling Component وجود دارد.

 



استفاده از Event Bus:

با استفاده از EventBus، بسیاری از معایب مطرح شده در روش قبلی را نخواهیم داشت:



 تعریف Event Bus: یک Design Pattern ^ ,^  می باشد. در Vue.js یک نمونه از vue را بصورت سراسری (global) ایجاد میکنیم و درکامپوننت‌هایی که نیاز به ارتباط دارند، آن را فراخوانی (import) و با استفاده از متدهای emit$ و on$، ارتباط را ایجاد میکنیم.


یک فایل جاوا اسکریپتی را با نامی دلخواه (eventBus.js) در فولدر src ایجاد میکنیم و یک نمونه از Vue را در آن وهله سازی میکنیم:

import Vue from 'vue'
export default new Vue()
سپس در کامپوننت‌هایی که قصد ارتباط دارند، این فایل را import میکنیم ( مثال سبد خرید را در مقاله‌ی قبلی، به روش جاری تغییر میدهیم). 

در کامپوننت Shop-Button-Add، کد زیر را در قسمت script اضافه میکنیم:

import  EventBus  from "../eventBus";

کد تابع buttonClicked را بشکل زیر تغییر میدهیم:

 buttonClicked() {
      EventBus.$emit("shop-button-clicked", this.item);
    }

در کامپوننت App.vue  هم کد زیر را در قسمت script اضافه میکنیم:

import  EventBus  from "./eventBus";

و در تابع mounted که از توابع life cycle مربوط به Vue.js میباشد، کد زیر را اضافه میکنیم:

mounted() {
    EventBus.$on("shop-button-clicked", item => {
      this.updateCart(item);
    });
  }


مقایسه‌ی روش استفاده از EventBus با روش قبلی :

مراحل انجام کار در روش قبلی:

دو کامپوننت ارتباط داشتند Shop-Button-Add و App.vue: 

1) در کامپوننت Shop-Button-Add با زدن دکمه Add To Cart متد buttonClicked اجرا میشد.

2) متد buttonClicked  یک سیگنال به کامپوننت Parent خود (Shop-Item) ارسال می‌نمود.

  this.$emit('button-clicked')

3) در کامپوننت Shop-Item مشخص شده بود در صورت ارسال سیگنال از Shop-Button-Add، متد addToCart اجرا شود.

 <Shop-Button-Add    @button-clicked="addToCart(item)"     :item="item">
            <p>Add To Cart</p>
 </Shop-Button-Add>

4) اجرای متد addToCart در کامپوننت Shop-Item یک سیگنال را به کامپوننت App.vue به همراه دیتای مورد نظر ارسال می‌نمود.

addToCart(item) {
                this.$emit('update-cart', item)
            }

5) در کامپوننت App.vue مشخص شده بود با ارسال سیگنال از کامپوننت Shop-Item، متد updateCart اجرا شود.

<shop-item v-for="item in this.items" :item="item" :key="item.id" 
@update-cart="updateCart">
</shop-item>

6) در نهایت کار بروزرسانی سبد خرید با اجرای متد updateCart انجام میشد:

updateCart(e) {
      this.cart.push(e);
      this.total = this.shoppingCartTotal;
    }


نتیجه گیری:

مزایای استفاده از Event Bus :

1) کم شدن مراحل ارتباط بین کامپوننت‌ها

2) حل مشکل ارتباطی بین Sibling Component 

3) نوشتن کد کمتر


 کد سبد خرید به روش مقاله‌ی جاری-استفاده از EventBus  


نکته: برای اجرای برنامه و دریافت پکیج‌های مورد استفاده در مثال جاری، نیاز است دستور زیر را اجرا کنید:  

npm install

همچنین نیاز هست تا پکیچ node-sass را نیز با دستور زیر برای این مثال نصب کنید.

npm install node-sass
نظرات مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 2 - بررسی ساختار جدید Solution
این مورد را در قسمت اول ذیل «اما هنوز تعداد زیادی از کتابخانه‌های Full framework به NET Core. انتقال پیدا نکرده‌اند »، توضیح دادم.

شما در ASP.NET Core امکان کار با هر دو فریم ورک یاد شده را دارید و این دو به هم وابستگی ندارند. به عبارتی چندین target را دراینجا می‌توانید معرفی و استفاده کنید. اگر دات نت 4.6 را هم استفاده کردید، برنامه فقط قابلیت چندسکویی خودش را از دست خواهد داد. برای مثال شما هم اکنون می‌توانید EF 6.x را با ASP.NET Core 1.0 استفاده کنید (اگر نمی‌خواهید تا زمان تکمیل نهایی EF Core صبر کنید). فقط در این حالت باید دقت داشته باشید که کدهای شما بر روی لینوکس اجرا نخواهند شد (چون EF 6.x مبتنی بر دات نت 4x است).
بازخوردهای دوره
تزریق خودکار وابستگی‌ها در برنامه‌های ASP.NET MVC
یک نکته‌ی تکمیلی در مورد Web API
Mark Seemann توصیه کرده‌است که از IDependencyResolver استفاده نکنید. روش دیگری برای کار با Web API مورد تائید ایشان است:
Dependency Injection and Lifetime Management with ASP.NET Web API
Dependency Injection in ASP.NET Web API with Castle Windsor
پیاده سازی این نکته با StructureMap در اینجا:
Better way to configure StructureMap in ASP.NET WebAPI
مطالب
آزمایش ساده‌تر Web APIs توسط strest
در سری کار با Postman، یک روش بسیار متداول آزمایش Web APIs را بررسی کردیم. اما ... برای کار آن با مدام نیاز است از این برگه به آن برگه مراجعه کرد و ارتباط دادن درخواست‌های متوالی در آن مشکل است. به همین منظور تابحال راه‌حل‌های زیادی برای جایگزین کردن postman ارائه شده‌اند که یکی از آن‌ها strest است. این ابزار خط فرمان:
- بسیار سبک ورزن است و تنها نیاز به نصب بسته‌ی npm آن‌را دارد.
- با فایل‌های متنی معمولی کار می‌کند که ویرایش و copy/paste در آن‌ها بسیار ساده‌است.
- قرار دادن فایل‌های نهایی متنی آن در ورژن کنترل بسیار ساده‌است.
- امکان نوشتن درخواست‌های به هم وابسته و آزمودن نتایج حاصل را دارا است.
- چون یک ابزار خط فرمان است، امکان استفاده‌ی از آن به سادگی در فرآینده‌های توسعه‌ی مداوم وجود دارد.
- ابزارهای npm، چندسکویی هستند.


نصب strest

در ادامه قصد داریم مطلب «آزمایش Web APIs توسط Postman - قسمت ششم - اعتبارسنجی مبتنی بر JWT» را با استفاده از strest بازنویسی کنیم. به همین جهت در ابتدا نیاز است بسته‌ی npm آن‌را به صورت سراسری نصب کنیم:
npm i -g @strest/cli
پس از آن فایل جدید JWT.strest.yml را در پوشه‌ای ایجاد کرده و آن‌را تکمیل می‌کنیم. برای اجرای فرامین موجود در آن تنها کافی است دستور strest JWT.strest.yml را درخط فرمان صادر کنیم.


مرحله 1: خاموش کردن بررسی مجوز SSL برنامه
مرحله 2: ایجاد درخواست login و دریافت توکن‌ها

مجوز SSL آزمایشی برنامه‌ی ASP.NET Core ما، از نوع خود امضاء شده‌است. به همین جهت اگر سعی در اجرای strest را با درخواست‌های ارسالی به آن داشته باشیم، باشکست مواجه خواهند شد. بنابراین در ابتدا، خاصیت allowInsecure را به true تنظیم می‌کنیم:
version: 2

variables:
  baseUrl: https://localhost:5001/api
  logResponse: false

allowInsecure: true
- این تنظیمات با فرمت yaml نوشته می‌شوند. به همین جهت در اینجا تعداد spaceها مهم است.
- همچنین در ابتدای این تنظیمات، روش تعریف متغیرها را نیز مشاهده می‌کنید که برای مثال توسط آن‌ها baseUrl تعریف شده‌است.
درست در سطر پس از این تنظیمات، دستور اجرا و اعتبارسنجی درخواست Login را می‌نویسیم:
requests:
  loginRequest:
    request:
      url: <$ baseUrl $>/account/login
      method: POST
      postData:
        mimeType: application/json
        text:
          username: "Vahid"
          password: "1234"
    log: <$ logResponse $>
    validate:
      - jsonpath: content.access_token
        type: [string]
      - jsonpath: content.refresh_token
        type: [string]
توضیحات:
- درخواست‌ها با requests شروع می‌شوند. سپس ذیل آن می‌توان نام چندین درخواست یا request را ذکر کرد که برای مثال نام درخواست تعریف شده‌ی در اینجا loginRequest است. این نام مهم است؛ از این جهت که با اشاره‌ی به آن می‌توان به فیلدهای خروجی response حاصل، در درخواست‌های بعدی، دسترسی یافت.
- سپس، آدرس درخواست مشخص شده‌است. در اینجا روش کار با متغیرها را نیز مشاهده می‌کنید.
- نوع درخواست POST است.
- در ادامه جزئیات اطلاعات ارسالی به سمت سرور باید مشخص شوند. برای مثال در اینجا با فرمت application/json قرار است یک شیء تشکیل شده‌ی از username و password ارسال شوند.
- در سطر بعدی، خاصیت log با متغیر logResponse مقدار دهی شده‌است. اگر به true تنظیم شود، اصل خروجی response را توسط برنامه‌ی خط فرمان strest می‌توان مشاهده کرد. اگر اینکار خروجی را شلوغ کرد، می‌توان آن‌را به false تنظیم کرد و این خروجی را در فایل strest_history.json نهایی که حاصل از اجرای آزمایش‌های تعریف شده‌است، در کنار فایل JWT.strest.yml خود یافت و مشاهده کرد.
- سپس به قسمت آزمودن نتیجه‌ی درخواست می‌رسیم. در اینجا انتظار داریم که درخواست حاصل که با فرمت json است، دارای دو خاصیت رشته‌ای access_token و refresh_token باشد.


 مرحله‌ی 3: ذخیره سازی توکن‌های دریافتی در متغیرهای سراسری
 مرحله‌ی 3: ذخیره سازی مراحل انجام شده
در حین کار با strest نیازی به ذخیره سازی نتیجه‌ی حاصل از response، در متغیرهای خاصی نیست. برای مثال اگر بخواهیم به نتیجه‌ی حاصل از عملیات لاگین فوق در درخواست‌های بعدی دسترسی پیدا کنیم، می‌توان نوشت <$ loginRequest.content.access_token $>
در اینجا درج متغیرها توسط <$ $> صورت می‌گیرد. سپس loginRequest به نام درخواست مرتبط اشاره می‌کند. خاصیت content.access_token نیز مقدار خاصیت access_token شیء response را بر می‌گرداند.

همچنین ذخیره سازی مراحل انجام شده نیز نکته‌ی خاصی را به همراه ندارد. یک تک فایل متنی JWT.strest.yml وجود دارد که آزمایش‌های ما در آن درج می‌شوند.


مرحله‌ی 4: دسترسی به منابع محافظت شده‌ی سمت سرور

در ادامه روش تعریف دو درخواست جدید دیگر را در فایل JWT.strest.yml مشاهده می‌کنید که از نوع Get هستند و به اکشن متدهای محافظت شده ارسال می‌شوند:
  myProtectedApiRequest:
    request:
      url: <$ baseUrl $>/MyProtectedApi
      method: GET
      headers:
        - name: Authorization
          value: Bearer <$ loginRequest.content.access_token $>
    log: <$ logResponse $>
    validate:
      - jsonpath: content.title
        expect: "Hello from My Protected Controller! [Authorize]"

  mProtectedAdminApiRequest:
    request:
      url: <$ baseUrl $>/MyProtectedAdminApi
      method: GET
      headers:
        - name: Authorization
          value: Bearer <$ loginRequest.content.access_token $>
    log: <$ logResponse $>
    validate:
      - jsonpath: content.title
        expect: "Hello from My Protected Admin Api Controller! [Authorize(Policy = CustomRoles.Admin)]"
دو نکته‌ی جدید در اینجا قابل مشاهده‌است:
- چون نیاز است به همراه درخواست خود، هدر اعتبارسنجی مبتنی بر JWT را که به صورت Bearer value است نیز به سمت سرور ارسال کنیم، خاصیت headers را توسط یک name/value مشخص کرده‌ایم. همانطور که عنوان شد در فایل‌های yaml، فاصله‌ها و تو رفتگی‌ها مهم هستند و حتما باید رعایت شوند.
- سپس دومین آزمون نوشته شده را نیز مشاهده می‌کنید. در قسمت validate، مشخص کرده‌ایم که خاصیت title دریافتی از response باید مساوی مقدار خاصی باشد.

دقیقا همین نکات برای درخواست دوم به MyProtectedAdminApi تکرار شده‌اند.


مرحله‌ی 5: ارسال Refresh token و دریافت یک سری توکن جدید

اکشن متد account/RefreshToken در سمت سرور، نیاز دارد تا یک شیء جی‌سون با خاصیت refreshToken را دریافت کند. مقدار این خاصیت از طریق response متناظر با درخواست نام‌دار loginRequest استخراج می‌شود که در قسمت postData مشخص شده‌است:
  refreshTokenRequest:
    request:
      url: <$ baseUrl $>/account/RefreshToken
      method: POST
      postData:
        mimeType: application/json
        text:
          refreshToken: <$ loginRequest.content.refresh_token $>
    log: <$ logResponse $>
    validate:
      - jsonpath: content.access_token
        type: [string]
      - jsonpath: content.refresh_token
        type: [string]
در آخر، به قسمت آزمودن نتیجه‌ی درخواست می‌رسیم. در اینجا انتظار داریم که درخواست حاصل که با فرمت json است، دارای دو خاصیت رشته‌ای access_token و refresh_token باشد که بیانگر صدور توکن‌های جدیدی هستند.


مرحله‌ی 6: آزمایش توکن جدید دریافتی از سرور

در قسمت قبل، توکن‌های جدیدی صادر شدند که اکنون برای کار با آن‌ها می‌توان از متغیر refreshTokenRequest.content.access_toke استفاده کرد:
  myProtectedApiRequestWithNewToken:
    request:
      url: <$ baseUrl $>/MyProtectedApi
      method: GET
      headers:
        - name: Authorization
          value: Bearer <$ refreshTokenRequest.content.access_token $>
    log: <$ logResponse $>
    validate:
      - jsonpath: content.title
        expect: "Hello from My Protected Controller! [Authorize]"
در اینجا با استفاده از توکن جدید درخواست نام‌دار refreshTokenRequest، آزمون واحد نوشته شده با موفقیت به پایان می‌رسد (یا باید برسد که اجرای نهایی آزمایش‌ها، آن‌را مشخص می‌کند).


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

اکنون که refresh token صورت گرفته‌است، دیگر نباید بتوانیم از توکن دریافتی پس از لاگین استفاده کنیم و برنامه باید آن‌را برگشت بزند:
  myProtectedApiRequestWithOldToken:
    request:
      url: <$ baseUrl $>/MyProtectedApi
      method: GET
      headers:
        - name: Authorization
          value: Bearer <$ loginRequest.content.access_token $>
    log: <$ logResponse $>
    validate:
      - jsonpath: status
        expect: 401
به همین جهت، درخواستی ارسال شده که به نتیجه‌ی درخواست نام‌دار loginRequest اشاره می‌کند. در این حالت برای آزمایش عملیات، اینبار status بازگشتی از سرور که باید 401 باشد، بررسی شده‌است.


مرحله‌ی 8: آزمایش خروج از سیستم

در اینجا نیاز است به آدرس account/logout، یک کوئری استرینگ را با کلید refreshToken و مقدار ریفرش‌توکن دریافتی از درخواست نام‌دار refreshTokenRequest، به سمت سرور ارسال کنیم:
  logoutRequest:
    request:
      url: <$ baseUrl $>/account/logout
      method: GET
      headers:
        - name: Authorization
          value: Bearer <$ refreshTokenRequest.content.access_token $>
      queryString:
        - name: refreshToken
          value: <$ refreshTokenRequest.content.refresh_token $>
    log: <$ logResponse $>
    validate:
      - jsonpath: content
        expect: true
خروجی آزمایش شده‌ی در اینجا، دریافت مقدار true از سمت سرور است.


مرحله‌ی 9: بررسی عدم امکان دسترسی به منابع محافظت شده‌ی سمت سرور، پس از logout

در مرحله‌ی قبل، از سیستم خارج شدیم. اکنون می‌خواهیم بررسی کنیم که آیا توکن دریافتی پیشین هنوز معتبر است یا خیر؟ آیا می‌توان هنوز هم به منابع محافظت شده دسترسی یافت یا خیر:
  myProtectedApiRequestWithNewTokenAfterLogout:
    request:
      url: <$ baseUrl $>/MyProtectedApi
      method: GET
      headers:
        - name: Authorization
          value: Bearer <$ refreshTokenRequest.content.access_token $>
    log: <$ logResponse $>
    validate:
      - jsonpath: status
        expect: 401
به همین جهت هدر Authorization را با اکسس‌توکنی که در مرحله‌ی ریفرش‌توکن دریافت کردیم (پیش از logout)، مقدار دهی می‌کنیم و سپس درخواستی را به یک منبع محافظت شده ارسال می‌کنیم. نتیجه‌ی حاصل باید status code ای مساوی 401 داشته باشد که به معنای برگشت خوردن آن است


مرحله‌ی 10: اجرای تمام آزمون‌های واحد نوشته شده

همانطور که در ابتدای بحث نیز عنوان شد فقط کافی است دستور strest JWT.strest.yml را در خط فرمان اجرا کنیم تا آزمون‌های ما به ترتیب اجرا شوند:


فایل نهایی این آزمایش را در اینجا می‌توانید مشاهده می‌کنید.
اشتراک‌ها
سری آموزشی مقدماتی Web API

Our beginner's guide to building Web APIs with ASP.NET Core is designed to provide you with the foundation you need to start building Web APIs with .NET in a collection of short, pragmatic collection of videos. Web APIs have become a critical component in almost every type of software we use today. In this introductory video series, we will walk you through the fundamental concepts you need to know to get started with building Web APIs using ASP.NET Core. We will cover topics such as routing, validation, working with data, and much more.  

سری آموزشی مقدماتی Web API
مطالب
معرفی و راهنمایی جهت انتخاب پلتفرم‌های توسعه‌ی رابط کاربری جدید مایکروسافت
اگر به تکنولوژی‌های شرکت مایکروسافت علاقمند باشید و اخبار آن را دنبال کرده باشید قطعا در جریان هستید که علاوه بر تکنولوژی‌های قدیمی (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 اجرا نمیشود

نظرات مطالب
امکان ساخت قالب برای پروژه‌های NET Core.
برای عزل آن یا از نام بسته‌ی NuGet استفاده کنید و یا مسیر کامل پوشه‌ای که فایل template.config در آن قرار دارد:
dotnet new -u <NUGET_PACKAGE_ID>
dotnet new -u <ABSOLUTE_Path to template.config folder>
نظرات مطالب
احراز هویت و اعتبارسنجی کاربران در برنامه‌های Angular - قسمت ششم - کار با منابع محافظت شده‌ی سمت سرور
یک نکته‌ی تکمیلی
اگر نکات مطلب «استفاده از مسیرهای مطلق در حین import ماژول‌ها در برنامه‌های مبتنی بر TypeScript» را به پروژه‌ی جاری اعمال کنیم، به این تغییرات خواهیم رسید.