نظرات مطالب
ارتقاء از WinForms به WPF
البته از یک لحاظ به سیر اسد حق میدم , مهاجرت به یک تکنولوژی مستلزم زمانی برای یادگیری و اون هست و ترس از Backward Compatibility که خیلی ها از رفتن به سمت تکنولوژی های جدید باز داشته ولی خوب اینها همش ناشی از عدم آشنایی با چیزی و ابعاد اون هست شما به WPF این مشکل رو نخواهید داشت WPF می تونه خیلی راحت با سیستمهای قبلی شما سازگار بشه حتی شما در سیستمهایی که با ++C نوشتید می تونید از اون استفاده کنید ولی خوب این مستلزم اینه که شما به ++C دات نت کوج کنید , خوب ممکنه برنامه های شما با زبانهای دیگه نوشته باشه مثل VB نه VB.NET شما بازهم نگران استفاده از WPF در اونها نباشید بدون مشکل این امر محقق میشه , یک مورد دیگری که خیلی مساله ساز میشه برای شرکتها و خیلی از برنامه نویسها هزینه های آموزش تکنولوژی های جدید هست , ولی خوب به نظر من این امر هم خیلی مساله بغرنجی نیست که نگران اون هستند اگر تیم برنامه نویسی واقعا" اصولی مطالب رو آموخته باشن می تونند براحتی به سمت تکنولوژی های جدید برن این امر خیلی دور از واقعیت نیست , ولی خوب بهر حال عامه جامعه برنامه نویسها زیر با تکنولوژی جدید نمی رن و جدای از چیزهایی که گفتم آنها یک شعار دارن که می گن "اینی که داریم کفایت کار ما رو میکنه و پول ساز هست " , پس دلیلی بر کوچ کردن به تکنولوژی های جدید وجود نداره.
مطالب دوره‌ها
بررسی Semantic Search و FTS Table-valued functions
Semantic Search جزو تازه‌های SQL Server 2012 است و مقدمات نصب و فعال سازی آن‌را در قسمت اول بررسی کردیم.
توابع Predicates مختص به FTS مانند Contains و Freetext، تنها ردیف‌های متناظر با جستجوی انجام شده را باز می‌گردانند و رتبه‌ای به نتایج جستجو اعمال نمی‌گردد. برای مثال، مشخص نیست اولین ردیف بازگشت داده شده بهترین تطابق را با جستجوی انجام شده دارد یا بدترین نتیجه‌ی ممکن است. برای رفع این مشکل FTS table-valued functions معرفی شده‌اند. حاصل این‌ها یک جدول با دو ستون است. ستون اول کلید متناظر با جدول تطابق یافته بوده و ستون دوم، Rank نام دارد که بیانگر میزان مفید بودن و درجه‌ی اعتبار ردیف بازگشت داده شده‌است.
Semantic Search نیز به کمک سه table-valued functions پیاده سازی می‌شود. همچنین باید دقت داشت که تمام زبان‌های پشتیبانی شده توسط FTS در حالت Semantic Search پشتیبانی نمی‌شوند. برای بررسی این مورد، دو کوئری ذیل را اجرا نمائید:
 -- Full text Languages
SELECT *
FROM sys.fulltext_languages
ORDER BY name;

-- Semantic Search Languages
SELECT *
FROM sys.fulltext_semantic_languages
ORDER BY name;
GO

بررسی table-valued functions مختص به FTS

دو متد ویژه‌ی CONTAINSTABLE و FREETEXTTABLE خروجی از نوع جدول دارند؛ با ستون‌هایی به نام‌های key و rank. اگر قسمت ایجاد کاتالوگ FTS و ایندکس آن‌را بخاطر داشته باشید، در حین ایجاد ایندکس FTS می‌بایستی KEY INDEX PK_Documents را نیز ذکر کرد. کاربرد آن در همین table-valued functions است.
مقدار rank، عددی است بین 0 و 1000 که هر چقدر مقدار آن بیشتر باشد، یعنی نتیجه‌ای نزدیک‌تر، به عبارت جستجو شده، یافت گردیده‌است. باید دقت داشت که این عدد فقط در زمینه‌ی یک کوئری معنا پیدا می‌کند و مقایسه‌ی rank دو کوئری مختلف با هم، بی‌معنا است.
عملکرد CONTAINSTABLE بسیار شبیه به متد Contains است با این تفاوت که قابلیت‌های بیشتری دارد. برای مثال در اینجا می‌توان برای قسمتی از جستجو، وزن و اهمیت بیشتری را قائل شد و این حالت تنها زمانی معنا پیدا می‌کند که خروجی جستجو، دارای rank باشد.
متد FREETEXTTABLE نیز بسیار شبیه به FREETEXT عمل کرده و نسبت به CONTAINSTABLE بسیار ساده‌تر است. برای نمونه امکان تعریف وزن، formsof، near و غیره در اینجا وجود ندارد. به علاوه عملگرهای منطقی مانند and و or نیز در اینجا کاربردی نداشته و صرفا یک noise word درنظر گرفته می‌شوند.


چند مثال جهت بررسی عملکرد دو متد CONTAINSTABLE و FREETEXTTABLE

استفاده از متد CONTAINSTABLE
 -- Rank with CONTAINSTABLE
SELECT D.id, D.title, CT.[RANK], D.docexcerpt
FROM CONTAINSTABLE(dbo.Documents, docexcerpt,
N'data OR level') AS CT
 INNER JOIN dbo.Documents AS D
  ON CT.[KEY] = D.id
ORDER BY CT.[RANK] DESC;
چون متد CONTAINSTABLE خروجی از نوع table دارد، در قسمت from ذکر شده‌است.
این متد ابتدا نام جدول مورد بررسی را دریافت می‌کند. سپس ستونی که باید جستجو بر روی آن انجام شود و در ادامه عبارت جستجو شونده، مشخص می‌گردد. اگر این متد را به تنهایی اجرا کنیم:
 SELECT * FROM CONTAINSTABLE(dbo.Documents, docexcerpt, N'data OR level')
همانطور که عنوان شد، صرفا یک سری ردیف اشاره کننده به id و rank را بازگشت می‌دهد. به همین جهت join نوشته شده‌است تا بتوان رکوردهای اصلی را نیز در همینجا به همراه rank متناظر، نمایش داد.


استفاده از متد FREETEXTTABLE

 -- Rank with FREETEXTTABLE
SELECT D.id, D.title, FT.[RANK], D.docexcerpt
FROM FREETEXTTABLE (dbo.Documents, docexcerpt,
N'data level') AS FT
 INNER JOIN dbo.Documents AS D
  ON FT.[KEY] = D.id
ORDER BY FT.[RANK] DESC;
کلیات عملکرد متد FREETEXTTABLE بسیار شبیه است به متد CONTAINSTABLE؛ با این تفاوت که ساده‌تر بوده و بسیاری از قابلیت‌های پیشرفته و سفارشی CONTAINSTABLE را به صورت خودکار و یکجا اعمال می‌کند. به همین جهت دقت آن، اندکی کمتر بوده و عمومی‌تر عمل می‌کند.
در اینجا اگر نیاز باشد تا تعداد نتایج را شبیه به کوئری‌های top n محدود نمود، می‌توان از پارامتر عددی بعدی که برای نمونه به 2 تنظیم شده‌است، استفاده کرد:
 -- Rank with FREETEXTTABLE and top_n_by_rank
