نظرات مطالب
ASP.NET MVC #9
همانطور که در مقاله فوق هم ذکر شده، اگر محل فایل helper شما در پوشه App_Code است (و نه یک View قرار گرفته در پوشه Views برنامه)، نمی‌توانید مستقیما با Html@‌ها کار کنید. نیاز است از طریق پارامتر WebViewPage page به آن‌ها دسترسی پیدا کنید؛ یعنی:
@page.Html.Raw(data)
مطالب
جایگزینی اسکریپت‌های WebResource.axd با فایل‌های استاتیک در ASP.NET Web forms
مدتی قبل سؤال مهمی در سایت مطرح شد، به شرح زیر:
«من از کنترل‌های تلریک استفاده می‌کنم که یک سری اسکریپت را بصورت
 http://localhost:1244/WebResource.axd?d=aklE6L8AEfPEgIS3T-oXc6mevPfbpi6VRp_ZTP2nBVrnt5ULOFYD3GNWRrDHwANC3VDQlL8dLAa5g35dzgHyuzAgAguIpYrf-_NXIJwNNu0YRSnH3-MgKMfnwKBKF_Lk2E5oeIcLL78uDlQ0se_GxQ2&t=635231470568640000 
به فرم تزریق می‌کند و بعضی وقت‌ها داخلش xp و یا یک سری دستورات اس‌کیوال تولید می‌شوند. در این حالت این مسیرها توسط ISA Server در شبکه داخلی حمله تشخیص داده شده و بلاک خواهند شد و عملا برنامه از کار می‌افتد. آیا راهی برای خلاصی از دست آن‌ها هست؟»

پاسخ: بلی. از دات نت 3 و نیم به بعد، امکان جایگزینی کامل اسکریپت‌های خودکار مدفون شده در اسمبلی‌ها با فایل‌های استاتیک پیش بینی شده‌است که در ادامه نحوه‌ی استخراج و کار با آن‌ها را بررسی خواهیم کرد.

الف) یافتن اسکریپت‌های مدفون در اسمبلی‌ها

در ابتدا اسمبلی حاوی کنترل‌های وب فرم مدنظر خود را باید توسط برنامه‌های Reflector یا ILSpy و امثال آن‌ها گشوده و نام دقیق منبع و همچنین محتوای آن فایل اسکریپت را استخراج کنید. برای مثال:


در این تصویر، اسمبلی استاندارد System.Web.Extensions مورد بررسی قرار گرفته است. برای نمونه اگر بخواهید اسکریپت‌های متناظر با ScriptManager و UpdatePanel را با معادل‌های استاتیک آن‌ها جایگزین کنید، باید دو فایل MicrosoftAjaxWebForms.js و MicrosoftAjax.js را از این اسمبلی استخراج نمائید. (برنامه‌های یاد شده امکان ذخیره سازی منابع را نیز می‌دهند)


ب) وادار کردن ASP.NET به استفاده از نسخه‌ی استاتیک منابع

    <asp:ScriptManager ID="Scriptmanager1" runat="server">
            <Scripts>
                <asp:ScriptReference Name="MicrosoftAjaxWebForms.js" Assembly="System.Web.Extensions"
                    Path="~/staticJS1.js" />
                <asp:ScriptReference Name="MicrosoftAjax.js" Assembly="System.Web.Extensions" Path="~/staticJS2.js" />
            </Scripts>
    </asp:ScriptManager>
فرض کنید دو اسکریپت یاد شده را در فایل‌های staticJS1.js و staticJS2.js در ریشه‌ی سایت خود ذخیره کرده‌اید. اکنون یک ScriptManager را به صفحه اضافه کرده و مطابق کدهای فوق، اسکریپت‌های مدفون شده در اسمبلی System.Web.Extensions را به این فایل‌های استاتیک هدایت کنید. همانطور که عنوان شد نام این مداخل باید دقیقا با نام موجود در اسمبلی یکی باشد؛ در غیر اینصورت با خطای ذیل مواجه خواهید شد:
 The assembly 'System.Web.Extensions' does not contain a Web resource that has the name 'xyz.js'.
Make sure that the resource name is spelled correctly.
Make sure that the application references the correct version of an ASP.NET AJAX Framework assembly.
اکنون اگر برنامه را اجرا کنید (با فرض قرار داشتن یک ScriptManager و UpdatePanel در صفحه)، اینبار دیگر در سورس صفحه، شاهد آدرس‌های طولانی WebResource.axd و ScriptResource.axd نخواهید بود. به صورت خودکار از دو فایل استاتیک تنظیم شده، استفاده می‌شود:
 <script src="staticJS1.js" type="text/javascript"></script>
<script src="staticJS2.js" type="text/javascript"></script>
بدیهی است در صورت نیاز، باید تعاریف سایر اسکریپت‌های مدفون در اسمبلی یاد شده یا اسمبلی System.Web را نیز به صفحه از طریق ScriptManager اضافه کرد. در مورد کنترل‌های ثالث نیز وضع به همین صورت است و استاندارد آن تفاوتی نمی‌کند.


