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

پرسش پاسخ
برای ایجاد یک وبلاگ بلاگری از کجا شروع کنم؟ با داشتن یک اکانت جی میل، به آدرس زیر مراجعه کرده و هر تعداد که مایل بودید می‌توانید وبلاگ ایجاد نمائید:
قالب‌های پیش فرض گوگل چنگی به دل نمی‌زنند و بود و نبود آن‌ها احساس نمی‌شود! چه باید کرد؟ برای تهیه قالب‌های فارسی به آدرس زیر مراجعه نمائید:
تاریخ فارسی را چه کنم؟ روش دوستان ، روش من
برنامه نویسم! کدهای من یا نمایش داده نمی‌شود یا فرمت آن‌ها هنگام ارسال به هم می‌ریزد. چه باید کرد؟ روش مورد علاقه‌ی من ، روش مایکروسافت (+ و + و افزونه‌ای برای این‌کار)
آخرین نظرات کاربران سایت را چگونه در ستون کناری سایت نمایش دهم؟ یکی از ویجت‌های پرکاربرد گوگل در بلاگر، ویجت فید است. هر بلاگ دارای دو فید مطالب و نظرات است. ویجت فید را اضافه کرده و سپس آدرس فید نظرات سایت خود را به آن معرفی کنید. همیشه آخرین 5 نظر ارسالی را نمایش می‌دهد. این ویجت کاربردهای قابل توجهی می‌تواند داشته باشد.
آمار مراجعان به سایت را باید در کجا ملاحظه کرد؟ جای پیش فرضی وجود ندارد! یک اکانت Analytics برای خود تهیه کرده و آن‌را به سایت اضافه کنید. همچنین پس از آن یک اکانت فید برنر را نیز برای خود تهیه کنید. فیدبرنر اکنون جزیی از گوگل است و پس از معرفی آدرس فید سایت خود به آن، یک آدرس جدید به همراه آیکونی برای نمایش در سایت به شما می‌دهد که می‌توانید تگ‌های آن تصویر ‌را توسط ویجت html نمایش دهید. همچنین از همین طریق نیز می‌توان اشتراک از طریق ایمیل را به وبلاگ اضافه کرد.
کامنت‌های سایت من در بیرون از سایت باز می‌شوند. چرا؟ به این مطلب مراجعه نمائید:
چگونه برای بلاگ خود قسمت ارسال نظرات را تهیه نمایم؟ من از سرویس فرم ساز Zoho‌ استفاده می‌کنم که در سال 2008 جزو برترین‌های وب شناخته شده بود. بعد از ایجاد فرم خود و دریافت کد مربوطه، یک مطلب جدید را ارسال کنید و در بدنه‌ی آن ، کدی را که Zoho به شما ارائه می‌دهد قرار دهید. سپس لینک این مطلب را توسط یک ویجت html به کنار سایت اضافه کنید تا همیشه در دسترس باشد.

اشتراک‌ها
NET Core 1.1.6. منتشر شد

.NET Core 1.1.6 is comprised of:

  • .NET Core Runtime 1.1.6
  • .NET Core SDK 1.1.7

SDK Installer SDK Binaries Runtime Installer Runtime Binaries
Windows 32-bit / 64-bit 32-bit / 64-bit 32-bit / 64-bit 32-bit / 64-bit
macOS 64-bit 64-bit 64-bit 64-bit
CentOS 7.1 - 64-bit - 64-bit
Debian 8 - 64-bit - 64-bit
Ubuntu 14.04 64-bit 64-bit 64-bit 64-bit
Ubuntu 16.04 64-bit 64-bit 64-bit 64-bit
Fedora 24 - 64-bit - 64-bit
RHEL 7 - 64-bit - 64-bit
NET Core 1.1.6. منتشر شد
نظرات مطالب
یکپارچه کردن ELMAH با WCF RIA Services
سلام