SELECT D.id, D.title, FT.[RANK], D.docexcerpt
FROM FREETEXTTABLE (dbo.Documents, docexcerpt,
N'data level', 2) AS FT
 INNER JOIN dbo.Documents AS D
  ON FT.[KEY] = D.id
ORDER BY FT.[RANK] DESC;
در این کوئری تنها 2 ردیف بازگشت داده می‌شود.

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

 -- Weighted terms
SELECT D.id, D.title, CT.[RANK], D.docexcerpt
FROM CONTAINSTABLE
(dbo.Documents, docexcerpt,
N'ISABOUT(data weight(0.8), level weight(0.2))') AS CT
 INNER JOIN dbo.Documents AS D
  ON CT.[KEY] = D.id
ORDER BY CT.[RANK] DESC;
با استفاده از واژه کلیدی ISABOUT، امکان تعیین وزن، برای واژه‌های در حال جستجو ممکن می‌شوند. در این کوئری اهمیت واژه data بیشتر از اهمیت واژه level تعیین شده‌است.


انجام جستجو‌های Proximity
 -- Proximity term
SELECT D.id, D.title, CT.[RANK]
FROM CONTAINSTABLE (dbo.Documents, doccontent,
N'NEAR((data, row), 30)') AS CT
 INNER JOIN dbo.Documents AS D
  ON CT.[KEY] = D.id
ORDER BY CT.[RANK] DESC;
GO
در اینجا مانند متد CONTAINS، امکان انجام جستجوهای Proximity نیز وجود دارد. برای مثال در کوئری فوق به دنبال رکوردهایی هستیم که در آن‌ها واژه‌های data و row وجود دارند، با فاصله‌ای کمتر از 30 کلمه.


بررسی Semantic Search key valued functions

متد SEMANTICKEYPHRASETABLE کار بازگشت واژه‌های کلیدی آنالیز شده توسط FTS را انجام داده و جدولی حاوی 4 ستون را باز می‌گرداند. این چهار ستون عبارتند از:
- column_id: شماره ستون واژه کلیدی یافت شده‌است. تفسیر آن نیاز به استفاده از تابع سیستمی COL_NAME دارد (مانند مثال زیر).
- document_key: متناظر است با کلید اصلی جدولی که بر روی آن کوئری گرفته می‌شود.
- keyphrase: همان واژه کلیدی است.
- score: رتبه‌ی واژه کلیدی است در بین سایر واژه‌هایی که بازگشت داده شده و عددی است بین صفر تا یک.

مثالی از آن‌را در ادامه ملاحظه می‌کنید:
 -- Top 100 semantic key phrases
SELECT TOP (100)
 D.id, D.title,
 SKT.column_id,
 COL_NAME(OBJECT_ID(N'dbo.Documents'), SKT.column_id) AS column_name,
 SKT.document_key,
 SKT.keyphrase, SKT.score
FROM SEMANTICKEYPHRASETABLE
(dbo.Documents, doccontent) AS SKT
 INNER JOIN dbo.Documents AS D
  ON SKT.document_key = D.id
ORDER BY SKT.score DESC;


در متد جدولی SEMANTICKEYPHRASETABLE، ابتدا جدول مورد نظر و سپس ستونی که نیاز است واژه‌های کلیدی آنالیز شده‌ی آن بازگشت داده شوند، قید می‌گردند. document_key آن به تنهایی شاید مفید نباشد. به همین جهت join شده‌است به جدول اصلی، تا بتوان رکوردهای متناظر را نیز بهتر تشخیص داد.
به این ترتیب مهم‌ترین واژه‌های کلیدی ستون doccontent را به همراه درجه‌ی اهمیت و رتبه‌ی آن‌ها، می‌توان گزارش گرفت.


متد SEMANTICSIMILARITYTABLE برای یافتن سندهای مشابه با یک سند مشخص بکار می‌روند؛ چیزی شبیه به گزارش «مقالات مشابه مطلب جاری» در بسیاری از سایت‌های ارائه‌ی محتوا. ستون‌های خروجی آن عبارتند از:
- source_column_id: شماره ستون منبع انجام کوئری.
- matched_column_id: شماره ستون سند مشابه یافت شده.
- matched_document_key: متناظر است با کلید اصلی جدولی که بر روی آن کوئری گرفته می‌شود.
- score: رتبه‌ی نسبی سند مشابه یافت شده.

 -- Documents that are similar to document 1
SELECT S.source_document_title,
 SST.matched_document_key,
 D.title AS matched_document_title,
 SST.score
FROM
 (SEMANTICSIMILARITYTABLE
  (dbo.Documents, doccontent, 1) AS SST
  INNER JOIN dbo.Documents AS D
ON SST.matched_document_key = D.id)
 CROSS JOIN
  (SELECT title FROM dbo.Documents WHERE id=1)
AS S(source_document_title)
ORDER BY SST.score DESC;



در این کوئری، اسناد مشابه با سند شماره 1 یافت شده‌اند. مبنای جستجو نیز ستون doccontent، جدول dbo.Documents است. از join بر روی matched_document_key و id جدول اصلی، مشخصات سند یافت شده را می‌توان استخراج کرد. کار CROSS JOIN تعریف شده، صرفا افزودن یک ستون مشخص به نتیجه‌ی خروجی کوئری است.
همانطور که در تصویر مشخص است، سند شماره 4 بسیار شبیه است به سند شماره 1. در ادامه قصد داریم بررسی کنیم که علت این شباهت چه بوده‌است؟


متد SEMANTICSIMILARITYDETAILSTABLE واژه‌های کلیدی مهم مشترک بین دو سند را بازگشت می‌دهد (سند منبع و سند مقصد). به این ترتیب می‌توان دریافت، چه واژه‌های کلیدی سبب شده‌اند تا این دو سند به هم شبیه باشند. ستون‌های خروجی آن عبارتند از:
- keyphrase: واژه‌ی کلیدی
- score: رتبه‌ی نسبی واژه‌ی کلیدی

 -- Key phrases that are common across two documents
SELECT SSDT.keyphrase, SSDT.score
FROM SEMANTICSIMILARITYDETAILSTABLE
(dbo.Documents, doccontent, 1,
doccontent, 4) AS SSDT
ORDER BY SSDT.score DESC;


در کوئری فوق قصد داریم بررسی کنیم چه واژه‌های کلیدی، سبب مشابهت سندهای شماره 1 و 4 شده‌اند و بین آن‌ها مشترک می‌باشند.
مطالب
جایگزین کردن jQuery با JavaScript خالص - قسمت دوم - کار با Attributes
عناصر HTML از سه قسمت نام، محتوا و ویژگی‌ها یا attributes تشکیل می‌شوند که دو مورد آخر، اختیاری هستند.
<form action="/rest/login" method="POST">
    <input name="username" required>
    <input type="password" name="password" required>
