نظرات مطالب
تغییرات بوجود آمده در Bundling and Minification -MVC4
- با توجه به محتوای فایل هست و این محاسبات فقط بر اساس درخواست مرورگر انجام می‌شود. یعنی هربار به ازای نمایش صفحات این کارها و محاسبات صورت نمی‌گیرد و اگر کش شده باشد (که شده برای یکسال)، اصلا فشاری به سرور وارد نمی‌شود چون مرورگر برای موارد کش شده درخواست جدیدی را به سرور ارسال نمی‌کند.
- نگارش تولیدی بر اساس هش محتوای فایل محاسبه می‌شود به صورت خودکار.
- در وب فرم‌ها هم این قابلیت مدتی هست که وجود دارد: (^)
مطالب
محاسبه NOPS برای سرور شیرپوینت
NOPS یا Normalized User Operations Per Second ، عملیات کاربر نرمال در هر ثانیه است که در سرور‌ها برای محاسبه بار وارده بر سرور محاسبه می‌شود . و تعداد آن ، در حقیقت عددی است که تعداد کل عملکرد‌های کاربران معمولی و نرمال را در یک روز معمولی نشان می‌دهد . برای سرور‌های شیرپوینت نیز محاسبه آن پیشنهاد شده است .
توسط این عدد ، شما می‌توانید تعداد کاربرهای قابل پشتیبانی خود را تخمین زده و سخت افزار مورد نیاز را تهیه کنید
 فرمول کلی و ثابت شده زیر ، برای این منظور استفاده می‌شود : 

موارد فوق تقریبا واضح هستند که فقط 2 مورد از آنها را توضیح می‌دهم :
مورد D یعنی peak Factor ، مقداری بین 1 تا 10 است که برای نشان دادن ساعات پیک در طول ساعت کاری استفاده می‌شود . برای مثال اگر سازمانی از از 9 صبح تا 5 بعد از ظهر کار کند ، می‌توان به جرات گفت که اکثر کامندان روز کاری خود را با باز کردن محیط برنامه شیرپوینت آغاز می‌کنند که یک پیک محسوب می‌شود . سپس دقیقا بعد از نهار ، استفاده در حد پیک می‌شود . مقدار Peak Factor برابر 1 به این معنی است که هیچ بارگذاری پیکی وجود ندارد . و peak factor برابر 10 بیانگر این است که تمام آن، پیک محسوب می‌شود . به طور معمول برای یک سازمان این عدد تا سقف 5 بیان می‌شود . اگر می‌خواهید محافظ کارانه برخورد کنید ، تا سقف 7 محاسبه کنید .
 
مورد بعدی C است که تعداد عملکرد به ازای کاربر فعال در روز است . این مقدار نیز که عددی بین 1 تا 10 است ،  با میزان بهره برداری از محیط شیرپوینت در ارتباط است . مقدار 1 به این معنی است که کاربران شما تقریبا هیچ زمانی را به استفاده از شیرپوینت اختصاص نمی‌دهند و مقدار 10 به معنی این است که کاربران تمام روز خود را مشغول کارکردن با شیرپوینت هستند . برای یک سازمان می‌تواند این مقدار عددی نزدیک به 10 باشد . 
برای اطلاعات بیشتر در این زمینه می‌توانید به Appendix A از کتاب Sharepoint Administration و یا مقاله Calculating Bandwidth Requirements to Support Regional Users  مراجعه نمایید
  
پاسخ به بازخورد‌های پروژه‌ها
مشکل در نمایش حروف انگلیسی HtmlHeader
در فضای نام PdfRpt.Core.Helper یک متد الحاقی به نام FixWeakCharacters وجود دارد که دقیقا برای همین مورد اضافه کردم:
var subNote = @"بدهی پیشین طبق صورتحساب شماره 454 تاریخ 1391/08/05 و کسورات قانونی طبق ماده 33 محاسبه می‌گردد(255/12)";
//نکته: در متن فوق برای اینکه تاریخ برعکس نمایش داده نشود نیاز است به نحو زیر عمل شود
subNote = subNote.FixWeakCharacters();


بازخوردهای پروژه‌ها
افزودن متد محاسبه زمان سپری شده
با سلام
پیشنهاد میشه یه متد برای محاسبه مدت زمان سپری شده با دریافت زمان از ورودی به صورت رشته و تبدیل به حروف هم به پروژه اضافه کنین.
به طور مثال:
این رشته
string s="2 12:10:45";
به دو صورت زیر تبدیل شود
string s="دو روز و دوازده ساعت و ده دقیقه و چهل و پنج ثانیه";

string s="2 روز و 12 ساعت و 10 دقیقه و 45 ثانیه";

مطالب
C# 7 - Tuple return types and deconstruction
روش‌های زیادی برای بازگشت چندین مقدار از یک متد وجود دارند؛ مانند استفاده‌ی از آرایه‌ها برای بازگشت اشیایی از یک جنس، ایجاد یک کلاس سفارشی با خواص متفاوت و استفاده از پارامترهای out و ref همانند روش‌های متداول در C و ++C. در این بین روش دیگری نیز به نام Tuples از زمان NET 4.0. برای بازگشت چندین شیء با نوع‌های مختلف، ارائه شده‌است که در C# 7 نحوه‌ی تعریف و استفاده‌ی از آن‌ها بهبود قابل ملاحظه‌ای یافته‌است.


Tuple چیست؟

هدف از کار با Tupleها، عدم تعریف یک کلاس جدید به همراه خواص آن، جهت بازگشت بیش از یک مقدار از یک متد، توسط وهله‌ای از این کلاس جدید می‌باشد. برای مثال اگر بخواهیم از متدی، دو مقدار شهر و ناحیه را بازگشت دهیم، یک روش آن، ایجاد کلاس مکان زیر است:
public class Location   
{ 
     public string City { get; set; } 
     public string State { get; set; } 
 
     public Location(string city, string state) 
     { 
           City = city; 
           State = state; 
     } 
}
و سپس، وهله سازی و بازگشت آن:
 var location = new Location("Lake Charles","LA");
اما توسط Tuples، بدون نیاز به تعریف یک کلاس جدید، باز هم می‌توان به همین دو خروجی، دسترسی یافت:
 var location = new Tuple<string,string>("Lake Charles","LA");   
// Print out the address
var address = $"{location.Item1}, {location.Item2}";


مشکلات نوع Tuple در نگارش‌های قبلی دات نت

هرچند Tuples از زمان دات نت 4 در دسترس هستند، اما دارای این کمبودها و مشکلات می‌باشند:
static Tuple<int, string, string> GetHumanData()
{
   return Tuple.Create(10, "Marcus", "Miller");
}
الف) پارامترهای خروجی آن‌ها ثابت و با نام‌هایی مانند Item1، Item2 و امثال آن هستند که در حین استفاده، به علت ضعف نامگذاری، کاربرد آن‌ها دقیقا مشخص نیست و کاملا بی‌معنا هستند:
 var data = GetHumanData();
