مطالب
اصلاح daylight saving time ویندوز تا 90 سال بعد
چند سالی هست (از سال 2009) که آپدیت‌های daylight saving time ویندوز شامل حال تنظیمات رسمی ایران نمی‌شود. برای نمونه، همین یکی دو روز قبل بود که ساعت ویندوز به صورت خودکار تغییر کرد؛ درحالیکه باید در انتهای روز 30 شهریور اینکار صورت می‌گرفت.
اطلاعات daylight saving time یا بازه صرفه جویی زمانی ویندوز در دو مدخل رجیستری زیر ثبت می‌شوند:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation]
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\Iran Standard Time]



تصویر سوم مرتبط است به ویندوزهای ویستا به بعد که مفهوم dynamic daylight saving time در آن‌ها معرفی شده است.
در اینجا یک نمونه اطلاعات زمانی ثبت شده مرتبط با ایران را مشاهده می‌کنید:
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\Iran Standard Time]
"Display"="(GMT+03:30) Tehran"
"Dlt"="Iran Daylight Time"
"Std"="Iran Standard Time"
"MapID"="-1,72"
"Index"=dword:000000a0
"TZI"=hex:2e,ff,ff,ff,00,00,00,00,c4,ff,ff,ff,00,00,09,00,04,00,03,00,17,00,3b,\
  00,3b,00,00,00,00,00,03,00,02,00,03,00,17,00,3b,00,3b,00,00,00
TZI ایی که در اینجا وجود دارد، دارای یک چنین ساختاری است:
using System.Runtime.InteropServices;

namespace TimeZoneInfo.Core
{
    [StructLayout(LayoutKind.Sequential)]
    public struct TZI
    {
        public int Bias;
        public int StandardBias;
        public int DaylightBias;
        public SystemTime StandardDate;
        public SystemTime DaylightDate;
    }
}
و SystemTime آن نیز به نحو زیر تعریف شده است:
using System;
using System.Runtime.InteropServices;

namespace TimeZoneInfo.Core
{
    [StructLayoutAttribute(LayoutKind.Sequential)]
    public struct SystemTime
    {
        public short Year;
        public short Month;
        public short DayOfWeek;
        public short Day;
        public short Hour;
        public short Minute;
        public short Second;
        public short Milliseconds;
    }
}
برای مثال اگر اطلاعات درج شده در TZI به صورت زیر باشد:
2C 01 00 00 00 00 00 00
C4 FF FF FF 00 00 0A 00
00 00 05 00 02 00 00 00
00 00 00 00 00 00 04 00
00 00 01 00 02 00 00 00
00 00 00 00
نمونه رمزگشایی شده آن به نحو ذیل خواهد بود:
(little-endian)   => (big-endian)
  2C 01 00 00     => 00 00 01 2C = 300 Bias
  00 00 00 00     => 00 00 00 00 = 0 Std Bias
  C4 FF FF FF     => FF FF FF C4 = 4294967236 Dlt Bias
( SYSTEM TIME ) StandardDate
  00 00           => 00 00 = Year
  0A 00           => 00 0A = Month
  00 00           => 00 00 = Day of Week
  05 00           => 00 05 = Day
  02 00           => 00 02 = Hour
  00 00           => 00 00 = Minutes
  00 00           => 00 00 = Seconds
  00 00           => 00 00 = Milliseconds
( SYSTEM TIME ) DaylightDate
  00 00           => 00 00 = Year
  04 00           => 00 04 = Month
  00 00           => 00 00 = Day of Week
  01 00           => 00 01 = Day
  02 00           => 00 02 = Hour
  00 00           => 00 00 = Minutes
  00 00           => 00 00 = Seconds
  00 00           => 00 00 = Milliseconds
