نظرات مطالب
پرسش و پاسخ‌های متداول ایجاد یک وبلاگ بلاگری
قرار بود فقط دو تا سؤال بپرسید :)
- فرمت قالب‌ها xml است و با فرانت پیج قدیمی یا expression web جدید قابل ویرایش نیست و اصلا ادیتوری هم ندارد (یا جایی منتشر نشده تا جایی که اطلاع دارم). دستی باید روی آن کار شود.
- برای قرار دادن عکس در بک گراند، شما فقط کافی است عکس مورد نظر را در یک سایت دیگر آپلود کنید، سپس یک css تعریف کرده و آن‌را اعمال نمائید. به سلکتور body یا تگ body قابل اعمال است. اطلاعات بیشتر:
http://www.w3schools.com/css/pr_background-image.asp
- برای تعیین رنگ و اندازه تاریخ، باز هم باید css‌ سایت را در همان قسمت ویرایش html سایت ویرایش کنید. برای مثال این موارد باید اضافه شود:
h1, h2, h3 {
font-family: Tahoma;
direction: rtl;
font-size:8pt;
color:green;
text-align: right;
}
- تاریخ آرشیو هم در همان مقاله هست و باید اعمال شده باشد.

در کل شکل و شمایل این قالب‌ها با ویرایش css آن تا حد قابل قبولی قابل تغییر است (بدون نیاز به دستکاری قسمت‌های دیگر که مربوط به تعریف ویجت‌ها است)
مطالب
استفاده از date picker شمسی جاوا اسکریپتی در Blazor با قابلیت ورود تاریخ به صورت دستی
دیت پیکرهای گوناگونی توسط افراد مختلف نوشته شده‌اند که هر یک مشکلات خاص خود را دارند. در این مطلب به چگونگی استفاده از یکی از سازگارترین  دیت پیکرهای جاوا اسکریپتی که توسط آقای امیرمسعود ایرانی نوشته شده است در Blazor خواهیم پرداخت.
مهم‌ترین ویژگی این دیت پیکر امکان ورود تاریخ به صورت دستی توسط کاربر است.

فرمت‌های قابل قبول برای ورود تاریخ عبارتند از:
۹۰۰۸۱۴ ۱۴۰۸۹۰ ۱۳۹۰۰۸۱۴ ۱۴/۸/۹۰ ۹۰/۸/۱۴ ۱۴/۸/۱۳۹۰ ۱۳۹۰/۸/۱۴ ۱۴-۸-۹۰ ۹۰-۸-۱۴ ۱۴-۸-۱۳۹۰ ۱۳۹۰-۸-۱۴ 
و فرمت‌های ویژه:
۰۸۱۴ ۱۴۰۸ ۱۴-۸ ۸-۱۴ ۱۴/۸ ۸/۱۴ ۱۴
در فرمت‌های ویژه که سال و ماه وارد نشده‌اند، سال و ماه فعلی به حساب خواهد آمد.
در فرمت‌هایی که سال مشخص نشده باشد، دو رقم ابتدایی در صورت امکان روز محاسبه خواهند شد.
بنابراین قادر خواهیم بود که در خروجی یک فرمت استاندارد داشته باشیم حتی با فرمت‌های مختلفی که کاربر وارد خواهد کرد.

روش به کارگیری تقویم در Blazor

در ابتدا فایل‌های مورد نیاز را دانلود کرده (AMIB_jsPersianCal_0.2.1.rar) و به پروژه اضافه می‌کنیم.
سپس به _layout رفته و ارجاعات زیر را برای افزودن فایل‌های css و js به پروژه اضافه می‌کنیم:
<link href="css/js-persian-cal.css" rel="stylesheet"/>
<script src="js/js-persian-cal.min.js"></script>
حال برای استفاده از دیت پیکر در کامپوننت‌ها از تگ input به شکل زیر استفاده می‌کنیم:
<input type="text" id="pcal1" />
Id آن مهم است زیرا توسط آن به تابع جاوااسکریپتی معرفی می‌شود. می‌توان هر اسمی را اختیار کرد فقط بهتر است تمامی دیت پیکرهای موجود در صفحه یک اسم داشته باشند اما با ایندکس‌های مختلف مانند pcal1، pcal2 و ... . دلیل آن این است که می‌توان تمامی دیت پیکرهای را توسط یک حلقه به تابع مربوطه معرفی کرد.
همانطور که می‌دانید برای استفاده از توابع جاوا اسکریپتی در Blazor از JSRuntime استفاده می‌شود. بنابراین به شکل زیر عمل خواهیم کرد.
protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        int dateFieldCount = 1;
        if (firstRender)
        {
            for (int i = 1; i <= dateFieldCount; i++)
            {
                await JsRuntime.InvokeVoidAsync("CallAmib", "pcal" + i.ToString());
            }
        }
    }
توسط حلقه for تمامی تگ‌های input موجود در کامپوننت را که Id آنها با pcal شروع می‌شود به دیت پیکر تبدیل خواهیم نمود. فقط مقدار متغیر dateFieldCount را باید به تعداد تگ‌های دیت پیکر موجود در کامپوننت تنظیم نمود.
لازم به ذکر است که باید در ابتدای کامپوننت، JSRuntime را به شکل زیر تزریق نمود.
@inject IJSRuntime  JsRuntime
حال فقط کافیست اسکریپت CallAmib را ایجاد کرده و به _layout اضافه نمود.
window.CallAmib = (objCal1) => {
    new AMIB.persianCalendar(objCal1);
}
  بنابراین فایل _layout برنامه الان چیزی شبیه به زیر خواهد بود:
