نظرات مطالب
EF Code First #13
سلام
در صورتی که در query از join و group استفاده کنیم، یعنی در خروجی ResultSet فیلدهای چند جدول و همچنین یکسری فیلدهای جدید که توسط توابع تولید می شوند را داشته باشیم، نحوه نگاشت به کلاس ها چگونه خواهد بود؟ EF خودش آن را مدیریت می کند؟
نظرات مطالب
EF Code First #2
سلام آقای نصیری.
code first اجازه درست کردن trigger رو می‌ده؟
کلا من یه مکانیزمی می‌خوام که اگه کسی (غیر خودم) تو یه جدول خاص insert کرد با یه چیزی مثل event تو برنامه متوجه بشم.
بازخوردهای پروژه‌ها
قراردادن فیلد Hyperlink
با سلام
آیا امکان تعریف فیلدهایی که حاوی لینک میباشند در گزارشات وجود دارد؟
مثلا گزارشی از سایت‌ها داشته باشم که مشخصات سایت‌ها توی جدول قرار بگیرند و با کلیک  بر روی نام سایت یا یه تصویر سایت مربوطه باز بشه؟
نظرات مطالب
پلاگین DataTables کتابخانه jQuery - قسمت چهارم
سلام، خواهش می‌کنم. می‌تونید در سمت سرور بعد از واکشی اطلاعات از دیتابیس اونو داخل یک منبع داده درون حافظه ای بریزید و هر تعداد ستون که لازم دارید به اون منبع داده جدید اضافه کنید. و با مقدارهای مناسبی هر مدخل از اون منبع داده رو پر کنید. مثلا فرضا اگه جدول دیتابیس شما دارای سه ستون Code و Caption و Comment هست کلاس جدیدی بسازید که این سه تا ستون رو داره (به عنوان پروپرتی) و پروپرتی‌های دلخواه دیگه ای هم داره. مثلا پروپرتی RowNumber . بعد لیستی از داده‌ها رو که از دیتابیس واکشی کردید داخل لیستی از ViewModel ساخته شده بریزید و خصوصیت RowNumber هر ViewModel رو مقداردهی مناسبی کنید.
نظرات مطالب
بررسی تفصیلی رابطه Many-to-Many در EF Code first
سلام
در قسمت :
//فقط موارد جدید به تگ‌ها و ارتباطات موجود اضافه می‌شوند
foreach (var tag in data.Tags)
{
     if (!listOfActualTagNames.Contains(tag.ToLowerInvariant().Trim()))
     {
            _tag.Add(new Tag { Title = tag.Trim() });
      }
}
 _uow.SaveChanges(); // ثبت موارد جدید

فقط تگ‌ها در جدول خودشون ذخیره میشن و ارتباطی با پست مربوطه ایجاد نمیشه.
آیا نباید به کد زیر تغییر داد؟
if (!listOfActualTagNames.Contains(tag.ToLowerInvariant().Trim()))
 {
      var tags = new Tag { Title = tag.Trim() };
       _tag.Add(tags);
       posts.Tags.Add(tags);
  }
نظرات مطالب
سفارشی سازی ASP.NET Core Identity - قسمت پنجم - سیاست‌های دسترسی پویا
با سلام؛ من یه AuthorizationHandler سفارشی نوشتم که داخلش یه Exception صادر میکنم. همچنین یک ExceptionMiddlware سفارشی نیز نوشتم که مدیریت خطاها رو بعهده داره.  اما زمانی که از داخل AuthorizationHandler  یک exception صادر میکنم ExceptionMiddlware   فراخوانی نمیشه ! آیا نمیتوان در داخل یک middlware یه exception صادر و در exceptionMiddlware آن را دریافت کرد؟
مطالب
HTML5 Web Component - قسمت دوم - Custom Elements
Custom Elements، دارای یک چرخه حیات می‌باشند. در طی این چرخه حیات، می‌توان تعدادی متد خاص را به المان سفارشی خود اضافه کرد که به صورت خودکار توسط مرورگر فراخوانی می‌شوند. به این متدها Life-cycle Callbacks یا Custom Element Reactions نیز می‌گویند. برای درک بهتر چرخه حیات مذکور، به تکه کد زیر توجه نمائید:
customElements.define("x-component", class extends HTMLElement {
    constructor() {
        super();
        console.log('constructed!');
    }

    connectedCallback() {
        console.log('connected!');
    }

    disconnectedCallback() {
        console.log('disconnected!');
    }

    adoptedCallback() {
        console.log('adopted!');
    }

    attributeChangedCallback(name, oldValue, newValue) {
        console.log('attirbuteChanged!', name, oldValue, newValue);
    }

    static get observedAttributes() {
        return ['checked','demo','label'];
    }
});

Element Upgrades
به صورت پیش‌فرض، المان‌های موجود در DOM که مبتنی‌بر استانداردهای HTML تعریف نشده‌ا‌ند، توسط مرورگر به عنوان HTMLUnknownElement تجزیه و تحلیل خواهند شد. ولی این موضوع برای المان‌های سفارشی که نام معتبری دارند (وجود «-»)، صدق نمی‌کند. برای مثال دو خط کد زیر را در کنسول مربوط به Developer tools مرورگر خود اجرا کنید:
// "tabs" is not a valid custom element name
document.createElement('tabs') instanceof HTMLUnknownElement === true //true