در ساختار SystemTime متناظر با TZI، فیلد Day دارای مقدار روز در یک ماه نیست. به معنای شماره هفته است. مثلا پنج شنبه (DayOfWeek) هفته سوم (Day) ماه 9 سال 2012.
همچنین Day از یک شروع می‌شود و DayOfWeek از صفر. Year اگر صفر وارد شود به معنای زمان نسبی است و برای سال بعد نیز می‌تواند کاربرد داشته باشد (و عموما صفر تعریف شده است).
بنابراین برای تبدیل DateTime به SystemTime سازگار با TZI به فرمول زیر خواهیم رسید:
        public static SystemTime ToSystemTime(DateTime time)
        {
            var result = new SystemTime
            {
                Year = 0, // سال نسبی وارد می‌شود نه مطلق
                Month = (short)time.Month,
                DayOfWeek = (short)time.DayOfWeek,
                Hour = (short)time.Hour,
                Minute = (short)time.Minute,
                Second = (short)time.Second,
                Milliseconds = (short)time.Millisecond
            };

            int weekdayOfMonth = 1; // شماره هفته است نه شماره روز
            for (int dd = time.Day; dd > 7; dd -= 7)
                weekdayOfMonth++;

            result.Day = (short)weekdayOfMonth;

            return result;
        }
در ادامه نیاز خواهیم داشت تا ساختار TZI سفارشی و بازسازی شده خودمان را بتوانیم به آرایه‌ای از بایت‌ها تبدیل کنیم تا بتوان در همان مدخل رجیستری نوشت. اینکار را توسط متد SerializeByteArray زیر می‌توان انجام داد:
using System;
using System.Runtime.InteropServices;