@using Microsoft.AspNetCore.Components.Web
@namespace ShamsiDatePickerBlazor.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="~/" />
    <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
    <link href="css/site.css" rel="stylesheet" />
    <link href="css/js-persian-cal.css" rel="stylesheet" />
    <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
</head>
<body>
    @RenderBody()

    <div id="blazor-error-ui">
        <environment include="Staging,Production">
            An error has occurred. This application may no longer respond until reloaded.
        </environment>
        <environment include="Development">
            An unhandled exception has occurred. See browser dev tools for details.
        </environment>
        <a href="">Reload</a>
        <a>🗙</a>
    </div>
    <script src="js/js-persian-cal.min.js"></script>
    <script src="js/CallAmib.js"></script>
    <script src="_framework/blazor.server.js"></script>
</body>
</html>
تا اینجای کار اگر پروژه را اجرا کنیم، دیت پیکری مانند زیر را خواهیم داشت:

مشکل!!

برای بایند کردن مقدار تاریخ انتخاب شده نمی‌توان از bind-value به طور معمول استفاده کرد؛ زیرا در حقیقت تغییرات input با جاوا اسکریپت انجام می‌گیرد و حالت صفحه تغییری نمی‌کند. برای مرتفع کردن این مشکل نیاز است که در اسکریپت CallAmib متد onchange به شکل زیر صدا زده شده و مقدار تاریخ انتخابی به یک متد داخل کامپوننت ارسال گردیده و در آنجا به یک فیلد منتسب شود.
window.CallCall = (objCal1) => {
    new AMIB.persianCalendar(objCal1,{
        onchange: function(pdate) {
            DotNet.invokeMethodAsync('ShamsiDatePickerBlazor', 'DateChanged', pdate.toString()).then(
                (date) => {
                    console.log(data);
                }
            );
        }
    });
}
توضیحات اسکریپت بالا:
متغیر pdate به صورت توکار مربوط به AMIB.persianCalendar می باشد و مقدار تاریخ انتخابی را در بر دارد.
متد DotNet.invokeMethodAsync یک متد توکار دات نت می‌باشد و برای فراخوانی متدهای سی شارپی از داخل توابع جاوا اسکریپتی به کار می‌رود. آرگومان اول آن در حقیقت نام اسمبلی پروژه می‌باشد. آرگومان دوم آن نام تابع سی شارپی‌است که باید فراخوانی شود و در نهایت آرگومان سوم آن تاریخ انتخاب شده می‌باشد.
در پایان باید متد DateChanged،  به شکل زیر در کامپوننت index نوشته شود:
static string selectedDate;
[JSInvokable]
public static void DateChanged(string pdate)
{
    selectedDate = pdate;
}
این تابع بایستی با صفت [JSInvokable] مزین شود و حتما هم استاتیک باشد.
برای دیدن مقدار جدید selectedDate کافی است روی دکمه ShowNewValue یکبار کلیک نمایید.
نکته: می‌توان به جای input، از InputText مربوط به EditForm هم استفاده نمود. فقط باید یک Id هم به آن انتساب داد. همچنین برای انتساب مقدار دیت پیکر به مدل، باید در متد DateChanged، فیلد مورد نظر از مدل را بجای متغیر selectedDate گذاشت.
شما می‌توانید در اینجا کدهای کامل این مطلب را ملاحظه نمایید.
مطالب
ASP.NET MVC #16

مدیریت خطاها در یک برنامه ASP.NET MVC


استفاده از فیلتر HandleError

یکی از فیلترهای توکار ASP.NET MVC به نام HandleError،‌ می‌تواند کار هدایت کاربر را به یک صفحه‌ی خطای عمومی، در حین بروز استثنایی در برنامه،‌ انجام دهد. برای آزمایش آن یک برنامه خالی جدید ASP.NET MVC را آغاز کنید. سپس یک کنترلر جدید را با محتوای زیر به آن اضافه نمائید:

using System;
using System.Web.Mvc;

namespace MvcApplication13.Controllers
{
public class HomeController : Controller
{
[HandleError]
public ActionResult Index()
{
throw new InvalidOperationException();
return View();
}
}
}

در اینجا جهت آزمایش برنامه، به عمد یک استثنای دستی را صادر می‌کنیم. برای آزمایش برنامه هم نیاز است آن‌را خارج از دیباگر VS.NET اجرا کرد (آدرس برنامه را مستقیما خارج از VS.NET در یک مرورگر وارد کنید). همچنین یک سطر زیر را نیز لازم است به فایل web.config برنامه اضافه نمائید:

<system.web>
<customErrors mode="On" />

اکنون اگر برنامه را خارج از مرورگر اجرا کنید، با توجه به استفاده از ویژگی HandleError و همچنین بروز یک استثنا در متد Index، خودبخود صفحه Views\Shared\Error.cshtml به کاربر نمایش داده خواهد شد. در غیراینصورت صفحه زرد رنگ پیش فرض خطای ASP.NET به کاربر نمایش داده می‌شود که محتوای آن‌ها بیشتر برای برنامه نویس‌ها مناسب است و نه کاربران نهایی سیستم.
اگر علاقمند باشید که این ویژگی به صورت خودکار به تمام متدهای کنترلرهای برنامه اعمال شود، کافی است یک سطر زیر را به متد Application_Start فایل Global.asax.cs اضافه نمائید:

GlobalFilters.Filters.Add(new HandleErrorAttribute());

البته نیازی به انجام اینکار نیست زیرا اگر به متد RegisterGlobalFilters فایل Global.asax.cs دقت کنیم، اینکار پیشتر توسط قالب پیش فرض VS.NET انجام شده است. فقط برای فعال سازی آن نیاز است تگ customErrors در فایل وب کانفیگ برنامه مقدار دهی و تنظیم شود.



استفاده از صفحه خطای سفارشی دیگری بجای فایل Error.cshtml

امکان تنظیم نمایش صفحه خطای سفارشی دیگری نیز وجود دارد. برای مثال استفاده از فایل Views\Shared\CustomErrorView.cshtml :

[HandleError(View = "CustomErrorView")]



استفاده از صفحات خطای متفاوت به ازای استثناهای مختلف

می‌توان فیلتر HandleError را تنها به یک نوع استثنای خاص محدود کرد. همچنین امکان استفاده از چندین ویژگی HandleError برای یک متد نیز وجود دارد:

[HandleError(ExceptionType = typeof(NullReferenceException), View = "ErrorHandling")]



دسترسی به اطلاعات استثناء در صفحه نمایش خطاها

زمانیکه برنامه به صفحه خطا هدایت می‌شود، نوع Model آن System.Web.Mvc.HandleErrorInfo می‌باشد:

@model System.Web.Mvc.HandleErrorInfo

@{
ViewBag.Title = "DbError";
}

<h2>An Error Has Occurred</h2>

@if (Model != null)
{
<p>@Model.Exception.GetType().Name<br />
thrown in @Model.ControllerName @Model.ActionName</p>
}

البته این نکته را صرفا به عنوان اطلاعات عمومی در نظر داشته باشید. زیرا اگر قرار باشد مجددا اصل استثناء را نمایش دهیم، همان صفحه زرد رنگ ASP.NET شاید بهتر باشد.



استفاده از تگ customErrors در فایل Web.config برنامه

ویژگی حالت تگ customErrors در فایل web.config برنامه، سه مقدار را می‌تواند بپذیرد:
الف) Off : صفحه زرد رنگ معرفی خطای ASP.NET را به همراه تمام اطلاعات مرتبط با استثنای رخ داده نمایش می‌دهد.
ب) RemoteOnly : همان حالت الف است با این تفاوت که صفحه خطا را فقط در کامپیوتری که وب سرور بر روی آن نصب است نمایش خواهد داد.
ج) On : یک صفحه خطای سفارشی شده را نمایش می‌دهد.

بنابراین هیچگاه از حالت Off استفاده نکنید. زیرا خطاهای نمایش داده شده، علاوه بر برنامه نویس، برای مهاجم به یک سایت نیز بسیار دلپذیر است!
حالت RemoteOnly در زمان توسعه برنامه توصیه می‌شود.
حالت On حین توزیع برنامه باید بکارگرفته شود.



مدیریت خطاهای رخ داده خارج از MVC Pipeline

HandleErrorAttribute تنها استثناهای رخ داده داخل ASP.NET MVC Pipeline را مدیریت می‌کند (یا خطاهایی از نوع 500). اگر این نوع استثناها خارج از آن رخ دهند مثلا فایلی یافت نشود (خطای 404) و امثال آن، باید به روش زیر عمل کرد:

<customErrors mode="On" defaultRedirect="error">
<error statusCode="404" redirect="error/notfound" />
<error statusCode="403" redirect="error/forbidden" />
</customErrors>

در اینجا اگر فایلی یافت نشد، کاربر به کنترلری به نام error و متدی به نام notfound هدایت خواهد شد. بنابراین نیاز به کنترلر زیر وجود دارد؛ به علاوه به ازای هر متد هم یک View متناظر باید اضافه شود (کلیک راست روی نام متد و انتخاب گزینه افزودن View جدید).

using System.Web.Mvc;

namespace MvcApplication13.Controllers
{
public class ErrorController : Controller
{
public ActionResult Index()
{
return View();
}

public ActionResult NotFound()
{
return View();
}

public ActionResult Forbidden()
{
return View();
}
}
}

برای آزمایش این قسمت، برنامه را اجرا کرده و سپس مثلا آدرس غیرموجود http://localhost/xyz را وارد کنید.



استفاده از فیلتر HandleError اجباری نیست

در همین قسمت قبل پس از افزودن customErrors و defaultRedirect آن که به نام یک کنترلر اشاره می‌کند، کلیه فیلترهای HandleError اضافه شده به برنامه را حذف کنید. سپس برنامه را خارج از محیط VS.NET اجرا کنید. باز هم متد Index کنترلر Error اجرا خواهد شد. به عبارتی الزاما نیازی به استفاده از فیلتر HandleError نیست و به کمک مقدار دهی صحیح تگ customErrors، کار نمایش خودکار صفحه سفارشی خطاها به کاربر انجام خواهد شد.
البته بدیهی است که گزینه‌های نمایش یک View خاص به ازای استثنایی ویژه، یکی از مزیت‌های استفاده از فیلتر HandleError می‌باشد که امکان تنظیم آن در فایل web.config وجود ندارد.



ثبت اطلاعات استثناهای رخ داده به کمک ELMAH

