مطالب
آشنایی با Gridify
Gridify چیست ؟

به طور خلاصه Gridify یک کتابخانه ساده و سریع است که عملیات‌های Filtering , Pagination و Sorting را با استفاده از شرط‌های متنی (string based) امکان پذیر میکند.
به طور مثال فرض کنید که یک API را برای دریافت لیست کاربران با نام UsersList نوشته‌اید. مثال:
 [HttpGet("[action]")]
 public async Task<IActionResult> UsersList()
 {
    var users =  await _dbContext.Users.AsNoTracking().ToListAsync();
    return Ok(users);
 }
طبیعتا بخش FrontEnd نرم افزار شما نیاز دارد این اطلاعات را به کاربر نمایش دهد. به همین جهت در بیشتر مواقع از یک گرید برای نمایش این اطلاعات استفاده میشود.
پس از دریافت اطلاعات از سرور با مشکلات زیر مواجه خواهیم شد.
  1. عدم پشتیبانی از Pagination: چون API، تمامی کاربران را به سمت کلاینت ارسال میکند؛ به همین جهت، هم با مشکل کارآیی (performance) در آینده مواجه میشویم و هم امکان گذاشتن صفحه بندی (Pagination) وجود نخواهد داشت. 
  2. عدم پشتیبانی از Sorting: اگر در گرید نمایش داده شده کاربر بخواهد اطلاعات را Sort کند، چون چنین امکانی هنوز برای API ما تعریف نشده، این عملیات سمت سرور امکان پذیر نیست.
  3. عدم پشتیبانی از Filtering: همیشه نمایش تمامی اطلاعات مفید نیست. در اکثر مواقع ما نیاز داریم تا قسمتی از اطلاعات را با شرطی خاص، برگردانیم. به طور مثال لیست کاربران فعال در سامانه یا لیست کاربران غیرفعال. 
این مشکلات بدون استفاده از هیچ کتابخانه‌ای قابل حل است ولی نه به سادگی؛ به طور مثال یا باید چندین API مختلف با امکانات مختلف بنویسیم، یا یک API را برای پشتیبانی از این موارد تغییر بسیار دهیم. من برای اینکه از بحث دور نشویم، به پیاده سازی نمونه دستی پشتیبانی از این موارد در اینجا نمی‌پردازم، چرا که اگر یکبار تلاشی را برای اینکار انجام داده باشیم، طبیعتا  مشکلات و کد کثیفی که در نهایت تولید شده است، یادآوری خواهد شد. 
برای رفع این مشکلات میتوان از کتابخانه Gridify استفاده کرد. مثال :
 [HttpGet("[action]")]
 public async Task<IActionResult> UsersList(GridifyQuery filter)
 {
    var users =  await _dbContext.Users.AsNoTracking().GridifyAsync(filter);
    return Ok(users);
 }
در مثال بالا با استفاده از کلاس GridifyQuery میتوانیم به کنترل هر سه مشکل Sorting - Pagination - Filtering سمت کلاینت بپردازیم. (در ادامه با این کلاس بیشتر آشنا خواهیم شد).


استفاده از Gridify به API‌ها محدود نمیشود. به طور کلی ما میتوانیم در هر نوع لیستی که امکان استفاده از IQueryable  را به ما میدهد از آن استفاده نماییم. 
فرض کنید در یک برنامه Console Application قصد داریم یک فیلتر را از کاربر دریافت کرده و آن را روی لیست خروجی خود اعمال کنیم. به دلیل اینکه امکان جستجوی متنی در دات نت وجود ندارد، برای انجام اینکار مجبور خواهیم شد که برای تک تک فیلدهایی که قرار است برای فیلترینگ پشتیبانی کنیم، یک query جداگانه بنویسیم؛ ولی این عملیات توسط کتابخانه Gridify امکان پذیر است. به طور مثال فرض کنید قصد داریم در لیست کاربران، کاربرانی را  با نام Ali، پیدا کنیم. 
var result = Users.AsQueryable().ApplyFiltering("name==Ali");
این کد دقیقا معادل کد زیر است.
var result = Users.AsQueryable().Where(q => q.Name == "Ali");
در اینجا با استفاده از کتابخانه Gridify ما توانستیم یک static Linq را به یک dynamic Linq که در runtime مقدار دهی خواهد شد، تغییر دهیم. به همین جهت استفاده از مورد اول در برنامه‌ی Console ما امکان پذیر است. تا اینجا ما با امکانات کلی این کتابخانه آشنا شدیم. در مقالات بعدی سعی میکنم به سایر امکانات این کتابخانه و بیشتر به جزئیات بپردازم. همینطور برای کسب اطلاعات بیشتر میتوانید به لینک زیر مراجعه نمایید.
مطالب دوره‌ها
یکپارچه سازی اعتبارسنجی EF Code first با امکانات WPF و حذف کدهای تکرای INotifyPropertyChanged
در لابلای توضیحات قسمت‌های قبل، به نحوه استفاده از کلاس‌های پایه‌ای که اعتبارسنجی یکپارچه‌ای را با WPF و EF Code first در قالب پروژه WPF Framework ارائه می‌دهند، اشاره شد. در این قسمت قصد داریم جزئیات بیشتری از پیاده سازی آن‌ها را بررسی کنیم.

بررسی سطح بالای مکانیزم‌های اعتبارسنجی و AOP بکارگرفته شده

در حین کار با قالب پروژه WPF Framework، هنگام طراحی Modelهای خود (تفاوتی نمی‌کند که Domain model باشند یا صرفا Model متناظر با یک View)،  نیاز است دو مورد را رعایت کنید:
 [ImplementPropertyChanged] // AOP
public class LoginPageModel : DataErrorInfoBase
الف) کلاس مدل شما باید مزین به ویژگی ImplementPropertyChanged شود.
ب) از کلاس پایه DataErrorInfoBase مشتق گردد

البته اگر به کلاس‌های  Domain model برنامه مراجعه کنید، صرفا مشتق شدن از BaseEntity را ملاحظه می‌کنید:
 public class User : BaseEntity
علت این است که دو نکته یاد شده در کلاس پایه BaseEntity پیشتر پیاده سازی شده‌اند:
 [ImplementPropertyChanged] // AOP
public abstract class BaseEntity : DataErrorInfoBase //پیاده سازی خودکار سیستم اعتبارسنجی یکپارچه

بررسی جزئیات مکانیزم AOP بکارگرفته شده

بسیار خوب؛ این‌ها چطور کار می‌کنند؟!
ابتدا نیاز است مطلب «معرفی پروژه NotifyPropertyWeaver» را یکبار مطالعه نمائید. خلاصه‌ای جهت تکرار نکات مهم آن:
ویژگی ImplementPropertyChanged به ابزار Fody اعلام می‌کند که لطفا کدهای تکراری INotifyPropertyChanged را پس از کامپایل اسمبلی جاری، بر اساس تزریق کدهای IL متناظر، به اسمبلی اضافه کن. این روش از لحاظ کارآیی و همچنین تمیز نگه داشتن کدهای نهایی برنامه، فوق العاده است.
برای بررسی کارکرد آن نیاز است اسمبلی مثلا Models را دی‌کامپایل کرد:


همانطور که ملاحظه می‌کنید، کدهای تکراری INotifyPropertyChanged به صورت خودکار به اسمبلی نهایی اضافه شده‌اند.
البته بدیهی است که استفاده از Fody الزامی نیست. اگر علاقمند هستید که این اطلاعات را دستی اضافه کنید، بهتر است از کلاس پایه BaseViewModel قرار گرفته در مسیر MVVM\BaseViewModel.cs پروژه Common استفاده نمائید.
در این کلاس، پیاده سازی‌های NotifyPropertyChanged را بر اساس متدهایی که یک رشته را به عنوان نام خاصیت دریافت می‌کنند و یا متدی که امکان دسترسی strongly typed به نام رشته را میسر ساخته است، ملاحظه می‌کنید.
   /// <summary>
  /// تغییر مقدار یک خاصیت را اطلاع رسانی خواهد کرد
  /// </summary>
  /// <param name="propertyName">نام خاصیت</param>
  public void NotifyPropertyChanged(string propertyName)

  /// <summary>
  /// تغییر مقدار یک خاصیت را اطلاع رسانی خواهد کرد
  /// </summary>
  /// <param name="expression">نام خاصیت مورد نظر</param>
  public void NotifyPropertyChanged(Expression<Func<object>> expression)
برای مثال در اینجا خواهیم داشت:
public class AlertConfirmBoxViewModel : BaseViewModel
    {
        AlertConfirmBoxModel _alertConfirmBoxModel;
        public AlertConfirmBoxModel AlertConfirmBoxModel
        {
            set
            {
                _alertConfirmBoxModel = value;
                NotifyPropertyChanged("AlertConfirmBoxModel");
                // ویا ....
                NotifyPropertyChanged(()=>AlertConfirmBoxModel);
            }
            get { return _alertConfirmBoxModel; }
        }
هر دو حالت استفاده از متدهای NotifyPropertyChanged به همراه کلاس پایه BaseViewModel در اینجا ذکر شده‌اند. حالت استفاده از Expression به علت اینکه تحت نظر کامپایلر است، در دراز مدت نگه‌داری برنامه را ساده‌تر خواهد کرد.


بررسی جزئیات اعتبارسنجی‌های تعریف شده

EF دارای یک سری ویژگی مانند Required و امثال آن است. WPF دارای اینترفیسی است به نام IDataErrorInfo. این دو را باید به نحوی به هم مرتبط ساخت که پیاده سازی‌های مرتبط با آن‌ها را در مسیرهای WpfValidation\DataErrorInfoBase.cs و WpfValidation\ValidationHelper.cs پروژه Common می‌توانید ملاحظه نمائید.
 <TextBox Text="{Binding Path=ChangeProfileData.UserName, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,
 NotifyOnValidationError=true, ValidatesOnExceptions=true, ValidatesOnDataErrors=True, TargetNullValue=''}"  />
برای نمونه در اینجا خاصیت Text یک TextBox به خاصیت UserName شیء ChangeProfileData تعریف شده در ViewModel تغییر اطلاعات کاربری برنامه مقید شده است.
همچنین حالت‌های بررسی اعتبارسنجی آن نیز به PropertyChanged تنظیم گردیده است. در این حالت WPF به تعاریف شیء ChangeProfileData مراجعه کرده و برای نمونه اگر این شیء اینترفیس IDataErrorInfo را پیاده سازی کرده بود، نام خاصیت جاری را به آن ارسال و از آن خطاهای اعتبارسنجی متناظر را درخواست می‌کند. در اینجا وقت خواهیم داشت تا بر اساس ویژگی‌ها و Data annotaions اعمالی، کار اعتبارسنجی را انجام داده و نتیجه را بازگشت دهیم.
خلاصه‌ی تمام این اعمال و کلاس‌ها، در کلاس پایه DataErrorInfoBase این قالب پروژه قرار گرفته‌اند. بنابراین تنها کاری که باید صورت گیرد، مشتق کردن کلاس مدل مورد نظر از آن می‌باشد.
همچنین باید دقت داشت که نمایش اطلاعات خطاهای حاصل از اعتبارسنجی در این قالب پروژه بر اساس امکانات قالب متروی MahApps.Metro انجام می‌گیرد (این مورد از Silverlight toolkit به ارث رسیده است) و در حالت کلی خودکار نیست؛ اما در اینجا نیازی به کدنویسی اضافه‌تری ندارد.

به علاوه باید دقت داشت که این مورد ویژه را باید بر اساس آخرین Build کتابخانه MahApps.Metro که به‌روزتر است دریافت و استفاده کرد. در اینجا با پارامتر Pre ذکر شده است.

PM> Install-Package MahApps.Metro -Pre
مطالب
استفاده از Kendo UI TreeView به همراه یک منبع داده راه دور
یکی دیگر از ویجت‌های Kendo UI، ویجت نمایش ساختارهای درختی است به نام TreeView. در ادامه قصد داریم با نحوه‌ی نمایش آن، به کمک اطلاعات JSON دریافتی از سرور آشنا شویم.



ساختار مورد نیاز یک Kendo UI Tree View

فرض کنید قصد دارید نظرات تو در توی مطلبی را توسط Kendo UI Tree View نمایش دهید. مدل خود ارجاع دهنده‌ی آن می‌تواند چنین شکلی را داشته باشد:
namespace KendoUI11.Models
{
    public class BlogComment
    {
        public int Id { set; get; }
 
        public string Body { set; get; }
 
        public int? ParentId { get; set; }
 
        // مخصوص کندو یو آی هستند
        public bool HasChildren { get; set; }
        public string imageUrl { get; set; }
    }
}
سه خاصیت اول این کلاس همواره در تمام کلاس‌های خود ارجاع دهنده حضور دارند؛ شماره ردیف، متن و شماره Id والد احتمالی.
چند خاصیت بعدی مانند HasChildren و imageUrl مخصوص Kendo UI هستند. از imageUrl اختیاری می‌توان جهت نمایش آیکنی در کنار یک آیتم استفاده کرد و HasChildren به این معنا است که آیا گره جاری دارای عناصر فرزندی می‌باشد یا خیر.


تهیه یک منبع داده نمونه

شکل ابتدای مطلب، از طریق منبع داده ذیل تهیه شده‌است:
using System.Collections.Generic;
 
namespace KendoUI11.Models
{
    /// <summary>
    /// منبع داده فرضی جهت سهولت دموی برنامه
    /// </summary>
    public static class BlogCommentsDataSource
    {
        private static readonly IList<BlogComment> _cachedItems;
        static BlogCommentsDataSource()
        {
            _cachedItems = createBlogCommentsDataSource();
        }
 
        public static IList<BlogComment> LatestComments
        {
            get { return _cachedItems; }
        }
 
        /// <summary>
        /// هدف صرفا تهیه یک منبع داده آزمایشی ساده تشکیل شده در حافظه است
        /// </summary>
        private static IList<BlogComment> createBlogCommentsDataSource()
        {
            var list = new List<BlogComment>();
 
            var comment1 = new BlogComment
            {
                Id = 1, Body = "نظر من این است که", HasChildren = true, ParentId = null
            };
            list.Add(comment1);
 
            var comment12 = new BlogComment
            {
                Id = 2, Body = "پاسخی به نظر اول", HasChildren = true, ParentId = 1
            };
            list.Add(comment12);
 
            var comment12A = new BlogComment
            {
                Id = 3, Body = "پاسخی دیگری به نظر اول", HasChildren = false, ParentId = 1
            };
            list.Add(comment12A);
 
            var comment121 = new BlogComment
            {
                Id = 4, Body = "پاسخی به پاسخ به نظر اول", HasChildren = false, ParentId = 2
            };
            list.Add(comment121);
 
            var comment2 = new BlogComment
            {
                Id = 5, Body = "نظر 2", HasChildren = true, ParentId = null, imageUrl= "images/search.png"
            };
            list.Add(comment2);
 
            var comment21 = new BlogComment
            {
                Id = 6, Body = "پاسخ به نظر 2", HasChildren = false, ParentId = 5
            };
            list.Add(comment21);
 
            return list;
        }
    }
}
در اینجا نحوه‌ی مقدار دهی ParentId و HasChildren را جهت تو در تو سازی اطلاعات، مشاهده می‌کنید.
در این لیست دو رکورد، دارای ParentId مساوی null هستند. از این null بودن‌ها جهت کوئری گرفتن و نمایش ریشه‌های TreeView در ادامه استفاده خواهیم کرد.