namespace TimeZoneInfo.Core
{
    public static class ByteUtils
    {
        public static Byte[] SerializeByteArray<T>(T msg) where T : struct
        {
            int objsize = Marshal.SizeOf(typeof(T));
            Byte[] ret = new Byte[objsize];

            IntPtr buff = Marshal.AllocHGlobal(objsize);
            Marshal.StructureToPtr(msg, buff, true);
            Marshal.Copy(buff, ret, 0, objsize);
            Marshal.FreeHGlobal(buff);

            return ret;
        }
    }
}
و اگر اینکار را تا بیش از 90 سال بعد بر اساس تاریخ ایران انجام داده و مداخل رجیستری ویندوز را تکمیل کنیم، خروجی آن فایل reg زیر خواهد بود که به سادگی با کلیک راست و انتخاب گزینه‌ی merge به رجیستری ویندوز اضافه شده و تا چندین سال بعد، مشکل تنظیمات DST را برطرف خواهد کرد:
پس از اعمال تغییرات فوق، نیاز است یکبار ویندوز را ری استارت کنید.
مسیرراه‌ها
NHibernate
      مطالب
      پیش بینی وضعیت دنیای برنامه نویسی در 5 سال آینده

      در 5 سال آینده مواردی که در ادمه برشمرده خواهند شد، نقش بسیار مهمی را در دنیای برنامه نویسی و جهت گیری‌های آن ایفا خواهند کرد (برای مثال اگر برای شما این سؤال مطرح است که هدف از WCF ، REST services ، سیلورلایت 3 و غیره چیست، این مقاله‌ی کوتاه را مطالعه نمائید) :

      الف) Object Relational Mapping
      ORM یکی از بازیگرهای واضح خواهد بود. خصوصا پروژه‌ای مانند Fluent NHibernate با ویژگی‌های زیر:
      • سابقه‌ای 10 ساله (قسمت عمده‌ای از این سابقه به دنیای جاوا بر می‌گردد)
      • امکان استفاده از انواع و اقسام دیتابیس‌ها توسط آن
      • پشتیبانی از Linq
      • و ...

      ب) نرم افزار به عنوان سرویس ( Software as a Service یا SaaS )
      نرم افزار به عنوان سرویس یک مفهوم تجاری است که در آن مصرف کننده بر اساس نیازهایش هزینه‌ی یک نرم افزار را خواهد پرداخت. بر این اساس برنامه نویسی در زمینه‌های طراحی و مدیریت دست خوش تغییرات عمده‌ای می‌شود. شاید نیازی به ذکر نباشد که حتی مایکروسافت نیز در حال برنامه ریزی برای این نوع از توسعه است.
      پرداختن به SaaS نیازمند یک سری از ویژگی‌ها است:
      • سادگی توسعه و دستیابی: در این مدل تجاری، استفاده و دسترسی به نرم افزار مورد نظر باید بسیار ساده باشد. بر این اساس برنامه‌های تحت وب، یا برنامه‌های هاست شده توسط مرورگرها (مانند سیلورلایت) محبوبیت بیش از پیشی را خواهند یافت.
      • قابلیت تنظیم و ماژولار بودن برنامه‌ها: در این مدل نیاز است تا کاربر تنها هزینه‌ی ماژول‌هایی را بپردازد که به آن‌ها نیاز دارد و این امر سبب بازنگری در طراحی و توسعه‌ی برنامه‌های موجود خواهد شد.
      • نیاز به زیر ساخت بهینه و سریعی خواهد بود: از آنجائیکه کاربران بسیار ساده می‌توانند از یک برنامه به برنامه و شرکتی دیگر رجوع کنند، برای بقا باید جنگید! نیاز به زیر ساخت‌هایی وجود خواهد داشت که توسط آن‌ها بتوان نیازهای کاربران را در حداقل زمان ممکن برآورده کرد و این موارد نیاز به آموختن یکی از فریم ورک‌های مطرح موجود را خواهد داشت به همراه آموختن مباحث مدیریت پروژه، آشنایی با آزمون‌های واحد، کنترل کیفیت ، یکپارچگی مداوم و امثال آن.

      ج) پردازش ابری
      پردازش ابری شبیه به آن‌چیزی که مایکروسافت Azure ارائه می‌دهد، نیز یکی از نتایج مفهوم تجاری SaaS است. تمرکز پردازش ابری بر روی ارائه‌ی وب سرورها، مکان‌های ذخیره داده و امثال آن است. به این صورت شما دیگر درگیر تهیه و پرداخت هزینه جهت راه اندازی دیتاسنتر ویژه‌ی خود نخواهید شد و بسیاری از هزینه‌های شما کاهش خواهند یافت. بهره برداری تجاری گسترده از این روش با توجه به توسعه‌ی فریم ورک‌های ویژه‌ی این نوع پردازش‌ها، آموزش و غیره ، بین سال‌های 2010 و 2015 شروع خواهد شد.

      د) اجرای موازی
      پردازش ابری اثرات خاص خودش را بر روی دنیای نرم افزار و برنامه نویسی خواهد گذاشت. این طبیعت توزیع شده سبب خواهد شد که در آینده از برنامه نویسی‌های چند ریسمانی و مسایل همزمانی حاصل از آن‌ها بیشتر بشنوید و نهایتا معماری برنامه‌ها به سمت استفاده از روش‌های زیر سوق خواهند یافت:
      REST services;
      Message-based distributed architectures, i.e.: see NServiceBus, Mass Transit or Rhino Service Bus



      ه) برنامه‌های غنی وب یا Rich Internet Applications
      Rich Internet Applications یا RIA نقش مهمی را در SaaS بازی خواهند کرد و هدفگیری مایکروسافت در این باره ارائه Silverlight 3.0‌ و Microsoft .NET RIA Services است. هر چند این موارد راه طولانی (یکی دو ساله) را در پیش خواهند داشت تا به حد استانداردهای لازم برسند اما حرکت‌های مهمی در این زمینه به شمار می‌روند.

      برداشتی آزاد از Development in 5 Years Would be Affected by

      مطالب
      معماری لایه بندی نرم افزار #4

      UI

      در نهایت نوبت به طراحی و کدنویسی UI می‌رسد تا بتوانیم محصولات را به کاربر نمایش دهیم. اما قبل از شروع باید موضوعی را یادآوری کنم. اگر به یاد داشته باشید، در کلاس ProductService موجود در لایه‌ی Domain، از طریق یکی از روشهای الگوی Dependency Injection به نام Constructor Injection، فیلدی از نوع IProductRepository را مقداردهی نمودیم. حال زمانی که بخواهیم نمونه ای را از ProductService ایجاد نماییم، باید به عنوان پارامتر ورودی سازنده، شی ایجاد شده از جنس کلاس ProductRepository موجود در لایه Repository را به آن ارسال نماییم. اما از آنجایی که می‌خواهیم تفکیک پذیری لایه‌ها از بین نرود و UI بسته به نیاز خود، نمونه مورد نیاز را ایجاد نموده و به این کلاس ارسال کند، از ابزارهایی برای این منظور استفاده می‌کنیم. یکی از این ابزارها StructureMap می‌باشد که یک Inversion of Control Container یا به اختصار IoC Container نامیده می‌شود. با Inversion of Control در مباحث بعدی بیشتر آشنا خواهید شد. StructureMap ابزاری است که در زمان اجرا، پارامترهای ورودی سازنده‌ی کلاسهایی را که از الگوی Dependency Injection استفاده نموده اند و قطعا پارامتر ورودی آنها از جنس یک Interface می‌باشد را، با ایجاد شی مناسب مقداردهی می‌نماید.

      به منظور استفاده از StructureMap در Visual Studio 2012 باید بر روی پروژه UI خود کلیک راست نموده و گزینه‌ی Manage NuGet Packages را انتخاب نمایید. در پنجره ظاهر شده و از سمت چپ گزینه‌ی Online و سپس در کادر جستجوی سمت راست و بالای پنجره واژه‌ی structuremap را جستجو کنید. توجه داشته باشید که باید به اینترنت متصل باشید تا بتوانید Package مورد نظر را نصب نمایید. پس از پایان عمل جستجو، در کادر میانی structuremap ظاهر می‌شود که می‌توانید با انتخاب آن و فشردن کلید Install آن را بر روی پروژه نصب نمایید.

      جهت آشنایی بیشتر با NuGet و نصب آن در سایر نسخه‌های Visual Studio می‌توانید به لینک‌های زیر رجوع کنید:

      1. آشنایی با  NuGetقسمت اول

      2. آشنایی با  NuGetقسمت دوم

      3. Installing NuGet

      کلاسی با نام BootStrapper را با کد زیر به پروژه UI خود اضافه کنید:

      using StructureMap;
      using StructureMap.Configuration.DSL;
      using SoCPatterns.Layered.Repository;
      using SoCPatterns.Layered.Model;
      
      namespace SoCPatterns.Layered.WebUI
      {
          public class BootStrapper
          {
              public static void ConfigureStructureMap()
              {
                  ObjectFactory.Initialize(x => x.AddRegistry<ProductRegistry>());
              }
          }
          public class ProductRegistry : Registry
          {
              public ProductRegistry()
              {
                  For<IProductRepository>().Use<ProductRepository>();
              }
          }
      }

      ممکن است یک WinUI ایجاد کرده باشید که در این صورت به جای فضای نام SoCPatterns.Layered.WebUI از SoCPatterns.Layered.WinUI استفاده نمایید.

      هدف کلاس BootStrapper این است که تمامی وابستگی‌ها را توسط StructureMap در سیستم Register نماید. زمانی که کدهای کلاینت می‌خواهند به یک کلاس از طریق StructureMap دسترسی داشته باشند، Structuremap وابستگی‌های آن کلاس را تشخیص داده و بصورت خودکار پیاده سازی واقعی (Concrete Implementation) آن کلاس را، براساس همان چیزی که ما برایش تعیین کردیم، به کلاس تزریق می‌نماید. متد ConfigureStructureMap باید در همان لحظه ای که Application آغاز به کار می‌کند فراخوانی و اجرا شود. با توجه به نوع UI خود یکی از روالهای زیر را انجام دهید:

      در WebUI:

      فایل Global.asax را به پروژه اضافه کنید و کد آن را بصورت زیر تغییر دهید:

      namespace SoCPatterns.Layered.WebUI
      {
          public class Global : System.Web.HttpApplication
          {
              protected void Application_Start(object sender, EventArgs e)
              {
                  BootStrapper.ConfigureStructureMap();
              }
          }
      }

      در WinUI:

      در فایل Program.cs کد زیر را اضافه کنید:

      namespace SoCPatterns.Layered.WinUI
      {
          static class Program
          {
              [STAThread]
              static void Main()
              {
                  Application.EnableVisualStyles();
                  Application.SetCompatibleTextRenderingDefault(false);
                  BootStrapper.ConfigureStructureMap();
                  Application.Run(new Form1());
              }
          }
      }

      سپس برای طراحی رابط کاربری، با توجه به نوع UI خود یکی از روالهای زیر را انجام دهید:

      در WebUI:

      صفحه Default.aspx را باز نموده و کد زیر را به آن اضافه کنید:

      <asp:DropDownList AutoPostBack="true" ID="ddlCustomerType" runat="server">
          <asp:ListItem Value="0">Standard</asp:ListItem>
          <asp:ListItem Value="1">Trade</asp:ListItem>
      </asp:DropDownList>
      <asp:Label ID="lblErrorMessage" runat="server" ></asp:Label>
      <asp:Repeater ID="rptProducts" runat="server" >
          <HeaderTemplate>
              <table>
                  <tr>
                      <td>Name</td>
                      <td>RRP</td>
                      <td>Selling Price</td>
                      <td>Discount</td>
                      <td>Savings</td>
                  </tr>
                  <tr>
                      <td colspan="5"><hr /></td>
                  </tr>
          </HeaderTemplate>
          <ItemTemplate>
                  <tr>
                      <td><%# Eval("Name") %></td>
                      <td><%# Eval("RRP")%></td>
                      <td><%# Eval("SellingPrice") %></td>
                      <td><%# Eval("Discount") %></td>
                      <td><%# Eval("Savings") %></td>
                  </tr>
          </ItemTemplate>
          <FooterTemplate>
              </table>
          </FooterTemplate>
      </asp:Repeater>

      در WinUI:

      فایل Form1.Designer.cs را باز نموده و کد آن را بصورت زیر تغییر دهید:

      #region Windows Form Designer generated code
      /// <summary>
      /// Required method for Designer support - do not modify
      /// the contents of this method with the code editor.
      /// </summary>
      private void InitializeComponent()
      {
          this.cmbCustomerType = new System.Windows.Forms.ComboBox();
          this.dgvProducts = new System.Windows.Forms.DataGridView();
          this.colName = new System.Windows.Forms.DataGridViewTextBoxColumn();
          this.colRrp = new System.Windows.Forms.DataGridViewTextBoxColumn();
          this.colSellingPrice = new System.Windows.Forms.DataGridViewTextBoxColumn();
          this.colDiscount = new System.Windows.Forms.DataGridViewTextBoxColumn();
          this.colSavings = new System.Windows.Forms.DataGridViewTextBoxColumn();
          ((System.ComponentModel.ISupportInitialize)(this.dgvProducts)).BeginInit();
          this.SuspendLayout();
          //
          // cmbCustomerType
          //
          this.cmbCustomerType.DropDownStyle =                                                                                                                                                                             System.Windows.Forms.ComboBoxStyle.DropDownList;
          this.cmbCustomerType.FormattingEnabled = true;
          this.cmbCustomerType.Items.AddRange(new object[] {
              "Standard",
              "Trade"});
          this.cmbCustomerType.Location = new System.Drawing.Point(12, 90);
          this.cmbCustomerType.Name = "cmbCustomerType";
          this.cmbCustomerType.Size = new System.Drawing.Size(121, 21);
          this.cmbCustomerType.TabIndex = 3;
          //
          // dgvProducts
          //
          this.dgvProducts.ColumnHeadersHeightSizeMode =     System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
          this.dgvProducts.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
          this.colName,
          this.colRrp,
          this.colSellingPrice,
          this.colDiscount,
          this.colSavings});
          this.dgvProducts.Location = new System.Drawing.Point(12, 117);
          this.dgvProducts.Name = "dgvProducts";
          this.dgvProducts.Size = new System.Drawing.Size(561, 206);
          this.dgvProducts.TabIndex = 2;
          //
          // colName
          //
          this.colName.DataPropertyName = "Name";
          this.colName.HeaderText = "Product Name";
          this.colName.Name = "colName";
          this.colName.ReadOnly = true;
          //
          // colRrp
          //
          this.colRrp.DataPropertyName = "Rrp";
          this.colRrp.HeaderText = "RRP";
          this.colRrp.Name = "colRrp";
          this.colRrp.ReadOnly = true;
          //
          // colSellingPrice
          //
          this.colSellingPrice.DataPropertyName = "SellingPrice";
          this.colSellingPrice.HeaderText = "Selling Price";
          this.colSellingPrice.Name = "colSellingPrice";
          this.colSellingPrice.ReadOnly = true;
          //
          // colDiscount
          //
          this.colDiscount.DataPropertyName = "Discount";
          this.colDiscount.HeaderText = "Discount";
          this.colDiscount.Name = "colDiscount";
          //
          // colSavings
          //
          this.colSavings.DataPropertyName = "Savings";
          this.colSavings.HeaderText = "Savings";
          this.colSavings.Name = "colSavings";
          this.colSavings.ReadOnly = true;
          //
          // Form1
          //
          this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
          this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
          this.ClientSize = new System.Drawing.Size(589, 338);
          this.Controls.Add(this.cmbCustomerType);
          this.Controls.Add(this.dgvProducts);
          this.Name = "Form1";
          this.Text = "Form1";
          ((System.ComponentModel.ISupportInitialize)(this.dgvProducts)).EndInit();
          this.ResumeLayout(false);
      }
      #endregion
      private System.Windows.Forms.ComboBox cmbCustomerType;
      private System.Windows.Forms.DataGridView dgvProducts;
      private System.Windows.Forms.DataGridViewTextBoxColumn colName;
      private System.Windows.Forms.DataGridViewTextBoxColumn colRrp;
      private System.Windows.Forms.DataGridViewTextBoxColumn colSellingPrice;
      private System.Windows.Forms.DataGridViewTextBoxColumn colDiscount;
      private System.Windows.Forms.DataGridViewTextBoxColumn colSavings;

      سپس در Code Behind، با توجه به نوع UI خود یکی از روالهای زیر را انجام دهید:

      در WebUI:

      وارد کد نویسی صفحه Default.aspx شده و کد آن را بصورت زیر تغییر دهید:

      using System;
      using System.Collections.Generic;
      using SoCPatterns.Layered.Model;
      using SoCPatterns.Layered.Presentation;
      using SoCPatterns.Layered.Service;
      using StructureMap;
      
      namespace SoCPatterns.Layered.WebUI
      {
          public partial class Default : System.Web.UI.Page, IProductListView
          {
              private ProductListPresenter _productListPresenter;
              protected void Page_Init(object sender, EventArgs e)
              {
                  _productListPresenter = new ProductListPresenter(this,ObjectFactory.GetInstance<Service.ProductService>());
                  this.ddlCustomerType.SelectedIndexChanged +=
                      delegate { _productListPresenter.Display(); };
              }
              protected void Page_Load(object sender, EventArgs e)
              {
                  if(!Page.IsPostBack)
                      _productListPresenter.Display();
              }
              public void Display(IList<ProductViewModel> products)
              {
                  rptProducts.DataSource = products;
                  rptProducts.DataBind();
              }
              public CustomerType CustomerType
              {
                  get { return (CustomerType) int.Parse(ddlCustomerType.SelectedValue); }
              }
              public string ErrorMessage
              {
                  set
                  {
                      lblErrorMessage.Text =
                          String.Format("<p><strong>Error:</strong><br/>{0}</p>", value);
                  }
              }
          }
      }

      در WinUI:

      وارد کدنویسی Form1 شوید و کد آن را بصورت زیر تغییر دهید:

      using System;
      using System.Collections.Generic;
      using System.Windows.Forms;
      using SoCPatterns.Layered.Model;
      using SoCPatterns.Layered.Presentation;
      using SoCPatterns.Layered.Service;
      using StructureMap;
      
      namespace SoCPatterns.Layered.WinUI
      {
          public partial class Form1 : Form, IProductListView
          {
              private ProductListPresenter _productListPresenter;
              public Form1()
              {
                  InitializeComponent();
                  _productListPresenter =
                      new ProductListPresenter(this, ObjectFactory.GetInstance<Service.ProductService>());
                  this.cmbCustomerType.SelectedIndexChanged +=
                      delegate { _productListPresenter.Display(); };
                  dgvProducts.AutoGenerateColumns = false;
                  cmbCustomerType.SelectedIndex = 0;
              }
              public void Display(IList<ProductViewModel> products)
              {
                  dgvProducts.DataSource = products;
              }
              public CustomerType CustomerType
              {
                  get { return (CustomerType)cmbCustomerType.SelectedIndex; }
              }
              public string ErrorMessage
              {
                  set
                  {
                      MessageBox.Show(
                          String.Format("Error:{0}{1}", Environment.NewLine, value));
                  }
              }
          }
      }

      با توجه به کد فوق، نمونه ای را از کلاس ProductListPresenter، در لحظه‌ی نمونه سازی اولیه‌ی کلاس UI، ایجاد نمودیم. با استفاده از متد ObjectFactory.GetInstance مربوط به StructureMap، نمونه ای از کلاس ProductService ایجاد شده است و به سازنده‌ی کلاس ProductListPresenter ارسال گردیده است. در مورد Structuremap در مباحث بعدی با جزئیات بیشتری صحبت خواهم کرد. پیاده سازی معماری لایه بندی در اینجا به پایان رسید.

      اما اصلا نگران نباشید، شما فقط پرواز کوتاه و مختصری را بر فراز کدهای معماری لایه بندی داشته اید که این فقط یک دید کلی را به شما در مورد این معماری داده است. این معماری هنوز جای زیادی برای کار دارد، اما در حال حاضر شما یک Applicaion با پیوند ضعیف (Loosely Coupled) بین لایه‌ها دارید که دارای قابلیت تست پذیری قوی، نگهداری و پشتیبانی آسان و تفکیک پذیری قدرتمند بین اجزای آن می‌باشد. شکل زیر تعامل بین لایه‌ها و وظایف هر یک از آنها را نمایش می‌دهد.

      نظرات اشتراک‌ها
      برنامه‌های ASP.NET Core نیازی به ConfigureAwait(false) ندارند
      1 - طبق نوشته های Stephen Cleary ، تیم Entity Framework Core در ورژن 5.0.0، متد ConfigureAwait(false) رو مجددا اضافه کردن. آیا واقعا باید از ConfigureAwait(false) در برنامه‌های Asp.Net Core استفاده کنیم؟
      2 - اگه لایه API پروژه 6 net باشه و بقیه لایه‌ها با netstandard 2.0 نوشته شده باشن، توی همه لایه‌ها استفاده از ConfigureAwait(false) ضروریه؟