من از روش تشخیص هویت ویندوز استفاده نمی کنم چطور می تونم جلوی دسترسی افراد به صفحه myelmah.axd رو بگیرم

ممنون
نظرات مطالب
ASP.NET MVC #6
مطابق استاندارد، در HTTP header امکان قرار دادن کاراکترهای یونیکد نیست (پیش فرض آن حداکثر ISO-8859-1  است یا حروف لاتین):
 Reason-Phrase  = *<TEXT, excluding CR, LF>
“The TEXT rule is only used for descriptive field contents and values that are not intended to be interpreted by the message
parser. Words of *TEXT MAY contain characters from character sets other than ISO-8859-1
only when encoded according to the rules of RFC 2047”.
مگر اینکه مطابق RFC 2047 انکد شوند. (از این RFC هم بیشتر در عنوان ایمیل‌ها تابحال استفاده شده تا در هدر HTTP)
البته می‌شود توسط HttpUtility.UrlEncode این پیام را encode و در سمت کلاینت توسط مثلا jQuery با استفاده از متد استاندارد decodeURIComponent آن‌را دریافت کرد ولی ... به صورت پیش فرض و encode نشده، تفسیر نمی‌شود و حتی به عنوان یک هدر مخرب شاید برگشت زده شود.
مطالب
پیشنهاد یک دیکشنری کم دردسرتر!
نگارش ابتدایی «iTextSharp.LGPLv2.Core » بر اساس کدهای اولیه‌ی iTextSharp بود که مستقیما از جاوا به سی‌شارپ ترجمه شده بود. این کدها پر بودند از ساختارهای داده‌ای مانند Hashtable و ArrayList که مرتبط هستند با روزهای آغازین ارائه‌ی دات نت 1؛ پیش از ارائه‌ی Generics. برای مثال نوع Hashtable، همانند ساختار داده‌ی Dictionary عمل می‌کند، اما جنریک نیست؛ یعنی شبیه به <Dictionary<object, object عمل می‌کند و برای کار با آن، باید مدام از تبدیل نوع‌های داده‌ها (یا همان boxing) از نوع object‌، به نوع داده‌ی مدنظر، استفاده کرد که این تبدیل نوع‌ها، همیشه به همراه کاهش کارآیی هم هستند. به علاوه در حین کار با Hashtable، اگر کلیدی در مجموعه‌ی آن وجود نداشته باشد، فقط نال را بازگشت می‌دهد، اما Dictionary، یک استثنای یافت نشدن کلید را صادر می‌کند. بنابراین فرض کنید که با هزاران سطر کد استفاده کننده‌ی از Hashtable طرف هستید که اگر آن‌ها را تبدیل به Dictionary‌های جنریک متناسبی کنید تا کارآیی برنامه بهبود یابد، تمام موارد استفاده‌ی از آن‌ها‌را نیز باید به همراه TryGetValue‌ها کنید تا از شر استثنای یافت نشدن کلید درخواستی، در امان باشید. در این مطلب روش مواجه شدن با یک چنین حالتی را با حداقل تغییر در کدها بررسی خواهیم کرد.


ممنوع کردن استفاده‌ی از ساختارهای داده‌ی غیرجنریک

قدم اول مواجه شدن با یک چنین کدهای قدیمی، ممنوع کردن استفاده‌ی از ساختارهای داده‌ی غیرجنریک و الزام به تبدیل آن‌ها به نوع‌های جدید است. برای این منظور می‌توان از Microsoft.CodeAnalysis.BannedApiAnalyzers استفاده کرد که توضیحات بیشتر آن‌را در مطلب «غنی سازی کامپایلر C# 9.0 با افزونه‌ها» پیشتر بررسی کرده‌ایم. به صورت خلاصه، ابتدا بسته‌ی نیوگت آن‌را به صورت یک آنالایزر جدید به فایل csproj. برنامه معرفی می‌کنیم:
<Project Sdk="Microsoft.NET.Sdk">
    <ItemGroup>
        <PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.3">
            <PrivateAssets>all</PrivateAssets>
            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
        </PackageReference>
    </ItemGroup>
    <ItemGroup>
        <AdditionalFiles Include="$(MSBuildThisFileDirectory)BannedSymbols.txt" Link="Properties/BannedSymbols.txt"/>
    </ItemGroup>