Console.WriteLine("What is this value {0} or this {1}",  data.Item1, data.Item3);
ب) Reference Type هستند (کلاس هستند) و در زمان وهله سازی، میزان مصرف حافظه‌ی بیشتری را نسبت به Value Types (معادل Tuples در C# 7) دارند.
ج) Tuples در دات نت 4، صرفا یک کتابخانه‌ی اضافه شده‌ی به فریم ورک بوده و زبان‌های دات نتی، پشتیبانی توکاری را از آن‌ها جهت بهبود و یا ساده سازی تعریف آن‌ها، ارائه نمی‌دهند.


ایجاد Tuples در C# 7

برای ایجاد Tuples در سی شارپ 7، از پرانتزها به همراه ذکر نام و نوع پارامترها استفاده می‌شود.
(int x1, string s1) = (3, "one");
Console.WriteLine($"{x1} {s1}");
در مثال فوق، یک Tuple ایجاد شده‌است و در آن مقدار 3 به x1 و مقدار "one" به s1 انتساب داده شده‌اند. به این عملیات deconstruction هم می‌گویند.
دسترسی به این مقادیر نیز همانند متغیرهای معمولی است.

اگر سعی کنیم این قطعه کد را کامپایل نمائیم، با خطای ذیل متوقف خواهیم شد:
 error CS8179: Predefined type 'System.ValueTuple`2' is not defined or imported
برای رفع این مشکل نیاز است بسته‌ی نیوگت ذیل را نیز نصب کرد:
 PM> install-package System.ValueTuple

تعاریف متغیرهای بازگشتی، خارج از پرانتزها هم می‌توانند صورت گیرند:
int x2;
string s2;
(x2, s2) = (42, "two");
Console.WriteLine($"{x2} {s2}");


بازگشت Tuples از متدها

متد ذیل، دو خروجی نتیجه و باقیمانده‌ی تقسیم دو عدد صحیح را باز می‌گرداند:
static (int, int) Divide(int x, int y)
{
   int result = x / y;
   int reminder = x % y;
 
   return (result, reminder);
}
برای این منظور، نوع خروجی متد به صورت (int, int) و همچنین مقدار بازگشتی نیز به صورت یک Tuple از نتیجه و باقیمانده‌ی تقسیم، تعریف شده‌است.
در ادامه نحوه‌ی استفاده‌ی از این متد را مشاهده می‌کنید:
 (int result, int reminder) = Divide(11, 3);
Console.WriteLine($"{result} {reminder}");

در اینجا امکان استفاده‌ی از var نیز برای تعریف نوع متغیرهای دریافتی از یک Tuple نیز وجود دارد و کامپایلر به صورت خودکار نوع آن‌ها را بر اساس نوع خروجی tuple مشخص می‌کند:
 (var result1, var reminder1) = Divide(11, 3);
Console.WriteLine($"{result1} {reminder1}");
و یا حتی چون نوع var پارامترها در اینجا یکی است و در هر دو حالت به int اشاره می‌کند، می‌توان این var را در خارج از پرانتز هم قرار داد:
 var (result1, reminder1) = Divide(11, 3);

و یا برای نمونه متد GetHumanData دات نت 4 ابتدای بحث را به صورت ذیل می‌توان در C# 7 بازنویسی کرد:
static (int, string, string) GetHumanData()
{
   return (10, "Marcus", "Miller");
}
و سپس به نحو واضح‌تری از آن استفاده نمود؛ بدون استفاده‌ی اجباری از Item1 و غیره (هرچند هنوز هم می‌توان از آن‌ها استفاده کرد):
 (int Age, string FirstName, string LastName) results = GetHumanData();
Console.WriteLine(results.Age);
Console.WriteLine(results.FirstName);
Console.WriteLine(results.LastName);


پشت صحنه‌ی Tuples در C# 7

همانطور که عنوان شد، برای اینکه بتوانید قطعه کدهای فوق را کامپایل کنید، نیاز به بسته‌ی نیوگت System.ValueTuple است. در حقیقت کامپایلر خروجی متد فوق را به نحو ذیل تفسیر می‌کند:
 ValueTuple<int, int> tuple1 = Divide(11, 3);
برای مثال قطعه کد
 (int, int) n = (1,1);
System.Console.WriteLine(n.Item1);
توسط کامپایلر به قطعه کد ذیل ترجمه می‌شود:
 ValueTuple<int, int> n = new ValueTuple<int, int>(1, 1);
System.Console.WriteLine(n.Item1);
- برخلاف نگارش‌های پیشین دات نت که Tuples در آن‌ها reference type بودند، این ValueTuple یک struct است و به همین جهت سربار تخصیص حافظه‌ی کمتری را به همراه داشته و از لحاظ کارآیی و میزان مصرف حافظه بهینه‌تر عمل می‌کند.
- همچنین در اینجا محدودیتی از لحاظ تعداد پارامترهای ذکر شده‌ی در یک Tuple وجود ندارد.
 (int,int,int,int,int,int,int,(int,int))
در اینجا هم مانند قبل (دات نت 4) 8 آیتم را می‌توان تعریف کرد؛ اما چون آخرین آیتم ValueTuple تعریف شده نیز یک Tuple است، در عمل محدودیتی از نظر تعداد پارامتر نخواهیم داشت.


مفهوم Tuple Literals

همانند نگارش‌های پیشین دات نت، خروجی یک Tuple را می‌توان به یک متغیر از نوع var و یا ValueType نیز نسبت داد:
 var tuple2 = ("Stephanie", 7);
Console.WriteLine($"{tuple2.Item1}, {tuple2.Item2}");
در این حالت برای دسترسی به مقادیر Tuple همانند قبل باید از فیلدهای Item1 و Item2 و ... استفاده کرد.
به علاوه در سی شارپ 7  می‌توان برای اعضای یک Tuple نام نیز تعریف کرد که به آن‌ها Tuple literals گویند:
 var tuple3 = (Name: "Matthias", Age: 6);
Console.WriteLine($"{tuple3.Name} {tuple3.Age}");
در این حالت زمانیکه Tuple به یک متغیر از نوع var نسبت داده می‌شود، می‌توان به خروجی آن بر اساس نام‌های اعضای Tuple، بجای ذکر Item1 و ... دسترسی یافت که خوانایی بیشتری دارند.

و یا هنگام تعریف نوع خروجی، می‌توان نام پارامترهای متناظر را نیز ذکر کرد که به آن named elements هم می‌گویند:
static (int radius, double area) CalculateAreaOfCircle(int radius)
{
   return (radius, Math.PI * Math.Pow(radius, 2));
}
و نمونه‌ای از کاربرد آن به صورت ذیل است که در اینجا خروجی Tuple صرفا به یک متغیر از نوع var نسبت داده شده‌است و توسط نام پارامترهای خروجی متد، می‌توان به اعضای Tuple دسترسی یافت.
 var circle = CalculateAreaOfCircle(2);
Console.WriteLine($"A circle of radius, {circle.radius}," +
 $" has an area of {circle.area:N2}.");


مفهوم Deconstructing Tuples

مفهوم deconstruction که در ابتدای بحث عنوان شد صرفا مختص به Tuples نیست. در C# 7 می‌توان مشخص کرد که چگونه یک نوع خاص، به اجزای آن تجزیه شود. برای مثال کلاس شخص ذیل را درنظر بگیرید:
class Person
{
    private readonly string _firstName;
    private readonly string _lastName;
 