یک نکته‌ی تکمیلی
در مطلب «ASP.NET 4.5 ScriptManager Improvements in WebForms » مشاهده خواهید کرد که از ASP.NET 4.5 به بعد، طی دو بسته‌ی نیوگت که هر از چندگاهی به روز می‌شوند، کلیه اسکریپت‌های System.Web و System.Web.Extensions خارج از این اسمبلی‌ها نیز قابل دریافت بوده و با استفاده از سیستم bunding & minification می‌توان آن‌ها را فشرده و یکی کرد.
نظرات مطالب
آشنایی و بررسی ابزار Version Manager
با تشکر از کار شما
من این ماژول را نصب کردم اما زمان فعال سازی خطا صادر می‌شود، فایل ActivityLog را بررسی کردم خطای ذیل ثبت شده بود.
<entry>
    <record>5390</record>
    <time>2013/09/09 08:41:39.525</time>
    <type>Error</type>
    <source>VisualStudio</source>
    <description>End package load [VersionManagerPackage]</description>
    <guid>{775E4DAB-A8DC-46E5-A64B-4072C0DD3A42}</guid>
    <hr>80004005 - E_FAIL</hr>
    <errorinfo>Could not load file or assembly 'Microsoft.VisualStudio.Shell.12.0, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.</errorinfo>
  </entry>


نظرات مطالب
چگونه نرم افزارهای تحت وب سریعتری داشته باشیم؟ قسمت پنجم
  1. فشرده سازی قبل از اجرای برنامه (Pre-Compression) یعنی که شما قبل از اینکه برنامه خود را در محیط اصلی نصب و اجرا کنید، فایل‌های اسکریپت آن را فشرده کنید. یعنی کاربران فایل اسکریپت فشرده شده را درخواست و دانلود می‌کنند و عملیات اضافی در سمت سرور انجام نمی‌شود. به عنوان مثال شما از فایل JQuery.min.js به جای jquery.js استفاده کنید. یعنی استفاده از نسخه فشرده شده اسکریپت ها.
  2. فشرده سازی زمان اجرا (Run-time Compression) یعنی فشرده سازی اسکریپت‌های مورد نیاز کاربر توسط خود برنامه وب (به صورت خودکار و یا توسط یک ماژول اضافی). این عمل باعث می‌شود که در هر بار درخواست هر کاربر برای یک فایل، برنامه آن را مجدد فشرده سازی کند (و یا از cache استفاده کند). این عمل به معنی استفاده بیشتر از منابع پر ارزش سرور شما می‌باشد. به عنوان مثال شما بخواهید در هر مرحله درخواست هر کاربر jquery.js را فشرده کنید!
از مقایسه دو حالت بالا مشخص است وقتی شما فقط یکبار اسکریپت‌های خود را فشرده می‌کنید بسیار از حالتی که در هر مرتبه از درخواست کاربران آن را فشرده کنید بهتر است و کمتر منابع سرور را هدر می‌دهد.
مطالب
نگاهی به هویت سنجی کاربران در ASP.NET MVC 5
در مقاله پیش رو، سعی شده‌است به شکلی تقریبا عملی، کلیاتی در مورد Authentication در MVC5 توضیح داده شود. هدف روشن شدن ابهامات اولیه در هویت سنجی MVC5 و حل شدن مشکلات اولیه برای ایجاد یک پروژه است.
در MVC 4 برای دسترسی به جداول مرتبط با اعتبار سنجی (مثلا لیست کاربران) مجبور به استفاده از متدهای از پیش تعریف شده‌ی رفرنس‌هایی که برای آن نوع اعتبار سنجی وجود داشت، بودیم. راه حلی نیز برای دسترسی بهتر وجود داشت و آن هم ساختن مدل‌های مشابه آن جدول‌ها و اضافه کردن چند خط کد به برنامه بود. با اینکار دسترسی ساده به Roles و Users برای تغییر و اضافه کردن محتوای آنها ممکن می‌شد. در لینک زیر توضیحاتی در مورد روش اینکار وجود دارد.
 در MVC5 داستان کمی فرق کرده است. برای درک موضوع پروژه ای بسازید و حالت پیش فرض آن را تغییر ندهید و آن را اجرا کنید و ثبت نام را انجام دهید، بلافاصله تصویر زیر در دیتابیس نمایان خواهد شد.

دقت کنید بعد از ایجاد پروژه در MVC5 دو پکیج بصورت اتوماتیک از طریق Nuget به پروژه شما اضافه میشود:
 Microsoft.AspNet.Identity.Core