نمایش صفحه‌ی خطای سفارشی به کاربر، یکی از موارد ضروری تمام برنامه‌های ASP.NET است، اما کافی نیست. ثبت اطلاعات جزئیات استثناهای رخ داده در طول زمان می‌توانند به بالا بردن کیفیت برنامه به شدت کمک کنند. برای این منظور می‌توان همانند سابق از متد Application_Error قابل تعریف در فایل Global.asax.cs کمک گرفت؛ اما با وجود افزونه‌ای به نام ELMAH اینکار اتلاف وقت است و اصلا توصیه نمی‌شود. همچنین به کمک ELMAH می‌توان مشکلات را تبدیل به ایمیل‌های خودکار کرد یا از آن‌ها فید RSS درست نمود.
برای دریافت ELMAH یا به سایت اصلی آن مراجعه نمائید و یا به کمک NuGet هم به سادگی قابل دریافت است. پس از دریافت، ارجاعی را به اسمبلی آن (Elmah.dll) اضافه نمائید. در ادامه فایل web.config برنامه را گشوده و چند سطر زیر را به آن در قسمت configuration اضافه کنید:

<configuration>
<configSections>
<sectionGroup name="elmah">
<section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah"/>
<section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah"/>
<section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah"/>
<section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah"/>
<section name="errorTweet" requirePermission="false" type="Elmah.ErrorTweetSectionHandler, Elmah"/>
</sectionGroup>
</configSections>

سپس ذیل قسمت appSettings، تنظیمات پروایدر ذخیره سازی اطلاعات آن‌را وارد نمائید. مثلا در اینجا از فایل‌های XML برای ذخیره سازی اطلاعات استفاده خواهد شد (که امن‌ترین حالت ممکن است؛ از این لحاظ که اگر بانک اطلاعاتی را انتخاب کنید، ممکن است مشکل اصلی از همانجا ناشی شده باشد. بنابراین خطایی ثبت نخواهد شد. همچنین در این حالت نیازی به سایر DLLهای همراه ELMAH هم نیست). در اینجا مسیر ذخیره سازی اطلاعات در پوشه app_data/errorslog تنظیم شده است:

<elmah>
<security allowRemoteAccess="1"/>
<errorLog type="Elmah.XmlFileErrorLog, Elmah" logPath="~/App_Data/ErrorsLog"/>
</elmah>

در ادامه در قسمت system.web، دو تعریف زیر را اضافه نمائید. به این ترتیب امکان دسترسی به آدرس http://server/elmah.axd مهیا می‌گردد:

<httpModules>
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah"/>
</httpModules>
<httpHandlers>
<add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah"/>
</httpHandlers>

البته برای IIS7 تنظیمات ذیل نیز باید اضافه شوند:

<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<modules runAllManagedModulesForAllRequests="true">
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah"/>
</modules>
<handlers>
<add name="Elmah" verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah"/>
</handlers>
</system.webServer>

و به این ترتیب تنظیمات اولیه ELMAH به پایان می‌رسد (و با ASP.NET Web forms هیچ تفاوتی ندارد).
مرحله بعد، تنظیمات مسیریابی ASP.NET MVC است برای اینکه آدرس http://server/elmah.axd را وارد سیستم پردازشی خود نکند. البته اینکار پیشتر انجام شده است:

public static void RegisterRoutes(RouteCollection routes)
{
//routes.IgnoreRoute("elmah.axd");
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

بنابراین همین تنظیمات، به همراه قالب پیش فرض یک پروژه جدید ASP.NET MVC برای استفاده از ELMAH کفایت می‌کند. اکنون پروژه جاری را یکبار دیگر خارج از VS.NET اجرا کرده و سپس به مسیر http://localhost/elmah.axd جهت مشاهده خطاهای لاگ شده به همراه جزئیات کامل آن‌ها مراجعه کنید.

مشکل: استثناهای برنامه توسط ELMAH لاگ نمی‌شوند!

فیلتر HandleError با ELMAH سازگار نیست. زیرا با استفاده از آن، متدهای کنترلرها به صورت خودکار داخل یک try/catch اجرا شده و به این ترتیب استثناهای رخ داده، مدیریت گردیده و به ELMAH هدایت نمی‌شوند. بنابراین نیاز است به متد RegisterGlobalFilters فایل Global.asax.cs مراجعه کرده و سطر زیر را حذف کنید:

filters.Add(new HandleErrorAttribute());

و یا اگر قصد نداشتید اینکار را انجام دهید، می‌توان به نحو زیر نیز مشکل را حل کرد:

using System.Web.Mvc;
using Elmah;

namespace MvcApplication13.CustomFilters
{
public class ElmahHandledErrorLoggerFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
if (context.ExceptionHandled)
ErrorSignal.FromCurrentContext().Raise(context.Exception);
// all other exceptions will be caught by ELMAH anyway
}
}
}

در اینجا یک فیلتر سفارشی به برنامه اضافه شده است تا خطاهای مدیریت شده برنامه (خطاهای مدیریت شده توسط فیلتر HandleError توکار) را به موتور ELMAH هدایت کند. سایر خطاهای مدیریت نشده به صورت خودکار توسط ELMAH ثبت خواهند شد و نیازی به انجام کار اضافی در این مورد نیست.
سپس این فیلتر جدید را به صورت سراسری تعریف کنید:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new ElmahHandledErrorLoggerFilter());
filters.Add(new HandleErrorAttribute());
}

ترتیب این‌ها هم مهم است. ابتدا باید ElmahHandledErrorLoggerFilter معرفی شود.


