نظرات مطالب
نظرات مطالب
زیباتر کد بنویسیم
خیلی خوب و کاربردی بود. البته شخصا بعضی وقتها مجبور هستم موارد ۴ و ۵ را به خاطر راحتی debug رعایت نکنم.
تست واحد چیست؟
تست واحد ابزاری است برای مشاهده چگونگی عملکرد یک متد که توسط خود برنامه نویس نوشته میشود. به این صورت که پارامترهای ورودی، برای یک متد ساخته شده و آن متد فراخوانی و خروجی متد بسته به حالت مطلوب بررسی میشود. چنانچه خروجی مورد نظر مطلوب باشد تست واحد با موفقیت انجام میشود.
اهمیت انجام تست واحد چیست؟
درستی یک متد، مهمترین مسئله برای بررسی است و بارها مشاهده شده، استثناهایی رخ میدهند که توان تولید را به دلیل فرسایش تکراری رخداد میکاهند. نوشتن تست واحد منجر به این میشود چناچه بعدها تغییری در بیزنس متد ایجاد شود و ورودی و خروجیها تغییر نکند، صحت این تغییر بیزنس، توسط تست بررسی مشود؛ حتی میتوان این تستها را در build پروژه قرار داد و در ابتدای اجرای یک Solution تمامی تستها اجرا و درستی بخش به بخش اعضا چک شوند.
شروع تست واحد:
یک پروژهی ساده را داریم برای تعریف حسابهای بانکی شامل نام مشتری، مبلغ سپرده، وضعیت و 3 متد واریز به حساب و برداشت از حساب و تغییر وضعیت حساب که به صورت زیر است:
تابع اصلی نیز به صورت زیر است:
به Solution، یک پروژه از نوع تست واحد اضافه میکنیم.
در این پروژه ابتدا Reference ایی از پروژهای که مورد تست هست میگیریم. سپس در کلاس تست مربوطه شروع به نوشتن متدی برای انواع تست متدهای پروژه اصلی میکنیم.
توجه داشته باشید که Data Annotationهای بالای کلاس تست و متدهای تست، در تعیین نوع نگاه کامپایلر به این بلوکها موثر است و باید این مسئله به درستی رعایت شود. همچنین در صورت نیاز میتوان از کلاس StartUp برای شروع تست استفاده کرد که عمدتا برای تعریف آن از نام ClassInit استفاده میشود و در بالای آن از [ClassInitialize] استفاده میشود.
در Library تست واحد میتوان به دو صورت چگونگی صحت عملکرد یک تست را بررسی کرد: با استفاده از Assert و با استفاده از ExpectedException، که در زیر به هر دو صورت آن میپردازیم.
همانطور که مشاهده میشود ابتدا در قسمت Arrange، خوراک تست آماده میشود. سپس در قسمت Act، فعالیتهایی که زیر ذره بین تست هستند صورت میپذیرند و سپس در قسمت Assert درستی مقادیر با مقادیر مورد انتظار ما مطابقت داده میشوند.
برای بررسی خطاهای تعیین شده هنگام نوشتن یک متد نیز میتوان به صورت زیر عمل کرد:
همانطور که مشخص است نام متد تست باید کامل و شفاف به صورتی انتخاب شود که بیانگر رخداد درون متد تست باشد. در این متدها Assert مورد انتظار با DataAnnotation که پیش از این توضیح داده شد کنترل گردیده است و بدین صورت کار میکند که وقتی Act انجام میشود، متد بررسی میکند تا آن Assert رخ بدهد.
استفاده از Library Moq در تست واحد
ابتدا باید به این توضیح بپردازیم که این کتابخانه چه کاری میکند و چه امکانی را برای انجام تست واحد فراهم میکند.
در پروژههای بزرگ و زمانی که ارتباطات بین لایهای زیادی موجود است و اصول SOLID رعایت میشود، شما در یک لایه برای ارایه فعالیتها و خدمات متدهایتان با Interfaceهای لایههای دیگر در ارتباط هستید و برای نوشتن تست واحد متدهایتان، مشکلی بزرگ دارید که نمیتوانید به این لایهها دسترسی داشته باشید و ماهیت تست واحد را زیر سوال میبرید. Library Moq این امکان را به شما میدهد که از این Interfaceها یک تصویر مجازی بسازید و همانند Snap Shot با آن کار کنید؛ بدون اینکه در لایههای دیگر بروید و ماهیت تست واحد را زیر سوال ببرید.
برای استفاده از متدهایی که در این Interfaceها موجود است شما باید یک شیء از نوع Mock<> از آنها بسازید و سپس با استفاده از متد Setup به صورت مجازی متد مورد نظر را فراخوانی کنید و مقدار بازگشتی مورد انتظار را با Return معرفی کنید، سپس از آن استفاده کنید.
همچنین برای دسترسی به خود شیء از Property ایی با نام Objet از موجودیت mock شده استفاده میکنیم.
برای شناسایی بهتر اینکه از چه اینترفیس هایی باید Mock<> بسازید، میتوانید به متد سازنده کلاسی که معرف لایه ایست که برای آن تست واحد مینویسید، مراجعه کنید.
نحوه اجرای یک تست واحد با استفاده از Moq با توجه به توضیحات بالا به صورت زیر است:
پروژه مورد بررسی لایه Service برای تعریف واحدهای سازمانی است که با الگوریتم DDD و CQRS پیاده سازی شده است.
ابتدا به Constructor خود لایه سرویس نگاه میکنیم تا بتوانید شناسایی کنید از چه Interface هایی باید Mock<> کنیم.
مشاهده میکنید که 4 Interface استفاده شده و در متد سازنده نیز مقدار دهی شده اند. پس 4 Mock نیاز داریم. در پروژه تست به صورت زیر و در ClassInitialize عمل میکنیم.
از خود لایه سرویس با نام OrganizationService یک آبجکت میگیریم و 4 واسط دیگر به صورت Mock شده تعریف میشوند. همچنین در کلاس بارگذار از همان نوع مقدار دهی میگردند تا در اجرای تمامی متدهای تست، در دست کامپایلر باشند. همچنین برای new کردن خود سرویس از mock.obectها که حاوی مقدار اصلی است استفاده میکنیم.
خود متد اصلی به صورت زیر است:
متدهای تست این متد نیز به صورت زیر هستند:
همانطور که مشاهده میشود ابتدا یک Guid به عنوان آی دی نوع واحد سازمانی گرفته میشود و همان آی دی برای تعریف کامند حذف به آن ارسال میشود. سپس یک نوع واحد سازمانی دلخواه تستی ساخته میشود و همچنین یک لیست خالی از واحدهای سازمانی که برای چک شدن توسط خود متد Handle استفاده شدهاست ساخته میشود. در اینجا این متد خالی است تا شرط غلط شود و عمل حذف به درستی صورت پذیرد.
برای اعمالی که در Handle انجام میشود و متدهایی که از Interfaceها صدا زده میشوند Setup میکنیم و آنهایی را که Return دارند به object هایی که مورد انتظار خودمان هست نسبت میدهیم.
در Setup اول میگوییم که آن Guid مربوط به "خوشه" است. در Setup بعدی برای عمل Remove کدی مینویسیم و چون عمل حذف Return ندارد میتواند، این خط به کل حذف شود! به طور کلی Setup هایی که Return ندارند میتوانند حذف شوند.
در Setup بعدی از Interface دیگر متد FindBy که قرار است چک کند این نوع واحد سازمانی برای تعریف واحد سازمانی استفاده شده است، در Return به آن یک لیست خالی اختصاص میدهیم تا نشان دهیم لیست خالی برگشته است.
عملیات Act را وارد Try میکنیم تا اگر به هر دلیل انجام نشد، Assert ما باشد.
دو حالت رخداد استثناء که در متد اصلی تست شده است در دو متد تست به طور جداگانه تست گردیده است:
متد DeleteUnitTypeCommand_ShouldNot_Delete_When_UnitTypeId_NotExist همانطور که از نامش معلوم است بررسی میکند که نوع واحد سازمانی که ID آن برای حذف ارسال میشود در Database وجود دارد و اگر نباشد Exception مطلوب ما باید داده شود.
در متد DeleteUnitTypeCommand_ShouldNot_Delete_When_UnitType_Exist_but_UsedForDefineOrganizationUnit بررسی میشود که از این نوع واحد سازمانی برای تعریف واحد سازمانی استفاده شده است یا نه و صحت این مورد با الگوی Specification صورت گرفته است. استثنای مطلوب ما Assert و شرط درستی این متد تست، میباشد.
تست واحد ابزاری است برای مشاهده چگونگی عملکرد یک متد که توسط خود برنامه نویس نوشته میشود. به این صورت که پارامترهای ورودی، برای یک متد ساخته شده و آن متد فراخوانی و خروجی متد بسته به حالت مطلوب بررسی میشود. چنانچه خروجی مورد نظر مطلوب باشد تست واحد با موفقیت انجام میشود.
اهمیت انجام تست واحد چیست؟
درستی یک متد، مهمترین مسئله برای بررسی است و بارها مشاهده شده، استثناهایی رخ میدهند که توان تولید را به دلیل فرسایش تکراری رخداد میکاهند. نوشتن تست واحد منجر به این میشود چناچه بعدها تغییری در بیزنس متد ایجاد شود و ورودی و خروجیها تغییر نکند، صحت این تغییر بیزنس، توسط تست بررسی مشود؛ حتی میتوان این تستها را در build پروژه قرار داد و در ابتدای اجرای یک Solution تمامی تستها اجرا و درستی بخش به بخش اعضا چک شوند.
شروع تست واحد:
یک پروژهی ساده را داریم برای تعریف حسابهای بانکی شامل نام مشتری، مبلغ سپرده، وضعیت و 3 متد واریز به حساب و برداشت از حساب و تغییر وضعیت حساب که به صورت زیر است:
/// <summary> /// حساب بانکی /// </summary> public class Account { /// <summary> /// مشتری /// </summary> public string Customer { get; set; } /// <summary> /// موجودی حساب /// </summary> public float Balance { get; set; } /// <summary> /// وضعیت /// </summary> public bool Active { get; set; } public Account(string customer, float balance) { Customer = customer; Balance = balance; Active = true; } /// <summary> /// افزایش موجودی / واریز به حساب /// </summary> /// <param name="amount">مبلغ واریز</param> public void Credit(float amount) { if (!Active) throw new Exception("این حساب مسدود است."); if (amount < 0) throw new ArgumentOutOfRangeException("amount"); Balance += amount; } /// <summary> /// کاهش موجودی / برداشت از حساب /// </summary> /// <param name="amount">مبلغ برداشت</param> public void Debit(float amount) { if (!Active) throw new Exception("این حساب مسدود است."); if (amount < 0) throw new ArgumentOutOfRangeException("amount"); if (Balance < amount) throw new ArgumentOutOfRangeException("amount"); Balance -= amount; } /// <summary> /// انسداد / رفع انسداد /// </summary> public void ChangeStateAccount() { Active = !Active; } }
class Program { static void Main(string[] args) { var account = new Account("Ali",1000); account.Credit(4000); account.Debit(2000); Console.WriteLine("Current balance is ${0}", account.Balance); Console.ReadKey(); } }
در این پروژه ابتدا Reference ایی از پروژهای که مورد تست هست میگیریم. سپس در کلاس تست مربوطه شروع به نوشتن متدی برای انواع تست متدهای پروژه اصلی میکنیم.
توجه داشته باشید که Data Annotationهای بالای کلاس تست و متدهای تست، در تعیین نوع نگاه کامپایلر به این بلوکها موثر است و باید این مسئله به درستی رعایت شود. همچنین در صورت نیاز میتوان از کلاس StartUp برای شروع تست استفاده کرد که عمدتا برای تعریف آن از نام ClassInit استفاده میشود و در بالای آن از [ClassInitialize] استفاده میشود.
در Library تست واحد میتوان به دو صورت چگونگی صحت عملکرد یک تست را بررسی کرد: با استفاده از Assert و با استفاده از ExpectedException، که در زیر به هر دو صورت آن میپردازیم.
[TestClass] public class UnitTest { /// <summary> /// تعریف حساب جدید و بررسی تمامی فرآیندهای معمول روی حساب /// </summary> [TestMethod] public void Create_New_Account_And_Check_The_Process() { //Arrange var account = new Account("Hassan", 4000); var account2 = new Account("Ali", 10000); //Act account.Credit(5000); account2.Debit(3000); account.ChangeStateAccount(); account2.Active = false; account2.ChangeStateAccount(); //Assert Assert.AreEqual(account.Balance,9000); Assert.AreEqual(account2.Balance,7000); Assert.IsTrue(account2.Active); Assert.AreEqual(account.Active,false); }
برای بررسی خطاهای تعیین شده هنگام نوشتن یک متد نیز میتوان به صورت زیر عمل کرد:
/// <summary> /// زمانی که کاربر بخواهد به یک حساب مسدود واریز کند باید جلوی آن گرفته شود. /// </summary> [TestMethod] [ExpectedException(typeof (Exception))] public void When_Deactive_Account_Wants_To_add_Credit_Should_Throw_Exception() { //Arrange var account = new Account("Hassan", 4000) {Active = false}; //Act account.Credit(4000); //Assert //Assert is handled with ExpectedException } [TestMethod] [ExpectedException(typeof (ArgumentOutOfRangeException))] public void When_Customer_Wants_To_Debit_More_Than_Balance_Should_Throw_ArgumentOutOfRangeException() { //Arrange var account = new Account("Hassan", 4000); //Act account.Debit(5000); //Assert //Assert is handled with ArgumentOutOfRangeException }
استفاده از Library Moq در تست واحد
ابتدا باید به این توضیح بپردازیم که این کتابخانه چه کاری میکند و چه امکانی را برای انجام تست واحد فراهم میکند.
در پروژههای بزرگ و زمانی که ارتباطات بین لایهای زیادی موجود است و اصول SOLID رعایت میشود، شما در یک لایه برای ارایه فعالیتها و خدمات متدهایتان با Interfaceهای لایههای دیگر در ارتباط هستید و برای نوشتن تست واحد متدهایتان، مشکلی بزرگ دارید که نمیتوانید به این لایهها دسترسی داشته باشید و ماهیت تست واحد را زیر سوال میبرید. Library Moq این امکان را به شما میدهد که از این Interfaceها یک تصویر مجازی بسازید و همانند Snap Shot با آن کار کنید؛ بدون اینکه در لایههای دیگر بروید و ماهیت تست واحد را زیر سوال ببرید.
برای استفاده از متدهایی که در این Interfaceها موجود است شما باید یک شیء از نوع Mock<> از آنها بسازید و سپس با استفاده از متد Setup به صورت مجازی متد مورد نظر را فراخوانی کنید و مقدار بازگشتی مورد انتظار را با Return معرفی کنید، سپس از آن استفاده کنید.
همچنین برای دسترسی به خود شیء از Property ایی با نام Objet از موجودیت mock شده استفاده میکنیم.
برای شناسایی بهتر اینکه از چه اینترفیس هایی باید Mock<> بسازید، میتوانید به متد سازنده کلاسی که معرف لایه ایست که برای آن تست واحد مینویسید، مراجعه کنید.
نحوه اجرای یک تست واحد با استفاده از Moq با توجه به توضیحات بالا به صورت زیر است:
پروژه مورد بررسی لایه Service برای تعریف واحدهای سازمانی است که با الگوریتم DDD و CQRS پیاده سازی شده است.
ابتدا به Constructor خود لایه سرویس نگاه میکنیم تا بتوانید شناسایی کنید از چه Interface هایی باید Mock<> کنیم.
public class OrganizationalService : ICommandHandler<CreateUnitTypeCommand>, ICommandHandler<DeleteUnitTypeCommand>, { private readonly IUnitOfWork _unitOfWork; private readonly IUnitTypeRepository _unitTypeRepository; private readonly IOrganizationUnitRepository _organizationUnitRepository; private readonly IOrganizationUnitDomainService _organizationUnitDomainService; public OrganizationalService(IUnitOfWork unitOfWork, IUnitTypeRepository unitTypeRepository, IOrganizationUnitRepository organizationUnitRepository, IOrganizationUnitDomainService organizationUnitDomainService) { _unitOfWork = unitOfWork; _unitTypeRepository = unitTypeRepository; _organizationUnitRepository = organizationUnitRepository; _organizationUnitDomainService = organizationUnitDomainService; }
[TestClass] public class OrganizationServiceTest { private static OrganizationalService _organizationalService; private static Mock<IUnitTypeRepository> _mockUnitTypeRepository; private static Mock<IUnitOfWork> _mockUnitOfWork; private static Mock<IOrganizationUnitRepository> _mockOrganizationUnitRepository; private static Mock<IOrganizationUnitDomainService> _mockOrganizationUnitDomainService; [ClassInitialize] public static void ClassInit(TestContext context) { TestBootstrapper.ConfigureDependencies(); _mockUnitOfWork = new Mock<IUnitOfWork>(); _mockUnitTypeRepository = new Mock<IUnitTypeRepository>(); _mockOrganizationUnitRepository = new Mock<IOrganizationUnitRepository>(); _mockOrganizationUnitDomainService=new Mock<IOrganizationUnitDomainService>(); _organizationalService = new OrganizationalService(_mockUnitOfWork.Object, _mockUnitTypeRepository.Object, _mockOrganizationUnitRepository.Object,_mockOrganizationUnitDomainService.Object); }
خود متد اصلی به صورت زیر است:
/// <summary> /// یک نوع واحد سازمانی را حذف مینماید /// </summary> /// <param name="command"></param> public void Handle(DeleteUnitTypeCommand command) { var unitType = _unitTypeRepository.FindBy(command.UnitTypeId); if (unitType == null) throw new DeleteEntityNotFoundException(); ICanDeleteUnitTypeSpecification canDeleteUnitType = new CanDeleteUnitTypeSpecification(_organizationUnitRepository); if (canDeleteUnitType.IsSatisfiedBy(unitType)) throw new UnitTypeIsUnderUsingException(unitType.Title); _unitTypeRepository.Remove(unitType); }
/// <summary> /// کامند حذف نوع واحد سازمانی باید به درستی حذف کند. /// </summary> [TestMethod] public void DeleteUnitTypeCommand_Should_Delete_UnitType() { //Arrange var unitTypeId=new Guid(); var deleteUnitTypeCommand = new DeleteUnitTypeCommand { UnitTypeId = unitTypeId }; var unitType = new UnitType("خوشه"); var org = new List<OrganizationUnit>(); _mockUnitTypeRepository.Setup(d => d.FindBy(deleteUnitTypeCommand.UnitTypeId)).Returns(unitType); _mockUnitTypeRepository.Setup(x => x.Remove(unitType)); _mockOrganizationUnitRepository.Setup(z => z.FindBy(unitType)).Returns(org); try { //Act _organizationalService.Handle(deleteUnitTypeCommand); } catch (Exception ex) { //Assert Assert.Fail(ex.Message); } }
برای اعمالی که در Handle انجام میشود و متدهایی که از Interfaceها صدا زده میشوند Setup میکنیم و آنهایی را که Return دارند به object هایی که مورد انتظار خودمان هست نسبت میدهیم.
در Setup اول میگوییم که آن Guid مربوط به "خوشه" است. در Setup بعدی برای عمل Remove کدی مینویسیم و چون عمل حذف Return ندارد میتواند، این خط به کل حذف شود! به طور کلی Setup هایی که Return ندارند میتوانند حذف شوند.
در Setup بعدی از Interface دیگر متد FindBy که قرار است چک کند این نوع واحد سازمانی برای تعریف واحد سازمانی استفاده شده است، در Return به آن یک لیست خالی اختصاص میدهیم تا نشان دهیم لیست خالی برگشته است.
عملیات Act را وارد Try میکنیم تا اگر به هر دلیل انجام نشد، Assert ما باشد.
دو حالت رخداد استثناء که در متد اصلی تست شده است در دو متد تست به طور جداگانه تست گردیده است:
/// <summary> /// کامند حذف یک نوع واحد سازمانی باید پیش از حذف بررسی کند که این شناسه داده شده برای حذف موجود باشد. /// </summary> [TestMethod] [ExpectedException(typeof(DeleteEntityNotFoundException))] public void DeleteUnitTypeCommand_ShouldNot_Delete_When_UnitTypeId_NotExist() { //Arrange var unitTypeId = new Guid(); var deleteUnitTypeCommand = new DeleteUnitTypeCommand(); var unitType = new UnitType("خوشه"); var org = new List<OrganizationUnit>(); _mockUnitTypeRepository.Setup(d => d.FindBy(unitTypeId)).Returns(unitType); _mockUnitTypeRepository.Setup(x => x.Remove(unitType)); _mockOrganizationUnitRepository.Setup(z => z.FindBy(unitType)).Returns(org); //Act _organizationalService.Handle(deleteUnitTypeCommand); } /// <summary> /// کامند حذف یک نوع واحد سازمانی نباید اجرا شود وقتی که نوع واحد برای تعریف واحدهای سازمان استفاده شده است. /// </summary> [TestMethod] [ExpectedException(typeof(UnitTypeIsUnderUsingException))] public void DeleteUnitTypeCommand_ShouldNot_Delete_When_UnitType_Exist_but_UsedForDefineOrganizationUnit() { //Arrange var unitTypeId = new Guid(); var deleteUnitTypeCommand = new DeleteUnitTypeCommand { UnitTypeId = unitTypeId }; var unitType = new UnitType("خوشه"); var org = new List<OrganizationUnit>() { new OrganizationUnit("مدیریت یک", unitType, null), new OrganizationUnit("مدیریت دو", unitType, null) }; _mockUnitTypeRepository.Setup(d => d.FindBy(deleteUnitTypeCommand.UnitTypeId)).Returns(unitType); _mockUnitTypeRepository.Setup(x => x.Remove(unitType)); _mockOrganizationUnitRepository.Setup(z => z.FindBy(unitType)).Returns(org); //Act _organizationalService.Handle(deleteUnitTypeCommand); }
در متد DeleteUnitTypeCommand_ShouldNot_Delete_When_UnitType_Exist_but_UsedForDefineOrganizationUnit بررسی میشود که از این نوع واحد سازمانی برای تعریف واحد سازمانی استفاده شده است یا نه و صحت این مورد با الگوی Specification صورت گرفته است. استثنای مطلوب ما Assert و شرط درستی این متد تست، میباشد.
پیش از ادامهی نوشتار بهتر است توضیحاتی دربارهی قالبهای T4 داده شود. این قالبهای مصنوعی حاوی کدهایی که است که هدف آن صرفهجویی در نوشتن کد توسط برنامه نویس است. مثلاً در MVC شما یکبار قالبی برای صفحه Index خود تهیه میکنید که برای نمونه بجای ساخت جدول ساده، از گرید Kendo استفاده کند و همچنین دارای دکمه ویرایش و جزئیات باشد. از این پس هر بار که نیاز به ساخت یک نمای نوع لیست برای یک ActionResult داشته باشید فرم ساز MVC از قالب شما استفاده خواهد کرد. روشن است که خود Visual Studio نیز از T4 در ساخت بسیاری از فرمها و کلاسها بهره میبرد.
خبر خوب اینکه برای ساخت کلاسهای هر موجودیت در Entity Framework نیز از قالبهای T4 استفاده میشود و اینکه این قالبها در دسترس توسعهدهندگان برای ویرایش یا افزودن است.
افزونهی Tangible را دریافت کنید و سپس نصب کنید. این افزونه ظاهر نامفهوم قالبهای T4 را ساده و روشن میکند.
ما نیاز داریم که خود Visual Studio زحمت این سه کار را بکشد:
1- بالای هر کلاس موجودیت عبارت using System.Runtime.Serialization; را بنویسید.
2- صفت [DataContract] را پیش از تعریف کلاس بیفزاید.
3- صفت [DataMember] را پیش از تعریف هر ویژگی بیفزاید.
همانند شکل زیر روی فایل MyNewsModel.tt دوکلیک کنید تا محتوای آن در سمت چپ نشان داده شود. این محتوا باید ظاهری همانند شکل پیدا کرده باشد:
کد زیر را در محتوای فایل جستوجو کنید:
public string Property(EdmProperty edmProperty) { return string.Format( CultureInfo.InvariantCulture, "{0} {1} {2} {{ {3}get; {4}set; }}", Accessibility.ForProperty(edmProperty), _typeMapper.GetTypeName(edmProperty.TypeUsage), _code.Escape(edmProperty), _code.SpaceAfter(Accessibility.ForGetter(edmProperty)), _code.SpaceAfter(Accessibility.ForSetter(edmProperty))); }
public string Property(EdmProperty edmProperty) { return string.Format( CultureInfo.InvariantCulture, "[DataMember]" + Environment.NewLine + "{0} {1} {2} {{ {3}get; {4}set; }}", Accessibility.ForProperty(edmProperty), _typeMapper.GetTypeName(edmProperty.TypeUsage), _code.Escape(edmProperty), _code.SpaceAfter(Accessibility.ForGetter(edmProperty)), _code.SpaceAfter(Accessibility.ForSetter(edmProperty))); }
public string EntityClassOpening(EntityType entity) { return string.Format( CultureInfo.InvariantCulture, "{0} {1}partial class {2}{3}", Accessibility.ForType(entity), _code.SpaceAfter(_code.AbstractOption(entity)), _code.Escape(entity), _code.StringBefore(" : ", _typeMapper.GetTypeName(entity.BaseType))); }
این کد را نیز به این صورت تغییر دهید:
public string EntityClassOpening(EntityType entity) { return string.Format( CultureInfo.InvariantCulture, "[DataContract]" + Environment.NewLine + "{0} {1}partial class {2}{3}", Accessibility.ForType(entity), _code.SpaceAfter(_code.AbstractOption(entity)), _code.Escape(entity), _code.StringBefore(" : ", _typeMapper.GetTypeName(entity.BaseType))); }
public string UsingDirectives(bool inHeader, bool includeCollections = true) { return inHeader == string.IsNullOrEmpty(_code.VsNamespaceSuggestion()) ? string.Format( CultureInfo.InvariantCulture, "{0}using System;{1}" + "{2}", inHeader ? Environment.NewLine : "", includeCollections ? (Environment.NewLine + "using System.Collections.Generic;") : "", inHeader ? "" : Environment.NewLine) : ""; }
public string UsingDirectives(bool inHeader, bool includeCollections = true) { return inHeader == string.IsNullOrEmpty(_code.VsNamespaceSuggestion()) ? string.Format( CultureInfo.InvariantCulture, "using System.Runtime.Serialization;" + Environment.NewLine + "{0}using System;{1}" + "{2}", inHeader ? Environment.NewLine : "", includeCollections ? (Environment.NewLine + "using System.Collections.Generic;") : "", inHeader ? "" : Environment.NewLine) : ""; }
فایل MyNewsModel.tt را ذخیره کنید و از آن خارج شوید. بار دیگر هر کدام از کلاسهای tblNews و tblCategory را باز کنید. خواهید دید که به صورت خودکار تغییرات مد نظر ما به آن افزوده شده است. از این پس بدون هیچ دلواپسی بابت حذف صفتها، میتوانید هرچند بار که خواستید مدل خود را بههنگام کنید.
در بخش پسین دوباره به WCF بازخواهیم گشت و به تعریف روالهای مورد نیاز خواهیم پرداخت.
نظرات مطالب
معرفی Kendo UI
- این مشکل از محل تعریف jQuery هست. بررسی کنید در فایل layout، تعریف مدخل jQuery قبل از تعریف section JavaScript فوق باشد. اگر پس از آن باشد یا حتی jQuery چندبار در صفحه شروع شده باشد، این مشکل را خواهید داشت.
+ از ASP.NET MVC 4 به بعد، نیازی به ذکر Url.Content در Viewها نیست و Razor قابلیت پردازش ~ را هم پیدا کردهاست؛ یعنی میتواند از تعاریفی مانند "src="~/path/file.js استفاده کند.
+ از ASP.NET MVC 4 به بعد، نیازی به ذکر Url.Content در Viewها نیست و Razor قابلیت پردازش ~ را هم پیدا کردهاست؛ یعنی میتواند از تعاریفی مانند "src="~/path/file.js استفاده کند.
jQuery یا کلا JavaScript یعنی کدهای سمت کاربر. بنابراین این کدها باید دسترسی رسیدن به مدخل سمت سرور را داشته باشند و اگر عموم از آن منع شده باشند، یک اسکریپت معمولی هم بدیهی است که دسترسی خاصی نخواهد داشت چون سمت سرور اجرا نمیشود. فقط نتیجه عملیات آن به سمت سرور Post میشود.
یکی از کارهای متداول سمت سرور جهت منع عموم و فقط دسترسی دادن به jQuery مورد زیر است:
«بررسی امنیتی، حین استفاده از jQuery Ajax»
یکی از کارهای متداول سمت سرور جهت منع عموم و فقط دسترسی دادن به jQuery مورد زیر است:
«بررسی امنیتی، حین استفاده از jQuery Ajax»
نظرات اشتراکها
ایجاد یک موتور جستجوی سفارشی جهت search bar فایرفاکس
خیلی مفید هست این لیست
فقط میشه بگین این فایرفاکس رو فقط برا توسعه وب استفاده میکتید یا برا وب گردی هم از همین استفاده میکنید. آخه هیچ افزونه ای مثلا برا مدیریت یوزر پس سایتها یا واسه بوکمارک و read later و از موارد نیست توش آخه
ولی خیلی افزونههای کاربردی هستن خداییش
100 تا تشکر از لیستتون
فقط میشه بگین این فایرفاکس رو فقط برا توسعه وب استفاده میکتید یا برا وب گردی هم از همین استفاده میکنید. آخه هیچ افزونه ای مثلا برا مدیریت یوزر پس سایتها یا واسه بوکمارک و read later و از موارد نیست توش آخه
ولی خیلی افزونههای کاربردی هستن خداییش
100 تا تشکر از لیستتون
برای تغییر نوع کتابخانه ای Kendo.DynamicLinq از netstandard2 به netcoreapp1.1 چه افزونههای باید نصب کرد؟
تا جای که معلومه System.Runtime.Serialization مخصوص netstandard2 و هنوز به netcoreapp1.1 نیومده!
آیا این کتابخانه Kendo.DynamicLinqCore جایگزین کاملی برای این کتاب خانه Kendo.DynamicLinq میباشد؟
مشکل من این جاهست پروژهی بنده Asp.net core 1.1 هست و نمیشود از کتابخانه Kendo.DynamicLinq استفاده کرد
- موجودیتهای مشترک بین افزونهها را در یک پروژهی مجزا قرار دهید؛ مانند: CommonEntities
- از این پروژهی مشترک، ارجاعی را به افزونههای مورد نظر اضافه کنید.
پروژهی جاری جهت افزودن کلید خارجی به کاربران مشترک بین تمام افزونهها به روز شد، با این تغییرات و با این خروجی (که در آن در هر دو افزونهی تعریف شده، ارجاعی به کلاس User مشترک هست):
- از این پروژهی مشترک، ارجاعی را به افزونههای مورد نظر اضافه کنید.
پروژهی جاری جهت افزودن کلید خارجی به کاربران مشترک بین تمام افزونهها به روز شد، با این تغییرات و با این خروجی (که در آن در هر دو افزونهی تعریف شده، ارجاعی به کلاس User مشترک هست):
برای یک برنامه وب روشهای سادهتری هم برای نمایش یا دستکاری اطلاعات روی صفحه هست. مثلا مانند مطلب تغییر تاریخ وبلاگهای بلاگر در همین سایت. یا حتی میشه اینکار رو با افزونههای مرورگرها نیز انجام داد. اتفاقا خیلی هم مرسوم است این روش. این هم یک مثال خاصش در مورد شیرپوینت.