    public Person(string firstname, string lastname)
    {
        _firstName = firstname;
        _lastName = lastname;
    }
 
    public override String ToString() => $"{_firstName} {_lastName}";
 
    public void Deconstruct(out string firstname, out string lastname)
    {
        firstname = _firstName;
        lastname = _lastName;
    }
}
- در اینجا یک متد جدید را به نام Deconstruct مشاهده می‌کنید. کار این متد جدید که توسط کامپایلر استفاده خواهد شد، ارائه‌ی روشی است برای «تجزیه‌ی» یک نوع، به یک Tuple‌. متد Deconstruct تعریف شده‌ی در اینجا توسط پارامترهایی از نوع out، دو خروجی را مشخص می‌کنند. امکان تعریف این متد ویژه، به صورتیکه یک Tuple را بازگرداند، وجود ندارد.
- علت تعریف این دو خروجی هم به constructor و یا سازنده‌ی کلاس بر می‌گردد که دو ورودی را دریافت می‌کند. اگر یک کلاس چندین سازنده داشته باشد، به همان تعداد می‌توان متد Deconstruct تعریف کرد؛ به همراه خروجی‌هایی متناظر با نوع پارامترهای سازنده‌ها.
- علت استفاده‌ی از نوع خروجی out نیز این است که در #C نمی‌توان چندین overload را صرفا بر اساس نوع خروجی‌های متفاوت متدها تعریف کرد.
- متد Deconstruct به صورت خودکار در زمان تجزیه‌ی یک شیء به یک tuple فراخوانی می‌شود. در مثال زیر، شیء p1 به یک Tuple تجزیه شده‌است و این تجزیه بر اساس متد Deconstruct این کلاس مفهوم پیدا می‌کند:
 var p1 = new Person("Katharina", "Nagel");
(string first, string last) = p1;
Console.WriteLine($"{first} {last}");


امکان تعریف متد Deconstruct‌، به صورت یک متد الحاقی

روش اول تعریف متد ویژه‌ی Deconstruct را در مثال قبل، در داخل کلاس اصلی مشاهده کردید. روش دیگر آن، استفاده‌ی از متدهای الحاقی است که در این مورد خاص نیز مجاز است:
public class Rectangle
{
    public Rectangle(int height, int width)
    {
        Height = height;
        Width = width;
    }
 
    public int Width { get; }
    public int Height { get; }
}
 
public static class RectangleExtensions
{
    public static void Deconstruct(this Rectangle rectangle, out int height, out int width)
    {
        height = rectangle.Height;
        width = rectangle.Width;
    }
}
در اینجا کلاس مستطیل دارای سازنده‌ای با دو پارامتر است؛ اما متد Deconstruct آن به صورت یک متد الحاقی، خارج از کلاس اصلی تعریف شده‌است.
اکنون امکان انتساب وهله‌ای از این کلاس به یک Tuple وجود دارد:
 var r1 = new Rectangle(100, 200);
(int height, int width) = r1;
Console.WriteLine($"height: {height}, width: {width}");


امکان جایگزین کردن Anonymous types با Tuples

قطعه کد ذیل را در نظر بگیرید:
List<Employee> allEmployees = new List<Employee>()
{
  new Employee { ID = 1L, Name = "Fred", Salary = 50000M },
  new Employee { ID = 2L, Name = "Sally", Salary = 60000M },
  new Employee { ID = 3L, Name = "George", Salary = 70000M }
};
var wellPaid =
  from oneEmployee in allEmployees
  where oneEmployee.Salary > 50000M
  select new { EmpName = oneEmployee.Name,
               Income = oneEmployee.Salary };
در اینجا خروجی LINQ تهیه شده یک لیست anonymously typed است؛ با محدودیت‌هایی مانند عدم امکان استفاده‌ی از خروجی آن در سایر اسمبلی‌ها. این نوع‌های ویژه تنها محدود هستند به همان اسمبلی که در آن تعریف می‌شوند. اما در C# 7 می‌توان قطعه کد فوق را با Tuples به صورت ذیل بازنویسی کرد که این محدودیت‌ها را هم ندارد (با هدف به حداقل رساندن تعداد ViewModel‌های تعریفی یک برنامه):
var wellPaid =
  from oneEmployee in allEmployees
  where oneEmployee.Salary > 50000M
  orderby oneEmployee.Salary descending
  select (EmpName: oneEmployee.Name,
          Income: oneEmployee.Salary);
var highestPaid = wellPaid.First().EmpName;


سایر کاربردهای Tuples

از Tuples صرفا برای تعریف چندین خروجی از یک متد استفاده نمی‌شود. در ذیل نحوه‌ی استفاده‌ی از آن‌ها را جهت تعریف کلید ترکیبی یک شیء دیکشنری و یا استفاده‌ی از آن‌ها را در آرگومان جنریک یک متد async هم مشاهده می‌کنید:
public Task<(int index, T item)> FindAsync<T>(IEnumerable<T> input, Predicate<T> match)
{
   var dictionary = new Dictionary<(int, int), string>();
   throw new NotSupportedException();
}
نظرات مطالب
بازنویسی سطح دوم کش برای Entity framework 6
کوئری من به صورت زیر هست
_uow.Set<Post>().Include(x => x.Comments).Cacheable().ToList()
و در اغلب مواقع بدون خطا کار میکنه ولی در بعضی مواقع (که کم هم نیست) خطای NullReferenceException رو میده. این کد توسط api به صورت مداوم در حال صدا زده شدن هست و وقتی که این خطا رو میده توی try catch با دوباره اجرا کردنش خطایی رخ نمیده!
System.NullReferenceException: Object reference not set to an instance of an object. at System.Data.Entity.Internal.Linq.InternalQuery`1.Include(String path) at System.Data.Entity.Infrastructure.DbQuery`1.Include(String path) at System.Data.Entity.QueryableExtensions.Include[T,TProperty](IQueryable`1 source, Expression`1 path)

مطالب
تهیه قالب برای ارسال ایمیل‌ها در ASP.NET Core توسط Razor Viewها
برای ارسال متن ایمیل‌ها، یا می‌توان یک سری رشته را با هم جمع زد و ارسال کرد و یا یک View را به همراه ViewModel آن، طراحی و سپس این View را تبدیل به یک رشته کرد. روش دوم هم قابلیت طراحی بهتری دارد و هم نگهداری و توسعه‌ی آن ساده‌تر است. در ادامه روش تبدیل Razor Viewهای ASP.NET Core را به یک رشته، بررسی می‌کنیم.


تهیه سرویسی برای رندر کردن Razor Viewها به صورت یک رشته

در ادامه کدهای کامل سرویسی را که توسط RazorViewEngine کار رندر کردن یک View و تبدیل آن‌را به رشته انجام می‌دهد، ملاحظه می‌کنید:
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.DependencyInjection;
using System.IO;
using System.Threading.Tasks;
using System;
 
namespace WebToolkit
{
    public static class RazorViewToStringRendererExtensions
    {
        public static IServiceCollection AddRazorViewRenderer(this IServiceCollection services)
        {
            services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddScoped<IViewRendererService, ViewRendererService>();
            return services;
        }
    }
 
