خیلی جست و جو کردم ولی خوب مفهوم رو درک نکردم اگر امکان داره مطلبی در موردش همراه با یک مثال
کاربردی بزنید
اجرتون با خدا
EntityFramework.Exceptions simplifies this by handling all the
database specific details and throwing different exceptions. All you
have
to do is inherit your DbContext
from ExceptionProcessorContext
and handle the exception(s) such as UniqueConstraintException
,
CannotInsertNullException
, MaxLengthExceededException
, NumericOverflowException
you need.
UserDialogs.Init(this); // Before Forms.Init
containerBuilder.RegisterInstance(UserDialogs.Instance);
public IUserDialogs UserDialogs { get; set; } public async Task Login() { if (string.IsNullOrWhiteSpace(UserName) || string.IsNullOrWhiteSpace(Password)) await UserDialogs.AlertAsync(message: "Please provide UserName and Password!", title: ")-:", okText: "Ok!"); }
using (UserDialogs.Loading("Logging in...", maskType: MaskType.Black)) { // Login implementation ... await Task.Delay(TimeSpan.FromSeconds(3)); }
await NavigationService.NavigateAsync("/Login", animated: false);
await NavigationService.NavigateAsync("/Nav/HelloWorld");
3- ممکن است بخواهید هنگام رفتن از صفحهای به صفحه دیگر، پارامتر نیز ارسال کنید. اگر برای مثال صفحه اول لیست محصولات را نمایش میدهد و با زدن روی هر محصول قرار است به صفحهای برویم که جزئیات آن محصول را ببینیم، بهتر است Id آن محصول به صورت پارامتر به صفحه دوم ارسال شود. برای این کار داریم:
await NavigationService.NavigateAsync("ProductDetail", new NavigationParameters { { "productId", productId } });
حال سؤال این است که در صفحه جزئیات یک محصول، چگونه productId را بگیریم؟ فرض کنید دو صفحه ProductsList و ProductDetail را داریم. هر صفحه دارای View و View Model است. در ViewModel مربوط به ProductDetail، یعنی ProductDetailViewModel که از BitViewModelBase ارث بری کردهاست، میتوانیم متد OnNavigatedToAsync را override کنیم. در آنجا به پارامترهای ارسال شده دسترسی داریم:
public async override Task OnNavigatedToAsync(INavigationParameters parameters) { await base.OnNavigatedToAsync(parameters); Guid productId = parameters.GetValue<Guid>("productId"); }
هر ViewModel علاوه بر OnNavigatedTo می تواند دارای OnNavigatedFrom هم باشد که زمانیکه داریم از صفحه مربوطه خارج میشویم، فراخوانی میشود.
4- برای نمایش صفحه به صورت Popup کافی است بجای اینکه View ما یک Content Page باشد، یک PopupPage باشد (برای درک بهتر، فایل IntroView.xaml را در فولدر Views باز کنید).
حتی میتوانید Animation مربوط به باز شدن پاپ آپ را هم کاملا Customize کنید. مثلا زمان باز شدن، از سمت راست صفحه وارد شود و زمان خارج شدن، Fade out شود. باز کردن Popup در Navigation Page معنی نمیدهد، پس با Nav/ در اینجا کاری نداریم. در مثال ما، بعد از لاگین میخواهیم یک صفحه Intro شامل هشدارها و راهنماییهای اولیه را در قالب Popup به کاربر نمایش دهیم. Popupها میتوانند همچون Content Pageها، دارای View Model باشند و مواردی چون OnNavigatedTo، ارسال پارامتر و هر آنچه که گفته شد، در مورد آنها نیز صدق میکند.
5- برای Master/Detail کافی است بجای Nav/HelloWorld/ از MasterDetail/Nav/HelloWorld/ استفاده کنید. این عمل باعث میشود HelloWorld در داخل Navigation Page و Navigation Page داخل Master Detail باز شود. از این سادهتر امکان ندارد!
برای تغییر UI مربوط به Master که از سمت چپ باز میشود، فایل XamAppMasterDetailView.xaml را تغییر دهید.
در قسمت بعدی به جزئیات Binding خواهیم پرداخت.
This article takes a comprehensive look at the business of generating and sending email from an ASP.NET MVC application. It covers the most common use cases as well as some advanced scenarios. It also explores some of the more common errors that arise from attempting to generate and send email programmatically from an ASP.NET MVC site.
Looking at these side-by-side randomly generated visualizations, neither of them seem substantively different from a distribution perspective. All to say, when generating a random color palette, there probably wasn't any need for me to use the Crypto module—I probably should have just stuck with Math. It's much faster and feels to be just as random. I'll leave the Crypto stuff to any client-side cryptography work (which I've never had to do).
error RZ9992: Script tags should not be placed inside components because they cannot be updated dynamically. To fix this, move the script tag to the 'index.html' file or another static location. For more information see https://go.microsoft.com/fwlink/?linkid=872131
<script suppress-error="BL9992" />
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 میتوانید به لینکهای زیر رجوع کنید:
کلاسی با نام 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) بین لایهها دارید که دارای قابلیت تست پذیری قوی، نگهداری و پشتیبانی آسان و تفکیک پذیری قدرتمند بین اجزای آن میباشد. شکل زیر تعامل بین لایهها و وظایف هر یک از آنها را نمایش میدهد.