</form>
در این مثال سه المان form و دو input را مشاهده می‌کنید. تگ المان <form> دارای نام form و تگ المان <input> دارای نام input است.
محتوا یا content به معنای المان‌هایی هستند که درون یک المان قرار می‌گیرند. برای مثال در اینجا المان <form> دارای محتوایی متشکل از دو المان <input> است و دون المان <input> دارای محتوایی نیستند.
از ویژگی‌ها و یا attributes، برای ارائه‌ی اطلاعات بیشتر و یا تعیین حالت عناصر استفاده می‌شود. برای نمونه در اینجا المان <form> دارای دو ویژگی action و method است که برای ارائه‌ی اطلاعاتی بیشتر جهت تعیین روش و محل ارسال اطلاعات به سرور از آن‌ها استفاده می‌شود. همچنین می‌توان ویژگی‌های سفارشی را نیز توسط ویژگی‌های شروع شده‌ی با -data نیز به المان‌ها اضافه کرد که جزئی از استاندارد HTML 5 است. هرچند می‌توان ویژگی کاملا غیرمتعارفی مانند myproject-uuid را نیز به یک المان اضافه کرد. این مورد مشکل خاصی را ایجاد نکرده و صفحه بدون مشکل رندر می‌شود؛ اما یک چنین صفحه‌ای دیگر به عنوان یک صفحه‌ی استاندارد HTML ارزیابی نخواهد شد؛ از این جهت که از ویژگی استفاده کرده‌است که در هیچکدام از استانداردهای HTML ذکر نشده‌است.
آخرین نگارش HTML5 به همراه 4 ویژگی جدید دیگر نیز هست:
- Boolean attribute : مانند ویژگی required که به المان‌های <input> قابل انتساب است. حضور این نوع ویژگی‌ها بدون مقداری در یک المان
 <input name=username required>
به معنای true بودن مقدار آن‌ها است و اگر به طور کامل ذکر نشوند، مقدار false را خواهند داشت.
نمونه‌ی دیگری از این نوع ویژگی‌ها، ویژگی hidden است که به HTML 5.1 اضافه شده‌است و اگر به عنصری اضافه شود، آن المان رندر نخواهد شد.
- unquoted attribute: به این معنا که می‌توان "" را از اطراف مقدار یک ویژگی حذف کرد:
 <input name=username required>
البته با این شرط که این مقدار دارای فاصله، علامت مساوی، مقداری خالی و یا >< نباشد.
- single-quoted and double-quoted attributes: که به معنای استفاده از "" و یا '' جهت تعیین مقدار یک ویژگی است.


تفاوت attributes با خواص المان‌ها چیست؟

Attributes در تعریف تگ HTML یک عنصر ظاهر می‌شوند اما خواص، جزئی از تعریف شیء یک عنصر هستند.
<div class="bold">I'm a bold element</div>
در این مثال المان <div> دارای ویژگی class است. هرچند ویژگی‌ها و خواص دارای مفاهیم یکسانی نیستند، اما در تعریف اشیاء HTML به ازای تمام ویژگی‌های استاندارد، یک خاصیت با نام معادل نیز در نظر گرفته‌است و تغییر مقدار آن‌ها از طریق کد، سبب به روز رسانی مقدار ویژگی‌های متناظر نیز می‌شود.
 <a href="http://www.site.com/blog/">Read the blog</a>
برای مثال اگر بخواهیم مقدار ویژگی href المان فوق را تغییر دهیم، می‌توانیم ابتدا این شیء را یافته و سپس خاصیت href آن‌را به روز رسانی کنیم تا بر روی ویژگی متناظر با آن تاثیرگذار شود:
<script>
   document.querySelector('A').href = 'https://www.dntips.ir';
</script>
هرچند در اکثر موارد تناظری بین نام خواص و ویژگی‌های المان‌ها برقرار است، اما یکسری استثناءهایی هم وجود دارند:
- برای مثال واژه‌ی class در زبان جاوا اسکریپت یک واژه‌ی کلیدی است. به همین جهت در اینجا اگر بخواهیم مقدار ویژگی class را تغییر دهیم باید از خاصیت className آن المان استفاده کنیم.
- مورد دوم ویژگی checked المان‌های radio و checkbox است. این ویژگی فقط در ابتدای کار این المان‌ها به آن‌ها متصل می‌شود:
  <input type="checkbox" checked>

  <script>
      // this does not remove the checked attribute 
      document.querySelector('INPUT').checked = false;
  </script>
با اجرای قطعه کد فوق، هرچند مقدار خاصیت checked این المان false می‌شود، اما سبب حذف خود ویژگی از المان نخواهد شد.
- تمام ویژگی‌های غیراستانداردی که تعریف شوند، دارای خاصیت متناظری در آن المان نخواهند بود، اما به آن‌ها expando properties گفته می‌شود.


یافتن المان‌ها بر اساس ویژگی‌های آن‌ها

از آنجائیکه attribute selectors در استاندارد W3C CSS 2 معرفی شده‌اند، امکان کار با آن‌ها از زمان IE 8.0 میسر بوده‌است و برای کار با آ‌ن‌ها الزاما نیازی به استفاده از jQuery نیست!


یافتن المان‌ها بر اساس نام ویژگی‌ها

  <form action="/submitHandler" method="POST">
      <input name="first-name">
      <input name="last-name" required>
      <input type="email" name="email" required>
      <button disabled>submit</button>
  </form>
در اینجا برای یافتن المان‌هایی که دارای ویژگی‌هایی با نام‌های required و disabled هستند، در جی‌کوئری از CSS 2+ attribute selector string آن‌ها استفاده می‌شود:
 var $result = $('[required], [disabled]');
و در جاوا اسکریپت خالص نیز دقیقا به همان شکل و با استفاده از همان استاندارد است:
 var result = document.querySelectorAll('[required], [disabled]');
که خروجی آن آرایه‌ای از المان‌های last-name، email و دکمه است.

در اینجا باید دقت داشت که این جستجو صرفا بر اساس نام ویژگی‌ها انجام می‌شود؛ حتی اگر این ویژگی دارای مقداری نباشد:
  <div class="bold">I'm bold</div>
  <span class>I'm not</span>
در اینجا ویژگی class دوم دارای مقداری نیست و اگر کوئری ذیل را اجرا کنیم، هر دو المان span و div را دریافت خواهیم کرد:
  var result = document.querySelectorAll('[class]');


یافتن المان‌ها بر اساس نام و مقدار ویژگی‌ها

  <section>
     <h2>Sites</h2>
     <ul>
          <li>
              <a href="https://www.dntips.ir/">dotnettips</a>
          </li>
          <li>
              <a href="https://google.com/">Google</a>
          </li>
      </ul>
  </section>
اگر یافتن المان‌ها صرفا بر اساس نام ویژگی‌های آن‌ها کافی نیست، استفاده از همان روش استاندارد CSS selector string برای یافتن عنصری بر اساس نام و مقدار یک ویژگی نیز میسر است. برای مثال در این حالت در جی‌کوئری خواهیم داشت:
 var $result = $('A[href="https://www.dntips.ir/"]');
معادل این کد در جاوا اسکریپت خالص نیز به همین شکل است؛ اما بدون نیاز به وابستگی خاصی و سریعتر:
 var result = document.querySelectorAll('A[href="https://www.dntips.ir/"]');

و یا اگر اینبار بخواهیم تمام ویژگی‌های کلاسی که دارای مقدار هستند را انتخاب کنیم، روش آن با استفاده از exclusion selector به صورت زیر است:
 var result = document.querySelectorAll('[class]:not([class=""]');


