سری آموزشی PRISM
PRISM یا Composite Application Guidance الگوهایی را برای تولید برنامههای WPF ویا Silverlight ماژولار با قابلیت تست پذیری بالا ارائه میدهند. شعار این مجموعه built for change و built to last است که به معنای تهیه سیستمهایی با قابلیت تغییر بالا و همچنین سهولت نگهداری آنها در دراز مدت میباشد.
جناب Mike Taulty را احتمالا با ویدیوهای آموزش WCF به خاطر دارید. ایشان مجموعه جدیدی را به نام Video Series on PRISM for Silverlight 3 تهیه کردهاند که از لینکهای زیر قابل دریافت است:
Part 2: Dependency Injection with Unity
Part 3: Modularity with Prism
Part 4: The Unity Bootstrapper
Part 5: Moving to a Modular Silverlight Project
Part 6: Shells, Regions, Views
Part 7: Commands
Part 8: Loosely Coupled Events with Event Aggregation
Part 9: Sharing Data via Region Contexts
Part 10: A Larger Example: "Email Client"
تزریق وابستگی در جاوا اسکریپت
الگوی معکوس سازی کنترل چیست؟
IoC یک الگوی سطح بالا است و به روشهای مختلفی به مسایل متفاوتی جهت معکوس سازی کنترل، قابل اعمال میباشد؛ مانند:
- کنترل اینترفیسهای بین دو سیستم
- کنترل جریان کاری برنامه
- کنترل بر روی ایجاد وابستگیها (جایی که تزریق وابستگیها و DI ظاهر میشوند)
سؤال: بین IoC و DIP چه تفاوتی وجود دارد؟
در DIP (قسمت قبل) به این نتیجه رسیدیم که یک ماژول سطح بالاتر نباید به جزئیات پیاده سازیهای ماژولی سطح پایینتر وابسته باشد. هر دوی اینها باید بر اساس Abstraction با یکدیگر ارتباط برقرار کنند. IoC روشی است که این Abstraction را فراهم میکند. در DIP فقط نگران این هستیم که ماژولهای موجود در لایههای مختلف برنامه به یکدیگر وابسته نباشند اما بیان نکردیم که چگونه.
معکوس سازی اینترفیسها
هدف از معکوس سازی اینترفیسها، استفاده صحیح و معنا دار از اینترفیسها میباشد. به این معنا که صرفا تعریف اینترفیسها به این معنا نیست که طراحی صحیحی در برنامه بکار گرفته شده است و در حالت کلی هیچ معنای خاصی ندارد و ارزشی را به برنامه و سیستم شما اضافه نخواهد کرد.
برای مثال یک مسابقه بوکس را درنظر بگیرید. در اینجا Ali یک بوکسور است. مطابق عادت معمول، یک اینترفیس را مخصوص این کلاس ایجاد کرده، به نام IAli و مسابقه بوکس از آن استفاده خواهد کرد. در اینجا تعریف یک اینترفیس برای Ali، هیچ ارزش افزودهای را به همراه ندارد و متاسفانه عادتی است که در بین بسیاری از برنامه نویسها متداول شده است؛ بدون اینکه علت واقعی آنرا بدانند و تسلطی به الگوهای طراحی برنامه نویسی شیءگرا داشته باشند. صرف اینکه به آنها گفته شده است تعریف اینترفیس خوب است، سعی میکنند برای همه چیز اینترفیس تعریف کنند!
تعریف یک اینترفیس تنها زمانی ارزش خواهد داشت که چندین پیاده سازی از آن ارائه شود. در مثال ما پیاده سازیهای مختلفی از اینترفیس IAli بیمفهوم است. همچنین در دنیای واقعی، در یک مسابقه بوکس، چندین و چند شرکت کننده وجود خواهند داشت. آیا باید به ازای هر کدام یک اینترفیس جداگانه تعریف کرد؟ ضمنا ممکن است اینترفیس IAli متدی داشته باشد به نام ضربه، اینترفیس IVahid متد دیگری داشته باشد به نام دفاع.
کاری که در اینجا جهت طراحی صحیح باید صورت گیرد، معکوس سازی اینترفیسها است. به این ترتیب که مسابقه بوکس است که باید اینترفیس مورد نیاز خود را تعریف کند و آن هم تنها یک اینترفیس است به نام IBoxer. اکنون Ali، Vahid و سایرین باید این اینترفیس را جهت شرکت در مسابقه بوکس پیاده سازی کنند. بنابراین دیگر صرف وجود یک کلاس، اینترفیس مجزایی برای آن تعریف نشده و بر اساس معکوس سازی کنترل است که تعریف اینترفیس IBoxer معنا پیدا کرده است. اکنون IBoxer دارای چندین و چند پیاده سازی خواهد بود. به این ترتیب، تعریف اینترفیس، ارزشی را به سیستم افزوده است.
به این نوع معکوس سازی اینترفیسها، الگوی provider model نیز گفته میشود. برای مثال کلاسی که از چندین سرویس استفاده میکند، بهتر است یک IService را ایجاد کرده و تامین کنندههایی، این IService را پیاده سازی کنند. نمونهای از آن در دنیای دات نت، Membership Provider موجود در ASP.NET است که پیاده سازیهای بسیاری از آن تاکنون تهیه و ارائه شدهاند.
معکوس سازی جریان کاری برنامه
جریان کاری معمول یک برنامه یا Noraml flow، عموما رویهای یا Procedural است؛ به این معنا که از یک مرحله به مرحلهای بعد هدایت خواهد شد. برای مثال یک برنامه خط فرمان را درنظر بگیرید که ابتدا میپرسد نام شما چیست؟ در مرحله بعد مثلا رنگ مورد علاقه شما را خواهد پرسید.
برای معکوس سازی این جریان کاری، از یک رابط کاربری گرافیکی یا GUI استفاده میشود. مثلا یک فرم را درنظر بگیرید که در آن دو جعبه متنی، کار دریافت نام و رنگ را به عهده دارند؛ به همراه یک دکمه ثبت اطلاعات. به این ترتیب بجای اینکه برنامه، مرحله به مرحله کاربر را جهت ثبت اطلاعات هدایت کند، کنترل به کاربر منتقل و معکوس شده است.
معکوس سازی تولید اشیاء
معکوس سازی تولید اشیاء، اصل بحث دوره و سری جاری را تشکیل میدهد و در ادامه مباحث، بیشتر و عمیقتر بررسی خواهد گردید.
روش متداول تعریف و استفاده از اشیاء دیگر درون یک کلاس، وهله سازی آنها توسط کلمه کلیدی new است. به این ترتیب از یک وابستگی به صورت مستقیم درون کدهای کلاس استفاده خواهد شد. بنابراین در این حالت کلاسهای سطح بالاتر به ماژولهای سطح پایین، به صورت مستقیم وابسته میگردند.
برای اینکه این کنترل را معکوس کنیم، نیاز است ایجاد و وهله سازی این اشیاء وابستگی را در خارج از کلاس جاری انجام دهیم. شاید در اینجا بپرسید که چرا؟
اگر با الگوی طراحی شیءگرای Factory آشنا باشید، همان ایده در اینجا مدنظر است:
Button button; switch (UserSettings.UserSkinType) { case UserSkinTypes.Normal: button = new Button(); break; case UserSkinTypes.Fancy: button = new FancyButton(); break; }
حال در این برنامه اگر قرار باشد کار و کنترل محل وهله سازی این دکمهها معکوس نشود، در هر قسمتی از برنامه نیاز است این سوئیچ تکرار گردد (برای مثال در چند ده فرم مختلف برنامه). بنابراین بهتر است محل ایجاد این دکمهها به کلاس دیگری منتقل شود مانند ButtonFactory و سپس از این کلاس در مکانهای مختلف برنامه استفاده گردد:
Button button = ButtonFactory.CreateButton();
بنابراین در مثال فوق، کنترل ایجاد دکمهها به یک کلاس پایه قرار گرفته در خارج از کلاس جاری، معکوس شده است.
انواع معکوس سازی تولید اشیاء
بسیاری شاید تصور کنند که تنها راه معکوس سازی تولید اشیاء، تزریق وابستگیها است؛ اما روشهای چندی برای انجام اینکار وجود دارد:
الف) استفاده از الگوی طراحی Factory (که نمونهای از آنرا در قسمت قبل مشاهده کردید)
ب) استفاده از الگوی Service Locator
Button button = ServiceLocator.Create(IButton.Class)
ج) تزریق وابستگیها
Button button = GetTheButton(); Form1 frm = new Form1(button);
به صورت خلاصه هر زمانیکه تولید و وهله سازی وابستگیهای یک کلاس را به خارج از آن منتقل کردید، کار معکوس سازی تولید وابستگیها انجام شده است.
مستندات ASP.NET 5
Getting Started Installing ASP.NET 5 On Windows Installing ASP.NET 5 On Mac OS X Installing ASP.NET 5 On Linux Choosing the Right .NET For You on the Server Tutorials Your First ASP.NET 5 Application Using Visual Studio Your First ASP.NET 5 Application on a Mac Publish to an Azure Web App using Visual Studio Conceptual Overview Introduction to ASP.NET 5 Introducing .NET Core DNX Overview Understanding ASP.NET 5 Web Apps Fundamentals Working with Static Files Routing Configuration Dependency Injection Diagnostics Working with Multiple Environments OWIN .NET Execution Environment (DNX) DNX Overview Creating a Cross-Platform Console App with DNX Working with DNX Projects Using Commands Publishing and Deployment Publish to a Docker Image Client-Side Development Grunt and Gulp: Task Runners Manage Client-Side Packages with Bower Building Beautiful, Responsive Sites with Bootstrap Knockout.js MVVM Framework Styling Applications with Less, Sass, and Font Awesome Security Enabling authenication using external providers Account Confirmation and Password Recovery with ASP.NET Identity Two-factor authenication with SMS using ASP.NET Identity Data Protection Extensibility Writing Middleware
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) بین لایهها دارید که دارای قابلیت تست پذیری قوی، نگهداری و پشتیبانی آسان و تفکیک پذیری قدرتمند بین اجزای آن میباشد. شکل زیر تعامل بین لایهها و وظایف هر یک از آنها را نمایش میدهد.
دو پروژهی سورس باز XML RPC و Log4Net برای اجرا شدن در برنامههای دات نت 4 نیاز به اندکی تغییر در هر دو برنامهی فراخوان و اسمبلیهای آنها دارند که در ادامه توضیحات مربوطه ارائه خواهند شد.
اگر یک پروژهی جدید دات نت 4 را آغاز کنید و سپس ارجاعی را به یکی از اسمبلیهای ذکر شده اضافه نمائید، اولین خطایی را که حین استفاده مشاهده خواهید نمود، مورد زیر است:
Could not resolve assembly "System.Web".
The assembly is not in the currently targeted framework ".NETFramework,Version=v4.0,Profile=Client".
Please remove references to assemblies not in the targeted framework or consider retargeting your project.
خطای دومی که حین کار با کتابخانههای XML RPC و یا Log4Net در یک برنامهی دات نت 4 حتما با آن مواجه خواهید شد در ادامه ذکر گردیده است:
Inheritance security rules violated while overriding member:
GetObjectData(System.Runtime.Serialization.SerializationInfo, System.Runtime.Serialization.StreamingContext),
Security accessibility of the overriding method must match the security accessibility of the method being overriden.
برای رفع این مشکل ابتدا سورس این کتابخانهها را دریافت کرده و سپس در فایل AssemblyInfo.cs آنها یک سطر زیر را حذف نموده و پروژه را مجددا کامپایل کنید:
[assembly: AllowPartiallyTrustedCallers]
برای مطالعه بیشتر:
Using Libraries from Partially Trusted Code
Security Changes in the .NET Framework 4
TypeLoadException based on Security-Transparent Code, Level 2
Making log4net run on .NET 4.0
سری مقدماتی ASP.NET Core
Introduction to ASP.NET Core part 15: starting with tag helpers
Introduction to ASP.NET Core part 14: the view start and the layout files
Introduction to ASP.NET Core part 13: the view imports file
Introduction to ASP.NET Core part 12: data annotation of view models
Introduction to ASP.NET Core part 11: inserting a new Book in a form
Introduction to ASP.NET Core part 10: the details page and more on view models
Introduction to ASP.NET Core part 9: MVC continued with routing
Introduction to ASP.NET Core part 8: MVC continued with controller actions and our first view
Introduction to ASP.NET Core part 7: starting with MVC
Introduction to ASP.NET Core part 6: environments and settings
Introduction to ASP.NET Core part 5: static files
Introduction to ASP.NET Core part 4: middleware and the component pipeline
Introduction to ASP.NET Core part 3: the configuration file
Introduction to ASP.NET Core part 2: dependencies and dependency injection
Introduction to ASP.NET Core part 1: anatomy of an empty web project
- نصب آسان با استفاده از Nuget
- بدون نیاز به هیچگونه وب سرویس و یا دانش پیاده سازی سیستمهای پرداخت آنلاین
- پشتیبانی از درگاههای: ملت، ملی (سداد)، پارسیان، پاسارگاد، ایران کیش و سامان
- انجام پرداخت، فقط با نوشتن ۳ خط کد
- طراحی کاملا یکپارچه برای انجام عملیات پرداخت با تمامی بانکها
- رعایت نکات امنیتی پرداخت آنلاین
- درگاه مجازی، برای شبیه سازی عملیات پرداخت
- امکان استفاده از پروکسی برای سرورهای خارج از ایران در صورت نیاز
- استفاده از تکنولوژیهای مدرن و استاندارد
- قابل نصب بر روی پروژههای: ASP.NET Core, ASP.NET MVC, ASP.NET WebForms
- ASP.NET WebForms
- ASP.NET MVC
- ASP.NET CORE
- درخواست پرداخت
- تایید پرداخت
- بازگرداندن مبلغ پرداخت شده
- درگاهها
- HttpContext
- پایگاه داده
- پیامها
- ایجاد یک صورتحساب پرداخت با استفاده از InvoiceBuilder
- درگاه مجازی پرداخت
- استفاده از پروکسی
- توکن پرداخت
- تزریق وابستگی
- Logging
Install-Package Parbad.Owin
Install-Package Parbad.Mvc5
Install-Package Parbad.AspNetCore
dotnet add package Parbad.AspNetCore