تذکر مهم!
حین استفاده از ELMAH یک نکته را فراموش نکنید:
اگر allowRemoteAccess آن‌را به عدد 1 تنظیم کرده‌اید، به هیچ عنوان از نام پیش فرض elmah.axd استفاده نکنید (هر نام اختیاری دیگری را که علاقمند بودید و به سادگی قابل حدس زدن نبود، در فایل web.config وارد کنید).


خلاصه بحث
1- در ASP.NET MVC نیازی نیست تا متدهای کنترلرها را با try/catch شلوغ کنید.
2- حتما قسمت customErrors فایل وب کانفیگ برنامه را دهی کنید (این مورد را به چک لیست اجباری تهیه یک برنامه ASP.NET MVC اضافه کنید).
3- استفاده از فیلتر HandleError اختیاری است. اگر از قابلیت فیلتر کردن استثناهای ویژه آن استفاده نمی‌کنید، مقدار دهی customErrors وب کانفیگ برنامه هم همان کار را انجام می‌دهد.
4- برای ثبت جزئیات دقیق استثناهای رخ داده در برنامه، از ELMAH استفاده کنید و بی‌جهت وقت خودتان را صرف بازنویسی این افزونه ارزشمند نکنید.

مطالب مشابه
معرفی ELMAH
ثبت استثناهای مدیریت شده توسط ELMAH

مطالب
استاندارد وب WIA-ARIA
چند روز پیش مطلبی به عنوان اشتراک در سایت جاری معرفی شده که به ما یادآوری می‌کرد، ما تنها استفاده کنندگان سیستم‌های کامپیوتری، به خصوص اینترنت نیستیم و معلولین هم نیازمند استفاده از این فناوری‌ها هستند.
WAI-ARIA  که برگرفته از Web Accessibility Initiative - Accessible Rich internet Application است به معنی برنامه‌ی اینترنتی تعامل گرا با خاصیت دسترسی پذیری بالا می‌باشد و یک راهنماست که توسط کنسرسیوم وب (+ ) معرفی گشته است تا وب سایت‌ها با رعایت این قوانین، دسترسی سایت خود را بالاتر ببرند. این قوانین به خصوص برای سایت‌هایی با محتوای پویا هستند که از فناوری‌هایی چون Ajax,Javascrip, HTML و دیگر فناوری‌های مرتبط استفاده می‌کنند.
امروزه طراحان وب بیش از هر وقتی از فناوری‌های سمت کلاینت چون جاوااسکریپت برای ساخت رابط‌های کاربری استفاده می‌کنند که html به تنها قادر به ایجاد آن‌ها نیست. یکی از تکنیک‌های جاوااسکریپت، دریافت محتوای جدید و به روزآوری قسمتی از صفحات وب است بدون اینکه مجددا کل صفحه از وب سرور درخواست گردد که به این تکنیک  Rich Internet Application هم می‌گویند. تا به اینجای کار هیچ مشکلی نیست و خوب هم هست؛ ولی مشکلی که در این بین وجود دارد این است که این نوع تکنیک‌ها باعث از بین رفتن خاصیت دسترسی پذیری معلولین می‌گردند. معلولینی که از صفحه خوان ها استفاده می‌کنند یا به دلیل معلولیت‌های خود قادر به حرکت دادن ماوس نیستند.
ARIA با استفاده از خصوصیت‌ها Properties، نقش‌ها Roles و وضعیت‌ها States به طراحان برنامه‌های وب و سازندگان فناوری‌های یاری رسان، اجازه می‌دهد که با ابزارهای کمکی معلولان ارتباط برقرار کنیم و یک صفحه‌ی وب ساده را به یک صفحه‌ی پویا تبدیل کنیم. ARIA تنها یک استاندارد برای وب نیست، بلکه یک فناوری چند پلتفرمه است که برای بازی‌های رایانه‌ای، موبایل‌ها، دستگاه‌های سرگرمی و سلامتی و دیگر انواع برنامه‌ها نیز تعریف شده است.



فریمورک ARIA
خود HTML به تنهایی نمی‌تواند نقش‌های هر المان و ارتباط بین آن‌ها را به درستی بیان کند و به این منظور ARIA به کمک می‌آید. با استفاده از نقش‌ها میتوان هدف هر المان را مشخص کرد و با استفاده از خصوصیات ARIA نحوه‌ی عملکرد آن‌ها را تعریف کرد.

نقش ها
نقش‌ها طبق مستندات کنسرسیوم وب بر 4 نوع هستند:
  • Abstract Roles
  • Widget Roles
  • Document Roles
  • Landmark Roles
فریمورک ARIA با استفاده از Landmark Roles یا نقش‌های راهنما، به معرفی بخش‌های ویژوالی می‌پردازد تا فناوری‌های کمکی به آن دسترسی سریعی داشته باشند. هشت نقش راهنما وجود دارد که در زیر آن‌ها را بررسی می‌کنیم.

 Banner این قسمت که عموما برای اجزای مهمی مثل هدر سایت قرار می‌گیرد و شامل معرفی وب سایت هست و در همه‌ی صفحات وجود دارد که شامل لوگو، اطلاعات عمومی سایت و اسپانسرها و ... می‌گردد و بسیار مهم است که تنها یکبار در صفحه‌ی وب به کار برود و تکرار آن پرهیز شود.
 Main  این نقش به محتوای اصلی وب سایت اشاره می‌کند و نباید بیشتر از یکبار در هر صفحه‌ی وب به کار برود و عموما بهتر است این خصوصیت در تگ div قرار گیرد:
<div Role="main"></div>
یا در HTML5 به طور مفهومی ساخته می‌شود:
<main role="main">.....

