مطالب
آشنایی با چالش های امنیتی در توسعه برنامه‌های تحت وب، بخش اول
در پروژه‌های بزرگ نرم افزاری، از قدیم بحث تامین امنیت پروژه، یکی از چالش‌های مهم بوده است. از دیدگاه شخصی بنده، یک مدیر نرم افزار یا حتی یک توسعه دهنده‌ی برنامه‌های تحت وب، لازم است علاوه بر صرف وقت مطالعاتی و آشنایی و تسلط بر مباحث طراحی معماری سیستم‌های تحت وب، که از اهمیت بالا و مقیاس بزرگی برخوردارند آشنایی لازم را با چالش‌های امنیتی در پیاده سازی اینگونه سیستم‌ها داشته باشد. امنیت در یک سیستم بزرگ و ارائه دهنده خدمات، باعث می‌شود تا کاربر علاوه بر یک تجربه کاربری (user experience) خوب از سیستم که حاصل پیاده سازی صحیح سیستم می‌باشد، اعتماد ویژه‌ای به سیستم مذکور داشته باشد. گاها کاربران به علت بی اعتمادی به شرایط امنیتی حاکم بر یک سیستم، از تجربه کاربری خوب یک سیستم چشم پوشی می‌کنند. اهمیت این مسئله تا جاییست که غول‌های تکنولوژی دنیا همچون Google درگیر این چالش می‌باشند و همیشه سعی بر تامین امنیت کاربران علاوه بر ایجاد تجربه کاربری خوب دارند. پس عدم توجه به این موضوع میتواند خسارات وارده جبران ناپذیری را به یک سیستم از جهت‌های مختلف وارد کند.

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

در این سری از مقالات چالش‌های امنیتی زیر مورد بحث و بررسی واقع خواهند گردید 

XSS , LDAPi ,RFI ,LFI ,SQLi ,RFD ,LFD ,SOF ,BSQLI ,DNN ,BOF ,CRLF ,CSRF ,SSI ,PCI ,SCD ,AFD ,RCE

در بخش اول از این سری مقالات ، به بررسی آسیب پذیری Cross-site scripting میپردازیم .

واژه XSS مخفف Cross-site scripting، نوعی از آسیب پذیریست که در برنامه‌های تحت وب نمود پیدا میکند. به طور کلی و خلاصه، این آسیب پذیری به فرد نفوذ کننده اجازه تزریق اسکریپت‌هایی را به صفحات وب، می‌دهد که در سمت کاربر اجرا می‌شوند ( Client Side scripts ) . در نهایت این اسکریپت‌ها توسط سایر افرادی که از صفحات مورد هدف قرار گرفته بازدید می‌کنند اجرا خواهد شد.

هدف از این نوع حمله :

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

به صورت کلی دو طبقه بندی برای انواع حملات Cross-site scripting وجود دارند.

حملات XSS ذخیره سازی شده ( Stored XSS Attacks ) :

در این نوع ، کدهای مخرب تزریق شده، در سرور سایت قربانی ذخیره میشوند. محل ذخیره سازی می‌تواند دیتابیس سایت یا هر جای دیگری که داده‌ها توسط سایت یا برنامه تحت وب بازیابی می‌شوند و نمایش داده می‌شوند باشد. اما اینکه چگونه کدهای مخرب در منابع یاد شده ذخیره میشوند؟

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

حملات XSS منعکس شده ( Reflected XSS Attacks ) :

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

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

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

www.test.com/search?q=PHNjcmlwdD5hbGVydChkb2N1bWVudC5jb29raWUpOzwvc2NyaXB0Pg==

این آدرس حاصل submit  شدن فرم جستجو وب‌سایت test (نام وب‌سایت واقعی نیست و برای مثال است )  و ارجاع به صفحه نتایج جستجو میباشد. در واقع این لینک برای جستجوی یک کلمه یا عبارت توسط این وبسایت تولید شده و از هر کجا به این لینک مراجعه کنید عبارت مورد نظر مورد جستجو واقع خواهد شد. در واقع عبارت جستجو به صورت Base64 به عنوان یک query String به وبسایت ارسال می‌شود؛ علاوه بر نمایش نتایج، عبارت جستجو شده نیز به کاربر نشان داده شده و اگر آسیب پذیری مورد بحث وجود داشته باشد و عبارت شامل کدهای مخرب باشد، کدهای مخرب بر روی مرورگر فردی که این لینک را باز کرده اجرا خواهد شد!

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