    public interface IViewRendererService
    {
        Task<string> RenderViewToStringAsync(string viewNameOrPath);
        Task<string> RenderViewToStringAsync<TModel>(string viewNameOrPath, TModel model);
    }
 
    /// <summary>
    /// Modified version of: https://github.com/aspnet/Entropy/blob/dev/samples/Mvc.RenderViewToString/RazorViewToStringRenderer.cs
    /// </summary>
    public class ViewRendererService : IViewRendererService
    {
        private readonly IRazorViewEngine _viewEngine;
        private readonly ITempDataProvider _tempDataProvider;
        private readonly IServiceProvider _serviceProvider;
        private readonly IHttpContextAccessor _httpContextAccessor;
 
        public ViewRendererService(
                    IRazorViewEngine viewEngine,
                    ITempDataProvider tempDataProvider,
                    IServiceProvider serviceProvider,
                    IHttpContextAccessor httpContextAccessor)
        {
            _viewEngine = viewEngine;
            _tempDataProvider = tempDataProvider;
            _serviceProvider = serviceProvider;
            _httpContextAccessor = httpContextAccessor;
        }
 
        public Task<string> RenderViewToStringAsync(string viewNameOrPath)
        {
            return RenderViewToStringAsync(viewNameOrPath, string.Empty);
        }
 
        public async Task<string> RenderViewToStringAsync<TModel>(string viewNameOrPath, TModel model)
        {
            var actionContext = getActionContext();
 
            var viewEngineResult = _viewEngine.FindView(actionContext, viewNameOrPath, isMainPage: false);
            if (!viewEngineResult.Success)
            {
                viewEngineResult = _viewEngine.GetView("~/", viewNameOrPath, isMainPage: false);
                if (!viewEngineResult.Success)
                {
                    throw new FileNotFoundException($"Couldn't find '{viewNameOrPath}'");
                }
            }
 
            var view = viewEngineResult.View;
            using (var output = new StringWriter())
            {
                var viewDataDictionary = new ViewDataDictionary<TModel>(new EmptyModelMetadataProvider(), new ModelStateDictionary())
                {
                    Model = model
                };
 
                var viewContext = new ViewContext(
                    actionContext,
                    view,
                    viewDataDictionary,
                    new TempDataDictionary(actionContext.HttpContext, _tempDataProvider),
                    output,
                    new HtmlHelperOptions());
                await view.RenderAsync(viewContext).ConfigureAwait(false);
                return output.ToString();
            }
        }
 
        private ActionContext getActionContext()
        {
            var httpContext = _httpContextAccessor?.HttpContext;
            if (httpContext != null)
            {
                return new ActionContext(httpContext, httpContext.GetRouteData(), new ActionDescriptor());
            }
 
            httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
            return new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
        }
    }
}
توضیحات:
اصل این کد متعلق است به مایکروسافت در اینجا. اما در کدهای فوق سه قسمت آن بهبود یافته‌است:
الف) به سازنده‌ی کلاس، سرویس IHttpContextAccessor نیز تزریق شده‌است تا بتوان به HttpContext و اطلاعات آن دسترسی یافت. حالت پیش فرض آن، استفاده از new DefaultHttpContext است. در این حالت اگر در قالب‌های ایمیل‌های خود از Url.Action استفاده کنید، استثنای index out of range مربوط به یافت نشدن مسیریابی‌ها را دریافت خواهید کرد. علت اینجا است که new DefaultHttpContext حاوی اطلاعات مسیریابی درخواست جاری سیستم نیست. به همین جهت توسط IHttpContextAccessor در متد getActionContext، کار مقدار دهی قسمت مسیریابی صورت گرفته‌است.
ب) در کدهای مثال اصلی، فقط viewEngine.FindView ذکر شده‌است. این متد حالت‌های یافتن Viewهایی را به صورت FolderName/ViewName، پشتیبانی می‌کند. اگر بخواهیم یک مسیر کامل را مانند "Areas/Identity/Views/EmailTemplates/_RegisterEmailConfirmation.cshtml/~" ذکر کنیم، کار نمی‌کند. به همین جهت در ادامه، بررسی viewEngine.GetView نیز اضافه شده‌است تا این نقصان را پوشش دهد.
ج) یک overload اضافه‌تر هم جهت رندر یک View بدون مدل نیز به آن اضافه شده‌است.


روش استفاده‌ی از سرویس ViewRenderer

اسمبلی که این سرویس در آن تعریف می‌شود باید دارای وابستگی‌های ذیل باشد:
{ 
    "dependencies": {
        "Microsoft.AspNetCore.Mvc.ViewFeatures": "1.1.0",
        "Microsoft.AspNetCore.Mvc.Razor": "1.1.0"
    }
}
سپس در متد ConfigureServices کلاس آغازین برنامه، سرویس‌های مورد نیاز را اضافه کنید:
public void ConfigureServices(IServiceCollection services)
{
   services.AddRazorViewRenderer();
}
کار متد AddRazorViewRenderer، افزودن سرویس‌های IViewRendererService و همچنین IHttpContextAccessor است.
پس از ثبت سرویس‌های مورد نیاز، اکنون می‌توان سرویس IViewRendererService را به سازنده‌ی کنترلرها و یا کلاس‌های برنامه تزریق و از متدهای RenderViewToStringAsync آن استفاده کرد:
public class RenderController : Controller
{
    private readonly IViewRendererService _viewRenderService;
    public RenderController(IViewRendererService viewRenderService)
    {
        _viewRenderService = viewRenderService;
    }
 
    public async Task<IActionResult> RenderInviteView()
    {
        var viewModel = new InviteViewModel
        {
            UserId = "1",
            UserName = "Vahid"
        };
        var emailBody = await _viewRenderService.RenderViewToStringAsync("EmailTemplates/Invite", viewModel).ConfigureAwait(false);
        //todo: send emailBody
        return Content(emailBody);
    }
}
برای مثال در اینجا در قالب Invite (یا فایل invite.cshtml) واقع در پوشه‌ی EmailTemplates، جهت ساخت متن ایمیل استفاده شده‌است.


چند نکته‌ی تکمیلی در مورد قالب‌های ایمیل

- پیش فرض این سرویس، یافتن Viewها در پوشه‌ی Views است؛ مانند: Views\EmailTemplates\_EmailsLayout.cshtml
مگر اینکه مسیر آن‌را به صورت کامل توسط filename.cshtml/.../~ ذکر کنید و در این حالت ذکر پسوند فایل الزامی است.
- ایمیل‌ها می‌توانند دارای Layout هم باشند. برای مثال فایل Views\EmailTemplates\_EmailsLayout.cshtml را با محتوای ذیل ایجاد کنید:
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Language" content="fa" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <style type='text/css'>
     .main {
            font-size: 9pt;
            font-family: Tahoma;
     }
    </style>
</head>
<body bgcolor="whitesmoke" style="font-size: 9pt; font-family: Tahoma; background-color: whitesmoke; direction: rtl;">
   <div class="main">@RenderBody()</div>