یافتن المان‌ها بر اساس نام و قسمتی از مقدار ویژگی‌ها

  <a href="https://www.dntips.ir/">home page</a>
  <a href="https://www.dntips.ir/postsarchive">articles</a>
  <a href="https://www.dntips.ir/newsarchive">news</a>
در مثال قبل، المان‌هایی را که دارای مقدار ویژگی کاملا مشخصی بودند، یافتیم. اما اگر بخواهیم در قطعه HTML فوق لینک‌هایی را که دارای domain مشخصی هستند بیابیم چطور؟ در اینجا باید از substring attribute selector که جزئی از استاندارد W3C CSS 3 است، استفاده کنیم:
 var result = document.querySelectorAll('A[href*="www.dotnettips.info"]');
در اینجا تمام anchor tagهایی که دارای ویژگی href با مقداری حاوی www.dotnettips.info هستند، یافت خواهند شد.


یافتن المان‌ها بر اساس نام و کلمه‌ای مشخص در مقدار ویژگی‌ها

<div class="one two three">1 2 3</div>
<div class="onetwothree">123</div>
در این مثال می‌خواهیم المانی را بیابیم که کلاس two به آن اعمال شده‌است. برای اینکار از attribute word selector استفاده می‌شود:
 var result = document.querySelectorAll('[class∼=two]');
خروجی این کوئری، لیستی است حاوی اولین div تعریف شده.

در اینجا نوع دیگری از کوئری را هم می‌توان مطرح کرد: آیا المانی مشخص، دارای کلاس two است؟
روش انجام آن در jQuery به صورت زیر است:
 var hasTwoClass = $divEl.hasClass('two');
و در جاوا اسکریپت خالص:
 var hasTwoClass = divEl.classList.contains('two');
DOM API به همراه خاصیتی است به نام classList که امکان یافتن عنصری خاص را در آن توسط متد استاندارد contains میسر می‌کند.
همچنین خاصیت classList به همراه متدهای استاندارد add و remove نیز هست که معادل متدهای addClass و removeClass جی‌کوئری هستند.
divEl.classList.remove('red');
divEl.classList.add('blue');
و یا متد toggle خاصیت classList سبب افزوده شدن کلاسی مشخص و یا فراخوانی مجدد آن سبب حذف آن کلاس می‌شود (معادل متد toggleClass جی‌کوئری است):
// removes "hide" class
divEl.classList.toggle('hide');

// re-adds "hide" class
divEl.classList.toggle('hide');


یافتن المان‌ها بر اساس نام و شروع یا خاتمه‌ی عبارتی مشخص در مقدار ویژگی‌ها

  <img id="cat" src="/images/cat.gif">
  <img id="zebra" src="zebra.gif">
  <a href="#zebra">watch the zebra</a>
  <a href="/logout">logout</a>
در اینجا می‌خواهیم تمام المان‌هایی را که از نوع تصاویر gif هستند، به همراه لینک‌هایی که به صفحه‌ی جاری اشاره می‌کنند، بیابیم:
 var result = document.querySelectorAll('A[href^="#"], [src$=".gif"]');
این کوئری نحوه‌ی استفاده‌ی از starts with attribute value selector یا ^ و ends with attribute value selector یا $ را نمایش می‌دهد. این مثال لینک‌هایی را که با # شروع می‌شوند و همچنین المان‌هایی را که دارای src ختم شده‌ی به gif هستند، پیدا می‌کند.


خواندن مقادیر ویژگی‌ها

 <input type="password" name="user-password" required>
روش خواندن مقدار ویژگی type و بررسی وجود ویژگی required در جی‌کوئری:
// returns "password"
$inputEl.attr('type');

// returns "true"
$inputEl.is('[required]');
و معادل همین قطعه کد در جاوا اسکریپت خالص به صورت زیر است:
// returns "password"
inputEl.getAttribute('type');

// returns "true"
inputEl.hasAttribute('required');
متد getAttribute از سال 1997 به همراه استاندارد W3C DOM Level 1 Core و متد hasAttribute از سال 2000 به همراه استاندارد DOM Level 2 Core معرفی شده‌اند.


تغییر مقدار ویژگی‌ها

 <input name="temp" required>
می‌خواهیم این المان را به نحوی تغییر دهیم که نوع آن email شود، بدون ویژگی required و نام آن به userEmail تغییر یابد.
روش انجام اینکار در جی‌کوئری:
 $inputEl
 .attr('type', 'email') // #1
 .removeAttr('required') // #2
 .attr('name', 'userEmail'); // #3
و با جاوا اسکریپت خالص:
 inputEl.setAttribute('type', 'email'); // #1
inputEl.removeAttribute('required'); // #2
inputEl.setAttribute('name', 'userEmail'); // #3
متدهای استاندارد setAttribute و removeAttribute نیز جزئی از استاندارد W3C DOM Level 1 Core سال 1997 هستند؛ اما مانند jQuery قابلیت ذکر زنجیروار را ندارند که ... مهم نیست.
مطالب
شروع به کار با EF Core 1.0 - قسمت 1 - برپایی تنظیمات اولیه
در ادامه‌ی سری «ارتقاء به ASP.NET Core 1.0» اگر بخواهیم مباحث اعتبارسنجی کاربران و ASP.NET Identity مخصوص آن‌را بررسی کنیم، نیاز است ابتدا مباحث Entity framework Core 1.0 را بررسی کنیم. به همین جهت در طی چند قسمت مباحث پایه‌ای کار با EF Core 1.0 را در ASP.NET Core 1.0، بررسی خواهیم کرد. بنابراین پیشنیاز ضروری این مباحث، مطالعه‌ی سری «ارتقاء به ASP.NET Core 1.0» است و در آن از مباحثی مانند چگونگی کار با فایل‌های کانفیگ جدید، تزریق وابستگی‌ها و سرویس‌ها، فعال سازی سرویس Logging، فعال سازی صفحات مخصوص توسعه دهنده‌ها و ... در ASP.NET Core 1.0 استفاده خواهد شد.


EF Core چیست؟

EF Core یک ORM یا object-relational mapper چندسکویی است که امکان کار با بانک‌های اطلاعاتی مختلف را از طریق اشیاء دات نتی میسر می‌کند. توسط آن قسمت عمده‌ی کدهای مستقیم کار با بانک‌های اطلاعاتی حذف شده و تبدیل به کدهای دات نتی می‌شوند. مزیت این لایه‌ی Abstraction اضافی (لایه‌ای بر روی کدهای مستقیم لایه ADO.NET زیرین)، امکان تعویض بانک اطلاعاتی مورد استفاده، تنها با تغییر کدهای آغازین برنامه‌است؛ بدون نیاز به تغییری در سایر قسمت‌های برنامه. همچنین کار با اشیاء دات نتی و LINQ، مزایایی مانند تحت نظر قرار گرفتن کدها توسط کامپایلر و برخورداری از ابزارهای Refactoring پیشرفته را میسر می‌کنند. به علاوه SQL خودکار تولیدی توسط آن نیز همواره پارامتری بوده و مشکلات حملات تزریق SQL در این حالت تقریبا به صفر می‌رسند (اگر مستقیما SQL نویسی نکنید و صرفا از LINQ استفاده کنید). مزیت دیگر همواره پارامتری بودن کوئری‌ها، رفتار بسیاری از بانک‌های اطلاعاتی با آن‌ها همانند رویه‌های ذخیره شده است که به عدم تولید Query plan‌های مجزایی به ازای هر کوئری رسیده منجر می‌شود که در نهایت سبب بالا رفتن سرعت اجرای کوئری‌ها و مصرف حافظه‌ی کمتری در سمت سرور بانک اطلاعاتی می‌گردد.