// "x-tabs" is a valid custom element name
document.createElement('x-tabs') instanceof HTMLElement === true //true
در این صورت، امکان استفاده از المان سفارشی، قبل از معرفی و ثبت آن توسط متد customElements.define نیز وجود خواهد داشت. یعنی اگر در DOM شما تعدادی المان سفارشی وجود داشته باشند که به هر دلیل نیاز است پس از گذشت یک بازه زمانی کوتاهی معرفی و ثبت شوند (مثال: lazy load اسکریپت‌های متناظر با المان‌های سفارشی در Angular)، این المان‌ها معتبر هستند. فرآیند فراخوانی متد define و استفاده از کلاس معرفی شده برای ارتقاء المان سفارشی موجود در DOM، اصطلاحا Element Upgrades نامیده می‌شود. همچنین با استفاده از متد customElements.whenDefined که یک Promise را بازگشت می‌دهد، می‌توان از معرفی و ثبت شدن المان خاصی آگاه شد:
customElements.whenDefined('x-component').then(() => {
  console.log('x-component defined');
});
یا حتی امکان استفاده از سلکتور «‎:defined‏» نیز به شکل زیر وجود دارد:
<share-buttons>
  <social-button type="twitter"><a href="...">Twitter</a></social-button>
  <social-button type="fb"><a href="...">Facebook</a></social-button>
  <social-button type="plus"><a href="...">G+</a></social-button>
</share-buttons>

// Fetch all the children of <share-buttons> that are not defined yet.
let undefinedButtons = buttons.querySelectorAll(':not(:defined)');

let promises = [...undefinedButtons].map(socialButton => {
  return customElements.whenDefined(socialButton.localName);
));

// Wait for all the social-buttons to be upgraded.
Promise.all(promises).then(() => {
  // All social-button children are ready.
});
در اینجا ابتدا تمام المان‌های تعریف نشده، کوئری شده‌اند و با استفاده از متد map و اجرای متد whenDefined، به لیستی از Promiseها رسیده‌ایم و در نهایت با استفاده از Promise.all منتظر اتمام مرحله upgrade المان‌های مذکور هستیم.
سازنده مرتبط با کلاس المان سفارشی x-component، در هنگام وهله‌سازی یا فرآیند upgrades فراخوانی می‌شود و می‌تواند برای مقداردهی اولیه خواص وهله جاری، تنظیم رخدادگردان‌ها (Event Listeners) و یا ایجاد و اتصال ShadowDOM با استفاده از متد attachShadow، محل مناسبی باشد. طبق مستندات مرتبط، فراخوانی ()super بدون ارسال هیچ آرگومانی باید در اولین خط این سازنده انجام شود.
برای وهله‌سازی المان سفارشی نیز می‌توان از متد customeElements.get به شکل زیر استفاده کرد:
customeElements.define('x-component',...)
let XComponent = customElements.get('x-component');
document.body.appendChild(new XComponent())
متد get، ارجاعی به سازنده کلاس x-component را بازگشت خواهد داد.

connectedCallback 
 اولین متد بعد از فراخوانی سازنده، connectedCallback نام دارد و زمانی رخ می‌دهد که وهله‌ای از یک المان سفارشی به Light DOM افزوده شده‌است و یا توسط Parser مرورگر، در DOM شناسایی شود. این متد، محل پیشنهاد شده برای اجرای کدهای زمان راه‌اندازی مانند دریافت منابع از سرور و یا رندر کردن محتوایی خاص، می‌باشد. 
نکته: این متد ممکن است بیش از یکبار نیز فراخوانی شود! هنگامیکه یک المان موجود در DOM از طریق کد از DOM جداشده و سپس اضافه شود:
const el = document.createElement('x-component');
document.body.appendChild(el);
// connectedCallback() called

el.remove();
// disconnectedCallback()

document.body.appendChild(el);
// connectedCallback() called again


disconnectedCallback
این متد نیز هر وقت المانی از DOM حذف شود، اجرا خواهد شد و مانند متد connectedCallback ممکن است چندین بار فراخوانی شود. همچنین محل مناسبی برای آزادسازی منابع استفاده شده در پیاده‌سازی المان سفارشی، می‌باشد. مانند: استفاده از متد clearInterval برای پاکسازی یک تایمر که با متد setInterval ایجاد شده‌است.  
نکته: هیچ تعهدی به اجرای متد disconnectedCallback در تمام حالاتی که یک المان از DOM حذف می‌شود، وجود ندارد. به عنوان مثال هنگامیکه یک برگه‌ی مرورگر بسته شود، این متد فراخوانی نخواهد شد.

‌attributeChangedCallback
 این متد هنگامی فراخوانی خواهد شد که خصوصیات مشخص شده از طریق observedAttributes به عنوان یک static getter، اضافه، حذف، ویرایش و یا جایگزین شوند. همچنین در مرحله Upgrades برای مقادیر اولیه خصوصیات که توسط استفاده کننده از المان سفارشی، مشخص شده‌است نیز فراخوانی می‌شود.