</body>
</html>
در اینجا RenderBody@ را مشاهده می‌کنید که محل رندر شدن ایمیل‌های برنامه است.
به علاوه در اینجا جهت ارسال ایمیل‌ها باید هر نوع شیوه نامه‌ای، به صورت صریح قید شود (inline css) و نباید فایل css ایی را لینک کنید.
- پس از اینکه فایل layout خاص ارسال ایمیل‌های خودتان را طراحی کردید، اکنون قالب یکی از ایمیل‌های برنامه، یک چنین فرمتی را پیدا می‌کند که Layout در ابتدای آن ذکر شده‌است:
 @using Sample.ViewModels
@model RegisterEmailConfirmationViewModel
@{
Layout = "~/Views/EmailTemplates/_EmailsLayout.cshtml";
}
با سلام
<br />
 اکانت شما با مشخصات ذیل ایجاد گردید:
....
- حتما تولید لینک‌ها را به صورت مطلق و نه نسبی انجام دهید. اینکار توسط قید صریح protocol صورت می‌گیرد:
 <a style="direction:ltr" href="@Url.Action("Index", "Home", values: new { area = "" }, protocol: this.Context.Request.Scheme)">@Model.EmailSignature</a>
مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 14 - فعال سازی اعتبارسنجی ورودی‌های کاربران
مباحث پایه‌ای اعتبارسنجی کاربران در ASP.NET Core با نگارش‌های پیشین ASP.NET MVC، آنچنان تفاوت ساختاری مهمی ندارند و یکی هستند. عمده‌ی تفاوت‌ها در نحوه‌ی برپایی تنظیمات اولیه‌ی اسکریپت‌های آن‌ها و همچنین یک سری Tag Helper جدید معادل با HTML Helperهای متداول اعتبارسنجی هستند.


دریافت وابستگی‌های سمت کاربر مباحث اعتبارسنجی

زمانیکه گزینه‌ی ایجاد یک پروژه‌ی جدید ASP.NET Core را در VS.NET انتخاب می‌کنیم، علاوه بر قالب empty آن، قالب دیگری به نام web application نیز در آن موجود است. با انتخاب این قالب، فایلی را به نام bower.json نیز با این محتوا مشاهده می‌کنید:
 {
  "name": "asp.net",
  "private": true,
  "dependencies": {
"bootstrap": "3.3.6",
"jquery": "2.2.0",
"jquery-validation": "1.14.0",
"jquery-validation-unobtrusive": "3.2.6"
  }
}
این مداخل تمام پیشنیازهای مباحث اعتبارسنجی کاربران را به صورت خودکار به پروژه اضافه می‌کنند. بنابراین افزودن فایل جدید bower.json به پروژه با محتوای فوق و سپس مراجعه به solution explorer و کلیک راست بر روی گره dependencies و در آخر انتخاب restore packages، سبب دریافت خودکار این بسته‌ها می‌شود.


این بسته‌ها را پس از دریافت، در پوشه‌ی bower_components خواهید یافت:


البته باید دقت داشت که استفاده از bower در اینجا الزامی نیست. اگر علاقمند بودید از npm و node.js استفاده کنید.


افزودن وابستگی‌های سمت کاربر مباحث اعتبارسنجی و عمومی کردن آن‌ها

پس از دریافت وابستگی‌های مورد نیاز توسط bower، به فایل layout برنامه مراجعه کرده و سپس آن‌ها را به ترتیب ذیل اضافه می‌کنیم:
    <script src="~/bower_components/jquery/dist/jquery.min.js"></script>
    <script src="~/bower_components/jquery-validation/dist/jquery.validate.min.js"></script>
    <script src="~/bower_components/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
 
    @RenderSection("scripts", required: false)
</body>
</html>
هرچند این ترتیب درست است، اما ... کار نمی‌کند. علت را هم در مبحث «ارتقاء به ASP.NET Core 1.0 - قسمت 4 - فعال سازی پردازش فایل‌های استاتیک» بررسی کردیم: تمام پوشه‌های موجود در ریشه‌ی یک برنامه‌ی ASP.NET Core، غیرعمومی هستند (و توسط کاربران قابل درخواست نیستند)، مگر اینکه آن‌ها‌را توسط میان افزار static files، عمومی کنیم. برای این منظور به کلاس آغازین برنامه مراجعه کرده و سپس به متد Configure آن، تنظیمات ذیل را اضافه کنید:
// Serve wwwroot as root
app.UseFileServer();
 
// Serve /bower_components as a separate root
app.UseFileServer(new FileServerOptions
{
    // Set root of file server
    FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "bower_components")),
    // Only react to requests that match this path
    RequestPath = "/bower_components",
    // Don't expose file system
    EnableDirectoryBrowsing = false
});
به این ترتیب فایل‌های موجود در پوشه‌ی bower_components به مسیر bower_components/ نگاشت می‌شوند. البته انتخاب مقدار RequestPath در اینجا اختیاری است و برای مثال می‌توانید مسیر scripts/ را نیز معرفی کنید (نگاشت مسیر فیزیکی و واقعی فایل‌ها به URL خاص دیگری که توسط وب سرور ارائه خواهد شد).
اگر RequestPath را به مسیر دیگری تنظیم کردید، نیاز است ابتدای سه مدخل ذکر شده را بر این اساس اصلاح کنید، تا فایل‌ها توسط وب سرور قابل ارائه شوند.


استفاده از CDN برای توزیع اسکریپت‌های اعتبارسنجی مورد نیاز

در مورد environment tag helper در مطلب «ارتقاء به ASP.NET Core 1.0 - قسمت 12 - معرفی Tag Helpers» پیشتر بحث شد. در اینجا نیز می‌توان برای مثال در حال توسعه، از اسکریپت‌های محلی
<environment name="Development">
   <script src="~/bower_components/jquery/dist/jquery.min.js"></script>
   <script src="~/bower_components/jquery-validation/dist/jquery.validate.min.js"></script>
   <script src="~/bower_components/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
</environment>
و در حالت نهایی توزیع برنامه، از CDNهای ارائه‌ی اسکریپت‌ها، جهت کاهش بار سرور استفاده کرد:
<environment names="Staging, Production">
   <script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.1.4.min.js"
asp-fallback-src="/bower_components/jquery/dist/jquery.min.js"
asp-fallback-test="window.jQuery">
  </script>
   <script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.14.0/jquery.validate.min.js"
asp-fallback-src="bower_components/jquery-validation/dist/jquery.validate.min.js"
asp-fallback-test="window.jQuery && window.jQuery.validator">
  </script>
   <script src="https://ajax.aspnetcdn.com/ajax/mvc/5.2.3/jquery.validate.unobtrusive.min.js"
asp-fallback-src="/bower_components/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"
asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive">
  </script>
</environment>
در اینجا fallback به آدرس محلی دریافت اسکریپت‌های مدنظر، در صورت در دسترس نبودن CDN، تنظیم شده‌است.
روش عملکرد fallback هم به این صورت است که بررسی می‌شود آیا عبارت ذکر شده‌ی در قسمت asp-fallback-test قابل اجرا است یا خیر؟ اگر خیر، یعنی CDN قابل دسترسی نیست و از نمونه‌ی محلی استفاده می‌کند.


خلاصه‌ای از Tag helpers اعتبارسنجی

در جدول «راهنمای تبدیل HTML Helpers به Tag Helpers» مطلب «ارتقاء به ASP.NET Core 1.0 - قسمت 12 - معرفی Tag Helpers»، معادل‌های HTML Helpers مباحث اعتبارسنجی را نیز ملاحظه کردید. خلاصه‌ی تکمیلی آن به صورت ذیل است:

ValidationSummary.All سبب نمایش خطاهای اعتبارسنجی خواص و همچنین کل مدل می‌شود:
@Html.ValidationSummary(false)
معادل است با
<div asp-validation-summary="All"></div>

ValidationSummary.ModelOnly صرفا خطاهای اعتبارسنجی در سطح مدل را نمایش می‌دهد:
@Html.ValidationSummary(true)
معادل است با
<div asp-validation-summary="ModelOnly"></div>

و برای تعیین نمایش خطاهای اعتبارسنجی یک خاصیت از مدل:
@Html.ValidationMessageFor(m => m.UserName, "", new { @class = "text-danger" })
معادل است با
<span asp-validation-for="UserName" class="text-danger"></span>
مطالب
مفاهیم برنامه نویسی ـ مروری بر فیلدها، متدها و ساخت اشیاء
شکستن یک مسئله بزرگ به تعدادی مسئله کوچک‌تر راهکار موثری برای حل آن است. این امر در برنامه نویسی نیز که هدف آن چیزی جز حل یک مسئله نیست همواره مورد توجه بوده است. به همین دلیل روش هایی که به کمک آن‌ها بتوان یک برنامه بزرگ را به قطعات کوچکتری تقسیم کرد تا هر قطعه کد مسئول انجام کار خاصی باشد پیشتر به زبان‌های برنامه نویسی اضافه شده اند. یکی از این ساختار‌ها تابع (Function) نام دارد. برنامه ای که از توابع برای تقسیم کدهای برنامه استفاده می‌کند یک برنامه ساخت‌یافته می‌گوییم.
در مطلب پیشین به پیرامون خود نگاه کردیم و اشیاء گوناگونی را مشاهده کردیم که در حقیقت دنیای ما را تشکیل داده اند و فعالیت‌های روزمره ما با استفاده از آن‌ها صورت می‌گیرد. ایده ای به ذهنمان رسید. اشیاء و مفاهیم مرتبط به آن می‌تواند روش بهتر و موثرتری برای تقسیم کدهای برنامه باشد. مثلاً اگر کل کدهای برنامه که مسئول حل یکی از مسئله‌های کوچک یاد شده است را یکجا بسته بندی کنیم و اصولی که از اشیاء واقعی پیرامون خود آموختیم را در مورد آن رعایت کنیم به برنامه بسیار با کیفیت‌تری از نظر خوانایی، راحتی در توسعه، اشکال زدایی ساده‌تر و بسیاری موارد دیگر خواهیم رسید.
توسعه دهندگان زبان‌های برنامه نویسی که با ما در این مورد هم عقیده بوده اند دست به کار شده و دستورات و ساختار‌های لازم برای پیاده کردن این ایده را در زبان برنامه نویسی قرار دادند و آن را زبان برنامه نویسی شیء گرا نامیدند. حتی جهت برخورداری از قابلیت استفاده مجدد از کد و موارد دیگر به جای آنکه کدها را در بسته هایی به عنوان یک شیء خاص قرار دهیم آن‌ها را در بسته هایی به عنوان قالب یا نقشه ساخت اشیاء خاصی که در ذهن داریم قرار می‌دهیم. یعنی مفهوم کلاس یا رده که پیشتر اشاره شد. به این ترتیب یک بار می‌نویسیم و بارها استفاده می‌کنیم. مانند همان مثال بازیکن در بخش نخست. هر زمان که لازم باشد با استفاده از دستورات مربوطه از روی کدهای کلاس که نقشه یا قالب ساخت اشیاء هستند شیء مورد نظر را ساخته و در جهت حل مسئله مورد نظر به کار می‌بریم.
حال برای آنکه به طور عملی بتوانیم از ایده شیء گرایی در برنامه هایمان استفاده کنیم و مسائل بزرگ را حل کنیم لازم است ابتدا مقداری با جزییات و دستورات زبان در این مورد آشنا شویم.
تذکر: دقت کنید برای آنکه از ایده شیء گرایی در برنامه‌ها حداکثر استفاده را ببریم مفاهیمی در مهندسی نرم افزار به آن اضافه شده است که ممکن است در دنیای واقعی نیازی به طرح آن‌ها نباشد. پس لطفاً تلاش نکنید با دیدن هر مفهوم تازه بلافاصله سعی در تطبیق آن با محیط اطراف کنید. هر چند بسیاری از آن‌ها به طور ضمنی در اشیاء پیرامون ما نیز وجود دارند.
زبان برنامه نویسی مورد استفاده برای بیان مفاهیم برنامه نویسی در این سری مقالات زبان سی شارپ است. اما درک برنامه‌های نوشته شده برای علاقه مندان به زبان‌های دیگری مانند وی بی دات نت نیز دشوار نیست. چراکه اکثر دستورات مشابه است و تبدیل Syntax نیز به راحتی با اندکی جستجو میسر می‌باشد. لازم به یادآوری است زبان سی شارپ به بزرگی یا کوچکی حروف حساس است.

تشخیص و تعریف کلاس‌های برنامه

کار را با یک مثال شروع می‌کنیم. فرض کنید به عنوان بخشی از راه حل یک مسئله بزرگ، لازم است محیط و مساحت یک سری چهارضلعی را محاسبه کنیم و قصد داریم این وظیفه را به طور کامل بر عهده قطعه کدهای مستقلی در برنامه قرار دهیم. به عبارت دیگر قصد داریم متناظر با هر یک از چهارضلعی‌های موجود در مسئله یک شیء در برنامه داشته باشیم که قادر است محیط و مساحت خود را محاسبه و ارائه نماید. کلاس زیر که با زبان سی شارپ نوشته شده امکان ایجاد اشیاء مورد نظر را فراهم می‌کند.

public class Rectangle
{
   public double Width;
   public double Height;
 
   public double Area()
   {
      return Width*Height;
   }
 
   public double Perimeter()
   {
      return 2*(Width + Height);
   }
}

در این قطعه برنامه نکات زیر قابل توجه است:
  • کلاس با کلمه کلیدی class تعریف می‌شود.
  • همان طور که مشاهده می‌کنید تعریف کلاس با کلمه public آغاز شده است. این کلمه محدوده دسترسی به کلاس را تعیین می‌کند. در اینجا از کلمه public استفاده کردیم تا بخش‌های دیگر برنامه امکان استفاده از این کلاس را داشته باشند.
  • پس از کلمه کلیدی class نوبت به نام کلاس می‌رسد. اگرچه انتخاب نام مورد نظر امری اختیاری است اما در آینده حتماً اصول و قراردادهای نام‌گذاری در دات‌نت را مطالعه نمایید. در حال حاضر حداقل به خاطر داشته باشید تا انتخاب نامی مناسب که گویای کاربرد کلاس باشد بسیار مهم است.
  • باقیمانده کد، بدنه کلاس را تشکیل می‌دهد. جاییکه ویژگی ها، رفتار‌ها و ... یا به طور کلی اعضای کلاس تعریف می‌شوند.