اهمیت مقابله با این حمله :

برای نمونه این نوع باگ حتی تا سال گذشته در سرویس ایمیل یاهو وجود داشت. به شکلی که یکی از افراد انجمن hackforums به صورت Private این باگ را به عنوان Yahoo 0-Day XSS Exploit در محیط زیر زمینی و بازار سیاه هکرها به مبلغ چند صد هزار دلار به فروش می‌رساند. کاربران مورد هدف کافی بود تا فقط یک ایمیل دریافتی از هکر را باز کنند تا کوکی‌های سایت یاهو برای هکر ارسال شده و دسترسی ایمیل‌های فرد قربانی برای هکر فراهم شود ... ( در حال حاظر این باگ در یاهو وجو ندارد ).

چگونگی جلوگیری از این آسیب پذیری

در این سری از مقالات کدهای پیرامون سرفصل‌ها و مثال‌ها با ASP.net تحت فریم ورک MVC و به زبان C# خواهند بود. هر چند کلیات مقابله با آسیب پذیری هایی از این دست در تمامی زبان‌ها و تکنولوژی‌های تحت وب یکسان میباشند.

خوشبختانه کتابخانه‌ای قدرتمند برای مقابله با حمله مورد بحث وجود دارد با نام AntiXSS که میتوانید آخرین نسخه آن را با فرمان زیر از طریق nugget به پروژه خود اضافه کنید. البته ذکر این نکته حائز اهمیت است که Asp.net و فریم ورک MVC به صورت توکار تا حدودی از بروز این حملات جلوگیری می‌کند. برای مثال به این صورت که در View ‌ها شما تا زمانی که از MvcHtmlString استفاده نکنید تمامی محتوای مورد نظر برای نمایش به صورت Encode شده رندر می‌شوند. این داستان برای Url ‌ها هم که به صورت پیش فرض encode میشوند صدق می‌کند. ولی گاها وقتی شما برای ورود اطلاعات مثلا از یک ادیتور WYSWYG استفاده می‌کنید و نیاز دارید داده‌ها را بدون encoding رندر کنید. آنگاه به ناچار مجاب بر اعمال یک سری سیاست‌های خاص‌تر بر روی داده مورد نظر برای رندر می‌شوید و نمی‌توانید از encoding توکار فوق الذکر استفاده کنید. آنگاه این کتابخانه در اعمال سیاست‌های جلوگیری از بروز این آسیب پذیری می‌تواند برای شما مفید واقع شود.

 PM> Install-Package AntiXSS
این کتابخانه مجموعه‌ای از توابع کد کردن عبارات است که از مواردی همچون Html, XML, Url, Form, LDAP, CSS, JScript and VBScript پشتیبانی می‌کند. استفاده از آن بسیار ساده می‌باشد. کافیست ارجاعات لازم را به پروژه خود افزوده و به شکل زیر از توابع ارائه شده توسط این کتابخانه استفاده کنید: 
…
var reviewContent = model.UserReview;
reviewContent = Microsoft.Security.Application.Encoder.HtmlEncode(review);
…

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

مطالب
jQuery Tips #2
چگونگی استفاده از Cookie در jQuery
در این پست قصد دارم نحوه‌ی کاربا Cookie را با استفاده از jQuery برسی کنم و در پست بعدی یک مثال عملی را برسی می‌کنیم.

همانطور که می‌دانید کوکی یکی از اشیاء بسیار مهم برای نگه داری داده‌ها در بحث وب می‌باشد که یک فایل متنی است که سمت Client ذخیره می‌شود. و ما زمانی که از کتابخانه jQuery استفاده می‌کنیم خیلی مهم است که بدانیم چگونه باید با Cookie‌ها کار کرد.