Microsoft.AspNet.Identity.EntityFrameWork
عامل اصلی تغییرات جدید، همین دو پکیج فوق است.
 اولین پکیج شامل اینترفیس‌های IUser و IRole است که شامل فیلدهای مرتبط با این دو می‌باشد. همچنین اینترفیسی به نام IUserStore وجود دارد که چندین متد داشته و وظیفه اصلی هر نوع اضافه و حذف کردن یا تغییر در کاربران، بر دوش آن است.
 دومین پکیج هم وظیفه پیاده سازی آن‌چیزی را دارد که در پکیج اول معرفی شده است. کلاس‌های موجود در این پکیج ابزارهایی برای ارتباط EntityFramework با دیتابیس هستند.
اما از مقدمات فوق که بگذریم برای درک بهتر رفتار با دیتابیس یک مثال را پیاده سازی خواهیم کرد.

 فرض کنید میخواهیم چنین ارتباطی را بین سه جدول در دیتابیس برقرار کنیم، فقط به منظور یادآوری، توجه کنید که جدول ASPNetUsers جدولی است که به شکل اتوماتیک پیش از این تولید شد و ما قرار است به کمک یک جدول واسط (AuthorProduct) آن را به جدول Product مرتبط سازیم تا مشخص شود هر کتاب (به عنوان محصول) به کدام کاربر (به عنوان نویسنده) مرتبط است.
 بعد از اینکه مدل‌های مربوط به برنامه خود را ساختیم، اولا نیاز به ساخت کلاس کانتکست نداریم چون خود MVC5 کلاس کانتکست را دارد؛ ثانیا نیاز به ایجاد مدل برای جداول اعتبارسنجی نیست، چون کلاسی برای فیلدهای اضافی ما که علاقمندیم به جدول Users اضافه شود، از پیش تعیین گردیده است.

دو کلاسی که با فلش علامت گذاری شده اند، تنها فایل‌های موجود در پوشه مدل، بعد از ایجاد یک پروژه هستند. فایل IdentityModel را به عنوان فایل کانتکست خواهیم شناخت (چون یکی از کلاسهایش Context است). همانطور که پیش از این گفتیم با وجود این فایل نیازی به ایجاد یک کلاس مشتق شده از DbContext نیست. همانطور که در کد زیر میبینید این فایل دارای دو کلاس است:
namespace MyShop.Models
{
    // You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
    public class ApplicationUser : IdentityUser
    {
    }

    public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext()
            : base("DefaultConnection")
        {
        }
      
}
کلاس اول همان کلاسی است که اگر به آن پراپرتی اضافه کنیم، بطور اتوماتیک آن پراپرتی به جدول ASPNetUsers در دیتابیس اضافه می‌شود و دیگر نگران فیلدهای نداشته‌ی جدول کاربران ASP.NET نخواهیم بود. مثلا در کد زیر چند عنوان به این جدول اضافه کرده ایم.
namespace MyShop.Models
{
    // You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
    public class ApplicationUser : IdentityUser
    {
        [Display(Name = "نام انگلیسی")]
        public string EnglishName { get; set; }

        [Display(Name = "نام سیستمی")]
        public string NameInSystem { get; set; }

        [Display(Name = "نام فارسی")]
        public string PersianName { get; set; }

        [Required]
        [DataType(DataType.EmailAddress)]
        [Display(Name = "آدرس ایمیل")]
        public string Email { get; set; }
     }
}
کلاس دوم نیز محل معرفی مدلها به منظور ایجاد در دیتابیس است. به ازای هر مدل یک جدول در دیتابیس خواهیم داشت. مثلا در شکل فوق سه پراپرتی به جدول کاربران اضافه میشود. دقت داشته باشید با اینکه هیچ مدلی برای جدول کاربران نساخته ایم اما کلاس ApplicatioUsers کلاسی است که به ما امکان دسترسی به مقادیر این جدول را می‌دهد(دسترسی به معنای اضافه و حذف وتغییر مقادیر این جدول است) (در MVC4 به کمک کلاس membership کارهای مشابهی انجام میدادیم)
 در ساختن مدل هایمان نیز اگر نیاز به ارتباط با جدول کاربران باشد، از همین کلاس فوق استفاده میکنیم. کلاس واسط(مدل واسط) بین AspNetUsers و Product در کد زیر زیر نشان داده شده است :
namespace MyShop.Models
{
    public class AuthorProduct
    {
        [Key]
        public int AuthorProductId { get; set; }
       /* public int UserId { get; set; }*/

        [Display(Name = "User")]
        public string ApplicationUserId { get; set; }

        public int ProductID { get; set; }

        public virtual Product Product { get; set; }
    
        public virtual ApplicationUser ApplicationUser { get; set; }
    }
}
همانطور که مشاهده میکنید، به راحتی ارتباط را برقرار کردیم و برای برقراری این ارتباط از کلاس ApplicationUser استفاده کردیم. پراپرتی ApplicationUserId نیز فیلد ارتباطی ما با جدول کاربران است. جدول product هم نکته خاصی ندارد و به شکل زیر مدل خواهد شد.
namespace MyShop.Models
{
    [DisplayName("محصول")]
    [DisplayPluralName("محصولات")]
    public class Product
    {
        [Key]
        public int ProductID { get; set; }