تفاوت EF Core با نگارش‌های دیگر Entity framework در چیست؟

سورس باز بودن
EF از نگارش‌های آخر آن بود که سورس باز شد؛ اما EF Core از زمان نگارش‌های پیش نمایش آن به صورت سورس باز در GitHub قابل دسترسی است.

چند سکویی بودن
EF Core برخلاف EF 6.x (آخرین نگارش مبتنی بر Full Framework آن)، نه تنها چندسکویی است و قابلیت اجرای بر روی Mac و لینوکس را نیز دارا است، به علاوه امکان استفاده‌ی از آن در انواع و اقسام برنامه‌های دات نتی مانند UWP یا Universal Windows Platform و Windows phone که پیشتر با EF 6.x میسر نبود، وجود دارد. لیست این نوع سکوها و برنامه‌های مختلف به شرح زیر است:
 • All .NET application (Console, ASP.NET 4, WinForms, WPF)
 • Mac and Linux applications (Mono)
 • UWP (Universal Windows Platform)
 • ASP.NET Core applications
 • Can use EF Core in Windows phone and Windows store app

افزایش تعداد بانک‌های اطلاعاتی پشتیبانی شده
در EF Full یا EF 6.x، هدف اصلی، تنها کار با بانک‌های اطلاعاتی رابطه‌‌ای بود و همچنین مایکروسافت صرفا نگارش‌های مختلف SQL Server را به صورت رسمی پشتیبانی می‌کرد و برای سایر بانک‌های اطلاعاتی دیگر باید از پروایدرهای ثالث استفاده کرد.
در EF Core علاوه بر افزایش تعداد پروایدرهای رسمی بانک‌های اطلاعاتی رابطه‌ای، پشتیبانی از بانک‌های اطلاعاتی NoSQL هم اضافه شده‌است؛ به همراه پروایدر ویژه‌‌ای به نام In Memory جهت انجام ساده‌تر Unit testing. کاری که با نگارش‌های پیشین EF به سادگی و از روز اول پشتیبانی نمی‌شد.

حذف و یا عدم پیاده سازی تعدادی از قابلیت‌های EF 6.x
اگر موارد فوق جزو مهم‌ترین مزایای کار با EF Core باشند، باید درنظر داشت که به علت حذف و یا تقلیل یافتن یک سری از ویژگی‌ها در NET Core.، مانند Reflection (جهت پشتیبانی از دات نت در سکوهای مختلف کاری و خصوصا پشتیبانی از حالتی که کامپایلر مخصوص برنامه‌های UWP نیاز دارد تمام نوع‌ها را همانند زبان‌های C و ++C، در زمان کامپایل بداند)، یک سری از قابلیت‌های EF 6.x مانند Lazy loading هنوز در EF Core پشتیبانی نمی‌شوند. لیست کامل و به روز شده‌ی این موارد را در اینجا می‌توانید مطالعه کنید.
بنابراین امکان انتقال برنامه‌های EF 6.x به EF Core 1.0 عموما وجود نداشته و نیاز به بازنویسی کامل دارند. هرچند بسیاری از مفاهیم آن با EF Code First یکی است.


برپایی تنظیمات اولیه‌ی EF Core 1.0 در یک برنامه‌ی ASP.NET Core 1.0

برای نصب تنظیمات اولیه‌ی EF Core 1.0 در یک برنامه‌ی ASP.NET Core 1.0، جهت کار با مشتقات SQL Server (و SQL LocalDB) نیاز است سه بسته‌ی ذیل را نصب کرد (از طریق منوی Tools -> NuGet Package Manager -> Package Manager Console):
PM> Install-Package Microsoft.EntityFrameworkCore.SqlServer
PM> Install-Package Microsoft.EntityFrameworkCore.Tools -Pre
PM> Install-Package Microsoft.EntityFrameworkCore.SqlServer.Design
البته در این قسمت صرفا از بسته‌ی اول که جهت اتصال به SQL Server است استفاده می‌کنیم. بسته‌های دیگر را در قسمت‌های بعد، برای به روز رسانی اسکیمای بانک اطلاعاتی (مباحث Migrations) و مباحث scaffolding استفاده خواهیم کرد.
پس از اجرای سه دستور فوق، تغییرات مداخل فایل project.json برنامه به صورت ذیل خواهند بود:
{
    "dependencies": {
       // same as before
        "Microsoft.EntityFrameworkCore.SqlServer": "1.0.0",
        "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final",
        "Microsoft.EntityFrameworkCore.SqlServer.Design": "1.0.0"
    }
}
این مداخلی که توسط نیوگت اضافه شده‌اند، نیاز به اصلاح دارند؛ به این صورت:
{
    "dependencies": {
       // same as before
        "Microsoft.EntityFrameworkCore.SqlServer": "1.0.0",
        "Microsoft.EntityFrameworkCore.Tools": {
            "version": "1.0.0-preview2-final",
            "type": "build"
        },
        "Microsoft.EntityFrameworkCore.SqlServer.Design": {
            "version": "1.0.0",
            "type": "build"
        }
    },

    "tools": {
       // same as before
        "Microsoft.EntityFrameworkCore.Tools": {
            "version": "1.0.0-preview2-final",
            "imports": [
                "portable-net45+win8"
            ]
        }   
   }
}
نیاز است در قسمت dependencies مشخص کنیم که ابزارهای اضافه شده مخصوص build هستند و نه اجرای برنامه. همچنین قسمت tools را باید با Microsoft.EntityFrameworkCore.Tools مقدار دهی کرد تا بتوان از این ابزار در خط فرمان، جهت اجرای فرامین migrations استفاده کرد.
بنابراین از همین ابتدای کار، بدون مراجعه‌ی به Package Manager Console، چهار تغییر فوق را به فایل project.json اعمال کرده و آن‌را ذخیره کنید؛ تا کار به روز رسانی و نصب بسته‌ها، به صورت خودکار و همچنین صحیحی انجام شود.


فعال سازی صفحات مخصوص توسعه دهنده‌های EF Core 1.0

در مطلب «ارتقاء به ASP.NET Core 1.0 - قسمت 5 - فعال سازی صفحات مخصوص توسعه دهنده‌ها» با تعدادی از اینگونه صفحات آشنا شدیم. برای EF Core نیز بسته‌ی مخصوصی به نام Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore وجود دارد که امکان فعال سازی صفحه‌ی نمایش خطاهای بانک اطلاعاتی را میسر می‌کند. بنابراین ابتدا به فایل project.json مراجعه کرده و این بسته را اضافه کنید:
{
    "dependencies": {
       // same as before
        "Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore": "1.0.0"
    }
}
سپس می‌توان متد جدید UseDatabaseErrorPage را در متد Configure کلاس آغازین برنامه، فراخوانی کرد:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
   if (env.IsDevelopment())
   {
      app.UseDatabaseErrorPage();
   }