</Project>
همچنین در اینجا نیاز است یک فایل متنی BannedSymbols.txt را نیز به آن معرفی کرد؛ برای مثال با این محتوا:
# https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.BannedApiAnalyzers/BannedApiAnalyzers.Help.md
T:System.Collections.ICollection;Don't use a non-generic data structure.
T:System.Collections.Hashtable;Don't use a non-generic data structure.
T:System.Collections.ArrayList;Don't use a non-generic data structure.
T:System.Collections.SortedList;Don't use a non-generic data structure.
T:System.Collections.Stack;Don't use a non-generic data structure.
T:System.Collections.Queue;Don't use a non-generic data structure.
این تنظیمات سبب خواهند شد تا اگر در کدهای ما، ساختارهای داده‌ی غیرجنریکی در حال استفاده بودند، با یک اخطار ظاهر شوند و جهت سخت‌گیری بیشتر، روش تبدیل اخطارها به خطاها را نیز در مطلب «غنی سازی کامپایلر C# 9.0 با افزونه‌ها» بررسی کرده‌ایم تا مجبور به اصلاح آن‌ها شویم.


پیشنهاد یک دیکشنری کم دردسرتر!

برای نمونه پس از تنظیمات فوق، مجبور به تغییر تمام hash tableها به دیکشنری‌های جدید جنریک خواهیم شد؛ اما ... اگر اینکار را انجام دهیم، برنامه‌ای که تا پیش از این بدون مشکل کار می‌کرد، اکنون با استثناهای متعدد یافت نشدن کلیدها، خاتمه پیدا می‌کند! چون دیگر دیکشنری‌های جدید، همانند hash tableهای قدیمی، در صورت عدم وجود کلیدی، نال را بازگشت نمی‌دهند.
برای رفع این مشکل و اصلاح انبوهی از کدها با حداقل تغییرات و عدم تکرار TryGetValueها در همه‌جا، می‌توان دسترسی به ایندکس‌های یک دیکشنری استاندارد دات نت را به صورت زیر با ارث‌بری از آن، بازنویسی کرد:
/// <summary>
///     This custom IDictionary doesn't throw a KeyNotFoundException while accessing its value by a given key
/// </summary>
public interface INullValueDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
    new TValue this[TKey key] { get; set; }
}

/// <summary>
///     This custom IDictionary doesn't throw a KeyNotFoundException while accessing its value by a given key
/// </summary>
public class NullValueDictionary<TKey, TValue> : Dictionary<TKey, TValue>, INullValueDictionary<TKey, TValue>
{
    public new TValue this[TKey key]
    {
        get => TryGetValue(key, out var val) ? val : default;
        set => base[key] = value;
    }
}
همانطور که مشاهده می‌کنید، اگر بجای Dictionary، از NullValueDictionary پیشنهادی استفاده کنیم، دیگر نیازی نیست تا هزاران TryGetValue را در سراسر کدهای برنامه، تکرار و پراکنده کنیم و با حداقل تغییرات می‌توان معادل بهتری را بجای Hashtable قدیمی داشت.
مطالب
Attribute Routing در ASP.NET MVC 5
Routing مکانیزم مسیریابی ASP.NET MVC است، که یک URI را به یک اکشن متد نگاشت می‌کند. MVC 5 نوع جدیدی از مسیر یابی را پشتیبانی میکند که Attribute Routing یا مسیریابی نشانه ای نام دارد. همانطور که از نامش پیداست، مسیریابی نشانه ای از Attribute‌ها برای این امر استفاده میکند. این روش به شما کنترل بیشتری روی URI‌های اپلیکیشن تان می‌دهد.
مدل قبلی مسیریابی (conventional-routing) هنوز کاملا پشتیبانی می‌شود. در واقع می‌توانید هر دو تکنیک را بعنوان مکمل یکدیگر در یک پروژه استفاده کنید.
در این پست قابلیت‌ها و گزینه‌های اساسی مسیریابی نشانه ای را بررسی میکنیم.
  • چرا مسیریابی نشانه ای؟
  • فعال سازی مسیریابی نشانه ای
  • پارامتر‌های اختیاری URI و مقادیر پیش فرض
  • پیشوند مسیر ها
  • مسیر پیش فرض
  • محدودیت‌های مسیر ها
      • محدودیت‌های سفارشی
  • نام مسیر ها
  • ناحیه‌ها (Areas)