Navigation اشاره به یک ناحیه پر از المان‌های لینک برای ارتباط با صفحات دیگر
 Complementary  مشخص سازی ناحیه‌ای که اطلاعات اضافی درباره‌ی محتوای اصلی سایت دارد؛ مانند بخش مقالات مرتبط، آخرین کامنت‌ها و ...
 ContentInfo  این نقش که بیشتر برای فوتر مناسب است برای محتوایی به کار می‌رود که در آن به قوانین کپی رایت و ... اشاره می‌شود.
 form  برای اشاره به فرم‌ها که دارای قسمت‌های ورودی کاربر هستند.
 search
 در صورتیکه فرمی دارید و از آن برای گزینه‌ی جست و جو استفاده می‌کنید، از این نقش استفاده کنید.
 application  برای اینکه وب سایت خود را به صورت یک وب اپلیکیشن معرفی کنید؛ تا یک صفحه وب معمولی، استفاده می‌شود و برای وب سایت‌های قدیمی یا با حالت سنتی توصیه نمی‌شود و به برنامه‌های کمکیار معلولین می‌گوند که از حالت عادی به حالت application سوئیچ کنند؛ پس با دقت بیشتری باید از این گزینه استفاده کرد.
 


خصوصیت‌ها و وضعیت ها

در حالیکه از نقش‌ها برای معرفی هر المان یا تگ استفاده می‌کنید؛ خصویت‌ها و وضعیت‌ها به کاربر اطلاعات اضافی می‌دهند که چگونه ز آن استفاده کنند. برای معرفی خصوصیت‌ها و وضعیت‌ها از یک خصوصیت که با -aria شروع می‌شود استفاده کنید. از معروفترین آن‌ها خصوصیت aria-required و وضعیت aria-checked می‌باشند، تا به ترتیب به کاربر اعلام کنید این تگ نیاز به پر شدن دارد، یا المانی نیاز به تغییر وضعیت انتخابی دارد.
نحوه‌ی استفاده از آن‌ها به شکل زیر است:
<div id="some-id" class="some-class" aria-live="assertive"><div>
aria-live سه مقدار می‌پذیرد که عبارتند از Off,Polite,Assertive  و مشخص می‌کنند که المان مورد نظر آپدیت پذیر هست یا خیر و اگر آری، نحوه‌ی به روز شوندگی آن به چه نحوی است.

ساخت ارتباطات میان المان‌ها با خصوصیت‌های ارتباطی

مثال شماره یک
<div role="main" aria-labelledby="some-id">
 
    <h1 id="some-id">This Is A Heading</h1>
 
    Main content...
 
</div>
خصوصیت aria-labelledby به تعریف المان‌هایی با نام جاری می‌پردازد. این خصوصیت معرفی کننده‌ی برچسب هاست. به عنوان مثال بین المان‌ها ورودی و برچسب آنان ارتباط ایجاد می‌کند تا ابزارهای معلولین، مانند صفحه خوان‌ها، در خواندن به مشکل برنخورند.

مثال شماره دو
در این مثال هر گروهی از المان‌ها یک برچسب و بعضی المان‌ها یک برچسب اختصاصی دارند که توسط خصوصیت معرفی شده aria-labelldby کامل شده‌اند:
<div id="billing">Billing Address</div>

<div>
    <div id="name">Name</div>
    <input type="text" aria-labelledby="name billing"/>
</div>
<div>
    <div id="address">Address</div>
    <input type="text" aria-labelledby="address billing"/>
</div>

مثال شماره سه

در این مثال گروهی از radio button‌ها با برچسبشان ارتباط برقرار می‌کنند.
<div id="radio_label">My radio label</div>
<ul role="radiogroup" aria-labelledby="radio_label">
    <li role="radio">Item #1</li>
    <li role="radio">Item #2</li>
    <li role="radio">Item #3</li>
</ul>

خصوصیت‌ها و وضعیت‌های aria را با چرخه‌ی فعالیت‌های صفحه به روز کنید

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


هر aria را دوباره استفاده نکنید

امروزه به خصوص با آمدن html5 و ویژگیهایی چون تگ‌های مفهومی، کار بسیار راحت‌تر شده‌است و مرورگر به طور خودکار می‌تواند aria را بر روی بعضی از المان‌ها پیاده کند. به عنوان نمونه:
<form></form>
<form role="form"></form>
همچنین به عنوان مثال با استفاده از خصوصیات HTML مثل hidden کردن یک شیء نیازی به استفاده از وضعیت aria-hidden نمی‌باشد. مرورگر به طور پیش فرض آن را لحاظ می‌کند.