نکته: کلماتی مانند public که پیش از تعریف کلاس یا اعضای آن قرار می‌گیرند Modifier یا پیراینده نام دارند. که البته به نظر من ترجمه این گونه واژه‌ها از کارهای شیطان است. بنابراین از این پس بهتر است همان Modifier را به خاطر داشته باشید. از آنجا که public مدیفایری است که سطح دسترسی را تعیین می‌کند به آن یک Access Modifier می‌گویند. در یک بخش از این سری مقالات تمامی مدیفایرها بررسی خواهند شد.

ایجاد شیء از یک کلاس و نحوه دسترسی به شیء ایجاد شده

شیء و کلاس چیزهای متفاوتی هستند. یک کلاس نوع یک شیء را تعریف می‌کند. اما یک شیء یک موجودیت عینی و واقعی بر اساس یک کلاس است. در اصطلاح از شیء به عنوان یک نمونه (Instance) یا وهله ای از کلاس مربوطه یاد می‌کنیم. همچنین به عمل ساخت شیء نمونه سازی یا وهله سازی گوییم.
برای ایجاد شیء از کلمه کلیدی new و به دنبال آن نام کلاسی که قصد داریم بر اساس آن یک شیء بسازیم استفاده می‌کنیم. همان طور که اشاره شد کلاس یک نوع را تعریف می‌کند. پس از آن می‌توان همانند سایر انواع مانند int, string, … برای تعریف متغیر استفاده نمود. به مثال زیر توجه کنید.
Rectangle rectangle = new Rectangle();
در این مثال rectangle که با حرف کوچک شروع شده و می‌توانست هر نام دلخواه دیگری باشد ارجاعی به شیء ساخته شده را به دست می‌دهد. وقتی نمونه ای از یک کلاس ایجاد می‌شود یک ارجاع به شیء تازه ساخته شده برای برنامه نویس برگشت داده می‌شود. در این مثال rectangle یک ارجاع به شیء تازه ساخته شده است یعنی به آن اشاره می‌کند اما خودش شامل داده‌های آن شیء نیست. تصور کنید این ارجاع تنها دستگیره ای برای شیء ساخته شده است که دسترسی به آن را برای برنامه نویس میسر می‌کند. درک این مطلب از این جهت دارای اهمیت است که بدانید می‌شود یک دستگیره یا ارجاع دیگر بسازید بدون آنکه شیء جدیدی تولید کنید.
Rectangle rectangle;
البته توصیه نمی‌کنم چنین ارجاعی را تعریف کنید چرا که به هیچ شیء خاصی اشاره نمی‌کند. و تلاش برای استفاده از آن منجر به بروز خطای معروفی در برنامه خواهد شد. به هر حال یک ارجاع می‌توان ساخت چه با ایجاد یک شیء جدید و یا با نسبت دادن یک شیء موجود به آن.
Rectangle rectangle1 = new Rectangle();
Rectangle rectangle2 = rectangle1;
در این کد دو ارجاع یا دستگیره ایجاد شده است که هر دو به یک شیء اشاره می‌کنند. بنابراین ما با استفاده از هر دو ارجاع می‌توانیم به همان شیء واحد دسترسی پیدا کنیم و اگر مثلاً با rectangle1 در شیء مورد نظر تغییری بدهیم و سپس با rectangle2 شیء را مورد بررسی قرار دهیم تغییرات داده شده قابل مشاهده خواهد بود چون هر دو ارجاع به یک شیء اشاره می‌کنند. به همین دلیل کلاس‌ها را به عنوان نوع ارجاعی می‌شناسیم در مقایسه با انواع داده دیگری که اصطلاحاً نوع مقداری هستند.
حالا می‌توان شیء ساخته شده را با استفاده از ارجاعی که به آن داریم به کار برد.
Rectangle rectangle = new Rectangle();
rectangle.Width = 10.5;
rectangle.Height = 10;
double a = rectangle.Area();
ابتدا عرض و ارتفاع شیء چهارضلعی را مقدار دهی کرده و سپس مساحت را دریافت کرده ایم. از نقطه برای دسترسی به اعضای یک شیء استفاده می‌شود.

فیلدها

اگر به تعریف کلاس دقت کنید مشخص است که دو متغییر Width و Height را با سطح دسترسی عمومی تعریف کرده ایم.
به متغیرهایی از هر نوع که مستقیماً درون کلاس تعریف شوند (و نه مثلاً داخل یک تابع درون کلاس) فیلد می‌گوییم. فیلدها از اعضای کلاس دربردارنده آن‌ها محسوب می‌شوند.
تعریف فیلدها مستقیماً در بدنه کلاس با یک Access Modifier شروع می‌شود و به دنبال آن نوع فیلد و سپس نام دلخواه برای فیلد می‌آید.
تذکر: نامگذاری مناسب یکی از مهمترین اصولی است که یک برنامه نویس باید همواره به آن توجه کافی داشته باشد و به شدت در بالا رفتن کیفیت برنامه موثر است. به خاطر داشته باشید تنها اجرا شدن و کار کردن یک برنامه کافی نیست. رعایت بسیاری از اصول مهندسی نرم افزار که ممکن است نقش مستقیمی در کارکرد برنامه نداشته باشند موجب سهولت در نگهداری و توسعه برنامه شده و به همان اندازه کارکرد صحیح برنامه مهم هستند. بنابراین مجدداً شما را دعوت به خواندن مقاله یاد شده بالا در مورد اصول نامگذاری صحیح می‌کنم. هر مفهوم تازه ای که می‌آموزید می‌توانید به اصول نامگذاری همان مورد در مقاله پیش گفته مراجعه نمایید. همچنین افزونه هایی برای Visual Studio وجود دارد که شما را در زمینه نامگذاری صحیح و بسیاری موارد دیگر هدایت می‌کنند که یکی از مهمترین آن‌ها Resharper نام دارد.
مثال:
// public field (Generally not recommended.)
public double Width;
همان طور که در این قطعه کد به عنوان توضیح درج شده است استفاده از فیلدهایی با دسترسی عمومی توصیه نمی‌شود. علت آن واضح است. چون هیچ کنترلی برای مقداری که برای آن در نظر گرفته می‌شود نداریم. به عنوان مثال امکان دارد یک مقدار منفی برای عرض یا ارتفاع شیء درج شود حال آنکه می‌دانیم عرض یا ارتفاع منفی معنا ندارد. در قسمت بعدی این سری مقالات این مشکل را بررسی و حل خواهیم نمود.
فیلد‌ها معمولاً با سطح دسترسی خصوصی و برای نگهداری از داده‌هایی که مورد نیاز بیش از یک متد (یا تابع) درون کلاس است و آن داده‌ها باید پس از خاتمه کار یک متد همچنان باقی بمانند استفاده می‌شود. بدیهی است در غیر اینصورت به جای تعریف فیلد می‌توان از متغیرهای محلی (متغیری که درون خود تابع تعریف می‌شود) استفاده نمود.
همان طور که پیشتر اشاره شد برای دسترسی به یک فیلد ابتدا یک نقطه پس از نام شیء درج کرده و سپس نام فیلد مورد نظر را می‌نویسیم.
Rectangle rectangle = new Rectangle();
rectangle.Width = 10.5;
در هنگام تعریف یک فیلد در صورت نیاز می‌توان برای آن یک مقدار اولیه را در نظر گرفت. مانند مثال زیر:
public class Rectangle
{
   public double Width = 5;
   // ...
}