بازگشت نظرات با فرمت JSON به سمت کلاینت

در ادامه یک کنترلر ASP.NET MVC را مشاهده می‌کنید که توسط اکشن متد GetBlogComments، رکوردهای مورد نظر را با فرمت JSON به سمت کلاینت ارسال می‌کند:
using System.Linq;
using System.Web.Mvc;
using KendoUI11.Models;
 
namespace KendoUI11.Controllers
{
 
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View(); // shows the page.
        }
 
        [HttpGet]
        public ActionResult GetBlogComments(int? id)
        {
            if (id == null)
            {
                //دریافت ریشه‌ها
                return Json(
                    BlogCommentsDataSource.LatestComments
                        .Where(x => x.ParentId == null) // ریشه‌ها
                        .ToList(),
                    JsonRequestBehavior.AllowGet);
            }
            else
            {
                //دریافت فرزندهای یک ریشه
                return Json(
                    BlogCommentsDataSource.LatestComments
                              .Where(x => x.ParentId == id)
                              .ToList(),
                              JsonRequestBehavior.AllowGet);
            }
        }
    }
}
اگر از سمت Kendo UI، مقدار id تنظیم نشود، به معنای درخواست نمایش ریشه‌ها است. در این حالت رکوردها را بر اساس مواردی که دارای ParentId مساوی null هستند، فیلتر خواهیم کرد.
اگر مقدار id به سمت سرور ارسال شود، یعنی کاربر گره و نودی را گشوده‌است. بر این اساس، تمامی فرزندان این گره را یافته و بازگشت می‌دهیم.


کدهای سمت کاربر نمایش Kendo UI Tree View

برای کار با Kendo UI TreeView نیاز است از منبع داده خاصی به نام HierarchicalDataSource به نحو ذیل استفاده کنیم. در قسمت transport آن مشخص می‌کنیم که اطلاعات باید از چه آدرسی خوانده شوند که در اینجا به آدرس اکشن متد  GetBlogComments اشاره می‌کند.
همچنین نیاز است مشخص کنیم کدامیک از خواص مدل بازگردانده شده، همان hasChildren است که در مثال فوق دقیقا به همین نام نیز تنظیم شده‌است.
<!--نحوه‌ی راست به چپ سازی -->
<div class="k-rtl k-header demo-section">
    <div id="my-treeview"></div>
</div>
 
@section JavaScript
{
    <script type="text/javascript">
        $(function () {
            var dataSource = new kendo.data.HierarchicalDataSource({
                transport: {
                    read: {
                        url: "@Url.Action("GetBlogComments", "Home")",
                        dataType: "json",
                        contentType: 'application/json; charset=utf-8',
                        type: 'GET'
                    }
                },
                schema: {
                    model: {
                        id: "Id",
                        hasChildren: "HasChildren"
                    }
                }
            });
 
            $("#my-treeview").kendoTreeView({
                //استفاده از قالب در صورت نیاز
                template: kendo.template($("#treeview-template").html()),
                checkboxes: {
                    checkChildren: false
                },
                dataSource: dataSource,
                dataTextField: "Body",
                //رخدادها
                select: function (e) { console.log("Selecting: " + this.text(e.node)); },
                check: function (e) { console.log("Checkbox changed :: " + this.text(e.node)); },
                change: function (e) { console.log("Selection changed"); },
                collapse: function (e) { console.log("Collapsing " + this.text(e.node)); },
                expand: function (e) { console.log("Expanding " + this.text(e.node)); }
            });
        });
    </script>
 
    <script id="treeview-template" type="text/kendo-ui-template">
        <strong> #: item.Body # </strong>
    </script>
 
    <style scoped>
        .demo-section {
            width: 100%;
            height: 300px;
        }
    </style>
}
 پس از تنظیم remote data source، اکنون نوبت به تعریف و تنظیم kendoTreeView است.
- در ابتدا به ازای هر ردیف این TreeView، از یک قالب استفاده شده‌است. تعریف این مورد اختیاری است. اگر نیاز به سفارشی سازی نحوه‌ی نمایش هر آیتم را داشتید، می‌توان از قالب‌ها استفاده کرد.
- قسمت checkboxes مشخص می‌کند که آیا نیاز است در کنار هر آیتم یک checkbox نیز نمایش داده شود یا خیر.
- dataSource را به HierarchicalDataSource تنظیم کرده‌ایم.
- dataTextField مشخص می‌کند که کدام فیلد دربرگیرنده‌ی متن هر آیتم TreeView است.
- تعدادی رخداد منتسب به TreeView نیز تنظیم شده‌اند که خروجی آن‌ها را در console تصویر ابتدای بحث مشاهده می‌کنید.


کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید.
مطالب دوره‌ها
نحوه‌ی ارتقاء برنامه‌های SignalR 1.x به SignalR 2.x
1) اگر هم اکنون یک پروژه جدید SignalR را آغاز و از طریق NuGet وابستگی‌های آن‌را اضافه کنید، به صورت خودکار SignalR نگارش 2 را در این تاریخ دریافت خواهید کرد. این نگارش صرفا با دات نت 4 و نیم به بعد سازگار است. بنابراین اولین کاری که باید برای ارتقاء پروژه‌های SignalR 1.x به نگارش جدید انجام دهید، تغییر Target framework پروژه به نگارش 4.5 است.
2) حذف وابستگی‌های قدیمی
 Uninstall-Package Microsoft.AspNet.SignalR -RemoveDependencies
فرمان فوق را اگر در کنسول پاورشل نیوگت اجرا کنید، به صورت خودکار وابستگی‌های قدیمی SignalR را حذف می‌کند.
3) نصب فایل‌های جدید SignalR
 Install-Package Microsoft.AspNet.SignalR
برای این منظور تنها کافی است دستور فوق را اجرا نمائید.
4) به روز رسانی ارجاعات اسکریپتی
 <script src="Scripts/jquery.signalR-2.0.0.min.js"></script>