با فعال سازی این صفحه، اگر در حین توسعه‌ی برنامه و اتصال به بانک اطلاعاتی، خطایی رخ دهد، بجای مشاهده‌ی یک صفحه‌ی خطای عمومی (اگر UseDeveloperExceptionPage را فعال کرده باشید)، اینبار ریز جزئیات بیشتری را به همراه توصیه‌هایی از طرف تیم EF مشاهده خواهید کرد.


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


در این تصویر، زیر ساخت نگاشت‌های EF Core را مشاهده می‌کنید. در سمت چپ، ظرفی را داریم به نام DB Context که در برگیرنده‌ی Db Setها است. در سمت راست که بیانگر ساختار کلی یک بانک اطلاعاتی است، معادل این‌ها را مشاهده می‌کنیم. هر Db Set به یک جدول بانک اطلاعاتی نگاشت خواهد شد و متشکل است از کلاسی به همراه یک سری خواص که این‌ها نیز به فیلدها و ستون‌های آن جدول در سمت بانک اطلاعاتی نگاشت می‌شوند.
بنابراین برای شروع کار، پوشه‌ای را به نام Entities به پروژه اضافه کرده و سپس کلاس ذیل را به آن اضافه می‌کنیم:
namespace Core1RtmEmptyTest.Entities
{
    public class Person
    {
        public int PersonId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
}
کلاس Person بیانگر ساختار جدول اشخاص بانک اطلاعاتی است. برای اینکه این کلاس را تبدیل و نگاشت به یک جدول کنیم، نیاز است آن‌را به صورت یک DbSet در معرض دید EF Core قرار دهیم و اینکار در کلاسی که از DbContex مشتق می‌شود، صورت خواهد گرفت:
using Microsoft.EntityFrameworkCore;

namespace Core1RtmEmptyTest.Entities
{
    public class ApplicationDbContext : DbContext
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
        {
        }

        public DbSet<Person> Persons { get; set; }
    }
}
بنابراین در ادامه کلاس جدید ApplicationDbContext را که از کلاس پایه DbContext مشتق می‌شود تعریف کرده و سپس کلاس Person را به صورت یک DbSet در معرض دید EF Core قرار می‌دهیم.
سازنده‌ی این کلاس نیز به نحو خاصی تعریف شده‌است. اگر به سورس‌های EF Core مراجعه کنیم، کلاس پایه‌ی DbContext دارای دو سازنده‌ی با و بدون پارامتر است:
protected DbContext()
   : this((DbContextOptions) new DbContextOptions<DbContext>())
{
}

public DbContext([NotNull] DbContextOptions options)
{
  // …
}
اگر از سازنده‌ی بدون پارامتر استفاده کنیم و برای مثال در کلاس ApplicationDbContext فوق، به طور کامل سازنده‌ی تعریف شده را حذف کنیم، باید به نحو ذیل تنظیمات بانک اطلاعاتی را مشخص کنیم:
using Microsoft.EntityFrameworkCore;

namespace Core1RtmEmptyTest.Entities
{
    public class ApplicationDbContext : DbContext
    {
        public DbSet<Person> Persons { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(@"... connection string ...");
        }
    }
}
در این حالت باید متد OnConfiguring را override و یا بازنویسی کنیم، تا بتوان از اول مشخص کرد که قرار است از پروایدر SQL Server استفاده کنیم و ثانیا رشته‌ی اتصالی به آن چیست.
اما چون در یک برنامه‌ی ASP.NET Core، کار ثبت سرویس مربوط به EF Core، در کلاس آغازین برنامه انجام می‌شود و در آنجا به سادگی می‌توان به خاصیت Configuration برنامه دسترسی یافت و توسط آن رشته‌ی اتصالی را دریافت کرد، مرسوم است از سازنده‌ی با پارامتر DbContext به نحوی که در ابتدا عنوان شد، استفاده شود.
بنابراین در ادامه، پس از مطالعه‌ی مطلب «ارتقاء به ASP.NET Core 1.0 - قسمت 7 - کار با فایل‌های config» به فایل appsettings.json مراجعه کرده و تنظیمات رشته‌ی اتصالی برنامه را به صورت ذیل در آن مشخص می‌کنیم:
{
    "ConnectionStrings": {
        "ApplicationDbContextConnection": "Data Source=(local);Initial Catalog=TestDbCore2016;Integrated Security = true"
    }
}
باید دقت داشت که نام این مداخل کاملا اختیاری هستند و در نهایت باید در کلاس آغازین برنامه به صورت صریحی مشخص شوند.
در اینجا به وهله‌ی پیش فرض SQL Server اشاره شده‌است؛ از حالت اعتبارسنجی ویندوزی SQL Server استفاده می‌شود و بانک اطلاعاتی جدیدی به نام TestDbCore2016 در آن مشخص گردیده‌است.

پس از تعریف رشته‌ی اتصالی، متد OnConfiguring را از کلاس ApplicationDbContext حذف کرده و از همان نگارش دارای سازنده‌ی با پارامتر آن استفاده می‌کنیم. برای اینکار به کلاس آغازین برنامه مراجعه کرده و توسط متد AddDbContext این Context را به سرویس‌های ASP.NET Core معرفی می‌کنیم:
    public class Startup
    {
        public IConfigurationRoot Configuration { set; get; }

        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                                .SetBasePath(env.ContentRootPath)
                                .AddJsonFile("appsettings.json", reloadOnChange: true, optional: false)
                                .AddJsonFile($"appsettings.{env}.json", optional: true);
            Configuration = builder.Build();
        }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<IConfigurationRoot>(provider => { return Configuration; });
            services.AddDbContext<ApplicationDbContext>(options =>
            {
                options.UseSqlServer(Configuration["ConnectionStrings:ApplicationDbContextConnection"]);
            });
در اینجا جهت یادآوری مطلب «ارتقاء به ASP.NET Core 1.0 - قسمت 7 - کار با فایل‌های config» نحوه‌ی وهله سازی خاصیت Configuration که در متد UseSqlServer مورد استفاده قرار گرفته‌است، نیز ذکر شده‌است.
بنابراین قسمت options.UseSqlServer را یا در اینجا مقدار دهی می‌کنید و یا از طریق بازنویسی متد OnConfiguring کلاس Context برنامه.


یک نکته: امکان تزریق IConfigurationRoot به کلاس Context برنامه وجود دارد

با توجه به اینکه Context برنامه را به صورت یک سرویس به ASP.NET Core معرفی کردیم، امکان تزریق وابستگی‌ها نیز در آن وجود دارد. یعنی بجای روش فوق، می‌توان IConfigurationRoot را به سازنده‌ی کلاس Context برنامه نیز تزریق کرد:
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;

namespace Core1RtmEmptyTest.Entities
{
    public class ApplicationDbContext : DbContext
    {
        private readonly IConfigurationRoot _configuration;

        public ApplicationDbContext(IConfigurationRoot configuration)
        {
            _configuration = configuration;
        }

        //public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
        //{
        //}

        public DbSet<Person> Persons { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(_configuration["ConnectionStrings:ApplicationDbContextConnection"]);
        }
    }
}
با توجه به اینکه IConfigurationRoot در کلاس ConfigureServices به صورت Singleton، به مجموعه‌ی سرویس‌های برنامه معرفی شده‌است، از آن در تمام کلاس‌های برنامه که تحت نظر سیستم تزریق وابستگی‌های توکار ASP.NET Core هستند، می‌توان استفاده کرد.
در این حالت متد ConfigureServices کلاس آغازین برنامه، چنین شکلی را پیدا می‌کند و ساده می‌شود:
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>();


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