امروزه شاهد پیشرفت فناوری در همه‌ی عرصه‌ها هستیم و همیشه این پیشرفت‌ها ما را ذوق زده کرده‌اند، ولی یکی از بی نظیرترین استفاده‌های فناوری روز، استفاده در صنایع سلامتی است که نه تنها ما را ذوق زده می‌کند، بلکه از لحاظ احساسی هم ما را به وجد می‌آورند و جزء زیباترین نتایج فناوری می‌باشند. بسیاری از شرکت‌ها چون گوگل در این راستا فعالیت‌های زیادی کرده‌اند تا بتوانند سلامت جامعه را کنترل کنند، از ساخت لنز چشمی برای کنترل دیابت گرفته تا ساخت قاشق عذای خوری برای بیماران پارکینسون، ولی استفاده‌های ساده از مسائلی مانند بالا به افراد معلول این مژده را می‌دهد که ما آن‌ها را فراموش نکرده‌ایم.
بازخوردهای پروژه‌ها
مشکل در گروه بندی اطلاعات بر اساس تاریخ
با سلام
همانطور که در اینجا ذکر کردم. مشکل در گروه بندی اطلاعات بر اساس تاریخ هنگامی وجود دارد که تنظیم 
GroupType = GroupType.IncludeGroupingColumns
انجام شده باشد، و بخواهیم خود فیلد را نیز نشان دهیم.
چون فیلد تاریخ میلادی دارد می‌بایست با کدی ان را تبدیل به تاریخ فارسی نموده و نشان دهیم.
حال مشکل اینجاست که مقدار فیلدی که بر اساس آن گروه بندی انجام می‌شود، فقط در سطر اول آن گروه بندی می‌آید، لذا در سطرهای بعدی هنگامی که میخواهیم تاریخ میلادی را به فارسی تبدیل کنیم
template.DisplayFormatFormula(obj =>DateTimeHelper.ToPersianShortDateString((DateTime)obj));
مقدار obj "" است و به خاطر همین خطای cast داریم. این هم تصویر هنگامی که تاریخ را تبدیل نمی‌کنیم.

آیا برای این حالت می‌توان کاری کرد؟
باتشکر
نظرات مطالب
احراز هویت و اعتبارسنجی کاربران در برنامه‌های Angular - قسمت چهارم - به روز رسانی خودکار توکن‌ها
نکاتی کوچک و پراکنده در سایت که به حل خطای 400 (Bad Request) در اجرای متد refreshToken کمک کرده و می‌تواند یافتن آن‌ها زمانبر باشد.
نکته:  "سرور و کلاینت در دو دامنه جدا از هم اجرا می‌شوند."

در این حالت می‌توان در سمت سرور در قسمت تنظیمات فایل Startup.cs  مقدار ClockSkew را تغییر داد
cfg.TokenValidationParameters = new TokenValidationParameters
{  
   //... 
   //ClockSkew = TimeSpan.Zero            
   ClockSkew = TimeSpan.FromMinutes(5)
}

برای ارسال کوکی XSRF-TOKEN  در هدر درخواست با عنوان  X-XSRF-TOKEN  بین دامنه‌ها باید در سمت کلاینت withCredentials: true تنظیم شود
this.http
    .post<Xyz>(`${this.apiUrl}`, data, { withCredentials: true /* For CORS */ })
    .map(response => response || {})
    .catch(this.handleError);
و  یا از یک HTTP Interceptor استفاده کرد:
@Injectable()
export class CORSInterceptor implements HttpInterceptor {

    constructor() {}

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        request = request.clone({
            withCredentials: true
        });
        return next.handle(request);
    }
}

3- تنظیمات CORS در ASP.NET Core 2.2
عدم استفاده از AllowAnyOrigin و AllowCredential با هم در تنظیمات سمت سرور در فایل Startup.cs:
app.UseCors(builder => builder
                .AllowAnyHeader()
                .AllowAnyMethod()
                //.AllowAnyOrigin()
                .SetIsOriginAllowed((host) => true)
                .AllowCredentials()
            );
و یا
services.AddCors(options =>
        {
            options.AddPolicy("CorsPolicy",
                builder => builder
                  .AllowAnyMethod()
                  .AllowAnyHeader()
                  .WithOrigins("http://localhost:4200")
                  .AllowCredentials()
            .Build());
        });
app.UseCors("CorsPolicy");
نظرات مطالب
پشتیبانی توکار از انجام کارهای پس‌زمینه در ASP.NET Core 2x
کتابخانه ای برای تولید عبارات Cron  که برای تاریخ شمسی نوشته ام. کتابخانه هایی که برای تاریخ میلادی نوشته شده اند، برای تاریخ شمسی در روزهای خاصی از سال مقدار درستی را خروجی نمی‌دهند. 
مطالب
تغییر ابعاد یک TextArea با استفاده از jQuery

اگر به سایت stackoverflow دقت کنید، اندازه textarea ایی که کاربران امکان ارسال مطلب دارند، قابل تغییر است:



شاید برای شما جالب باشد که بدانید به چه صورتی اینکار را انجام داده‌اند. اینکار با استفاده از افزونه TextArea Resizer صورت گرفته است. (دریافت کتابخانه به همراه مثال)

البته حالت عمومی‌تری نیز توسط jQuery-UI استاندارد پشتیبانی می‌شود (امکان تغییر اندازه یک المان با قابلیت تغییر اندازه در حالت کلی). برای مثال به صفحه‌ی ساده‌ی ASP.Net زیر دقت بفرمائید:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm5.aspx.cs" Inherits="testWebForms87.WebForm5" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.5.3/jquery-ui.min.js" type="text/javascript"></script>

<script type="text/javascript">
$(function() {
$("#resizableArea").resizable({
handles: "s"
})
.find("textarea").height("100%").width("100%");
});
</script>

</head>
<body>
<form id="form1" runat="server">
<div id="resizableArea" style="width:300px; height:200px" >
<asp:TextBox ID="TextBox1" runat="server" TextMode="MultiLine" ></asp:TextBox>
</div>
</form>
</body>
</html>