adoptedCallback
متدهای قبلی بیشترین استفاده را دارند؛ این متد خاص نیز زمانیکه یک المان سفارشی به یک DOM دیگری منتقل می‌شود، اجرا خواهد شد. برای مثال:
const iframe = document.querySelector('iframe');
const iframeImages = iframe.contentDocument.querySelectorAll('img');
const newParent = document.getElementById('images');

iframeImages.forEach(function(imgEl) {
  newParent.appendChild(document.adoptNode(imgEl));
});
در تکه کد بالا، لیست المان‌های img موجود در داخل iframe کوئری شده و سپس با پیمایش بر روی لیست بدست آمده و در زمان فراخوانی متد adoptNode که کار تغییر ownerDocument مرتبط با یک المان را انجام می‌دهد، متد adoptedCallback ما نیز اجرا خواهد شد.

Methods

اگر المان‌های بومی و استاندارد موجود را بررسی کنید، همه آنها دارای یکسری متد، پراپرتی و صفات مشخصی هستند. در اینجا نیز تعریف رفتاری برای یک المان سفارشی و کپسوله، نکته خاصی ندارد و به شکل زیر قابل تعریف و استفاده می‌باشد:
class XComponent extends HTMLElement {
  constructor() {
    super();
  }
  
  doSomething(){
    console.log('doSomething');
  }
}

let component = document.querySelector('x-component');
component.doSomething();
مشخص است که امکان تعریف انواع و اقسام متدها با پارامترها و خروجی‌های مختلفی و حتی نسخه‌های همزمان یا ناهمزمان آن‌ها وجود دارد.

Attributes & Properties

در HTML خیلی رایج است که مقادیر پراپرتی‌های یک المان در قالب یکسری صفات، نمودی در DOM هم داشته باشند. برای مثال:
div.id = 'id-value';
div.hidden = true;
انتظار چنین خروجی داریم:
<div id="id-value" hidden>
این موضوع، تحت عنوان «Reflecting Properties to Attributes» مطرح می‌باشد. در این صورت علاوه بر اینکه با یک نگاه به DOM، از مقادیر خصوصیات یک المان آگاه خواهیم بود، امکان استفاده از این صفات به عنوان سلکتورهایی در زمان استایل‌دهی نیز وجود دارد. حال از این مکانیزم برای اعمال یکسری صفات دسترسی‌پذیری مانند صفات ARIA به المان سفارشی خود نیز می‌توان استفاده کرد. برای مثال:
class XComponent extends HTMLElement {
    constructor() {
        super();
    }

    connectedCallback() {
        this._render();
    }

    get disabled() {
        return this.hasAttribute('disabled');
    }

    set disabled(val) {
        // Reflect the value of `disabled` as an attribute.
        if (val) {
            this.setAttribute('disabled', '');
        } else {
            this.removeAttribute('disabled');
        }

        this._render();
    }