        [Display(Name = "گروه محصول")]
        [Required(ErrorMessage = "لطفا {0} را وارد کنید")]
        public int ProductGroupID { get; set; }

        [Display(Name = "مدت زمان")]
        public string Duration { get; set; }

   
        [Display(Name = "نام تهیه کننده")]
        public string Producer { get; set; }

        [Display(Name = "عنوان محصول")]
        [Required(ErrorMessage = "لطفا {0} را وارد کنید")]
        public string ProductTitle { get; set; }

        [StringLength(200)]
        [Display(Name = "کلید واژه")]
        public string MetaKeyword { get; set; }

        [StringLength(200)]
        [Display(Name = "توضیح")]
        public string MetaDescription { get; set; }

        [Display(Name = "شرح محصول")]
        [UIHint("RichText")]
        [AllowHtml]
        public string ProductDescription { get; set; }

        [Display(Name = "قیمت محصول")]
        [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:#,0 ریال}")]
        [UIHint("Integer")]
        [Required(ErrorMessage = "لطفا {0} را وارد کنید")]
        public int ProductPrice { get; set; }
        [Display(Name = "تاریخ ثبت محصول")]

        public DateTime? RegisterDate { get; set; }

    }
}
به این ترتیب هم ارتباطات را برقرار کرده‌ایم و هم از ساختن یک UserProfile اضافی خلاص شدیم.
برای پر کردن مقادیر اولیه نیز به راحتی از seed موجود در Configuration.cs مربوط به migration استفاده میکنیم. نمونه‌ی اینکار در کد زیر موجود است:
protected override void Seed(MyShop.Models.ApplicationDbContext context)
        {
            context.Users.AddOrUpdate(u => u.Id,
                      new ApplicationUser() {  Id = "1",EnglishName = "MortezaDalil", PersianName = "مرتضی دلیل", UserDescription = "توضیح در مورد مرتضی", Email = "mm@mm.com", Phone = "2323", Address = "test", NationalCode = "2222222222", ZipCode = "2222222222" },
                            new ApplicationUser() { Id = "2", EnglishName = "MarhamatZeinali", PersianName = "محسن احمدی", UserDescription = "توضیح در مورد محسن", Email = "mm@mm.com", Phone = "2323", Address = "test", NationalCode = "2222222222", ZipCode = "2222222222" },
                            new ApplicationUser() { Id = "3", EnglishName = "MahdiMilani", PersianName = "مهدی محمدی", UserDescription = "توضیح در مورد مهدی", Email = "mm@mm.com", Phone = "2323", Address = "test", NationalCode = "2222222222", ZipCode = "2222222222" },
                            new ApplicationUser() { Id = "4", EnglishName = "Babak", PersianName = "بابک", UserDescription = "کاربر معمولی بدون توضیح", Email = "mm@mm.com", Phone = "2323", Address = "test", NationalCode = "2222222222", ZipCode = "2222222222" }
                     
                        );


            context.AuthorProducts.AddOrUpdate(u => u.AuthorProductId,
              new AuthorProduct() { AuthorProductId = 1, ProductID = 1, ApplicationUserId = "2" },
              new AuthorProduct() { AuthorProductId = 2, ProductID = 2, ApplicationUserId = "1" },
              new AuthorProduct() { AuthorProductId = 3, ProductID = 3, ApplicationUserId = "3" }

          );
 می‌توانیم از کلاس‌های خود Identity برای انجام روش فوق استفاده کنیم؛ فرض کنید بخواهیم یک کاربر به نام admin و با نقش admin به سیستم اضافه کنیم.
            if (!context.Users.Where(u => u.UserName == "Admin").Any())
            {
                var roleStore = new RoleStore<IdentityRole>(context);
                var rolemanager = new RoleManager<IdentityRole>(roleStore);

                var userstore = new UserStore<ApplicationUser>(context);
                var usermanager = new UserManager<ApplicationUser>(userstore);
                
                var user = new ApplicationUser {UserName = "Admin"};
                
                usermanager.Create(user, "121212");
                rolemanager.Create(new IdentityRole {Name = "admin"});
                
                usermanager.AddToRole(user.Id, "admin");
            }
   در عبارت شرطی موجود کد فوق، ابتدا چک کردیم که چنین یوزری در دیتابیس نباشد، سپس از کلاس RoleStore که پیاده سازی شده‌ی اینترفیس IRoleStore است استفاده کردیم. سازنده این کلاس به کانتکست نیاز دارد؛ پس به آن context را به عنوان ورودی می‌دهیم. در خط بعد، کلاس rolemanager را داریم که بخشی از پکیج Core است و پیش از این درباره اش توضیح دادیم ( یکی از دو رفرنسی که خوبخود به پروژه اضافه میشوند) و از ویژگی‌های Identity است. به آن آبجکتی که از RoleStore ساختیم را پاس میدهیم و خود کلاس میداند چه چیز را کجا ذخیره کند.
برای ایجاد کاربر نیز همین روند را انجام می‌دهیم. سپس یک آبجکت به نام user را از روی کلاس ApplicationUser میسازیم. برای آن پسورد 121212 سِت میکنیم و نقش ادمین را به آن نسبت میدهیم. این روش قابل تسری به تمامی بخش‌های برنامه شماست. میتوانید عملیات کنترل و مدیریت اکانت را نیز به همین شکل انجام دهید. ساخت کاربر و لاگین کردن یا مدیریت پسورد نیز به همین شکل قابل انجام است.
 بعد از آپدیت دیتابیس تغییرات را مشاهده خواهیم کرد. 
نظرات مطالب
آپلود همزمان چندین فایل در Asp.Net Web Forms
ابتدا تگ input خود را در فرم قرار دهید :
<input type="file" multiple="multiple" name="File1"  id="File1" runat="server" />  
و در پشت فرم می‌توانید با استفاده از یک حلقه ، همه فایل‌های انتخاب شده را آپلود کنید :
 for (int i = 1; i <= Request.Files.Count; i++)
            {
                var file = Request.Files[i];
            }
مطالب
روش کار با فایل‌های ایستا در برنامه‌های React
روش ذکر فایل‌های ایستا در کامپوننت‌های جاوا اسکریپتی برنامه‌های React

React، برای مدیریت پروژه‌ی خود، از Webpack استفاده می‌کند و در این حالت، کار با فایل‌های ایستا مانند تصاویر و قلم‌های وب، شبیه به کار با فایل‌های CSS خواهد بود؛ یعنی این نوع فایل‌ها را باید در فایل‌های جاوا اسکریپتی برنامه، import کرد. به این ترتیب Webpack کار یکی سازی این فایل‌ها را با bundle نهایی تولید شده، انجام می‌دهد.

یک مثال: فرض کنید فایل button.css به صورت زیر تعریف شده‌است:
.Button {
    padding: 20px;
}

برای استفاده‌ی از این فایل css در یک کامپوننت، ابتدا آن‌را import کرده و سپس از classNameهای تعریف شده‌ی در آن استفاده می‌کنیم:
import React, { Component } from 'react';
import './Button.css'; 

class Button extends Component {
  render() {
    return <div className="Button" />;
  }
}
در حالت توسعه، با هر تغییری در این فایل css، بارگذاری مجدد برنامه به صورت خودکار صورت گرفته و نتیجه‌ی نهایی رندر خواهد شد. در حالت نهایی ارائه‌ی برنامه، تمام فایل‌های css، با هم یکی شده و نگارش minified آن‌ها، به bundle نهایی برنامه اضافه می‌شوند. توصیه شده‌است یک فایل css را در چندین کامپوننت برنامه import نکنید. بهتر است یک کامپوننت دکمه را ایجاد کنید که فایل css مشخصی را import می‌کند و سپس از آن کامپوننت در قسمت‌های مختلف برنامه استفاده کنید.

البته برخلاف حالت کار با CSS imports، با import یک فایل ایستا، یک رشته در اختیار ما قرار می‌گیرد که از آن می‌توان در کدهای خود استفاده کرد. برای کاهش تعداد رفت و برگشت‌های به سرور، اگر فایل‌های تصویری با فرمت‌های bmp, gif, jpg, jpeg و  png، کمتر از 10,000 بایت باشند، از data URI آن‌ها بجای مسیر نهایی استفاده خواهد شد. این مورد شامل فایل‌های svg نمی‌شود.

یک مثال:
import React from 'react';
import logo from './logo.svg'; 

console.log(logo);

function Header() {
  return <img src={logo} alt="Logo" />;
}

export default Header;
در اینجا ابتدا یک فایل تصویری، import شده‌است. سپس می‌توان از رشته‌ی متناظر با آن، به عنوان src المان تصویر استفاده کرد.

این مورد برای تصاویر ذکر شده‌ی در فایل‌های CSS نیز صادق است:
.Logo {
    background-image: url(./logo.png);
}
Webpack در فایل‌های CSS به دنبال مسیرهای فایل‌های ثابت شروع شده‌ی با /. می‌گردد و مسیرهای این نوع فایل‌ها را با مسیر نهایی ارائه‌ی برنامه، به صورت خودکار جایگزین و اصلاح می‌کند. همچنین نیازی هم به نگرانی در مورد کش شدن این فایل‌های ثابت وجود ندارد؛ چون webpack از نام‌های خاصی به همراه hash این نوع فایل‌ها، برای جایگزینی نهایی استفاده خواهد کرد و اگر محتوای فایل‌های ثابت تغییر کنند، این هش نیز تغییر کره و مرورگر نگارش جدید آن‌ها را دریافت می‌کند. مزیت دیگر کار با webpack، ارائه‌ی خطاهای زمان کامپایل برنامه است. برای مثال اگر فایل‌های ثابت مورد استفاده‌ی در برنامه به درستی مسیر دهی نشده باشند، یک خطای زمان کامپایل صادر می‌شود.

یک مثال: فرض کنید در برنامه‌ی ASP.NET Core خود که با React یکی شده‌است، فایل project_folder/ClientApp/src/images/progress_bar.gif را قرار داده‌اید. روش import آن با توجه به مسیرهای نسبی برنامه به صورت زیر است:
import progressBar from '../images/progress_bar.gif';
و روش فراخوانی آن در کدهای یک کامپوننت به نحو زیر خواهد بود:
<img alt="loading..." src={progressBar} />


روش ذکر فایل‌های ایستا در کامپوننت‌های تایپ اسکریپتی برنامه‌های React

اگر از تایپ‌اسکریپت استفاده می‌کنید، چنین importهایی سبب بروز خطای «'Cannot find module './logo.png» می‌شوند. برای رفع این مشکل، فایلی را به نام assets.d.ts به پروژه‌ی خود اضافه کرده و آن‌را به صورت زیر تکمیل کنید:
declare module "*.gif";
declare module "*.jpg";
declare module "*.jpeg";
declare module "*.png";
declare module "*.svg";
به این ترتیب پسوند‌های فایل‌های مختلف ایستا، به عنوان فرمت‌های مجاز ماژول‌ها، قابل استفاده می‌شوند.


نحوه‌ی پردازش پوشه‌ی ویژه‌ی public در برنامه‌های React

اگر فایلی در پوشه‌ی ویژه‌ی public برنامه‌های react قرار گیرد، توسط webpack پردازش نخواهد شد. در این حالت این نوع فایل‌ها بدون هیچ نوع تغییری به پوشه‌ی build نهایی کپی می‌شوند. بنابراین برای کار با فایل‌های ایستای قرار گرفته‌ی در پوشه‌ی public باید از متغیر خاصی به نام PUBLIC_URL استفاده کرد. برای مثال درون فایل index.html، چنین تعریفی را می‌توان مشاهده کرد:
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
اگر نیاز به استفاده‌ی از فایلی درون پوشه‌ی src و یا node_modules دارید، باید آن‌ها را به این پوشه کپی کنید تا جزئی از پروسه‌ی build شوند. متغیر PUBLIC_URL در زمان اجرای دستور npm run build، با مسیر صحیحی جایگزین خواهد شد.
برای دسترسی به این مسیر در کامپوننت‌های برنامه نیز می‌توان از متغیر محیطی process.env.PUBLIC_URL استفاده کرد:
render() {
    return <img src={process.env.PUBLIC_URL + '/img/logo.png'} />;
}
البته روش توصیه شده، همان ذکر importهای فایل‌های ایستا است و بهتر است از این متغیر محیطی زیاد استفاده نکنید؛ چون پردازش ثانویه‌ای بر روی آن‌ها صورت نمی‌گیرد و یا minified نمی‌شوند. نبود آن‌ها سبب بروز خطای زمان کامپایل نخواهد شد و همچنین هیچ hash ای به نام نهایی آن‌ها به صورت خودکار اضافه نمی‌گردد که ممکن است سبب بروز مشکلات کش شدن طولانی مدت این فایل‌های ایستا شود.

بنابراین اکنون این سؤال مطرح می‌شود که چه زمانی بهتر است از پوشه‌ی public استفاده شود؟
- اگر می‌خواهید نام فایل نهایی ایستای مدنظر مانند manifest.json، بدون تغییر باقی بماند.
- هزاران فایل ایستا را دارید و می‌خواهید این مسیرها را به صورت پویا در برنامه فراخوانی کنید (و قرار نیست جزئی از bundle نهایی شوند).
- می‌خواهید فایل‌های js خاصی را خارج از سیستم bundle اصلی قرار دهید؛ چون به هر دلیلی این نوع فایل‌ها با سیستم webpack سازگاری ندارند و نباید توسط آن پردازش شوند. در این حالت باید این نوع فایل‌ها را با تگ script به فایل index.html به صورت دستی معرفی کنید.
مطالب
آشنایی و استفاده از WCF Data Services در Visualstudio 2012
مقدمه:

WCF Data Services جزئی از NET Framework است که امکان ایجاد سرویس دهنده‌های با قرارداد OData را به روی وب یا Intranet با استفاده از REST مهیا می‌سازد. OData از داده هایی که با Url آدرس پذیر هستند استفاده می‌نماید. دسترسی و تغییر داده‌ها با استفاده از استاندارد HTTP و کلمات GET، PUT، POST و DELETE صورت می‌پذیرد. برای اینکه درک بهتری داشته باشید به یک مثال می‌پردازیم.

ایجاد یک برنامه سرویس دهنده WCF Data Service در 2012 VisualStudio
  1. یک ASP.NET Web Application با نام NorthwindService ایجاد نمایید و بر روی پروژه راست کلیک کنید و از منوی Add گزینه New Item را انتخاب نمایید  از پنجره باز شده از دسته Data گزینه ADO.NET Entity Data Model  را انتخاب و نام ان را Northwind بگذارید.
  2. از پنجره باز شده Generate from Databaseرا انتخاب و با انتخاب کانکشن از نوع Sql Server Compact 4  اتصال به فایل Northwind.sdf را انتخاب تا کلاس‌های لازم تولید شود.
  3. برای تولید data service بر روی پروژه راست کلیک کنید و از منوی Add گزینه New Item را انتخاب نمایید از پنجره باز شده گزینه  WCF Data Service را انتخاب و نام آن را Northwind.svc بگذارید. کد زیر خودکار تولید می‌شود
     public class Northwind : DataService< /* TODO: put your data source class name here */ >
        {
            // This method is called only once to initialize service-wide policies.
            public static void InitializeService(DataServiceConfiguration config)
            {
                // TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
                // Examples:
                // config.SetEntitySetAccessRule("MyEntityset", EntitySetRights.AllRead);
                // config.SetServiceOperationAccessRule("MyServiceOperation", ServiceOperationRights.All);
                config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
            }
        }
  4. برای دسترسی به موجودیت‌های Northwind بجای عبارت put your data source نام مدل را تایپ کنید
    public class Northwind : DataService<NorthwindEntities>
  5. برای فعال کردن دسترسی به منابع data source متغیر config کلاس DataServiceConfiguration را بصورت زیر تنظیم نمایید. تابع SetEntitySetAccessRule با گرفتن نام موجودیت و نحوه دسترسی امکان استفاده از این موجودیت را با استفاده از WCF Data Service فزاهم می‌نمایید. مثلا در زیر امکان دسترسی به موجودیت Orders را با امکان خواندن همه، نوشتن ادقامی و جایگزین فراهم نموده است.
    config.SetEntitySetAccessRule("Orders", EntitySetRights.AllRead 
         | EntitySetRights.WriteMerge 
         | EntitySetRights.WriteReplace );
    config.SetEntitySetAccessRule("Customers", EntitySetRights.AllRead);
  6. اگر بخواهیم امکان خواندن همه موجودیت‌ها را فراهم کنیم از کد زیر می‌توانیم استفاده نمایید که * به معنای همه موجودیت‌های data model می‌باشد
    config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);

دسترسی به WCF Data Service بوسیله مرورگر وب
برای دسترسی به وب سرویس برنامه را اجرا نمایید تا آدرس http://localhost:8358/Northwind.svc مشخصات وب سرویس را نمایش دهد
<service xmlns="http://www.w3.org/2007/app" xmlns:atom="http://www.w3.org/2005/Atom" xml:base="http://localhost:8358/Northwind.svc/">
<workspace>
<atom:title>Default</atom:title>
<collection href="Categories">
<atom:title>Categories</atom:title>
</collection>
<collection href="Customers">
<atom:title>Customers</atom:title>
</collection>
<collection href="Employees">
<atom:title>Employees</atom:title>
</collection>
<collection href="Order_Details">
<atom:title>Order_Details</atom:title>
</collection>
<collection href="Orders">
<atom:title>Orders</atom:title>
</collection>
<collection href="Products">
<atom:title>Products</atom:title>
</collection>
<collection href="Shippers">
<atom:title>Shippers</atom:title>
</collection>
<collection href="Suppliers">
<atom:title>Suppliers</atom:title>
</collection>
</workspace>
</service>
 حال اگر آدرس را به http://localhost:8358/Northwind.svc/Products وارد نمایید لیست کالا‌ها بصورت Atom xml قابل دسترس می‌باشد.
ایجاد یک برنامه گیرنده WCF Data Service در Visual Studio 2012
  1. بر روی Solution پروژه جاری راست کلیک و از منوی Add گزینه New Project را انتخاب و یک پروژه از نوع WPF Application با نام NorthwindClient ایجاد نمایید.
  2. در پنجره MainWindow مانند کد زیر از یک Combobox و DataGrid برای نمایش اطلاعات استفاده نمایید
        <Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Northwind Orders" Height="335" Width="425" 
            Name="OrdersWindow" Loaded="Window1_Loaded">
        <Grid Name="orderItemsGrid">
            <ComboBox DisplayMemberPath="Order_ID" ItemsSource="{Binding}"
                      IsSynchronizedWithCurrentItem="true" 
                      Height="23" Margin="92,12,198,0" Name="comboBoxOrder" VerticalAlignment="Top"/>
            <DataGrid ItemsSource="{Binding Path=Order_Details}"  
                      CanUserAddRows="False" CanUserDeleteRows="False"  
                      Name="orderItemsDataGrid" Margin="34,46,34,50"
                      AutoGenerateColumns="False">
                <DataGrid.Columns>
                    <DataGridTextColumn  Header="Product" Binding="{Binding Product_ID, Mode=OneWay}" />
                    <DataGridTextColumn  Header="Quantity" Binding="{Binding Quantity, Mode=TwoWay}" />
                    <DataGridTextColumn  Header="Price" Binding="{Binding UnitPrice, Mode=TwoWay}" />
                    <DataGridTextColumn  Header="Discount" Binding="{Binding Discount, Mode=TwoWay}" />                
                </DataGrid.Columns>     
            </DataGrid>
            <Label Height="28" Margin="34,12,0,0" Name="orderLabel" VerticalAlignment="Top" 
                   HorizontalAlignment="Left" Width="65">Order:</Label>
            <StackPanel Name="Buttons" Orientation="Horizontal" HorizontalAlignment="Right" 
                        Height="40" Margin="0,257,22,0">
                <Button Height="23" HorizontalAlignment="Right" Margin="0,0,12,12" 
                    Name="buttonSave" VerticalAlignment="Bottom" Width="75" 
                        Click="buttonSaveChanges_Click">Save Changes
                </Button>
                <Button Height="23" Margin="0,0,12,12" 
                    Name="buttonClose" VerticalAlignment="Bottom" Width="75" 
                        Click="buttonClose_Click">Close</Button>
            </StackPanel>
        </Grid>
    </Window>