برای کار با کوکی‌ها در jQuery باید از Plugin ‌های موجود استفاده کرد . برای ایجاد یک Cookie ابتدا فایل jQuery و سپس این کتابخانه را به صفحه مورد نظر اضافه نموده و کد زیر را برای ایجاد یک کوکی می‌نویسیم
<script src="jquery-1.7.1.min.js" type="text/javascript"></script>
    <script src="jquery.cookie.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(function () {
            $.cookie("TestCookie", "Test Cookie By Mohsen Bahrzadeh ");
        });
    </script>
در اینجا یک کوکی با نام TestCookie با مقدار Test Cookie By Mohsen Bahrzadeh ایجاد می‌کنیم
حال پروژه را اجرا می‌کنیم. و در تصویر زیر مشاهده می‌کنید که کوکی ما ایجاد شده است

یکی از آیتم‌های بسیار مهم در کوکی‌ها تعریف زمان انقضاء کوکی است برای ست کردن تاریخ از کد زیر استفاده می‌کنیم
  $(function () {
            $.cookie("TestCookie", "Test Cookie By Mohsen Bahrzadeh ", { expires: 7 });
        });
و برای خواندن مقدار کوکی از کد زیر استفاده می‌کنیم
 $(function () {
          
            alert($.cookie("TestCookie"));
        });
و برای حذف کوکی از کد زیر استفاده می‌کنیم

 $(function () {

            $.cookie("TestCookie", null);
        });

مطالب
لینک‌های هفته‌ی دوم اسفند

وبلاگ‌ها ، سایت‌ها و مقالات ایرانی (داخل و خارج از ایران)

امنیت

Visual Studio

ASP. Net

طراحی و توسعه وب

PHP

اس‌کیوال سرور

سی شارپ

VB

CPP

عمومی دات نت

مسایل اجتماعی و انسانی برنامه نویسی

متفرقه
مطالب
مباحث تکمیلی مدل‌های خود ارجاع دهنده در EF Code first
در مورد طراحی Self Referencing Entities پیشتر مطلبی را در این سایت مطالعه کرده‌اید .
یک مثال دیگر آن می‌تواند نظرات چند سطحی در یک سایت باشند. نحوه تعریف آن با مطالبی که در قسمت هشتم عنوان شود تفاوتی نمی‌کند؛ اما ... زمانیکه نوبت به نمایش آن فرا می‌رسد، چند نکته اضافی را باید درنظر گرفت. ابتدا مثال کامل زیر را در نظر بگیرید:
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq;

namespace EFGeneral
{
    public class BlogComment
    {
        public int Id { set; get; }

        [MaxLength]
        public string Body { set; get; }

        public virtual BlogComment Reply { set; get; }
        public int? ReplyId { get; set; }
        public ICollection<BlogComment> Children { get; set; }
    }

    public class MyContext : DbContext
    {
        public DbSet<BlogComment> BlogComments { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            // Self Referencing Entity
            modelBuilder.Entity<BlogComment>()
                        .HasOptional(x => x.Reply)
                        .WithMany(x => x.Children)
                        .HasForeignKey(x => x.ReplyId)
                        .WillCascadeOnDelete(false);

            base.OnModelCreating(modelBuilder);
        }
    }

    public class Configuration : DbMigrationsConfiguration<MyContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = true;
            AutomaticMigrationDataLossAllowed = true;
        }

        protected override void Seed(MyContext context)
        {
            var comment1 = new BlogComment { Body = "نظر من این است که" };
            var comment12 = new BlogComment { Body = "پاسخی به نظر اول", Reply = comment1 };
            var comment121 = new BlogComment { Body = "پاسخی به پاسخ به نظر اول", Reply = comment12 };

            context.BlogComments.Add(comment121);
            base.Seed(context);
        }
    }

    public static class Test
    {
        public static void RunTests()
        {
            Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, Configuration>());

            using (var ctx = new MyContext())
            {
                var list = ctx.BlogComments
                          //.where ...
                          .ToList() // fills the childs list too
                          .Where(x => x.Reply == null) // for TreeViewHelper                        
                          .ToList();

                if (list.Any())
                {

                }
            }
        }
    }
}