    _render() {
        //... 
    }
}
ایده کار خیلی ساده است؛ پراپرتی‌های یک المان‌سفارشی را از طریق متدهای getter و setter تعریف کرده و در بدنه پیاده‌سازی آنها، صفات HTML ای المان جاری را تغییر داده و یا از مقادیر آنها استفاده کنیم.
اینبار با مقداردهی پراپرتی disabled برروی وهله‌ای از المان سفارشی ما، این مقادیر نمودی در DOM هم خواهند داشت. با استفاده از متدهای setAttribute یا removeAttribute کار همگام‌سازی پراپرتی‌ها با صفات را انجام داده‌ایم.
همچین با استفاده از متد attributeChangedCallback نیز می‌توان برای اعمال صفات ARIA که اشاره شد، به شکل زیر استفاده کرد:
attributeChangedCallback(name, oldValue, newValue) {
  switch (name) {
    case 'checked':
      // Note the attributeChangedCallback is only handling the *side effects*
      // of setting the attribute.
      this.setAttribute('aria-disabled', !!newValue);
      break;
    ...
  }
یا حتی به شکل زیر:
attributeChangedCallback(name, oldValue, newValue) {
    // When the component is disabled, update keyboard/screen reader behavior.
    if (this.disabled) {
      this.setAttribute('tabindex', '-1');
      this.setAttribute('aria-disabled', 'true');
    } else {
      this.setAttribute('tabindex', '0');
      this.setAttribute('aria-disabled', 'false');
    }
    // TODO: also react to the other attribute changing.
  }
در اینجا از همان getter که طبق پیاده‌سازی ما، در پشت صحنه از همان مقدار صفت disabled استفاده می‌کند، برای تنظیم یکسری صفات دیگر استفاده کرده‌ایم. به عنوان مثال اگر المان ما غیرفعال شده بود، صفت tabindex آن را با «‎-1‏» مقداردهی می‌کنیم تا از توالی پیمایش مبتنی‌بر Tab خارج شود.
نکته: پیشنهاد می‌شود از مکانیزم همگام‌سازی پراپرتی‌ها و صفات، برای انواع داده‌ای اولیه (رشته، عدد و ...) استفاده شود و برای دریافت مقادیری مانند objects و یا arrays، از متدها یا پراپرتی‌ها استفاده کنید. در غیر این صورت نیاز خواهد بود که این مقادیر را سریالایز و در داخل المان سفارشی، عملیات معکوس آن را انجام دهید که می‌تواند هزینه‌ی زیادی داشته باشد. عملیات سریالایز نیز خود باعث از دست دادن ارجاعات به آن مقادیر خواهد شد. به صورت کلی هیچکدام از المان‌های بومی موجود، چنین اطلاعاتی را دریافت نمی‌کند. برای مثال:
constructor() {
    super();

    this._data = [];
}

get data() {
    return _data;
}

set data(value) {
    if (this_data === value) return;
    this._data = value;
    this._render();
}

Lazy Properties

همانطور که اشاره شد حتی قبل از مرحله upgrades مربوط به المان‌های سفارشی استفاده شده در سند HTML برنامه شما، به عنوان المان‌های معتبری هستند که امکان کوئری کردن و مقداردهی اولیه خصوصیات آنها از طریق کد نیز ممکن است. این موضوع زمانیکه از فریم‌ورکی مثل Angular استفاده می‌شود، المان موردنظر به صورت خودکار توسط فریم‌ورک لود و به صفحه اضافه شده و در انتهای عملیات، binding پراپرتی‌های آن به خصوصیات موجود در کامپوننت Angular ای انجام خواهد شد. به مثال زیر توجه کنید:
<x-component [disabled]="model.disabled"></x-component>
در این صورت اگر لود اسکریپت، معرفی و ثبت این المان سفارشی به صورت Lazy انجام شود، امکان آن وجود دارد که فریم‌ورک، عملیات binding را قبل از مرحله upgrades انجام دهد. خوب... این موضوع چه مشکلی را ایجاد می‌کند؟ در این صورت چون مرحله upgrades تمام نشده است، پیاده‌سازی بدنه متد setter متناظر با خصوصیات المان سفارشی، توسط پراپرتی جدیدی که توسط فریم‌ورک برروی وهله موجود تعریف می‌شود، بی‌استفاده خواهد ماند. برای مثال، اگر سعی کنیم قبل از مرحله upgrades خصوصیت disabled المان x-component را مقداردهی کنیم، عملیات مکانیزم همگام‌سازی مدنظر ما اجرا نخواهد شد:
let el = document.querySelector('x-component');
el.disabled = true;

customElements.define("x-component", class extends HTMLElement {
    constructor() {
        super();
    }

    get disabled() {
        return this.hasAttribute('disabled');
    }

    set disabled(val) {
        // Reflect the value of `disabled` as an attribute.
        if (val) {
            this.setAttribute('disabled', '');
        } else {
            this.removeAttribute('disabled');
        }

        this._render();
    }
});

با این خروجی مواجه خواهیم شد که هیچ اثری از صفت disabled دیده نمی‌شود:


یکی از روش‌های پیشنهاد شده برای حل این مشکل، مقداردهی مجدد پراپرتی‌ها بعد از مرحله upgrades و پس از اینکه متد setter تعریف شده‌است، می‌باشد:
let el = document.querySelector('x-component');
el.disabled = true;

customElements.define("x-component", class extends HTMLElement {
    constructor() {
        super();
    }

    connectedCallback() {
        this._upgradeProp('disabled');
    }

    get disabled() {
        return this.hasAttribute('disabled');
    }

    set disabled(val) {
        // Reflect the value of `disabled` as an attribute.
        if (val) {
            this.setAttribute('disabled', '');
        } else {
            this.removeAttribute('disabled');
        }

        this._render();
    }

    _upgradeProp(prop) {
        if (this.hasOwnProperty(prop)) {
            let value = this[prop];
            delete this[prop]; //delete instance property
            this[prop] = value; // set prototype property
        }
    }
});
ایده کار به این صورت است که مقدار پراپرتی مورد نظر را که قبل از مرحله upgrades برروی وهله جاری (instance property) تنظیم شده‌است، در متغییری نگهداری کرده و آن پراپرتی را حذف و سپس پراپرتی تعریف شده در کلاس (prototype property) را برای وهله جاری مقداردهی کنیم.
نکته: به یاد داشته باشید که قبل از اینکه یکسری صفات خاص را مقدار دهی کنید، بررسی شود که استفاده کننده از المان سفارشی، مقداری را تنظیم نکرده باشد. برای مثال اگر قصد دارید المان سفارشی شما قابلیت focus را داشته باشد، نیاز است شما حداقل tabindex=-1 را تنظیم کنید؛ حتی اگر استفاده کننده، آن را مقداردهی نکرده باشد:
connectedCallback() {
  if (!this.hasAttribute('role'))
    this.setAttribute('role', 'checkbox');
  if (!this.hasAttribute('tabindex'))
    this.setAttribute('tabindex', -1); //element is not reachable via sequential keyboard navigation, but could be focused
}

مطالب
سرویس جمع و مفرد سازی اسامی

اگر به Entity data model wizard در VS.Net 2010 دقت کرده باشید، گزینه‌ی "Pluralize or singularize generated object names" نیز به آن اضافه شده است:



این مورد از این جهت حائز اهمیت است که عموما نام جداول در بانک اطلاعاتی، جمع است و نام کلاس متناظر ایجاد شده برای آن در کدهای برنامه بهتر است مفرد باشد. برای مثال نام جدول، Customers است و نام کلاس آن بهتر است Customer تعریف گردد. به این صورت کار کردن با آن توسط یک ORM با معناتر خواهد بود؛ زیرا زمانیکه یک وهله از شیء Customer ایجاد می‌شود، فقط یک رکورد از بانک اطلاعاتی مد نظر است؛ در حالیکه یک جدول مجموعه‌ای است از رکوردها.
زبان انگلیسی هم پر است از اسامی جمع و مفرد باقاعده و بی‌قاعده و کل عملیات با اضافه و حذف کردن یک s و یا es پایان نمی‌یابد؛ برای مثال phenomenon و phenomena را در نظر بگیرد تا Money و Moneys.
این امکان مهیا شده توسط Entity Framework 4.0 یا همان EF v2 با برنامه نویسی هم قابل دسترسی است و در اسمبلی System.Data.Entity.Design.dll و فضای نام System.Data.Entity.Design.PluralizationServices قرار گرفته است.
این اسمبلی جزیی از دات نت 4 است و اگر آن‌را توسط گزینه‌ی Add references در VS.NET مشاهده نمی‌کنید، علت آن است که در تنظیمات پروژه جاری، گزینه‌ی Target framework بر روی Client profile قرار گرفته است که باید به دات نت 4 کامل تغییر یابد.
استفاده از آن هم به صورت زیر است:

using System;
using System.Data.Entity.Design.PluralizationServices;
using System.Globalization;

namespace PluralizationServicesTest
{
class Program
{
static void Main(string[] args)
{
var service = PluralizationService.CreateService(CultureInfo.GetCultureInfo("en"));
Console.WriteLine(service.Pluralize("mouse"));
Console.WriteLine(service.IsPlural("phenomena"));
}
}
}

ملاحظات:
این روش فعلا به زبان انگلیسی محدود است و اگر Culture را به مورد دیگری تنظیم کنید با خطای "We don't support locales other than English yet" متوقف خواهید شد.


روش دیگر:
کتابخانه‌ی سورس باز Castle ActiveRecord نیز دارای کلاسی است به نام Inflector که برای همین منظور طراحی شده است:


کاربرد آن در Fluent NHibernate
در Fluent NHibernate کار نگاشت کلاس‌ها به جداول به صورت خودکار صورت می‌گیرد و همچنین تولید ساختار بانک اطلاعاتی نیز به همین نحو می‌باشد. اما می‌توان تولید نام جداول را سفارشی نیز نمود. برای مثال از کلاس Book به صورت خودکار ساختار جدولی به نام Books را تولید کند:
using FluentNHibernate.Conventions;
using FluentNHibernate.Conventions.Instances;
using NHibernate.Helper.Toolkit;

namespace NHibernate.Helper.MappingConventions
{
public class TableNameConvention : IClassConvention
{
public void Apply(IClassInstance instance)
{
instance.Table(Inflector.Pluralize(instance.EntityType.Name));
}
}
}
و برای تزریق آن خواهیم داشت:

... = new AutoPersistenceModel()
.Where(...)
.Conventions.Setup(c =>c.Add<TableNameConvention>())
.AddEntityAssembly(...)
...

مطالب
آشنایی با CLR: قسمت چهاردهم
در ادامه قسمت قبلی روش‌های زیادی جهت اضافه شدن یک ماژول به یک اسمبلی وجود دارند. اگر شما از کامپایلر سی‌شارپ برای ساخت یک فایل PE با جدول مانیفست استفاده می‌کنید، می‌توانید از سوئیچ AddModule/ استفاده کنید. برای اینکه بدانیم چگونه می‌توان یک اسمبلی چند فایله ساخت بیاید فرض کنیم که دو فایل سورس کد با مشخصات زیر داریم:
RUT.cs: این سورس شامل کدهایی است که به ندرت در برنامه استفاده می‌شود.
FUT.cs: این سورس شامل کدهایی است که به طور مکرر مورد استفاده قرار می‌گیرد.

ابتدا به صورت زیر کد سورسی را که به ندرت استفاده می‌شود، به عنوان یک ماژول جداگانه کامپایل می‌کنم:
csc /t:module RUT.cs
اجرای این خط سبب ایجاد یک فایل به نام RUT.netmodule می‌گردد که یک DLL استاندارد است؛ ولی CLR به تنهایی توانایی بارگیری آن را ندارد. دفعه‌ی بعد سورس کدی را که مکرر استفاده می‌شود، به صورت یک ماژول کامپایل می‌کنیم و از آنجائیکه این ماژول استفاده‌ی زیادی دارد، آن را نگهدارنده‌ی جدول مانیفست معرفی می‌کنیم و به این دلیل که این ماژول نماینده‌ی کل اسمبلی است، نام خروجی آن را به جای FUT.dll به MultiFileLibrary.dll تغییر می‌دهیم:
csc /out:MultiFileLibrary.dll /t:library /addmodule:RUT.netmodule FUT.cs
خط بالا به علت سوئیچ t:library\ فایل MultiFileLibrary.dll را ایجاد می‌کند. این فایل شامل جدول متادیتای مانیفست می‌شود و سوئیچ به آن می‌گوید که باید ماژول RUT.netmodule را جزئی از اسمبلی بداند. این سوئیچ به کامپایلر اعلام می‌کند که ارجاع این فایل در جدول FileDef  و ExportedTypesDef ثبت شود.
بعد از اتمام عملیات کامپایل، مطابق شکل زیر دو فایل ایجاد می‌شود که فایل سمت راست شامل جدول مانیفست است. فایل RUT.netmodule شامل کد IL و جداول متادیتاهای مربوط به خواص و رویدادها و مواردی از این قبیل است که در این ماژول یافت می‌شود. فایل بعدی MultiFileLibrary.dll هست که شامل کد IL کد FUT.CS می‌شوذ بعلاوه جداول متادیتا مثل ماژول قبلی و جدول متادیتای مانیفست که باعث می‌شود به عنوان یک اسمبلی شناخته شود.



البته توجه داشته باشید که جدول مانیفست ارجاعی به نوع‌های عمومی استخراج شده داخل فایل خودش ندارد، زیرا که در جداول اختصاصی خودش موجود است و در ذخیره سازی صرفه جویی می‌گردد.
بعد از اینکه MultiFileLibrary.dll ساخته شد، به منظور آزمایش کردن جداول متادیتا می‌توانید از ابزار ILDasm.exe استفاده کنید تا ارجاع به فایل RUT.netmodule به شما ثابت شود. آنچه در زیر می‌بینید نمایی از جداول FileDef و ExportedTypesDef است:
File #1 (26000001)
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Token: 0x26000001
Name : RUT.netmodule
HashValue Blob : e6 e6 df 62 2c a1 2c 59 97 65 0f 21 44 10 15 96 f2 7e db c2
Flags : [ContainsMetaData] (00000000)


ExportedType #1 (27000001)
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Token: 0x27000001
Name: ARarelyUsedType
Implementation token: 0x26000001
TypeDef token: 0x02000002
Flags : [Public] [AutoLayout] [Class] [Sealed] [AnsiClass]
[BeforeFieldInit](00100101)
 
همانطور که در بالا می‌بینید فایل RUT.netmodule با شناسه‌ی (توکن) 0x26000001 به عنوان بخشی از اسمبلی شناخته می‌شود و به نوع کد IL آن اشاره می‌کند.

قابل توجه افراد کنجکاو: توکن‌های جداول متا، مقادیر 4 بایتی است که بایت پر ارزش آن اشاره می‌کند که برای یافتن آن باید به چه جدولی ارجاع کرد. مقادیر زیر این نکته را روشن می‌کند که هر کد ابتدایی به چه جدولی اشاره می‌کند:
 0x01
 TypeRef
 0x02
 TypeDef
 0x23
 AssemblyRef
 0x26
 File
file definition

 0x27
 ExportedType
برای دیدن لیست کاملی از این کدها فایل Corhdr.h را که به همراه فریم ورک دات نت نصب می‌شود، مطالعه فرمایید. سه بایت باقیمانده هم بر اساس جدولی که به آن ارجاع شده است مشخص می‌گردد؛ مثلا در مثال بالا کد 0x26000001  به اولین سطر جدول File اشاره می‌کند. برای اکثر جدول‌ها شماره گذاری سطرها از عدد 1 آغاز می‌شود نه صفر یا برای برای جداول TypeDef عموما از عدد 2 آغاز می‌شود. 

برای اجرای اسمبلی، کامپایلر نیاز دارد که همه‌ی فایل‌های اسمبلی، نصب شده و قابل دسترس باشند و در صورتیکه شما فایل RUT.netmodule را حذف کنید کامپایلر سی شارپ خطای زیر را صادر می‌کند:
fatal error CS0009: Metadata file 'C:\ MultiFileLibrary.dll' could not be opened—'Error importing module 'RUT.netmodule' of assembly 'C:\ MultiFileLibrary.dll'—The system cannot find the file specified'

و این خطا بدین معنی است که برای ساخت اسمبلی باید تمامی فایل‌ها حاضر و مهیا باشند. هر کد کلاینتی که اجرا می‌شود آن متد را صدا می‌زنند. موقعی که یک متد برای اولین بار فراخوانی می‌شود، CLR عملیات شناسایی جهت شناسایی ارجاعات آن در پارامترها، نوع خروجی متد و متغیرهای محلی آن اجرا می‌کند. سپس تلاش می‌کند تا فایل اسمبلی ارجاع شده را که شامل مانیفست هست، بار کند. اگر نوعی که لازم داریم در همین فایل متد وجود داشته باشد، اجرای عملیات را به سمت آن آغاز می‌کند ولی اگر جدول مانیفست ارجاع را به فایل دیگری بدهد، آن فایل در حافظه بار شده و سپس آن نوع را در دسترس قرار می‌دهد. 
خطوط بالا این نکته را روشن می‌کند که فایل‌های اسمبلی را تنها موقعی در حافظه بار میکند که ارجاعی از نوع موجود در آن صدا زده شده باشد؛ یعنی اینکه در زمان اجرای برنامه، لازم نیست که همه‌ی فایل‌ها حاضر و مهیا باشند.
مطالب
پلاگین DataTables کتابخانه jQuery - قسمت سوم
در این قسمت اطلاعات را به صورت ajax از یک فایل متنی می‌خوانیم و آنها را در جدول قرار می‌دهیم. سپس به سفارشی کردن بعضی از قسمت‌های DataTables خواهیم پرداخت.

دریافت اطلاعات به صورت ajax از یک فایل متنی

فرض کنید که اطلاعات در یک فایل txt به صورت اشیاء جاوا اسکریپتی ذخیره شده اند، و این فایل بر روی سرور قرار دارد. می‌خواهیم از این فایل به عنوان منبع داده استفاده کرده و اطلاعات درون آن را به صورت ajax دریافت کرده و در یک جدول html تزریق کنیم. خوشبختانه با استفاده از امکاناتی که این پلاگین تهیه کرده است این کار به سادگی امکان پذیر است.

همان طور که در اینجا بیان شده است ، فرض کنید که جدولی داشته باشیم و بخواهیم اطلاعات راجع به مرورگرهای مختلف را در آن نمایش دهیم. قصد داریم این جدول شامل قسمتهای header و footer و نیز body باشد، بدین صورت:
<table id="browsers-grid">
    <thead>
       <tr>
          <th width="20%">موتور رندرگیری</th>
          <th width="25%">مرورگر</th>
          <th width="25%">پلتفرم (ها)</th>
          <th width="15%">نسخه موتور</th>
          <th width="15%">نمره css</th>
       </tr>
    </thead>

    <tbody>

    </tbody> 

    <tfoot>
       <tr>
          <th>موتور رندرگیری</th>
          <th>مرورگر</th>
           <th>پلتفرم (ها)</th>
          <th>نسخه موتور</th>
          <th>نمره css</th>
       </tr>
    </tfoot>
</table>
برای هر ستون از این جدول عرضی در نظر گرفته شده است. اگر این کار انجام نشود به صورت خودکار به تمام ستونها عرض داده می‌شود.

داده هایی که باید در بدنه جدول قرار بگیرند، در یک فایل متنی روی سرور قرار دارند. محتویات این فایل چیزی شبیه زیر است:
{
   "aaData": [
      {"engine":"Trident", "browser":"Internet Explorer 4.0", "platform":"Win95+", "version":"4", "grade":"X"},
      {"engine":"Trident", "browser":"Internet Explorer 5.0", "platform":"Win95+", "version":"5", "grade":"C"},
      {"engine":"Trident", "browser":"Internet Explorer 5.5", "platform":"Win95+", "version":"5.5", "grade":"A"}
   ]
}
همان طور که مشاهده می‌کنید فرمت ذخیره داده‌ها در این فایل به صورت json یا اشیاء جاوا اسکریپتی است. این اشیاء باید به خصوصیت aaData نسبت داده شوند که در قسمت قبل راجع به آن توضیح دادیم. تعداد این اشیاء 57 تا بود که برای سادگی بیشتر 3 تا از آنها را اینجا ذکر کردیم.

اسکریپتی که داده‌ها را از فایل متنی خوانده و آنها را در جدول قرار می‌دهد هم بدین صورت خواهد بود:
$(document).ready(function () {
        $('#browsers-grid').dataTable({
            "sAjaxSource": "datasource/objects.txt",
            "bProcessing": true,
            "aoColumns": [
                { "mDataProp": "engine" },
                { "mDataProp": "browser" },
                { "mDataProp": "platform" },
                { "mDataProp": "version" },
                { "mDataProp": "grade" }
            ]
    });
});
شرح کد:
sAjaxSource : رشته
نوع داده ای که قبول می‌کند رشته ای و بیان کننده آدرسی است که داده‌ها باید از آنجا دریافت شوند. در اینجا داده‌ها در فایل متنی objects.txt در پوشه datasource قرار دارند.

bProcessing : بولین
نوع داده‌های قابل قبول این خصوصیت true یا false هست و بیان کننده این است که یک پیغام loading تا زمانی که داده‌ها دریافت شوند و در جدول قرار بگیرند نمایش داده شوند یا خیر.


تنظیم کردن گزینه‌های اضافی دیگر

sAjaxDataProp : رشته
همان طور که گفتیم در فایل متنی که حاوی اشیاء json بود ، این اشیاء را به متغیری به اسم aaData منتسب کردیم. این نام را می‌توان تغییر داد مثلا فرض کنید در فایل متنی داده‌ها به متغیری به اسم data منتسب شده اند:
{
   "data": [
      {"engine":"Trident", "browser":"Internet Explorer 4.0", "platform":"Win95+", "version":"4", "grade":"X"},
      {"engine":"Trident", "browser":"Internet Explorer 5.0", "platform":"Win95+", "version":"5", "grade":"C"},
      {"engine":"Trident", "browser":"Internet Explorer 5.5", "platform":"Win95+", "version":"5.5", "grade":"A"}
   ]
}
در این صورت باید خصوصیت sAjaxDataProp را به همان نامی که در فایل متنی مشخص کرده اید مقداردهی کنید، در غیر این صورت داده‌های جدول هیچ گاه بارگذاری نخواهند شد. بدین صورت:
"sAjaxDataProp": "data"
یا اگر داده‌ها را بدین صورت در فایل متنی ذخیره کرده اید:
{ "data": { "inner": [...] } }
آنگاه خصوصیت sAjaxDataProp بدین صورت مقداردهی خواهد شد:
"sAjaxDataProp": "data.inner"

sPaginationType: رشته
نحوه صفحه بندی و حرکت بین صفحات مختلف را بیان می‌کند. اگر با two_buttonمقدار دهی شود (مقدار پیش فرض) حرکت بین صفحات مختلف به وسیله دکمه‌های Next و Previous امکان پذیر خواهد بود. اگر با full_numbersمقدار دهی شود حرکت بین صفحات با دکمه‌های Next و Previous ، و همچنین دکمه‌های First و Last و نیز شماره صفحه فعلی و دو صفحه بعدی و دو صفحه قبلی قابل انجام است.

شکل الف) صفحه بندی به صورت full_numbers