  3. برای ارجاع به wcf data service بر روی پروژه راست کلیک و گزینه Add Service Reference را انتخاب نمایید در پنجره باز شده گزینه Discover را انتخاب تا سرویس را یافته و نام Namespase را Northwind بگذارید.
  4. حال مانند کد زیر یک شی از مدل NorthwindEntities با آدرس وب سرویس ایجاد نموده ایم و نتیحه کوئری با استفاده از کلاس DataServiceCollection به DataContext گرید انتصاب داده ایم که البته پیش فرض آن آشنایی با DataBinding در WPF است.
            private NorthwindEntities context;
            private string customerId = "ALFKI";
            private Uri svcUri = new Uri("http://localhost:8358/Northwind.svc");
    
            private void Window1_Loaded(object sender, RoutedEventArgs e)
            {
                try
                {
                    context = new NorthwindEntities(svcUri);
                    var ordersQuery = from o in context.Orders.Expand("Order_Details")
                                      where o.Customers.Customer_ID == customerId
                                      select o;
                    DataServiceCollection<Orders> customerOrders = new DataServiceCollection<Orders>(ordersQuery);
                    this.orderItemsGrid.DataContext = customerOrders;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }
    
  5. با صدا زدن تابع SaveChanges مدل می‌توانید تغییرات را در پایگاه داده ذخیره نمایید.
    private void buttonSaveChanges_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            context.SaveChanges();
        }
        catch (DataServiceRequestException ex)
        {
            MessageBox.Show(ex.ToString());
    
        }
    }

  1. برنامه را اجرا نمایید تا خروجی کار را مشاهده نمایید. مقادیر Quantity را تغییر دهید و دکمه Save Changes را انتخاب تا تغییرات دخیره شود.