در مثال فوق کلاس نظرات به صورت خود ارجاع دهنده (خاصیت Reply به همین کلاس اشاره می‌کند) تعریف شده است تا کاربران بتوانند تا هر چند سطح لازم، به یک نظر خاص، پاسخ دهند.
در اینجا یک چنین جدولی با اطلاعاتی که ملاحظه می‌کنید تشکیل خواهند شد:


یک نظر ارائه شده و سپس دو نظر تو در توی دیگر برای این نظر ثبت شده است.

اولین نکته اضافه‌‌تری که نسبت به قسمت هشتم قابل ملاحظه است، تعریف خاصیت جدید Children به نحو زیر می‌باشد:
    public class BlogComment
    {
        // ... 
        public ICollection<BlogComment> Children { get; set; }
    }
این خاصیت تاثیری در نحوه تشکیل جدول ندارد. علت تعریف آن به توانمندی EF در پرکردن خودکار آن بر می‌گردد.
اگر به کوئری نوشته شده در متد RunTests دقت کنید، ابتدا یک ToList نوشته شده است. این مورد سبب می‌شود که تمام رکوردهای مرتبط دریافت شوند. مثلا در اینجا سه رکورد دریافت می‌شود. سپس برای اینکه حالت درختی آن حفظ شود، در مرحله بعد ریشه‌ها فیلتر می‌شوند (مواردی که reply آن‌ها null است). سپس این مورد تبدیل به list خواهد شد. اینبار اگر خروجی را بررسی کنیم، به ظاهر فقط یک رکورد است اما ... به نحو زیبایی توسط EF به شکل یک ساختار درختی، بدون نیاز به کدنویسی خاصی، منظم شده است:


سؤال:
برای نمایش این اطلاعات درختی و تو در تو در یک برنامه وب چکار باید کرد؟
تا اینجا که توانستیم اطلاعات را به نحو صحیحی توسط EF مرتب کنیم، برای نمایش آن‌ها در یک برنامه ASP.NET MVC می‌توان از یک TreeViewHelper سورس باز استفاده کرد.
البته کد آن در اصل برای استفاده از EF Code first طراحی نشده و نیاز به اندکی تغییر به نحو زیر دارد تا با EF هماهنگ شود (متد ToList و Count موجود در سورس اصلی آن باید به نحو زیر حذف و اصلاح شوند):
private void AppendChildren(TagBuilder parentTag, T parentItem, Func<T, IEnumerable<T>> childrenProperty)
        {
            var children = childrenProperty(parentItem);
            if (children == null || !children.Any())
            {
                return;
            }
//...

 
نظرات مطالب
Blazor 5x - قسمت 30 - برنامه‌ی Blazor WASM - افزودن پرداخت آنلاین توسط درگاه مجازی پرباد
سلام
موقع ریدایرکت از api به سمت کلاینت پس از پرداخت خطای CORS  داریم . علت چیه ؟ با اینکه اگر api را دستی اجرا کنیم بدون مشکل ریدایرکت میشه ، 
basket:1 Access to fetch at ' https://localhost:7145  ' (redirected from 'https://localhost:44307/api/v1.0/order/pay/44') from origin 'https://localhost:7145' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
نظرات مطالب
ASP.NET MVC #18
- بررسی اختصاصی و مفصل asp.net identity در گروه مربوطه‌ی آن در سایت، انجام شده.
- برای استفاده از asp.net identity با روش database first دو سری ویدیو در یوتیوب هست: (^ و ^)
مطالب
هدایت خودکار آدرس‌های یافت نشد در یک سایت ASP.NET MVC به جستجوی سایت
هر از چندگاهی یک چنین آدرس‌های یافت نشدی را در لاگ‌های سایت مشاهده می‌کنم:
https://www.dntips.ir/jquery
https://www.dntips.ir/mvc
https://www.dntips.ir/برنامه
روش متداول مدیریت این نوع آدرس‌ها، هدایت خودکار به صفحه‌ی 404 است. اما شاید بهتر باشد بجای اینکار، کاربران به صورت خودکار به صفحه‌ی جستجوی سایت هدایت شوند. در ادامه مراحل اینکار را بررسی خواهیم کرد.

الف) ساختار کنترلر جستجوی سایت
فرض کنید جستجوی سایت در کنترلری به نام Search و توسط اکشن متد پیش فرضی با فرمت زیر مدیریت می‌شود:
   [ValidateInput(false)] //برنامه نویس‌ها نیاز دارند تگ‌ها را جستجو کنند
  public virtual ActionResult Index(string term)
  {

ب) مدیریت کنترلرهای یافت نشد
اگر از یک IoC Container در برنامه‌ی ASP.NET MVC خود مانند StructureMap استفاده می‌کنید، نوشتن کد متداول زیر کافی نیست:
public class StructureMapControllerFactory : DefaultControllerFactory
    {
        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            return ObjectFactory.GetInstance(controllerType) as Controller;
        }
    }