متدها

متدها قطعه کدهایی شامل یک سری دستور هستند. این مجموعه دستورات با فراخوانی متد و تعیین آرگومان‌های مورد نیاز اجرا می‌شوند. در زبان سی شارپ به نوعی تمام دستورات در داخل متدها اجرا می‌شوند. در این زبان تمامی توابع در داخل کلاس‌ها تعریف می‌شوند و بنابراین همه متد هستند.
متدها نیز مانند فیلد‌ها در داخل کلاس تعریف می‌شوند. ابتدا یک Access Modifier سطح دسترسی را تعیین می‌نماید. سپس به ترتیب نوع خروجی، نام متد و لیست پارامترهای آن در صورت وجود درج می‌شود. به مجموعه بخش‌های یاد شده امضای متد می‌گویند.
پارامترهای یک متد داخل یک جفت پرانتز قرار می‌گیرند و با کاما (,) از هم جدا می‌شوند. یک جفت پرانتز خالی نشان دهنده آن است که متد نیاز به هیچ پارامتری ندارد.
بار دیگر به بخش تعریف متدهای کلاسی که ایجاد کردیم توجه نمایید.
public class Rectangle
{
   // ...
 
   public double Area()
   {
      return Width*Height;
   }
 
   public double Perimeter()
   {
      return 2*(Width + Height);
   }
}
در این کلاس دو متد به نام‌های  Area و Perimeter به ترتیب برای محاسبه مساحت و محیط چهارضلعی تعریف شده است. همانطور که پیشتر اشاره شد متدها برای پیاده سازی رفتار اشیاء یا همان کارکردهای آن‌ها استفاده می‌شوند. در این مثال شیء ما قادر است مساحت و محیط خود را محاسبه نماید. چه شیء خوش رفتاری!
همچنین توجه نمایید این شیء برای محاسبه مساحت و محیط خود نگاهی به ویژگی‌های خود یعنی عرض و ارتفاعش که در فیلدهای آن نگهداری می‌کنیم می‌اندازد.
فراخوانی متد یک شیء همانند دسترسی به فیلد آن است. ابتدا نام شیء سپس یک نقطه و به دنبال آن نام متد مورد نظر به همراه پرانترها. آرگومان‌های مورد نیاز در صورت وجود داخل پرانتزها قرار می‌گیرند و با کاما از هم جدا می‌شوند. که البته در این مثال متد ما نیازی به آرگومان ندارد. به همین دلیل برای فراخوانی آن تنها یک جفت پرانتز خالی قرار می‌دهیم.
در این بخش به دو مفهوم پارامتر و آرگومان اشاره شد. تفاورت آن‌ها چیست؟
در هنگام تعریف یک متد نام و نوع پارامترهای مورد نیاز را تعیین و درج می‌نماییم. حال وقتی قصد فراخوانی متد را داریم باید مقادیر واقعی که آرگومان نامیده می‌شود را برای هر یک از پارامترهای تعریف شده فراهم نماییم. نوع آرگومان باید با نوع پارامتر تعریف شده تطبیق داشته باشد. اما اگر یک متغیر را به عنوان آرگومان در هنگام فراخوانی متد استفاده می‌کنیم نیازی به یکسان بودن نام آن متغیر و نام پارامتر تعریف شده نیست.
متدها می‌توانند یک مقدار را به کدی که آن متد را فراخوانی کرده است بازگشت دهند.
Rectangle rectangle = new Rectangle();
rectangle.Width = 10.5;
rectangle.Height = 10;
double p = rectangle.Perimeter();
در این مثال مشاهده می‌کنید که پس از فراخوانی متد Perimeter مقدار بازگشتی آن در متغیری به نام p قرار گرفته است. اگر نوع خروجی یک متد که در هنگام تعریف آن پیش از نام متد قرار می‌گیرد void یا پوچ نباشد، متد می‌تواند مقدار مورد نظر را با استفاده از کلمه کلیدی return بازگشت دهد. کلمه return و به دنبال آن مقداری که از نظر نوع باید با نوع خروجی تعیین شده تطبیق داشته باشد، مقدار درج شده را به کد فراخوان متد بازگشت می‌دهد.
نکته: کلمه return علاوه بر بازگشت مقدار مورد نظر سبب پایان اجرای متد نیز می‌شود. حتی در صورتی که نوع خروجی یک متد void تعریف شده باشد استفاده از کلمه return بدون اینکه مقداری به دنبال آن بیاید می‌تواند برای پایان اجرای متد، در صورت نیاز و مثلاً برقراری شرطی خاص مفید باشد. بدون کلمه return متد زمانی پایان می‌یابد که به پایان قطعه کد بدنه خود برسد. توجه نمایید که در صورتی که نوع خروجی متد چیزی به جز void است استفاده از کلمه return به همراه مقدار مربوطه الزامی است.
مقدار خروجی یک متد را می‌توان هر جایی که مقداری از همان نوع مناسب است مستقیماً به کار برد. همچنین می‌توان آن را در یک متغیر قرار داد و سپس از آن استفاده نمود.
به عنوان مثال کلاس ساده زیر را در نظر بگیرید که متدی دارد برای جمع دو عدد.
public class SimpleMath
{
   public int AddTwoNumbers(int number1, int number2)
   {
      return number1 + number2;
   }
}
و حال دو روش استفاده از این متد:
SimpleMath obj = new SimpleMath();

Console.WriteLine(obj.AddTwoNumbers(1, 2));

int result = obj.AddTwoNumbers(1, 2);
Console.WriteLine(result);
در روش اول مستقیماً خروجی متد مورد استفاده قرار گرفته است و در روش دوم ابتدا مقدار خروجی در یک متغیر قرار گرفته است و سپس از مقدار درون متغیر استفاده شده است. استفاده از متغیر برای نگهداری مقدار خروجی اجباری نبوده و تنها جهت بالا بردن خوانایی برنامه یا حفظ مقدار خروجی تابع برای استفاده‌های بعدی به کار می‌رود.

در بخش‌های بعدی بحث ما در مورد سایر اعضای کلاس و برخی جزییات پیرامون اعضای پیش گفته خواهد بود.
 
نظرات مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 2 - بررسی ساختار جدید Solution
این مورد را در قسمت اول ذیل «اما هنوز تعداد زیادی از کتابخانه‌های Full framework به NET Core. انتقال پیدا نکرده‌اند »، توضیح دادم.

شما در ASP.NET Core امکان کار با هر دو فریم ورک یاد شده را دارید و این دو به هم وابستگی ندارند. به عبارتی چندین target را دراینجا می‌توانید معرفی و استفاده کنید. اگر دات نت 4.6 را هم استفاده کردید، برنامه فقط قابلیت چندسکویی خودش را از دست خواهد داد. برای مثال شما هم اکنون می‌توانید EF 6.x را با ASP.NET Core 1.0 استفاده کنید (اگر نمی‌خواهید تا زمان تکمیل نهایی EF Core صبر کنید). فقط در این حالت باید دقت داشته باشید که کدهای شما بر روی لینوکس اجرا نخواهند شد (چون EF 6.x مبتنی بر دات نت 4x است).