bLengthChange: بولین
بیان می‌کند کاربر بتواند اندازه صفحه را تغییر دهید یا نه. به صورت پیش فرض این گزینه true است. اگر آن به false مقدار دهی شود لیست بازشونده مربوط به اندازه صفحه مخفی خواهد شد.

aLengthMenu  :  آرایه یک بعدی یا دو بعدی
به صورت پیش فرض در لیست باز شونده مربوط به تعداد رکوردهای قابل نمایش در هر صفحه اعداد 10 ، 25 ، 50 ، و 100 قرار دارند.

شکل ب ) لیست بازشونده شامل اندازه‌های صفحه

در صورتی که بخواهیم این گزینه‌ها را تغییر دهیم باید خصوصیت aLengthMenu را مقدار دهی کنیم. اگر مقداری که به این خصوصیت می‌دهیم یک آرایه یک بعدی باشد، مثلا

"aLengthMenu": [25, 50, 100, -1],
نتیجه یک لیست باز شوند است که دارای چهار عنصر است که value و text آنها یکی است. (نکته: چهارمین عنصر از لیست بالا دارای مقدار 1- خواهد بود که با انتخاب این گزینه تمام رکوردها نمایش می‌یابند). اما اگر می‌خواهیم که text و value این عناصر با هم فرق کند از یک آرایه دو بعدی استفاده خواهیم کرد، مثلا:

"aLengthMenu": [[25, 50, 100, -1], ["همه", "صد", "پنجاه", "بیست و پنج"]],

iDisplayLength
: عدد صحیح
تعداد رکوردهای قابل نمایش در هر صفحه هنگامی که داده‌ها در جدول ریخته می‌شوند را معین می‌کند. می‌توانید این را مقداری بدهید که در خصوصیت aLengthMenu ذکر نشده است، مثلا 28 تا.


sDom : رشته
پلاگین DataTables به صورت پیش فرض لیست بازشونده اندازه صفحه و کادر متن مربوط به جستجو را در بالای جدول داده‌ها اضافه می‌کند، و نیز اطلاعات دیگر و همچنین امکانات مربوط به صفحه بندی را به قسمت پایین جدول اضافه می‌کند. شما می‌توانید موقعیت این عناصر را با استفاده از پارامتر sDom تغییر دهید.

نحو (syntax) مقداری که پارامتر sDom قبول می‌کند مقداری عجیب و غریب است، مثلا:

'<"top"iflp<"clear">>rt<"bottom"iflp<"clear">>'

این خط بیان می‌کند که در قسمت بالای جدول یک تگ div با کلاس top قرار بگیرد. در این تگ قسمت اطلاعات (یعنی Showing x to xx from xxx entries) (با حرف i) ، کادر جستجو (با حرف f) ، لیست بازشونده مربوط به اندازه صفحه (با حرف l) ، و نیز قسمت صفحه بندی (با حرف p)قرار خواهند گرفت. در انتهای تگ div با کلاس top، یک تگ div با کلاس clear قرار خواهد گرفت. بعد قسمت مربوط به پیغام loading (با حرف r) و بعد با حرف t جدول حاوی داده‌ها قرار می‌گیرد. در نهایت یک تگ div با کلاس bottom قرار می‌گیرد و با حرفهای i ، و f ، و l و p درون آن قسمتهای اطلاعات ، کادرجستجو، لیست بازشونده اندازه صفحه و نیز قسمت صفحه بندی قرار خواهد گرفت و در نهایت یک تگ div با کلاس clear قرار خواهد گرفت.