ارجاع به افزونه جی‌کوئری SignalR نیز باید به نگارش 2 ارتقاء یابد.
5) حذف نحوه‌ی تعریف مسیریابی هاب‌های SignalR از فایل global.asax برنامه.
 protected void Application_Start(object sender, EventArgs e)
{
   //RouteTable.Routes.MapHubs();
}
فایل یاد شده را گشوده و سطر فوق را از آن حذف کنید. سپس یک کلاس دلخواه جدید را مثلا به نام Startup، ایجاد و محتوای آن را به نحو ذیل تغییر دهید:
using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(SignalRChat.Startup))]
namespace SignalRChat
{   
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }
}
این فایل به صورت خودکار در زمان آغاز برنامه‌های SignalR 2 مورد استفاده قرار می‌گیرد (با کمک ویژگی assembly: OwinStartup آن).
اگر از آخرین نگارش VS.NET استفاده می‌کنید، این کلاس را توسط گزینه Add -> New Item -> Owin Startup Class نیز می‌توانید اضافه نمائید.
مطالب دوره‌ها
استفاده از AutoMapper در برنامه‌های چند ریسمانی
نکته‌ی بسیار مهمی را که حین کار با AutoMapper باید بخاطر داشت، عدم thread safety متد Mapper.CreateMap آن است و استفاده‌ی از آن در برنامه‌های چند ریسمانی و خصوصا برنامه‌های وب، مشکلات متعددی را به همراه خواهد داشت. بنابراین بهترین محل تعریف و معرفی این نگاشت‌ها، در حین آغاز برنامه‌‌است؛ برای مثال در متد Application_Start فایل global.asax برنامه‌های وب، یا ابتدای متد Main برنامه‌های دسکتاپ.
برای نمونه یک چنین کدی را نباید در برنامه‌های خود داشته باشید:
public ActionResult Index()
{
    Mapper.CreateMap<UserViewModel, User>();
    //ادامه‌ی کدها
در اینجا از متد استاتیک Mapper.CreateMap، در یک اکشن متد برنامه‌ی ASP.NET MVC استفاده شده‌است. این متد thread safe نیست و چون کار تنظیمات اولیه‌ی این نگاشت‌ها (پیش از کش شدن آن‌ها) اندکی زمانبر است، ممکن است در این بین، دو کاربر همزمان به این قطعه کد رسیده و شاهد این باشند که تعدادی از خواص در اینجا نگاشت نشده‌اند.

نمونه‌ی دیگر آن، یک چنین کدهایی هستند:
    using (var context = new TestDbContext())
    {
        Mapper.CreateMap<SourceClass, DestinationClass>()
            .AfterMap((src, dest) =>
            {
                  //using context
            });

         var dest = Mapper.Map<DestinationClass>(source);
    }
در اینجا برحسب نیاز از context مربوط به Entity framework داخل تنظیمات Mapper.CreateMap استفاده شده‌است. متد Mapper.CreateMap استاتیک است و context استفاده شده‌ی در آن thread safe نیست. همینجا است که مشکلات تخریب اطلاعات را شاهد خواهید بود.
اگر در یک چنین حالتی نیاز به استفاده‌ی context داشتید، بهتر است متدهای استاتیک AutoMapper را فراموش کرده و به نحو ذیل یک موتور محلی نگاشت را ایجاد کنید. چون سطح دید و دسترسی این موتور، عمومی و سراسری نیست، مشکلات thread safety را نخواهد داشت.
 var configurationStore = new ConfigurationStore(new TypeMapFactory(), MapperRegistry.Mappers);
configurationStore.AddProfile<TestProfile1>();
var mapper = new MappingEngine(configurationStore);
configurationStore.CreateMap<SourceClass, DestinationClass>()
//ادامه‌ی کدها 
مطالب
بررسی مفاهیم متغیرهای Value Type و Reference Type در سی شارپ
نوع داده(Data Type) ، متغیر‌ها(Variables) ، انواع مقداری(Value Type) ، انواع ارجاعی(Reference Type)

مقدمه :
نوع داده‌ها، اجزای اصلی سازنده‌ی یک زبان برنامه نویسی و شبیه قواعد هر زبانی هستند.
مفاهیمی که در این مطلب بررسی خواهد شد :
 • Data Type نوع داده
 • Variables  متغیرها
 • Naming Convention قرارداد‌های نامگذاری
 • Value Type/Reference Type انواع مقداری و ارجاعی
 • Stack/heap memory  حافظه پشته و هرم

نوع داده

در دنیای واقعی، برای نگهداری مواد مختلف، ظروف مختلفی با اندازه‌های مختلفی طراحی شده است. در دنیای برنامه نویسی، به تناسب اطلاعاتی که می‌خواهیم در حافظه ذخیره کنیم، باید نوع ظرف ذخیره سازی را انتخاب کنیم. نوع ظرف ذخیره سازی را در دنیای برنامه نویسی، نوع داده‌ها مشخص می‌کنند.
در دات نت، همه‌ی نوع داده‌ها (Data Type) بصورت مستقیم و یا غیر مستقیم، از کلاس System.Object مشتق شده‌اند.


متغیرها

متغیر‌ها برای ذخیره‌ی مقادیر (اطلاعات)، استفاده می‌شوند. به این مثال دقت کنید: ما یک کیف داریم که در آن یک کتاب قرار دارد. در اینجا کیف نقش متغیر و کتاب نقش مقدار (value) را ایفا می‌کند. اندازه‌ی کیف همان نوع داده (Data Type) در دنیای برنامه نویسی می‌باشد.


چک کردن سایز نوع داده (Data Type)

ما نیازی به حفظ کردن اندازه‌ی نوع داده‌ها نداریم. در سی شارپ متدی به نام () sizeof مهیا شده است که با چک کردن نوع داده، اندازه‌ی آن را بر حسب بایت نمایش می‌دهد.
به مثال زیر دقت کنید:
Console.WriteLine(sizeof(int));
Console.WriteLine(sizeof(char));
Console.WriteLine(sizeof(bool));
Console.WriteLine(sizeof(decimal));
Console.WriteLine(sizeof(float));
خروجی کد‌های بالا :
 4
2
1
16
4

نکته : متد sizeof فقط برای نمایش اندازه‌ی نوع داده‌های مقداری (value type) می‌تواند مورد استفاده قرار گیرد.


چک کردن نوع داده

ما می‌توانیم نوع داده‌ها را برای بدست آوردن کلاسی که به آن تعلق دارند، چک کنیم.
مثال :
 int a = 23;
float b = 3.14f;
Console.WriteLine(a.GetType());
Console.WriteLine(b.GetType());
خروجی کد‌های بالا : 
System.Int32
System.Single

چک کردن نوع داده‌ی دو شیء

فرض کنید 2 شیء را با نام‌های obj1 و obj2 داریم که هر دو از نوع long هستند. برای اینکه این مقایسه را انجام دهیم، از متد Object.RefrenceEqual می‌توان استفاده کرد.
مثال :
long obj1 = 356;
long obj2 = 54;
float obj3 = 234;
Console.WriteLine(object.ReferenceEquals(obj1.GetType(), obj2.GetType()));
Console.WriteLine(object.ReferenceEquals(obj1.GetType(), obj3.GetType()));
خروجی کد‌های بالا : 
True
False

تعریف یک متغیر ومقدار دهی به آن
سی شارپ یک زبان strongly typed است (البته با در نظر نگرفتن نوع dynamic آن). به این معنا که کلیه‌ی متغیر‌ها، قبل از استفاده باید تعریف و مقدار دهی شوند و بعد از تعریف متغیر، نمی‌توان نوع آن را تغییر داد. رفتار یک متغیر بر اساس نوع انتخابی ما مشخص می‌شود. بطور مثال با انتخاب نوع int تنها می‌توان اعداد صحیح را ذخیره و نگهداری کرد و برای تغییر رفتار متغیر‌ها باید آنها را تبدیل کنیم.

تعریف یک متغیر
برای استفاده از یک متغیر ابتداباید آن را تعریف کنیم :
//<data type> <variable name>;
Int a;

مقداردهی اولیه یک متغیر

مقدار دهی اولیه‌ی یک متغیر با استفاده از عملگر = و نوشتن مقدار مورد نظر برای ذخیره کردن در متغیر، در سمت راست عملگر اتفاق خواهد افتاد.
//<data type> <variable name>=value;
Int a=23;
Int a;//declare تعریف
a=23;//مقدار دهی اولیه initializing
Int a=23;//تعریف و مقدار دهی در یک خط
Int a,b,c=23;//تعریف چند متغیر و مقدار دهی در یک خط


قرار دا‌دهای نام گذاری متغیر‌ها :

در دنیای برنامه نویسی دو نوع قرار داد نام گذاری بسیار متداول وجود دارند:
 1-  camelCase : در این قرار داد، حرف اول کلمه‌ی اول، بصورت کوچک و حرف اول از کلمه‌ی دوم، بصورت بزرگ نوشته خواهد شد. برای مثال: firstName,lastName
 2- PascalCase : در این قرار داد حروف ابتدایی دو کلمه‌ی مجاور، بصورت بزرگ نوشته خواهند شد: FirstName,LastName

چند نکته :
 • نامگذاری متغیر‌ها را می‌توانید با علامت _ و یا @ شروع کنید.
 • کلمات کلیدی (key word) سی شارپ نمی‌توانند به عنوان نام متغیر مورد استفاده قرار بگیرند (مگر آنکه با @ شروع شوند).
 • در بین نام متغیر نباید فضای خالی وجود داشته باشد. کاراکتر‌های سازنده‌ی متغیر می‌توانند اعداد، حروف و زیر خط باشند.
لیستی از نام گذاری‌های مجاز:
 int abc;
long _abcd;
float @abcd;
bool main_button;
decimal piValue;
string firstName;
string first_name;
bool button55_on;
لیستی از نام گذاری‌های غیر مجاز
long _a.5bc5d;
float @ab cd;
decimal pi@Value;
//استفاده از کلمات کلیدی سی شارپ که کامپایلر آنها را مجاز نمی‌داند
bool class;
string namespace;
string string;
int static;
برای مطالعه‌ی کاملتر کلمات کلیدی سی شارپ می‌توانید اینجا را مطالعه کنید.


در ادامه کمی در مورد نوع داده‌ها بحث خواهیم کرد.
در سی شارپ دو مدل نوع داده وجود دارد:
 • انواع مقداری Value Type
 • انواع ارجاعی یا اشاره‌ای Reference Type

انواع مقداری (Value Type) :
 • انواع مقداری مستقیما حاوی داده‌ها هستند. اگر یک متغیر از نوع مقداری را به یک متغیر دیگر تخصیص دهید، مقدار آنها مستقیما کپی می‌شوند؛ برعکس نوع‌های اشاره‌ای که با نخصیص یک متغیر به یک متغیر دیگر، تنها اشاره‌گر به مقدار شیء کپی خواهد شد و نه خود شیء.
 • کلیه نوع‌های مقداری از کلاس ValueType مشتق شده‌اند.
 • در فضای stack  به آنها حافظه تخصیص داده می‌شود.
 • نمی‌توانند مقدار null  بپذیرند. البته با قابلیت nullabletype امکان تخصیص مقدار null به نوع داده‌های مقداری نیز مهیا شده است.
 • همه نوع‌های داده‌های مقداری، یک سازنده پیش فرض دارند که به صورت ضمنی کار مقدار دهی اولیه برای آنها را انجام می‌دهد. برای مطالعه بیشتر درباره مقادیر پیش فرض به اینجا مراجعه کنید.

انواع مقداری به دو دسته‌ی اصلی تقسیم می‌شود :
 • Structs
 • Enumerations

طبقه بندی Structs به صورت زیر است :
 • Numeric Type
* Integral Type : sbyte,short,ushort,int,uint,long,ulong,char
* Floating-Point Types : float,double
* Decimal : decimal
 •  Bool دو مقدار true و false
 • User Defined Struct


نوع داده نال (تهی) پذیر (nullable Type) و چگونگی تعریف آن

در ابتدای معرفی نوع داده‌های مقداری گفتیم همیشه باید وضعیت متغیر مشخص و مقدار دهی اولیه‌ی آن یا به صورت ضمنی و یا آشکار انجام شود. هیچ یک از نوع داده‌های مقداری نمی‌توانند بصورت null تعریف شوند. برای تبدیل یک نوع داده مقداری به صورتی که قابلیت ذخیره‌ی مقدار null را داشته باشد، بعد از نوشتن نوع داده، علامت سوال ؟ قرار می‌دهیم.
 < data type >? < variable name >= null; //syntax

int? a = null; //assigning null
int? b = 55; //assigning null and a value
var? c = 55 //it will give error

نکته :  var نمی‌تواند بصورت nullable تعریف شود.

برای چک کردن مقدار در انواع تهی پذیر (nullable) دو خصوصیت وجود دارد:
 • HasValue
اگر مقداری در متغیر وجود داشته باشد ارزش true  بازگردانده می‌شود؛ در غیر اینصورت ارزش false
 • Value
مقدار واقعی متغیر را باز می‌گرداند.

مثال :
 int? a = null;
int? b = 22;
Console.WriteLine(a.HasValue);
//------------
Console.WriteLine(b.HasValue);
Console.WriteLine(b.Value);
خروجی کد بالا :
 False
True
22

انواع ارجاعی Reference Type

انواع ارجاعی مستقیما حاوی اطلاعات نیستند و ارجاعی هستند به آدرسی از حافظه که حاوی اطلاعات واقعی است. به بیانی دیگر، اشاره‌گری به آدرسی از حافظه هستند.
 • انواع ارجاعی بصورت غیر مستقیم حاوی داده‌ها هستند.
 • در بخشی از حافظه که به آن heap می‌گوییم، به آنها فضا اختصاص داده می‌شود.
 • می‌توانند بصورت null (بدون مقدار) باشند.

انواع ارجاعی نیز به دو دسته‌ی کلی تقسیم می‌شوند :

 • انواع از پیش تعریف شده
  Object,string,dynamic
 • انواع تعریف شده توسط کاربر
        class,interface,delegate

نکته : آدرس مکانی از حافظه که داده‌ها در آن قرار دارند، در بخش پشته یا Stack ذخیره می‌شود و داد‌ه‌ها در فضای heap ذخیره می‌شوند.
مثال :
 test obj; //allocating reference on stack
obj= new test(55);//allocating object on heap

نکته : دو متغیر از نوع ارجاعی می‌توانند به یک آدرس از حافظه اشاره کنند. در شکل زیر این موضوع نشان داده شده است.

 
در شکل زیر طبقه بندی نوع داده‌ها در سی شارپ نشان داده شده است :


• عملیات کپی در نوع داده مقداری
وقتی از یک متغیر مقداری را به یک متغیر دیگر تخصیص می‌دهیم، یک کپی جدید از آن در فضای stack  ایجاد می‌شود. بدین معنی که محتوای دو متغیر یکسان هستند، ولی در دو بخش مجزای در حافظه‌ی Stack قرار دارند. به همین خاطر تغییر  محتوای یک متغیر، محتوای متغیر دیگر را تغییر نمی‌دهد.
مثال :
 int a = 55;//declare a and initialize
int copya = a;//copya contains the copy of value a
دیاگرام حافظه کد بالا :

 

• عملیات کپی، در نوع داده‌ی ارجاعی
وقتی یک متغیر از نوع ارجاعی را به یک متغیر دیگر تخصیص می‌دهیم، دو اشاره‌گر در فضای Stack ایجاد می‌شود که به یک مقدار واحد در حافظه‌ی heap اشاره می‌کنند. آدرس‌های ذخیره شده‌ی در stack  یکسان هستند.
مثال : در اینجا فرض بر این است کهtest یک کلاس تعریف شده‌ی توسط کاربر می‌باشد.
test obj;
obj=new test(23);
test objCopy;
objCopy = obj;

دیاگرام حافظه‌ی قطعه کد بالا به شکل زیر است :



تخصیص حافظه در بخش Stack  و Heap به متغیر‌ها

سیستم عامل و net CLR. حافظه را به دو بخش stack و heap تقسیم بندی می‌کنند.
زمانی که یک متد را فراخوانی می‌کنیم، در بخش پشته به پارامتر‌های متد فضا تخصیص داده می‌شود و بعد از پایان کار متد، فضای اشغال شده‌ی بوسیله GC یا همان Garbage collection  آزاد می‌شود.
تخصیص حافظه در Stack  بر اساس قانون LIFO انجام و به ترتیب و پشت سر هم، حافظه تخصیص داده می‌شود. دیاگرام تخصیص حافظه به stack:


تخصیص حافظه در Heap بصورت تصادفی است؛ بر عکس پشته (stack) که به ترتیب و متوالی انجام می‌شد. انواع ارجاعی در Stack  ذخیره می‌شوند؛ ولی داده‌ی واقعی در heap قرار می‌گیرد.
حافظه‌های پویا در بخش heap و حافظه‌های استاتیک در بخش stack تخصیص داده می‌شوند.
 
مطالب
آشنایی با ساختار IIS قسمت پنجم
در مطالب قبلی در مورد ماژولار بودن IIS زیاد صحبت کردیم، ولی اجازه بدهید این مورد را به صورت کاربردی‌تر و موشکافانه‌تر بررسی کنیم. برای اینکه به مشکلی در طول این سری از مطالب برنخورید، IIS را به صورت کامل یعنی full feature نصب نمایید. از بخش control panel>programs & features>Turn Windows features on or off اقدام نمایید و هرچه زیر مجموعه Internet information service هست را برگزینید. در صورتی که از نسخه‌های ویندوز سرور 2008 استفاده می‌کنید از طریق server manager>roles>web server اقدام نمایید.
برای نصب یک ماژول باید دو مرحله را انجام داد:
  1. نصب ماژول
  2. فعال سازی ماژول
نکته ای که در مورد ماژول‌های native وجود دارد این هست که این ماژول‌ها دسترسی بدون محدودیتی به منابع سروری دارند و از این رو حتما باید این نکته را دقت کنید که ماژول native شما از یک منبع مورد اعتماد دریافت شده باشد.

نصب یک native module
برای نصب می‌توانید یکی از سه راه زیر را استفاده کنید:
  1. ویرایش دستی فایل کانفیگ و از نسخه IIS7.5 به بعد هم می‌توانید از configuration editor هم استفاده کنید.
  2. استفاده از محیط گرافیکی IIS
  3. استفاده از خط فرمان با دستور Appcmd
مزیت روش دستی این هست که شما دقیقا می‌دانید در پشت صحنه چه اتفاقی می‌افتد و نتیجه هر کدام از این سه روش، اضافه شدن یک مدخل ورودی به تگ <globalmodules> است. برای اعمال تغییرات، مسیر زیر را بروید:
%windir%\system32\inetsrv\config\applicationhost.config
کسی که نیاز به دسترسی به این مسیر و انجام تغییرات دارد باید در بالاترین سطح مدیریتی سرور باشد.
اگر فایل را باز کنید و تگ globalmodule را پیدا کنید متوجه می‌شوید که تمامی ماژول‌ها در این قسمت معرفی شده‌اند و برای خود یک مدخل ورودی یا همان تگ add را دارند که در آن مسیر فایل dll هم ذکر شده است:
<globalModules> 
 
 <addname="DefaultDocumentModule"image="%windir%\system32\inetsrv\defdoc.dll"/> 
 
 <addname="DirectoryListingModule"image="%windir%\system32\inetsrv\dirlist.dll"/> 

<add name="StaticFileModule"image="%windir%\system32\inetsrv\static.dll"/>
...

 </globalModules>

برای حذف یا جایگزینی یک ماژول به راحتی می‌توانید مدخل ورودی یک ماژول را به صورت دستی حذف نمایید و برای جایگزینی هم بعد از حذف، ماژول خود را معرفی کنید. ولی توجه داشته باشید که این حذف به معنی حذف این ماژول از تمامی اپلیکیشن‌های موجود بر روی IIS هست و سپس اضافه کردن یک ماژول به این بخش. همچنین اگر قصد شما فقط حذف یک ماژول از روی یکی از اپلیکشن‌ها باشد باید از طریق فایل کانفیگ سایت از مسیر تگ‌های <system.webserver><modules> و با استفاده از تگ‌های add و remove به معرفی یک ماژول مختص این اپلیکیشن و یا حذف یک ماژول خاص اقدام نمایید.

PreConditions
این ویژگی می‌تواند در خط معرفی ماژول، مورد استفاده قرار بگیرد. اگر به فایل نگاه کنید می‌بینید که در بعضی خطوط این ویژگی ذکر شده است. تعریف این ویژگی به هسته IIS می‌گوید که این ماژول در چه مواردی و به چه شیوه ای باید به کار گرفته شود.
 <add name="ManagedEngine64" image="%windir%\Microsoft.NET\Framework64\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness64" /> 
 
 <add name="ManagedEngine" image="%windir%\Microsoft.NET\Framework\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness32" /> 
 
<add name="ManagedEngineV4.0_32bit" image="%windir%\Microsoft.NET\Framework\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness32" /> 
 
<add name="ManagedEngineV4.0_64bit" image="%windir%\Microsoft.NET\Framework64\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness64" />

مقادیری که precondition میتواند بگیر شامل موارد زیر هستند:
bitness
این گزینه به دو صورت bitness32 و bitness64 یافت می‌شود. امروزه پردازنده‌های 64 بیتی بسیار متداول شده اند و بسیاری از تولید کنندگان دارند به سمت عرضه ابزارهای 64 بیتی رو می‌آورند و به زودی عرضه‌های 32 بیتی را متوقف می‌کنند و به سمت سیستم عامل‌های 64 بیت سوییچ خواند کرد ولی باز هم هنوز برنامه‌های 32 بیتی زیادی هستند که مورد استفاده قرار می‌گیرند و نمی‌توان آن‌ها را نادیده گرفت. برای همین ویندوزهای 64 بیتی مایکروسافت در کنار محیط 64 بیتی‌شان از یک محیط 32 بیت به اسم WOW64 استفاده می‌کنند. در این حالت این امتیاز به شما داده می‌شود که از پروسه‌های کارگر 32 بیتی در کنار پروسه‌های کارگر 64 بیتی استفاده کنید و PreCondition به bitness32 یا bitness64 تنظیم می‌شود تا از صحت بارگزاری dll در یک محیط درست مطمئن شود. در صورتی که این خصوصیت ذکر نشود یک هندلر 32 بیتی و 64 بیتی و یک module map اجرا می‌شود.

Runtime version
اگر ماژول خاصی برای اجرا به ورژن خاصی از net framwork. نیاز دارد، این ویژگی ذکر می‌شود. در صورتی که ماژولی قصد اجرای بر روی فریم ورک اشتباهی داشته باشد سبب خطا خواهد شد.

Mana gedHandler 
با معرفی IIS7 ما با یک مدل توسعه پذیر روبرو شدیم و می‌توانستیم ماژول‌ها و هندلرهای خود را بنویسیم و مستقیما در Pipeline قرار دهیم ولی سوییچ کردن بین دو بخش کدهای مدیریت شده و native یک عمل سنگین برای سیستم به شمار می‌آید و به منظور کاهش این بار گزینه managedhandler قرار داده شده است تا تعیین کند مواقعی که درخواست نیازی به این ماژول ندارد، این ماژول اجرا نگردد. به عنوان مثال فایل‌های ایستا چون jpg یا html و... شامل این ماژول نخواهند شد. واضح‌ترین مثال در این زمینه Forms Authentication می‌باشد و موقعی اجرا می‌شوند که درخواست فایل‌های aspx شده باشد و اگر یک فایل html را درخواست کنید این ماژول امنیتی روی آن اثری ندارد و عملیات شناسایی هویت روی آن اجرا نمی‌شود و اگر می‌خواهید روی همه فایل‌ها، این عملیات شناسایی انجام شود باید خصوصیت "precondition="managedhandler حذف شود.
در صورتی که تگ module را به صورت زیر بنویسید تمامی ماژول‌ها برای تمامی درخواست‌ها اجرا خواهد شد، صرف نظر از اینکه آیا ماژولی به صورت "precondition="managedmodule مقداردهی شده است یا خیر.
<modules runAllManagedModulesForAllRequests="true"/>
 
The Mode Precondition 
تا به الان گفتیم که چگونه میتوانیم یک ماژول و یا هندلر مدیریت شده‌ای را به Pipeline اضافه کنیم؛ ولی IIS7 به بالا نیاز دارد که تا پروسه‌های کارگر را به روشی خاص به این منظور اجرا کند و فریم ورک دات نت را برای اجرای آن‌ها بارگزاری کند. همچنین به اجرای ماژولی به اسم webengine.dll برای مدیریت  ماژولهای مدیریت شده نیازمند است و خود IIS در مورد کدهای مدیریت شده چیزی متوجه نمی‌شود. پس ما برای اینکه IIS را متوجه این موضوع نمائیم، باید Integrated mode را به آن معرفی کنیم.
در نسخه‌های قبلی IIS یک روش قدیمی برای کدهای مدیریت شده وجود داشت که از طریق اینترفیسی به نام ISAPI صورت می‌گرفت. در این حالت ASPNET_ISAPI.DLL مسئول این کار بود و اگر هنوز هم میخواهید از این dll در نسخه‌های جدیدتر IIS کمک بگیرید باید به جای معرفی classic mode ، integration mode را معرفی کنید.
با برابر کردن precondtion به مقدار "intgretedmode" هندلر یا ماژول شما در یک پول با خصوصیت integrated بارگزاری خواهد شد و اگر مقدار آن "classicmode" باشد در یک پول بدون خاصیت integrated بارگزاری می‌شود.
تفاوت بین دو روش کلاسیک و مجتمع integrated بر سر این هست که در روش جدید، ماژول شما به عنوان یک پلاگین برای IIS دیده نمی‌شود و کد شما را جزئی از کامپوننت‌های خود به شمار می‌آورد. به صورت واضح‌تر در حالت کلاسیک موقعی که درخواستی وارد pipeline میشد ابتدا از کامپوننت‌ها و ماژول‌های داخلی خود IIS عبور داده میشد و بعد فایل ASPNET_ISAPI.DLL جهت پردازش کدهای مدیریت شده صدا زده میشد و با توجه به کدهای شما، بعضی مراحل تکرار میشد؛ مثلا اگر کد شما در مورد Authentication بود و بعد از گذر از مراحل auth داخل خود IIS و بقیه موارد دوباره نوبت کد شما و گذر از مراحل authentication بود. یعنی وجود دو pipeline؛ ولی در حالت مجتمع این دوبار انجام وظیفه از بین رفته است چرا که کدهای شما به طور مستقیم در pipeline قرار دارند و آن‌ها را جزئی از خود می‌داند، نه یک پلاگین که افزون بر فعالیت خودشان، اجرای کدهای شما رو هم بر دوش بکشند.
شکل زیر نمونه ای از حالت کلاسیک را نشان می‌دهد که در آن دو بار عمل auth دارد انجام میگیرد.
 



شکل زیر هم نمونه ای حالت مجتمع هست:

 
در کل امروزه دیگر استفاده از روش کلاسیک راهکار درستی نیست و این ویژگی تنها به عنوان یک سازگاری با نمونه کارهای قدیمی است.
تگ‌هایی که از خصوصت precondition استفاده می‌کنند به شرح زیر هستند:
  • ISAPI filters 
  • globalModules 
  • handlers 
  • modules 

در مورد بقیه تگ‌ها در آینده بیشتر بحث می‌کنیم. بهتر هست مطلب را با توضیح precondition جهت ممانعت از طولانی و طومار شدن در اینجا ببندیم و در قسمت آینده دیگر روش‌های نصب ماژولمان را دنبال کنیم.
مطالب
استفاده از Google Analytics API در دات نت فریم ورک

بالاخره گوگل کار تهیه API مخصوص ابزار Analytics خود را به پایان رساند و اکنون برنامه نویس‌ها می‌توانند همانند سایر سرویس‌های گوگل از این ابزار گزارشگیری نمایند.
خلاصه کاربردی این API ، دو صفحه تعاریف پروتکل (+) و ریز مواردی (+) است که می‌توان گزارشگیری نمود.
هنوز کتابخانه google-gdata جهت استفاده از این API به روز رسانی نشده است؛ بنابراین در این مقاله سعی خواهیم کرد نحوه کار با این API را از صفر بازنویسی کنیم.
مطابق صفحه تعاریف پروتکل، سه روش اعتبارسنجی جهت دریافت اطلاعات API معرفی شده است که در اینجا از روش ClientLogin که مرسوم‌تر است استفاده خواهیم کرد.
مطابق مثالی که در آن صفحه قرار دارد، اطلاعاتی شبیه به اطلاعات زیر را باید ارسال و دریافت کنیم:

POST /accounts/ClientLogin HTTP/1.1
User-Agent: curl/7.15.1 (i486-pc-linux-gnu) libcurl/7.15.1
OpenSSL/0.9.8a zlib/1.2.3 libidn/0.5.18
Host: www.google.com
Accept: */*
Content-Length: 103
Content-Type: application/x-www-form-urlencoded
accountType=GOOGLE&Email=userName@google.com&Passwd=myPasswrd&source=curl-tester-1.0&service=analytics

HTTP/1.1 200 OK
Content-Type: text/plain
Cache-control: no-cache
Pragma: no-cache
Date: Mon, 02 Jun 2008 22:08:51 GMT
Content-Length: 497
SID=DQ...
LSID=DQAA...
Auth=DQAAAG8...
در دات نت فریم ورک، این‌کار را به صورت زیر می‌توان انجام داد:
        string getSecurityToken()
{
if (string.IsNullOrEmpty(Email))
throw new NullReferenceException("Email is required!");

if (string.IsNullOrEmpty(Password))
throw new NullReferenceException("Password is required!");

WebRequest request = WebRequest.Create("https://www.google.com/accounts/ClientLogin");
request.Method = "POST";

string postData = "accountType=GOOGLE&Email=" + Email + "&Passwd=" + Password + "&service=analytics&source=vahid-testapp-1.0";
byte[] byteArray = Encoding.ASCII.GetBytes(postData);

request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;

using (Stream dataSt = request.GetRequestStream())
{
dataSt.Write(byteArray, 0, byteArray.Length);
}

string auth = string.Empty;
using (WebResponse response = request.GetResponse())
{
using (Stream dataStream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(dataStream))
{
string responseFromServer = reader.ReadToEnd().Trim();
string[] tokens = responseFromServer.Split('\n');
foreach (string token in tokens)
{
if (token.StartsWith("SID="))
continue;

if (token.StartsWith("LSID="))
continue;

if (token.StartsWith("Auth="))
{
auth = token.Substring(5);
}
else
{
throw new AuthenticationException("Error authenticating Google user " + Email);
}
}
}
}
}

return auth;

}

همانطور که ملاحظه می‌کنید به آدرس https://www.google.com/accounts/ClientLogin ، اطلاعات postData با متد POST ارسال شده (دقیقا مطابق توضیحات گوگل) و سپس از پاسخ دریافتی، مقدار نشانه Auth را جدا نموده و در ادامه عملیات استفاده خواهیم کرد. وجود این نشانه در پاسخ دریافتی به معنای موفقیت آمیز بودن اعتبار سنجی ما است و مقدار آن در طول کل عملیات باید نگهداری شده و مورد استفاده مجدد قرار گیرد.
سپس مطابق ادامه توضیحات API گوگل باید لیست پروفایل‌هایی را که ایجاد کرده‌ایم پیدا نمائیم:

string getAvailableProfiles(string authToken)
{
return fetchPage("https://www.google.com/analytics/feeds/accounts/default", authToken);
}

متد fetchPage را از پیوست این مقاله می‌توانید دریافت نمائید. خروجی یک فایل xml است که با انواع و اقسام روش‌های موجود قابل آنالیز است، از کتابخانه‌های XML دات نت گرفته تا Linq to xml و یا روش serialization که من روش آخر را ترجیح می‌دهم.
مرحله بعد، ساخت URL زیر و دریافت مجدد اطلاعات مربوطه است:
            string url = string.Format("https://www.google.com/analytics/feeds/data?ids={0}&metrics=ga:pageviews&start-date={1}&end-date={2}", id, from, to);
return fetchPage(url, auth);
و سپس آنالیز اطلاعات xml دریافتی، جهت استخراج تعداد بار مشاهده صفحات یا pageviews استفاده شده در این مثال. لیست کامل مواردی که قابل گزارشگیری است، در صفحه Dimensions & Metrics Reference گوگل ذکر شده است.

فایل‌های کلاس‌های مورد استفاده را از اینجا دریافت نمائید.‌

مثالی در مورد نحوه استفاده از آن:
            CGoogleAnalytics cga = new CGoogleAnalytics
{
Email = "username@gmail.com",
Password = "password",
From = DateTime.Now.Subtract(TimeSpan.FromDays(1)),
To = DateTime.Now.Subtract(TimeSpan.FromDays(1))
};
List<CGoogleAnalytics.SitePagePreviews> pagePreviews =
cga.GetTotalNumberOfPageViews();

foreach (var list in pagePreviews)
{
//string site = list.Site;
//int pw = list.PagePreviews;
}

نظرات مطالب
افزودن یک DataType جدید برای نگه‌داری تاریخ خورشیدی - 1
سلام
کدهای شمارو درست همونطوریکه گفتین کپی کردم ولی موقعی که Publish رو میزنم پیغام زیر رو میده :
Publish cannot begin until your project(s) build successfully
و پنجره publish ظاهر نمی‌شه و هیچ جایی هم برای تعریف کانکشن وجود نداره... مشکل از کجاست؟
دوم اینکه clr رو هربار که خواستیم روی یک دیتابیس جدید این نوع رو تعریف کنیم باید فعال کنیم... مثلا توی ایجاد سال مالی جدید که سیستم یک دیتابیس خام ایجاد میکنه تا مانده حسابها رو بهش انتقال بدیم قبلش باید دستور فعال سازی clr رو هم مجددا بدیم یافقط توی زمان طراحی کفایت میکنه ؟
سوم اینکه : در مورد استفاده اون توی EF Code First هم اگه نکته‌ی خاصی وجود داره محبت کنین ممنون میشم.
شاد وپیروز باشید.
مطالب دوره‌ها
معرفی پروژه NotifyPropertyWeaver
پس از معرفی مباحث IL Code Weaving و همچنین ارائه راه حلی در مورد «استفاده از AOP Interceptors برای حذف کدهای تکراری INotifyPropertyChanged در WPF» راه حل مشابهی به نام NotifyPropertyWeaver ارائه شده است که همان کار AOP Interceptors را انجام می‌دهد؛ اما بدون نیاز به تشکیل پروکسی و سربار اضافی. کار نهایی را توسط ویرایش اسمبلی و افزودن کدهای IL لازم انجام می‌دهد؛ البته بدون استفاده از PostSharp. این پروژه از کتابخانه سورس باز پایه‌ای به نام Fody استفاده می‌کند که جهت IL Code weaving طراحی شده است.
اگر به Wiki آن مراجعه نمائید، لیست افزونه‌های قابل توجهی را در مورد آن خواهید یافت که PropertyChanged تنها یکی از آن‌ها است.


پیشنیازها
الف) صفحه پروژه در GitHub
ب) دریافت از طریق نوگت


روش استفاده

پس از نصب بسته نوگت پروژه PropertyChanged.Fody
 PM> Install-Package PropertyChanged.Fody
کلاسی را که باید پس از کامپایل، پیاده سازی‌های خودکار OnPropertyChanged را شامل شود، با ویژگی ImplementPropertyChanged مزین کنید.
using PropertyChanged;

namespace AOP02
{
    [ImplementPropertyChanged]
    public class Person
    {
        public string Id { set; get; }
        public string Name { set; get; }
    }
}
و سپس پروژه را کامپایل نمائید. خروجی کنسول Build در VS.NET :
------ Build started: Project: AOP02, Configuration: Debug x86 ------
  Fody (version 1.13.6.1) Executing
  Finished Fody 287ms.
  AOP02 -> D:\Prog\AOP02\bin\Debug\AOP02.exe
========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========
اکنون اگر فایل اسمبلی نهایی پروژه را در برنامه ILSpy باز کنیم، چنین پیاده سازی را می‌توان شاهد بود:
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace AOP02
{
    public class Person : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public string Id
        {
            [System.Runtime.CompilerServices.CompilerGenerated]
            get
            {
                return this.<Id>k__BackingField;
            }
            [System.Runtime.CompilerServices.CompilerGenerated]
            set
            {
              if (string.Equals(this.<Id>k__BackingField, value, System.StringComparison.Ordinal))
              {
                  return;
              }
              this.<Id>k__BackingField = value;
              this.OnPropertyChanged("Id");
            }
        }
        public string Name
        {
            [System.Runtime.CompilerServices.CompilerGenerated]
            get
            {
               return this.<Name>k__BackingField;
            }
            [System.Runtime.CompilerServices.CompilerGenerated]
            set
           {
             if (string.Equals(this.<Name>k__BackingField, value, System.StringComparison.Ordinal))
             {
                return;
             }
             this.<Name>k__BackingField = value;
             this.OnPropertyChanged("Name");
            }
        }
        public virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
            if (propertyChanged != null)
            {
                propertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}