در اینجا در یک برنامه ویندوزی استفاده از WCF Data Service را تست نمودیم اما براحتی به همین شیوه در یک برنامه وب نیز قابل استفاده است.  
نظرات مطالب
ASP.NET MVC #18
از تگ authorization در وب کانفیگ برنامه‌های ASP.NET MVC استفاده نکنید. این تنظیم بیشتر مربوط به برنامه‌های وب فرم است تا MVC (در اینجا فقط جهت یادآوری عنوان شده).
در برنامه‌های MVC فیلتر Authorize را به صورت Global تعریف کنید: «... امکان تعریف AuthorizeAttribute در فایل global.asax.cs و متد RegisterGlobalFilters آن به صورت سراسری نیز وجود دارد ...»
نظرات مطالب
فرم‌های مبتنی بر قالب‌ها در Angular - قسمت چهارم - اعتبارسنجی ورودی‌ها
یک نکته‌ی تکمیلی
در صورتی که تعداد فیلد‌های فرم زیاد باشد با غیر فعال کردن دکمه submit کاربر نمی‌تواند تشخیص دهد که کدام المان ورودی را باید مقدار دهی کند یک راه حل این است که در کنار المان‌های که required  می‌باشند یک * قرمز رنگ قرار دهیم . 
راه حل دوم این است که کاربر با زدن submit  خطاهای فرم را مشاهده کند : 
// student-model.ts
export interface Student {
    id: number;
    name: string;
}
کامپوننت : 
  // app.component.ts
  public model: Student;

  ngOnInit(): void {
    this.setDefaultValueForModel();
  }

  saveForm(form: NgForm, evetn: Event) {
    evetn.preventDefault();
    if (form.valid) {
      alert('everything is ok');
    }
  }

  setDefaultValueForModel() {
    this.model = {
      id: 1,
      name: ''
    };
  }
و در نهایت محتوای app.component.html
        <form #form="ngForm" novalidate (submit)="saveForm(form,$event)">
          <div>
            <label>Name</label>
            <input type="text" required name="name" autocomplete="off" [(ngModel)]="model.name" #name="ngModel">

            <p [hidden]="name.valid || (name.pristine && !form.submitted)">
              Name is required and should be minimum 4 characters.
            </p>

          </div>

          <div>
            <input type="submit" value="submit">
          </div>
        </form>