از این جهت که اگر کاربر آدرس https://www.dntips.ir/test را وارد کند، controllerType درخواستی نال خواهد بود؛ چون جزو کنترلرهای سایت نیست. به همین جهت نیاز است موارد نال را هم مدیریت کرد:
public class StructureMapControllerFactory : DefaultControllerFactory
    {
        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            if (controllerType == null)
            {
                var url = requestContext.HttpContext.Request.RawUrl;
                //string.Format("Page not found: {0}", url).LogException();

                requestContext.RouteData.Values["controller"] = MVC.Search.Name;
                requestContext.RouteData.Values["action"] = MVC.Search.ActionNames.Index;
                requestContext.RouteData.Values["term"] = url.GetPostSlug().Replace("-", " ");
                return ObjectFactory.GetInstance(typeof(SearchController)) as Controller;
            }
            return ObjectFactory.GetInstance(controllerType) as Controller;
        }
    }
کاری که در اینجا انجام شده، هدایت خودکار کلیه کنترلرهای یافت نشد برنامه، به کنترلر Search است. اما در این بین نیاز است سه مورد را نیز اصلاح کرد. در RouteData.Values جاری، نام کنترلر باید به نام کنترلر Search تغییر کند. زیرا مقدار پیش فرض آن، همان عبارتی است که کاربر وارد کرده. همچنین باید مقدار action را نیز اصلاح کرد، چون اگر آدرس وارد شده برای مثال https://www.dntips.ir/mvc/test بود، مقدار پیش فرض action همان test می‌باشد. بنابراین صرف بازگشت وهله‌ای از SearchController تمام موارد را پوشش نمی‌دهد و نیاز است دقیقا جزئیات سیستم مسیریابی نیز اصلاح شوند. همچنین پارامتر term اکشن متد index را هم در اینجا می‌شود مقدار دهی کرد. برای مثال در اینجا عبارت وارد شده اندکی تمیز شده (مطابق روش متد تولید Slug) و سپس به عنوان مقدار term تنظیم می‌شود.

ج) مدیریت آدرس‌های یافت نشد پسوند دار
تنظیمات فوق کلیه آدرس‌های بدون پسوند را مدیریت می‌کند. اما اگر درخواست رسیده به شکل https://www.dntips.ir/mvc/test/file.aspx بود، خیر. در اینجا حداقل سه مرحله را باید جهت مدیریت و هدایت خودکار آن به صفحه‌ی جستجو انجام داد
- باید فایل‌های پسوند دار را وارد سیستم مسیریابی کرد:
 routes.RouteExistingFiles = true; //نیاز هست دانلود عمومی فایل‌ها تحت کنترل قرار گیرد
- در ادامه نیاز است مسیریابی Catch all اضافه شود:
پس از مسیریابی پیش فرض سایت (نه قبل از آن)، مسیریابی ذیل باید اضافه شود:
routes.MapRoute(
                "CatchAllRoute", // Route name
                "{*url}", // URL with parameters
                new { controller = "Search", action = "Index", term = UrlParameter.Optional, area = "" }, // Parameter defaults                
                new { term = new UrlConstraint() }
            );