حرفهایی که در sDom معنی خاصی می‌دهند :
  • l سر حرف Length Changing برای لیست بازشونده مربوط به اندازه صفحه
  • f سر حرف Filtering input برای قسمت کادر جستجو
  • t سرحرف table برای جدول حاوی داده ها
  • i سر حرف information برای قسمت Showing x to xx from xxx entries
  • p سر حرف pagination برای قسمت صفحه بندی
  • r حرف دوم pRocessing برای قسمت پیغام قبل از بار کردن داده‌های جدول (قسمت loading)
  • H و F که مربوط به theme‌های jQuery UI می‌شوند که بعدا درباره آنها توضیح داده می‌شود.

همچنین بین علامت‌های کوچکتر (>) و بزرگتر (<) یعنی اگر چیزی بیاید در یک تگ div قرار خواهد گرفت. اگر بخواهیم div ی بسازیم و به آن کلاس بدهیم از نحو زیر استفاده خواهیم کرد:

'<"class" and '>'
و اگر بخواهیم یک تگ div با یک id مشخص بسازیم از نحو زیر استفاده خواهیم کرد:
'<"#id" and '>'
در نهایت جدولی مثل جدول زیر تولید خواهد شد:

شکل ج) جدول نهایی تولید شده توسط DataTables

کدهای نهایی این مثال را از DataTables-DoteNetTips-Tutorial-03.zip دریافت کنید.