اشتراکها
اشتراکها
استفاده از WebSocket در دات نت
اشتراکها
دریافت پوستر دنیای دات نت در 2014
در پروژه http://nopcommerce.codeplex.com استفاده از Repository جهت اجبار به رویکرد Command/Query بوده است.(البته اینطور برداشت میشود) جهت مطالعه
http://nopcommerce.codeplex.com/SourceControl/latest#src/Libraries/Nop.Data/EfRepository.cs
و همینطور جهت تست پذیری پروژه، راه حلهای اشاره شده را پیاده سازی کرده.
http://nopcommerce.codeplex.com/SourceControl/latest#src/Libraries/Nop.Data/EfRepository.cs
و همینطور جهت تست پذیری پروژه، راه حلهای اشاره شده را پیاده سازی کرده.
آشنایی با NUnit
NUnit یکی از فریم ورکهای آزمایش واحد سورس باز مخصوص دات نت فریم ورک است. (کلا در دات نت هرجایی دیدید که N ، به ابتدای برنامهای یا کتابخانهای اضافه شده یعنی نمونه منتقل شده از محیط جاوا به دات نت است. برای مثال NHibernate از Hibernate جاوا گرفته شده است و الی آخر)
این برنامه با سی شارپ نوشته شده است اما تمامی زبانهای دات نتی را پشتیبانی میکند (اساسا با زبان نوشته شده کاری ندارد و فایل اسمبلی برنامه را آنالیز میکند. بنابراین فرقی نمیکند که در اینجا چه زبانی بکار گرفته شده است).
ابتدا NUnit را دریافت نمائید:
http://nunit.org/index.php?p=download
یک برنامه ساده از نوع console را در VS.net آغاز کنید.
کلاس MyList را با محتوای زیر به پروژه اضافه کنید:
using System.Collections.Generic;
namespace sample
{
public class MyList
{
public static List<int> GetListOfIntItems(int numberOfItems)
{
List<int> res = new List<int>();
for (int i = 0; i < numberOfItems; i++)
res.Add(i);
return res;
}
}
}
اکنون بر روی نام پروژه در قسمت solution explorer کلیک راست کرده و گزینه add->new project را انتخاب کنید. نوع این پروژه را که متدهای آزمایش واحد ما را تشکیل خواهد داد، class library انتخاب کنید. با نام مثلا TestLibrary (شکل زیر).
با توجه به اینکه NUnit ، اسمبلی برنامه (فایل exe یا dll آنرا) آنالیز میکند، بنابراین میتوان پروژه تست را جدای از پروژه اصلی ایجاد نمود و مورد استفاده قرار داد.
پس از ایجاد پروژه class library ، باید ارجاعی از NUnit framework را به آن اضافه کنیم. به محل نصب NUnit مراجعه کرده (پوشه bin آن) و ارجاعی به فایل nunit.framework.dll را به پروژه اضافه نمائید (شکل زیر).
سپس فضاهای نام مربوطه را به کلاس آزمایش واحد خود اضافه خواهیم کرد:
using NUnit.Framework;
using NUnit.Framework.SyntaxHelpers;
سپس باید ویژگی جدیدی به نام TestFixture را به این کلاس اضافه کرد.
[TestFixture]
public class TestClass
سپس هر متدی که به عنوان متد آزمایش واحد نوشته میشود، باید دارای ویژگی Test باشد تا توسط NUnit بررسی گردد:
[Test]
public void TestGetListOfIntItems()
اکنون برای اینکه بتوانیم متد GetListOfIntItems برنامه خود را در پروژه دیگری تست کنیم، باید ارجاعی را به اسمبلی آن اضافه کنیم. همانند قبل، از منوی project گزینه add reference ، فایل exe برنامه کنسول خود را انتخاب کرده و ارجاعی از آنرا به پروژه class library اضافه میکنیم. بدیهی است امکان اینکه کلاس تست در همان پروژه هم قرار میگرفت وجود داشت و صرفا جهت جداسازی آزمایش از برنامه اصلی اینکار صورت گرفت.
پس از این مقدمات، اکنون متد آزمایش واحد ساده زیر را در نظر بگیرید:
[Test]
public void TestGetListOfIntItems()
{
const int count = 5;
List<int> items = sample.MyList.GetListOfIntItems(count);
Assert.That(items.Count,Is.EqualTo(5));
}
اگر آن را (سطر مربوط به Assert را) کلمه به کلمه بخواهیم به فارسی ترجمه کنیم به صورت زیر خواهد بود:
میخواهیم اثبات کنیم که count مربوط به شیء items مساوی 5 است.
پس از اضافه کردن متد فوق، پروژه را کامپایل نمائید.
اکنون برنامه nunit.exe را اجرا کنید تا NUnit IDE ظاهر شود (در همان دایرکتوری bin مسیر نصب NUnit قرار دارد).
از منوی File آن یک پروژه جدید را آغاز نموده و آنرا ذخیره کنید.
سپس از منوی project آن، با استفاده از گزینه add assembly ، فایل dll کتابخانه تست خود را اضافه نمائید.
احتمالا پس از انجام این عملیات بلافاصله با خطای زیر مواجه خواهید شد:
---------------------------
Assembly Not Loaded
---------------------------
System.ApplicationException : Unable to load TestLibrary because it is not located under
the AppBase
----> System.IO.FileNotFoundException : Could not load file or assembly
'TestLibrary' or one of its dependencies. The system cannot find the file specified.
For further information, use the Exception Details menu item.
همانطور که ملاحظه میکنید، NUnit با استفاده از قابلیتهای reflection در دات نت، اسمبلی را بارگذاری میکند و تمامی کلاسهایی که دارای ویژگی TestFixture باشند در آن لیست خواهد شد.
اکنون بر روی دکمه run کلیک کنید تا اولین آزمایش ما انجام شود. (شکل زیر)
رنگ سبز در اینجا به معنای با موفقیت انجام شدن آزمایش است.
ادامه دارد...
تا قبل از ES 6 در جاوا اسکریپت از توابع جهت ایجاد کامپوننتهایی با قابلیت استفاده مجدد استفاده میشد. این امر برای برنامهنویسانی که با زبانهای OOP آشنایی دارند، شاید چندان خوشایند نباشد. در TypeScript نیز همانند ES 6 امکان استفاده از کلاسها مهیا است.
سازنده (Constructor)
همانطور که مشاهده میکنید یک سازنده شبیه به یک متد است؛ با این تفاوت که برای نام آن از کلمه کلیدی constructor استفاده میشود. در TypeScript برای یک کلاس تنها یک سازنده را میتوانیم داشته باشیم. البته در دیگر زبانهای برنامهنویسی امکان تعریف چندین سازنده را با پارامترهای مختلف برای یک کلاس میتوانید داشته باشید. برای رسیدن به این هدف در TypeScript میتوان از Optional Parameters استفاده کرد. برای ایجاد یک وهله از کلاس فوق میتوانیم به این صورت عمل کنیم:
در کد فوق با استفاده از کلمهی کلیدی new یک وهله از کلاس ReferenceItem را ایجاد کردهایم و در نهایت آن را به متغیری با نام encyclopedia انتساب دادهایم. یعنی در واقع با استفاده از new توانستهایم سازندهی کلاس را فراخوانی کرده و سپس وهلهایی از آن را به متغیر ذکر شده انتساب دهیم.
پراپرتی، متد
برای دسترسی به این پراپرتی میتوانیم از سینتکس نقطه (.) استفاده کنیم. روش دوم برای تعریف یک پراپرتی، ایجاد accessorهای سفارشی است. accessors در واقع توابع getter و setter هستند که به شما در نحوهی get و set کردن یک پراپرتی کمک خواهند کرد:
همانطور که مشاهده میکنید، accessorهایی را برای پراپرتی editor با استفاده از کلمات کلیدی get و set ایجاد کردهایم. این accessorها در واقع توابعی همنام هستند. تابع get همیشه فاقد پارامتر است. میتوانیم برای تابع get نوع برگشتی را نیز تعیین کنیم (به عنوان مثال در کد فوق نوع برگشتی string است). setter نیز باید تنها یک پارامتر از ورودی دریافت کند. همچنین نمیتوانیم برای آن نوع برگشتی را تعیین کنیم. درون بدنهی این accessorها میتوانیم هر نوع کنترلی را بر روی پراپرتی داشته باشیم. برای دسترسی این accessorها نیز باید از سینتکس نقطه (.) استفاده کنیم.
Parameter properties
با کمک Parameter properties میتوانیم به صورت خلاصهتری اینکار را انجام دهیم:
همانطور که مشاهده میکنید اینکار را با افزودن کلمهی کلیدی public به ابتدای پارامتر name انجام دادهایم. در اینحالت دیگر نیازی به تعریف یک پراپرتی اضافی درون کلاس نخواهیم داشت. کامپایلر TypeScript خودش یک پراپرتی را با همین نام ایجاد کرده و مقدار دریافتی از سازنده را برای آن ست خواهد کرد.
Access Modifiers
همانطور که مشاهده میکنید با استفاده از کلمهی کلیدی extends توانستهایم یک sub-class ایجاد کنیم. بنابراین وهلههای کلاس Journal علاوه بر پراپرتیهای خود (در اینجا contributors ) دارای پراپرتی title و همچنین متد printItem نیز هستند. نکتهایی که در اینجا وجود دارد این است که تمامی sub-classها یا کلاسهای مشتق شده باید درون سازندهی خود، تابع super را فراخوانی کنند؛ با اینکار سازندهی کلاس پایه فراخوانی خواهد شد.
با استفاده از super.printItem به کامپایلر TypeScript گفتهایم که تمامی کدهای درون متد printItem در کلاس پایه نیز اجرا شوند. اگر مایل بودید میتوانید از آن صرفنظر کنید.
همانطور که مشاهده میکنید درون یک کلاس abstract میتوانیم متدهای abstract را نیز داشته باشیم؛ یعنی تنها امضای متد را تعیین کرده و پیادهسازی آن را به کلاسهای مشتق شده واگذار کنیم.
در حالت کلی یک کلاس قالبی برای ایجاد اشیاء است. تمامی اشیاء ایجاد شده از این الگو دارای یکسری پراپرتی و متد میباشند. از پراپرتیها جهت تعریف وضعیتها و از متدها جهت تعریف رفتارها استفاده خواهد شد. همچنین مزیت اصلی یک کلاس، کپسولهسازی قابلیتهای یک موجودیت خاص است. همانند دیگر زبانهای شیءگرا، در TypeScript نیز یک کلاس میتواند ویژگیهای زیر را داشته باشد:
- سازنده (constructor)
- پراپرتی، متد
- Access Modifiers
- ارثبری
- کلاسهای Abstract
در ادامه هر کدام از موارد فوق را بررسی خواهیم کرد.
سازنده (Constructor)
از سازندهها جهت مقداردهی وهلههای یک کلاس استفاده میشود. در ادامه یک کلاس جدید را با استفاده از کلمهی کلیدی class ایجاد کردهایم. این کلاس دارای یک سازنده است:
class ReferenceItem { constructor(title: string, publisher?: string) { // perform initialization here } }
let encyclopedia = new ReferenceItem('WorldPedia', 'WorldPub');
پراپرتی، متد
همانند اینترفیسها، کلاسها نیز میتوانند پراپرتی و متد داشته باشند. با این تفاوت که در کلاسها جزئیات پیادهسازی نیز ذکر خواهد شد. در یک کلاس به دو روش متفاوت میتوانیم پراپرتی را تعریف کنیم. روش اول همانند تعریف یک متغیر است. به عنوان مثال در کلاس زیر یک پراپرتی با نام numberOfPages را از نوع عددی تعریف کردهایم:
class ReferenceItem { numberOfPages: number; }
class ReferenceItem { numberOfPages: number; get editor(): string { // custom getter logic goes here, should return a value } set editor(newEditor: string) { // custom setter logic goes here } }
متدها نیز توابعی هستند که درون یک کلاس تعریف میشوند. برای نمونه در کد زیر یک تابع با نام printChapterTitle را تعریف کردهایم که یک پارامتر را از ورودی دریافت کرده و هیچ مقداری را در خروجی بر نمیگرداند:
class ReferenceItem { numberOfPages: number; get editor(): string { // custom getter logic goes here, should return a value } set editor(newEditor: string) { // custom setter logic goes here } printChapterTitle(chapterNum: number): void { // print title here } }
در حالت عادی برای مقداردهی اولیهی پراپرتیها یک شیء میتوانیم یکسری پارامتر را برای سازنده کلاس تعریف کرده و درون سازنده، پراپرتیهای موردنیازمان را مقداردهی کنیم:
class Author { name: string; constructor(authorName: string) { name = authorName; } }
class Author { constructor(public name: string){} }
Static Properties
تاکنون دربارهی اعضای مربوط به هر وهله از کلاسها صحبت کردیم؛ یعنی اعضایی که در زمان وهلهسازی در دسترس خواهند بود. در واقع میتوانیم اعضای استاتیک را نیز برای کلاسها داشته باشیم. منظور از استاتیک این است که مقادیر یک عضوء استاتیک در وهلههای مختلف یک شیء، متفاوت نیست. بلکه یک مقدار آن برای تمامی وهلهها به اشتراک گذاشته خواهد شد:
class Library { constructor(public name: string) {} static description: string = 'A source of knowledge'; } let lib = new Library('New York Public Library'); console.log(lib.name); // available on instances of the class console.log(Library.description);
با استفاده از Access Modifier میتوانیم میدان دید یک پراپرتی و یا یک متد را برای مصرف کنندهی کلاس کنترل کنیم. TypeScript دارای سه Access Modifier است:
public: در حالت پیشفرض تمامی اعضای یک کلاس عمومی (public) هستند. در نتیجه لزومی به ذکر آن برای پراپرتیها و متدها نیست. یک حالت استثناء، استفاده از Parameter properties است. در این حالت باید کلمهی کلیدی public حتماً ذکر شود.
private: برای محدود کردن دسترسی اعضای یک کلاس میتوانید از کلمهی کلیدی private استفاده کنید. در اینحالت مصرف کنندهی کلاس به اعضای خصوصی (private) دسترسی نخواهد داشت.
protected: این modifier نیز شبیه به private عمل میکند، با این تفاوت که توسط subclassهای مربوط به کلاس تعریف شده در آن نیز قابل دسترس است.
Inheritance
منظور از Inheritance یا ارثبری، اشتراکگذاری تعاریف یک کلاس برای یک یا چند sub-class است. فرض کنید یک کلاس با نام ReferenceItem با یکسری اعضای تعریف شده درون آن داریم و میخواهیم دو کلاس مشتق شده را از این کلاس تهیه کنیم. در اینحالت کلاس ReferenceItem کلاس پایه (base class) و کلاسهای مشتق شده از آن sub-class نامیده میشوند. بنابراین وهلههای ایجاد شده از کلاسهای مشتق شده دارای پراپرتیهای کلاس پایه نیز خواهند بود. برای داشتن قابلیت ارثبری در TypeScript میتوانیم به اینصورت عمل کنیم:
class ReferenceItem { title: string; printItem(): void { // print something here } } class Journal extends ReferenceItem { constructor() { super(); } contributors: string[]; }
لازم به ذکر است که میتوان متدهای کلاس پایه را درون کلاسهای مشتق شده، override کرد. برای اینکار کافی است متد موردنظر در کلاس پایه را درون کلاس مشتق شده مجدداً تعریف کرده و منطق موردنظر را درون آن نوشت:
class Journal extends ReferenceItem { constructor() { super(); } printItem(): void { super.printItem(); console.log('message from Journal'); } contributors: string[]; }
Abstract Classes
کلاسهای Abstract یک نوع خاص از کلاسها هستند که نمیتوان آنها را وهلهسازی کرد. یعنی تنها برای تعریف کلاسهای پایه از آنها استفاده خواهد شد. این نوع کلاسها شبیه به اینترفیسها هستند؛ اما ممکن است دارای پیادهسازی نیز باشند. در ادامه یک نمونه از abstract class را مشاهده میکنید:
abstract class ReferenceItem { private _publisher: string; static departement: string = 'Research'; constructor(public title: string, protected year: number) { } printItem(): void { console.log('message from abstract class'); } get publisher(): string { return this._publisher.toUpperCase(); } set publisher(newPublisher: string) { this._publisher = newPublisher; } abstract printCitation(): void; } class Encyclopedia extends ReferenceItem { constructor(newTitle: string, newYear, public edition: number) { super(newTitle, newYear); } printCitation(): void { console.log('message'); } } let test = new Encyclopedia('WorldPerdia', 1900, 10); test.printItem();
نظرات مطالب
متدهای الحاقی - Extension Methods
سلام
مشابه Class helper در دلفی است...
با بررسی فیلد مورد نظر در خروجی html تولید شده، میتوانید صحت عملکرد برنامه را بررسی کنید.
مثال زیر در این زمینه میباشد که مدل آن در یک class library دیگر است (البته در اینجا به جای استفاده از نام اکشن و نام کنترلر از نام روت استفاده شده است)
حالت اول: مدل برنامه در حالتی که فقط فیلد مورد نظر باید بررسی شود (ایجاد کاربر):
namespace Project.Models { public class EmployeeCreateModel { [Required] [Display(Name = "آدرس ایمیل")] [EmailAddress(ErrorMessage = "لطفاً {0} معتبر وارد کنید.")] [Remote("UserExistByEmailValidation", HttpMethod = "POST", ErrorMessage = "ایمیل وارد شده هم اکنون توسط یکی از کاربران مورد استفاده است.")] public string Email { get; set; } ... } }
- حالت دوم: مدل برنامه در حالتی که به جز فیلد مورد نظر باید یک فیلد دیگر نیز مورد بررسی قرار گیرد (ویرایش کاربر):
namespace Project.Models { public class EmployeeEditModel { public int Id { get; set; } [Required] [Display(Name = "آدرس ایمیل")] [EmailAddress(ErrorMessage = "لطفاً {0} معتبر وارد کنید.")] [Remote("EmailExistForOtherUserValidation", AdditionalFields = "Id", HttpMethod = "POST", ErrorMessage = "ایمیل وارد شده هم اکنون توسط یکی از کاربران مورد استفاده است.")] public string Email { get; set; } .... } }
namespace Project.Web.Controllers { [RoutePrefix("UserValidation")] [Route("{Action}")] [OutputCache(Location = OutputCacheLocation.None, NoStore = true)] public partial class UserValidationController : Controller { readonly IUserService<User> _userService; readonly IUnitOfWork _uow; public UserValidationController(IUnitOfWork uow, IUserService<User> userService) { _userService = userService; _uow = uow; } [HttpPost] [Route("~/CheckEmail", Name = "UserExistByEmailValidation")] public virtual JsonResult CheckEmail(string email) { return Json(!_userService.UserExistsByEmail(email)); } [HttpPost] [Route("~/CheckEmailForOtherUser", Name = "EmailExistForOtherUserValidation")] public virtual JsonResult CheckEmailForOtherUser(string email, int id) { return Json(!_userService.EmailExistForOtherUser(email, id)); } } }
- حالت اول:
- حالت دوم (فیلد Id هم ارسال میگردد):
در صورتی که خروجی درست بود، باید scriptها را مورد بررسی قرار دهید که یکی از متدوالترین آنها
@section Scripts { @Scripts.Render("~/bundles/jqueryval") }