همینقدر که ApplicationDbContext را به عنوان سرویسی در ConfigureServices تعریف کردیم، امکان تزریق آن در اجزای مختلف یک برنامه‌ی ASP.NET Core نیز وجود دارد:
using System.Linq;
using Core1RtmEmptyTest.Entities;
using Microsoft.AspNetCore.Mvc;

namespace Core1RtmEmptyTest.Controllers
{
    public class TestDBController : Controller
    {
        private readonly ApplicationDbContext _ctx;

        public TestDBController(ApplicationDbContext ctx)
        {
            _ctx = ctx;
        }

        public IActionResult Index()
        {
            var name = _ctx.Persons.First().FirstName;
            return Json(new { firstName = name });
        }
    }
}
در اینجا نحوه‌ی تزریق DB Context برنامه را به یک کنترلر مشاهده می‌کنید. البته هرچند تزریق یک کلاس مشخص به این شکل، تزریق وابستگی‌ها نام ندارد و هنوز این کنترلر دقیقا وابسته‌است به پیاده سازی خاص کلاس ApplicationDbContext، اما ... در کل امکان آن هست.

در این حالت پس از اجرای برنامه، خطای ذیل را مشاهده خواهیم کرد:


علت اینجا است که هنوز این بانک اطلاعاتی ایجاد نشده‌است و همچنین ساختار جداول را به آن منتقل نکرده‌ایم که این موارد را در قسمت‌های بعدی مرور خواهیم کرد.
مطالب
آشنایی با NuGet - قسمت دوم

قسمت قبل از دید یک مصرف کننده بود؛ این قسمت جهت توسعه‌ دهنده‌ها تهیه شده است. کسانی که قصد دارند تا بسته‌های NuGet ایی از کارشان تهیه کنند. مراحل اینکار به شرح زیر است:

الف) برای این منظور نیاز است تا برنامه‌ی‌ خط فرمان NuGet.exe معرفی شده در قسمت قبل را ابتدا دریافت کنید : (+)

ب) برای بسته نرم افزاری خود یک پوشه جدید درست کنید. سپس فرمان nuget.exe spec را در این پوشه صادر نمائید. بلافاصله فایلی به نام Package.nuspec تشکیل خواهد شد:
D:\Prog\1389\CodePlex\slpdatepicker\SlPDatePickerNuGet>NuGet.exe spec
Created 'Package.nuspec' successfully.

فایل Package.nuspec، یک فایل XML ساده است. آن‌را با یک ادیتور متنی باز کرده و تغییرات لازم را اعمال نمائید. برای مثال من جهت پروژه Silverlight 4 Persian DatePicker ، محتویات آن‌را به صورت زیر تغییر داده‌ام:

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Silverlight.4.Persian.DatePicker</id>
<version>1.0</version>
<authors>Vahid Nasiri</authors>
<owners>Vahid Nasiri</owners>
<licenseUrl>http://slpdatepicker.codeplex.com/license</licenseUrl>
<projectUrl>http://slpdatepicker.codeplex.com/</projectUrl>
<iconUrl>https://slpdatepicker.svn.codeplex.com/svn/SilverlightPersianDatePicker/Views/Images/date.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Silverlight 4 Persian DatePicker Control</description>
<tags>Silverlight WPF Persian DatePicker</tags>
</metadata>
<files>
<file src="..\SilverlightPersianDatePicker\Bin\Release\*.dll" target="lib" />
<file src="..\SilverlightPersianDatePicker\Bin\Release\*.pdb" target="lib" />
<file src="..\SilverlightPersianDatePicker\Bin\Release\*.xml" target="lib" />
</files>
</package>

همانطور که ملاحظه می‌کنید یک سری اطلاعات عمومی از پروژه مورد نظر درخواست شده است؛ برای مثال آدرس آیکن آن چیست یا کجا می‌توان آن‌را یافت؟ مجوز استفاده از آن چیست و مواردی از این دست. به کمک تگ files هم فایل‌های کتابخانه در اینجا لحاظ شده‌اند. فایل آیکن معرفی شده باید در اندازه‌ی 32*32 و با فرمت png باشد. باید دقت داشت که در سایت nuget.org ، بسته شما بر اساس id ذکر شده معرفی خواهد شد و آدرسی بر این اساس تشکیل می‌گردد. بنابراین از فاصله یا موارد مشکل ساز در این بین استفاده نکنید.

در مورد نحوه‌ی ایجاد قدم به قدم یک پروژه جدید در سایت کدپلکس می‌توان به این مطلب مراجعه نمود: (+)

ج) اکنون نوبت به تهیه بسته نهایی می‌رسد. برای این منظور دستور زیر را در خط فرمان صادر کنید:
NuGet.exe pack Package.nuspec
پس از چند لحظه فایل Silverlight.4.Persian.DatePicker.1.0.nupkg جهت ارائه عمومی تولید خواهد شد.

د) قبل از اینکه این فایل نهایی را در سایت nuget.org آپلود کنیم، می‌توان مشخصات آن‌را به صورت محلی نیز یکبار مرور کرد. برای این منظور در VS.NET به منوی Tools گزینه‌ی Options مراجعه کرده و در قسمت package manager ، آدرس پوشه بسته مورد نظر را وارد کنید. برای مثال:



اکنون اگر کنسول پاورشل توضیح داده شده در قسمت قبل را باز نمائید، منبع جدید اضافه شده مشخص است یا می‌توان توسط دستور ذیل از آن کوئری گرفت:
get-package -remote -filter silverlight



و یا اگر همانند توضیحات قبل به صفحه‌ی دیالوگ add library package reference‌ مراجعه کنیم، مشخصات کامل بسته به همراه منبع محلی باید قابل مشاهده باشند:



ه) پس از بررسی محلی بسته مورد نظر، اکنون نوبت به ارائه عمومی آن می‌باشد. برای این منظور ابتدا باید در سایت nuget.org ثبت نام کرد : (+). اگر آدرس ایمیل شما را نپذیرفت، از مرورگر IE استفاده کنید!
پس از ثبت نام تنها کافی است به قسمت contribute سایت مراجعه کرده و فایل بسته نهایی را در آنجا آپلود کرد. به این صورت بسته نهایی در سایت پدیدار خواهد شد :‌(+)
همچنین بلافاصله در قسمت گالری آنلاین صفحه add library package reference نیز قابل دسترسی خواهد بود.


در آینده جهت توزیع به روز رسانی‌های جدید، همین مراحل باید تکرار شوند. البته در نظر داشته باشید که version ذکر شده در فایل Package.nuspec را باید حتما تغییر داد تا بسته‌ها از یکدیگر متمایز شوند. امکان اتوماسیون این توزیع نیز وجود دارد. همان فایل nuget.exe ، امکان ارسال بسته نهایی را به سایت nuget.org نیز دارد:
nuget push name.nupkg key
در اینجا key مخصوص به خود را می‌توان در صفحه‌ی http://nuget.org/Contribute/MyAccount مشاهده و استفاده نمود.