مسیریابی پیش فرض، تمام آدرس‌های سازگار با ساختار MVC را می‌تواند مدیریت کند. فقط حالتی از آن عبور می‌کند که پسوند داشته باشد. با قرار دادن این مسیریابی جدید پس از آن، کلیه آدرس‌های مدیریت نشده به کنترلر Search و اکشن متد Index آن هدایت می‌شوند.
مشکل! نیاز است پارامتر term را به صورت پویا مقدار دهی کنیم. برای اینکار می‌توان یک RouteConstraint سفارشی نوشت:
    public class UrlConstraint : IRouteConstraint
    {
        public bool Match(System.Web.HttpContextBase httpContext, 
                          Route route, string parameterName, 
                          RouteValueDictionary values, 
                          RouteDirection routeDirection)
        {
            var url = httpContext.Request.RawUrl;
            //string.Format("Page not found: {0}", url).LogException();

            values["term"] = url.GetPostSlug().Replace("-", " ");
            return true;
        }
    }
UrlConstraint مطابق تنظیم CatchAllRoute فقط زمانی فراخوانی خواهد شد که برنامه به این مسیریابی خاص برسد (و نه در سایر حالات متداول کار با کنترلر جستجو). در اینجا فرصت خواهیم داشت تا مقدار term را به RouteValueDictionary آن اضافه کنیم.
نظرات مطالب
احراز هویت و اعتبارسنجی کاربران در برنامه‌های Angular - قسمت دوم - سرویس اعتبارسنجی
ASP.NET Core در نگارش فعلی آن برای خطای 500 یا Internal server error (خطای سمت سرور که باید لاگ و بررسی شود)، حتی اگر CORS را تنظیم کرده باشید، هدرهای آن‌را ارسال نمی‌کند. به همین جهت مرورگر خطای عدم تنظیم این هدرها را نمایش می‌دهد (که مهم نیست و بی‌ربط به اصل موضوع خطای سمت سرور است). 
نظرات مطالب
کار با اسکنر در برنامه های تحت وب (قسمت دوم و آخر)
- در کانفیگ کدهای شما قسمت زیر موجود نیست (مربوط است به Cross-Origin Request یا Cors و برای دسترسی به آن از طریق وب ضروری است):
      <behaviorExtensions>
        <add name="CorsSupport" type="WebHttpCors.CorsSupportBehaviorElement, WebHttpCors, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      </behaviorExtensions>
کدهای WebHttpCors کمی بالاتر ارسال شده‌است.
- همچنین نحوه‌ی خطایابی و تفسیر این کدها نیز مهم هستند (^ و ^ و ^).
مطالب
نمایش پیغامی به کاربر در هنگام استفاده از MS Ajax

مطلب "نمایش یک پیغام به کاربر در ASP.Net" را احتمالا به خاطر دارید. این روش در حالت postback کامل و یا در حالت page_load بدون مشکل کار می‌کند. اما اگر در حال استفاده از آپدیت پنل MS Ajax باشیم، دیگر کار نخواهد کرد چون تنها قسمتی از صفحه به روز رسانی می‌شود و یک postback کامل رخ نمی‌دهد تا از شیء صفحه جهت تزریق اسکریپت خود بتوانیم استفاده نمائیم. خوشبختانه طراحان MS Ajax به این مورد هم توجه داشته‌اند و متد RegisterStartupScript را جزئی از کلاس ScriptManager قرار داده‌اند. برای مثال اگر نیاز باشد در پایان عملیات یک متد که از آپدیت پنل کمک می‌گیرد، یک alert نمایش داده شود می‌توان از متد زیر استفاده کرد:

void jsCall(string alert)
{
string script = @"alert('" + alert + "');";
ScriptManager.RegisterStartupScript(this, this.GetType(), "jsCall", script, true);
}

با توجه به این نکته، مطلب "نمایش یک پیغام به کاربر در ASP.Net" را به صورت زیر نیز می‌توان با MS Ajax‌ سازگار کرد:

if (page != null)
{
ScriptManager sMgr = ScriptManager.GetCurrent(page);
if (sMgr != null)
{
ScriptManager.RegisterStartupScript(page, page.GetType(),
"script" + new Guid().ToString("N"),
scriptBlock, false);
}
else
//همان روش قبلی
...