در اینجا با استفاده از jQuery-UI ابتدا div ایی با id مساوی resizableArea پیدا می‌شود و تابع resizable به آن اعمال می‌گردد. سپس در این div ، تمامی عناصر textarea موجود یافت شده و طول و عرض آن‌ها به اندازه‌ی جدید تغییر یافته div تنظیم خواهد شد. در مورد تنظیم‌های دیگری مانند نمایش ناحیه تغییر یافته به صورت animation می‌توان به راهنمای آن مراجعه نمود.
برای مثال با استفاده از این روش می‌توان یک GridView با قابلیت تغییر اندازه ایجاد کرد و امثال آن. یا برای نمونه شاید با مثال‌هایی که به گرید نمایش داده شده اسکرول بار اضافه می‌کنند برخورده باشید:

<div id="resizableArea" style="overflow:auto;height:200px;">
My Grid view ...
</div>

و یا استفاده از یک پنل:

<asp:Panel ID="pnlScroll" runat="server" Width="391px" Height="282px" ScrollBars="Vertical">
My Grid view ...
</asp:Panel>

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

مطالب
غیرفعال کردن کش مرورگر هنگام استفاده از jQuery Ajax

برای استفاده از قابلیت‌های Ajax کتابخانه jQuery ، شش متد زیر در اختیار برنامه نویس‌ها است:

$.ajax(), load(), $.get(), $.getJSON(), $.getScript(), and $.post()
که در حقیقت 5 مورد آخر ذکر شده صرفا بیان اولین متد ajax فوق به نحوی دیگر می‌باشند و محصور کننده‌ توانایی‌های آن هستند.

برای مثال کد زیر زمان جاری را از سرور دریافت کرده و نتیجه را در سه تکست باکس قرار داده شده در صفحه نمایش می‌دهد.
ابتدا وب سرویس ساده زیر را در نظر بگیرید که زمان شمسی جاری را بر می‌گرداند:

using System;
using System.Globalization;
using System.Web.Script.Services;
using System.Web.Services;

namespace TestJQueryAjax
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[ScriptService]
public class AjaxSrv : WebService
{
public class TimeInfo
{
public string Date { set; get; }
public string Hr { set; get; }
public string Min { set; get; }
}

[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public TimeInfo GetTime()
{
DateTime now = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day);
PersianCalendar pc = new PersianCalendar();
string today = string.Format("{0}/{1}/{2}",
pc.GetYear(now),
pc.GetMonth(now).ToString("00"),
pc.GetDayOfMonth(now).ToString("00"));
TimeInfo ti = new TimeInfo
{
Date = today,
Hr = DateTime.Now.Hour.ToString("00"),
Min = DateTime.Now.Minute.ToString("00")
};
return ti;
}
}
}
سپس اگر از تابع Ajax کتابخانه jQuery جهت دریافت زمان جاری از وب سرویس استفاده نمائیم، کد صفحه ما به صورت زیر خواهد بود:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="TestFillCtrls.aspx.cs"
Inherits="TestJQueryAjax.TestFillCtrls" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>

<script src="js/jquery.js" type="text/javascript"></script>

<script type="text/javascript">
function validate() {
$.ajax({
type: "POST",
url: 'AjaxSrv.asmx/GetTime',
data: '{}',
contentType: "application/json; charset=utf-8",
dataType: "json",
success:
function(msg) {
$("#<%=txtDate.ClientID %>").val(msg.d.Date);
$("#<%=txtHr.ClientID %>").val(msg.d.Hr);
$("#<%=txtMin.ClientID %>").val(msg.d.Min);
},
error:
function(XMLHttpRequest, textStatus, errorThrown) {
alert("خطایی رخ داده است");
}
});
//debugger;
}
</script>

</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="txtDate" runat="server" />
<br />
<asp:TextBox ID="txtHr" runat="server" />
<br />
<asp:TextBox ID="txtMin" runat="server" />
<br />
<asp:Button ID="btnGetTime" runat="server" Text="Click here!" UseSubmitBehavior="false"
OnClientClick="validate();return false;" />
</div>
</form>
</body>
</html>
تنها نکته‌ی جدید این اسکریپت، نحوه‌ی استفاده از خروجی JSON وب متد ما است که از نوع TimeInfo تعریف شده است. خروجی نمونه این وب متد به صورت زیر می‌تواند باشد:

{"d":{"__type":"TestJQueryAjax.AjaxSrv+TimeInfo","Date":"1388/07/14","Hr":"12","Min":"59"}}
که نحوه‌ی دسترسی به اجزای آن‌را در متد validate‌ ملاحظه می‌نمائید.

باید به خاطر داشت که برای هر 6 متد Ajax ایی jQuery ، عملیات کش شدن اطلاعات در مرورگر کاربر به صورت پیش فرض فعال است. اما این نکته تنها زمانیکه dataType مورد استفاده از نوع script یا jsonp باشد، صادق نبوده و کش شدن به صورت خودکار غیرفعال می‌گردد.
روش سنتی غیرفعال کردن کش در حین عملیات اجکسی، استفاده از یک کوئری استرینگ متغیر در پایان url درخواستی است. به این صورت مرورگر درخواست صادره را جدید فرض کرده و از کش خود استفاده نمی‌نماید (همین مورد در حالت کش شدن تصاویر هم صادق است).
jQuery نیز همین عملیات را در پشت صحنه انجام داده اما تنظیم آن‌را به نحوی مطلوب‌تری ارائه می‌دهد. یا پارامتر cache را در تعریف متد ajax خود اضافه نموده و مقدار آن را مساوی false قرار دهید و یا جهت تاثیر گذاری بر روی کلیه متدهای مورد استفاده، پیش از استفاده از آن‌ها این تنظیم را مشخص سازید:

$.ajaxSetup({cache: false});