چرا مسیریابی نشانه ای

برای مثال یک وب سایت تجارت آنلاین بهینه شده اجتماعی، می‌تواند مسیرهایی مانند لیست زیر داشته باشد:
  • {productId:int}/{productTitle}
نگاشت می‌شود به: (ProductsController.Show(int id
  • {username}
نگاشت می‌شود به: (ProfilesController.Show(string username
  • {username}/catalogs/{catalogId:int}/{catalogTitle}
نگاشت می‌شود به: (CatalogsController.Show(string username, int catalogId
در نسخه قبلی ASP.NET MVC، قوانین مسیریابی در فایل RouteConfig.cs تعریف می‌شدند، و اشاره به اکشن‌های کنترلرها به نحو زیر انجام می‌شد:
routes.MapRoute(
    name: "ProductPage",
    url: "{productId}/{productTitle}",
    defaults: new { controller = "Products", action = "Show" },
    constraints: new { productId = "\\d+" }
);
هنگامی که قوانین مسیریابی در کنار اکشن متدها تعریف می‌شوند، یعنی در یک فایل سورس و نه در یک کلاس پیکربندی خارجی، درک و فهم نگاشت URI‌ها به اکشن‌ها واضح‌تر و راحت می‌شود. تعریف مسیر قبلی، می‌تواند توسط یک attribute ساده بدین صورت نگاشت شود:
[Route("{productId:int}/{productTitle}")]
public ActionResult Show(int productId) { ... }

فعال سازی Attribute Routing

برای فعال سازی مسیریابی نشانه ای، متد MapMvcAttributeRoutes را هنگام پیکربندی فراخوانی کنید.
public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 
        routes.MapMvcAttributeRoutes();
    }
}
همچنین می‌توانید مدل قبلی مسیریابی را با تکنیک جدید تلفیق کنید.
public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 
    routes.MapMvcAttributeRoutes();
 
    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

پارامترهای اختیاری URI و مقادیر پیش فرض

می توانید با اضافه کردن یک علامت سوال به پارامترهای مسیریابی، آنها را optional یا اختیاری کنید. برای تعیین مقدار پیش فرض هم از فرمت parameter=value استفاده می‌کنید.
public class BooksController : Controller
{
    // eg: /books
    // eg: /books/1430210079
    [Route("books/{isbn?}")]
    public ActionResult View(string isbn)
    {
        if (!String.IsNullOrEmpty(isbn))
        {
            return View("OneBook", GetBook(isbn));
        }
        return View("AllBooks", GetBooks());
    }
 
    // eg: /books/lang
    // eg: /books/lang/en
    // eg: /books/lang/he
    [Route("books/lang/{lang=en}")]
    public ActionResult ViewByLanguage(string lang)
    {
        return View("OneBook", GetBooksByLanguage(lang));
    }
}
در این مثال، هر دو مسیر books/ و books/1430210079/ به اکشن متد "View" نگاشت می‌شوند، مسیر اول تمام کتاب‌ها را لیست میکند، و مسیر دوم جزئیات کتابی مشخص را لیست می‌کند. هر دو مسیر books/lang/ و books/lang/en/ به یک شکل نگاشت می‌شوند، چرا که مقدار پیش فرض این پارامتر en تعریف شده.



پیشوند مسیرها (Route Prefixes)

برخی اوقات، تمام مسیرها در یک کنترلر با یک پیشوند شروع می‌شوند. بعنوان مثال:
public class ReviewsController : Controller
{
    // eg: /reviews
    [Route("reviews")]
    public ActionResult Index() { ... }
    // eg: /reviews/5
    [Route("reviews/{reviewId}")]
    public ActionResult Show(int reviewId) { ... }
    // eg: /reviews/5/edit
    [Route("reviews/{reviewId}/edit")]
    public ActionResult Edit(int reviewId) { ... }
}
همچنین می‌توانید با استفاده از خاصیت [RoutePrefix] یک پیشوند عمومی برای کل کنترلر تعریف کنید:
[RoutePrefix("reviews")]
public class ReviewsController : Controller
{
    // eg.: /reviews
    [Route]
    public ActionResult Index() { ... }
    // eg.: /reviews/5
    [Route("{reviewId}")]
    public ActionResult Show(int reviewId) { ... }
    // eg.: /reviews/5/edit
    [Route("{reviewId}/edit")]
    public ActionResult Edit(int reviewId) { ... }
}
در صورت لزوم، می‌توانید برای بازنویسی (override) پیشوند مسیرها از کاراکتر ~ استفاده کنید:
[RoutePrefix("reviews")]
public class ReviewsController : Controller
{
    // eg.: /spotlight-review
    [Route("~/spotlight-review")]
    public ActionResult ShowSpotlight() { ... }
 
    ...
}

مسیر پیش فرض

می توانید خاصیت [Route] را روی کنترلر اعمال کنید، تا اکشن متد را بعنوان یک پارامتر بگیرید. این مسیر سپس روی تمام اکشن متدهای این کنترلر اعمال می‌شود، مگر آنکه یک [Route] بخصوص روی اکشن‌ها تعریف شده باشد.
[RoutePrefix("promotions")]
[Route("{action=index}")]
public class ReviewsController : Controller
{
    // eg.: /promotions
    public ActionResult Index() { ... }
 
    // eg.: /promotions/archive
    public ActionResult Archive() { ... }
 
    // eg.: /promotions/new
    public ActionResult New() { ... }
 
    // eg.: /promotions/edit/5
    [Route("edit/{promoId:int}")]
    public ActionResult Edit(int promoId) { ... }
}

محدودیت‌های مسیر ها

با استفاده از Route Constraints می‌توانید نحوه جفت شدن پارامتر‌ها در قالب مسیریابی را محدود و کنترل کنید. فرمت کلی {parameter:constraint} است. بعنوان مثال:
// eg: /users/5
[Route("users/{id:int}"]
public ActionResult GetUserById(int id) { ... }
 
// eg: users/ken
[Route("users/{name}"]
public ActionResult GetUserByName(string name) { ... }
در اینجا، مسیر اول تنها در صورتی انتخاب می‌شود که قسمت id در URI یک مقدار integer باشد. در غیر اینصورت مسیر دوم انتخاب خواهد شد.
جدول زیر constraint‌ها یا محدودیت هایی که پشتیبانی می‌شوند را لیست می‌کند.
 مثال  توضیحات  محدودیت
 {x:alpha}  کاراکترهای الفبای لاتین را تطبیق (match) می‌دهد (a-z, A-Z).  alpha
 {x:bool}  یک مقدار منطقی را تطبیق می‌دهد.  bool
 {x:datetime}  یک مقدار DateTime را تطبیق می‌دهد.  datetime
 {x:decimal}  یک مقدار پولی را تطبیق می‌دهد.  decimal
 {x:double}  یک مقدار اعشاری 64 بیتی را تطبیق می‌دهد.  double
 {x:float}  یک مقدار اعشاری 32 بیتی را تطبیق می‌دهد.  float
 {x:guid}  یک مقدار GUID را تطبیق می‌دهد.  guid
 {x:int}  یک مقدار 32 بیتی integer را تطبیق می‌دهد.  int
 {(x:length(6}
{(x:length(1,20}
 رشته ای با طول تعیین شده را تطبیق می‌دهد.  length
 {x:long}  یک مقدار 64 بیتی integer را تطبیق می‌دهد.  long
 {(x:max(10}  یک مقدار integer با حداکثر مجاز را تطبیق می‌دهد.  max
 {(x:maxlength(10}  رشته ای با حداکثر طول تعیین شده را تطبیق می‌دهد.  maxlength
 {(x:min(10}  مقداری integer با حداقل مقدار تعیین شده را تطبیق می‌دهد.  min
 {(x:minlength(10}  رشته ای با حداقل طول تعیین شده را تطبیق می‌دهد.  minlength
 {(x:range(10,50}  مقداری integer در بازه تعریف شده را تطبیق می‌دهد.  range
 {(${x:regex(^\d{3}-\d{3}-\d{4}  یک عبارت با قاعده را تطبیق می‌دهد.  regex

توجه کنید که بعضی از constraint ها، مانند "min" آرگومان‌ها را در پرانتز دریافت می‌کنند.
می توانید محدودیت‌های متعددی روی یک پارامتر تعریف کنید، که باید با دونقطه جدا شوند. بعنوان مثال:
// eg: /users/5
// but not /users/10000000000 because it is larger than int.MaxValue,
// and not /users/0 because of the min(1) constraint.
[Route("users/{id:int:min(1)}")]
public ActionResult GetUserById(int id) { ... }
مشخص کردن اختیاری بودن پارامتر ها، باید در آخر لیست constraints تعریف شود:
// eg: /greetings/bye
// and /greetings because of the Optional modifier,
// but not /greetings/see-you-tomorrow because of the maxlength(3) constraint.
[Route("greetings/{message:maxlength(3)?}")]
public ActionResult Greet(string message) { ... }

محدودیت‌های سفارشی

با پیاده سازی قرارداد IRouteConstraint می‌توانید محدودیت‌های سفارشی بسازید. بعنوان مثال، constraint زیر یک پارامتر را به لیستی از مقادیر قابل قبول محدود می‌کند:
public class ValuesConstraint : IRouteConstraint
{
    private readonly string[] validOptions;
    public ValuesConstraint(string options)
    {
        validOptions = options.Split('|');
    }
 
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        object value;
        if (values.TryGetValue(parameterName, out value) && value != null)
        {
            return validOptions.Contains(value.ToString(), StringComparer.OrdinalIgnoreCase);
        }
        return false;
    }
}
قطعه کد زیر نحوه رجیستر کردن این constraint را نشان می‌دهد:
public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 
        var constraintsResolver = new DefaultInlineConstraintResolver();
 
        constraintsResolver.ConstraintMap.Add("values", typeof(ValuesConstraint));
 
        routes.MapMvcAttributeRoutes(constraintsResolver);
    }
}
حالا می‌توانید این محدودیت سفارشی را روی مسیرها اعمال کنید:
public class TemperatureController : Controller
{
    // eg: temp/celsius and /temp/fahrenheit but not /temp/kelvin
    [Route("temp/{scale:values(celsius|fahrenheit)}")]
    public ActionResult Show(string scale)
    {
        return Content("scale is " + scale);
    }
}

نام مسیر ها

می توانید به مسیرها یک نام اختصاص دهید، با این کار تولید URI‌ها هم راحت‌تر می‌شوند. بعنوان مثال برای مسیر زیر:
[Route("menu", Name = "mainmenu")]
public ActionResult MainMenu() { ... }
می‌توانید لینکی با استفاده از Url.RouteUrl تولید کنید:
<a href="@Url.RouteUrl("mainmenu")">Main menu</a>

ناحیه‌ها (Areas)

برای مشخص کردن ناحیه ای که کنترلر به آن تعلق دارد می‌توانید از خاصیت [RouteArea] استفاده کنید. هنگام استفاده از این خاصیت، می‌توانید با خیال راحت کلاس AreaRegistration را از ناحیه مورد نظر حذف کنید.
[RouteArea("Admin")]
[RoutePrefix("menu")]
[Route("{action}")]
public class MenuController : Controller
{
    // eg: /admin/menu/login
    public ActionResult Login() { ... }
 
    // eg: /admin/menu/show-options
    [Route("show-options")]
    public ActionResult Options() { ... }
 
    // eg: /stats
    [Route("~/stats")]
    public ActionResult Stats() { ... }
}
با این کنترلر، فراخوانی تولید لینک زیر، رشته "Admin/menu/show-options/" را بدست میدهد:
Url.Action("Options", "Menu", new { Area = "Admin" })
به منظور تعریف یک پیشوند سفارشی برای یک ناحیه، که با نام خود ناحیه مورد نظر متفاوت است می‌توانید از پارامتر AreaPrefix استفاده کنید. بعنوان مثال:
[RouteArea("BackOffice", AreaPrefix = "back-office")]
اگر از ناحیه‌ها هم بصورت مسیریابی نشانه ای، و هم بصورت متداول (که با کلاس‌های AreaRegistration پیکربندی می‌شوند) استفاده می‌کنید باید مطمئن شوید که رجیستر کردن نواحی اپلیکیشن پس از مسیریابی نشانه ای پیکربندی می‌شود. به هر حال رجیستر کردن ناحیه‌ها پیش از تنظیم مسیرها بصورت متداول باید صورت گیرد. دلیل آن هم مشخص است، برای اینکه درخواست‌های ورودی بدرستی با مسیرهای تعریف شده تطبیق داده شوند، باید ابتدا attribute routes، سپس area registration و در آخر default route رجیستر شوند. بعنوان مثال:
public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 
    routes.MapMvcAttributeRoutes();
 
    AreaRegistration.RegisterAllAreas();
 
    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

اشتراک‌ها
API ویندوز چیست و چه کاربردی دارد ؟

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

API ویندوز چیست و چه کاربردی دارد ؟
مطالب
گوگل ریدر و افزودن توضیحات

اگر به گوگل ریدر دقت کرده باشید، دو گزینه‌ی به اشتراک گذاری دارد: share و share with note .


اگر گزینه‌ی share with note را انتخاب کرده و توضیحی را ارسال یا اضافه کنیم، این توضیحات، به فید از نوع Atom اشتراک‌ها هم اضافه می‌شود. مثلا:

<?xml version="1.0"?>
<feed xmlns:media="http://search.yahoo.com/mrss/"
xmlns:gr="http://www.google.com/schemas/reader/atom/"
xmlns:idx="urn:atom-extension:indexing"
xmlns="http://www.w3.org/2005/Atom"
idx:index="no"
gr:dir="ltr">

...

<entry gr:crawl-timestamp-msec="1316627782108">
...
<gr:annotation>
<content type="html">text-text-text</content>
<author>
<name>Vahid</name>
</author>
</gr:annotation>
...
</entry>

...

</feed>



این افزونه استاندارد نیست و همانطور که در قسمت xmlns:gr اطلاعات فوق مشخص است، در فضای نام http://www.google.com/schemas/reader/atom/ معنا پیدا می‌کند. از دات نت سه و نیم به بعد هم کلاسی جهت خواندن فیدهای استاندارد وجود دارد (تعریف شده در فضای نام System.ServiceModel.Syndication). اما چگونه می‌توان این افزونه‌ی غیر استاندارد را با کمک امکانات توکار دات نت خواند؟
روش کار با استفاده از ElementExtensions هر آیتم یک فید است؛ به صورت زیر :

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Syndication;
using System.Xml;
using System.Xml.Linq;

namespace Linq2Rss
{
public class RssEntry
{
public string Title { set; get; }
public string Description { set; get; }
public string Link { set; get; }
public DateTime PublicationDate { set; get; }
public string Author { set; get; }
public string BlogName { set; get; }
public string BlogAddress { set; get; }
public string Annotation { set; get; }
}

public static class AtomReader
{
private static string getAtomAnnotation(this SyndicationElementExtensionCollection items)
{
if (!items.Any()) return string.Empty;
var item = items.Where(x => x.OuterName.ToLowerInvariant() == "annotation").FirstOrDefault();
if (item == null) return string.Empty;

var element = item.GetObject<XElement>();
var content = element.Element("{http://www.w3.org/2005/Atom}content");
return content == null ? string.Empty : content.Value;
}

public static IList<RssEntry> GetEntries(string feedUrl)
{
using (var reader = XmlReader.Create(feedUrl))
{
var feed = SyndicationFeed.Load(reader);
if (feed == null) return null;

return feed.Items.Select(x =>
new RssEntry
{
Title = x.Title.Text,
Author = x.Authors.Any() ? x.Authors.First().Name : string.Empty,
Description = x.Content == null ? string.Empty : ((TextSyndicationContent)x.Content).Text,
Link = x.Links.Any() ? x.Links.First().Uri.AbsoluteUri : string.Empty,
PublicationDate = x.PublishDate.UtcDateTime,
BlogName = x.SourceFeed.Title.Text,
BlogAddress = x.SourceFeed.Links.Any() ? x.SourceFeed.Links.First().Uri.AbsoluteUri : string.Empty,
Annotation = x.ElementExtensions.getAtomAnnotation()

}).ToList();
}
}
}
}

در این مثال به کمک متد الحاقی getAtomAnnotation، مجموعه‌ی SyndicationElementExtensionCollection هر آیتم یک فید بررسی شده، در بین این‌ها، موردی که از نوع annotation باشد انتخاب و سپس content آن استخراج می‌گردد.


نکته‌ای دیگر:
اکثر کلاس‌های موجود در فضاهای نام مرتبط با XML در دات نت امکان خواندن اطلاعات را از یک Uri هم دارند؛ مانند مثال فوق و متد XmlReader.Create بکارگرفته شده در آن. اما اگر بخواهیم حین خواندن اطلاعات، یک پروکسی را نیز به پروسه جاری اضافه کنیم، به نظر خاصیت یا متدی جهت انجام اینکار وجود ندارد. برای رفع این مشکل می‌توان یک پروکسی سراسری را تعریف کرد. تنها کافی است خاصیت System.Net.WebRequest.DefaultWebProxy مقدار دهی شود. پس از آن به صورت خودکار بر روی کل برنامه تاثیر خواهد گذاشت.


نظرات مطالب
Owin چیست ؟ قسمت اول
سلام
ممنون بابت مطلب مفیدتون.
بدون وابستگی به IIS یعنی هر web server ی که OWIN را پیاده سازی کند امکان اجرای برنامه هایی که مثلا با asp.net mvc نوشته شدن رو خواهند داشت؟
همین که مثلا با asp.net mvc برنامه نوشته شده به معنی این هست که برنامه بر اساس استاندارد OWIN هست؟ یا کارهایی برای این منظور باید انجام داد؟
اشتراک‌ها
ویراست جدید دستور خطّ فارسی

ویراست جدید دستور خطّ فارسی در ۸۸ صفحه و با شمارگان ۳هزار نسخه در ادارۀ نشر فرهنگستان زبان و ادب فارسی منتشر شده است. برای دسترسی به نسخۀ الکترونیک این کتاب به پیوند زیر در وبگاه #فرهنگستان_زبان_و_ادب_فارسی مراجعه کنید.

ویراست جدید دستور خطّ فارسی