اگر علاقمند به مشاهده جزئیات بیشتری از این پروسه هستید، می‌توان به سایت رسمی آن مراجعه کرد: (+)

نظرات مطالب
نمایش تاریخ شمسی توسط JavaScript در AngularJS
با تشکر از مقاله خوبتون. خیلی کار را ساده میکنه فیلتری که نوشتید.
فقط من در هنگام استفاده از moment-jalali مشکلی برام به وجود اومد که برطرفش کردم. حس کردم شاید مشکل دوستان دیگر هم باشه. مشکل به این صورت بود که با اینکه من تمام کارهایی که در مقاله ذکر شده بود را انجام دادم، برای نمایش تاریخ فارسی میشد اما باز هم مینوشت x days ago به جای نمایش فارسی چند روز قبل. در مورد ماه و سال هم به همین صورت بود. من در خود وب سایت momentJs مطالعه کردم و متوجه شدم این کتابخانه درون خودش یک سری فایل برای زبان‌های گوناگون داره. بنده فایل اسکریپت زبان فارسی به همراه یک تکه کد که زبان فارسی را به عنوان زبان پیش فرض قرار میداد را اضافه کردم و مشکل حل شد.
    <!-- BEGIN MOMENT -->
    <script src="/bower_components/moment/moment.js"></script>
    <script src="/bower_components/moment/locale/fa.js"></script>
    <script src="/bower_components/moment-jalaali/build/moment-jalaali.js"></script>
    <script>
        moment.locale('fa');  // Set the default/global locale
        // ...
    </script>
    <!-- END MOMENT -->
و یک کار دیگه اینکه میشه این فیلتر را به هر صورتی خودتون ترجیح میدید Customize کنید. من از این فیلتر چندین نسخه تهییه کردم. به عنوان مثال یک فیلتر برای نمایش مدت زمان گذشته (مثلا چند ماه قبل)، یک فیلتر برای نمایش تاریخ به تنهایی و ...
یک نمونه از این پیاده سازی را آوردم امیدوارم مفید باشه.
app.filter('jalaliDateFromNow', function () {
    return function (inputDate) {
        var date = moment(inputDate);
        return date.fromNow();
    }
});

نظرات مطالب
بررسی بهبودهای پروسه‌ی Build در دات‌نت 8

یک نکته‌ی تکمیلی: چگونه تاریخ Build را به اسمبلی برنامه اضافه کنیم؟

شاید علاقمند باشید که بجای نمایش شماره نگارش برنامه، تاریخ Build آن‌را در قسمتی خاص، نمایش دهید. برای اینکار می‌توان یک ویژگی جدید را به صورت زیر به اسمبلی برنامه اضافه کرد:

[AttributeUsage(AttributeTargets.Assembly)]
public sealed class BuildDateAttribute : Attribute
{
    public BuildDateAttribute(string buildDateTime) => BuildDateTime = buildDateTime;

    public string BuildDateTime { get; }
}

تا در زمان کامپایل برنامه، فایل obj\Debug\net8.0\DntSite.Web.AssemblyInfo.cs را به این صورت تکمیل کند:

using System;
using System.Reflection;

[assembly: DNTCommon.Web.Core.BuildDateAttribute("1403.05.28.15.17")]
[assembly: System.Reflection.AssemblyCompanyAttribute("DntSite.Web")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]

مقدار دهی این این ویژگی جدید، در زمان Build و توسط تنظیمات زیر در فایل csproj. برنامه انجام می‌شود:

<Project>
  <ItemGroup>
        <AssemblyAttribute Include="DNTCommon.Web.Core.BuildDateAttribute">
            <_Parameter1>$([System.DateTime]::Now.ToString("yyyy.MM.dd.HH.mm"))</_Parameter1>
        </AssemblyAttribute>
  </ItemGroup>

با استفاده از AssemblyAttribute می‌توان پارامترهای دلخواهی را به ویژگی Include شده، ارسال کرد؛ برای مثال، تاریخ جاری سیستم را. اگر تعداد پارامترهای سازنده بیشتر بود، می‌توان Parameter2_ و Parameter3_ و ... را هم تنظیم کرد.

همین اندازه تنظیم برای اضافه شدن خودکار این ویژگی جدید به اسمبلی نهایی برنامه کافی است (و همانطور که عنوان شد، محل درج خودکار اولیه‌ی آن، در فایل AssemblyInfo.cs پوشه‌ی obj برنامه‌است). برای خواندن و نمایش آن هم می‌توان به صورت زیر عمل کرد:

public static class BuildDateAttributeExtensions
{
    public static string? GetBuildDateTime(this Assembly? assembly) =>
        assembly?.GetCustomAttribute<BuildDateAttribute>()?.BuildDateTime ??
        assembly?.GetName().Version?.ToString();
}

برای نمونه می‌توان اطلاعات BuildDateAttribute اسمبلی جاری را به صورت زیر استخراج کرد:

private static string? GetVersionInfo() => Assembly.GetExecutingAssembly().GetBuildDateTime();
مطالب
فایل‌های chm و مشکل فارسی - قسمت اول

همانطور که مطلع هستید از ویندوز ویستا به بعد، فرمت قدیمی فایل‌های راهنمای ویندوز (فایل‌های hlp) منسوخ شده تلقی می‌شود و فرمت پیشنهادی، chm است. نرم افزارهای زیادی برای تهیه فایل‌های compiled html help یا همان chm های معروف وجود دارند که معروفترین آن‌ها برنامه‌ی Help & Manual است.
اما تمام این برنامه‌ها در حقیقت پوسته‌ای هستند برای برنامه‌ی رایگان html help work shop مایکروسافت و در نهایت از کامپایلر آن استفاده می‌کنند. بنابراین چرا از برنامه‌ی رایگان اصلی استفاده نشود؟

اگر تا به حال با html help work shop کار نکرده‌اید، در ادامه مروری سریع بر آن خواهیم داشت:

الف) درست کردن فایل‌های صفحات راهنما
برنامه‌ی Help & Manual ایی که معرفی شد و تمام نمونه‌های مشابه آن، تنها کار مهمی را که انجام می‌دهند این است که شما را از یک html editor بی‌نیاز می‌کنند. بنابراین زمانیکه می‌خواهیم از برنامه‌ی اصلی html help work shop استفاده کنیم نیاز به یک html editor خارجی برای تهیه فایل‌های راهنما خواهیم داشت. مثلا مرحوم front page یا نگارش جدید آن به نام Microsoft expression web یا Dreamweaver یا Aptana یا حتی notepad !
در اینجا تنها مشخص کردن نوع encoding نمایش صفحه برای صحیح نمایش داده شدن متون فارسی کافی است. اما این تمام ماجرا نیست.

ب) کامپایل کردن فایل‌های راهنمای ایجاد شده
برای این منظور بجای آپلود بیش از 30 تصویر جهت توضیحات قدم به قدم نحوه‌ی انجام این‌کار، یک فایل ویدیویی درست کرده‌ام که آن‌‌را از آدرس زیر می‌توانید دریافت کنید.
دریافت فایل

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

در قسمت دوم، نحوه‌ی رفع این دو مشکل (مشکل جستجوی عبارات فارسی و مشکل عنوان‌های به هم ریخته) را بررسی خواهیم کرد.

ادامه دارد ...