اشتراک‌ها
طراحی افزونه پذیر و ماژولار در Asp.net core

ExtCore allows you to decouple your application into the modules (or extensions) and reuse that modules in other applications in various combinations. Each ExtCore extension may consist of one or more projects and each project may include everything you want (as any other ASP.NET Core project). Controllers, view components, views (added as resources and/or precompiled), static content (added as resources) will be resolved automatically. These projects (extension pieces) may be added to the application directly as dependencies in project.json of your main application project (as source code or NuGet packages), or by copying compiled DLL-files to the Extensions folder. ExtCore supports both of these approaches out of the box and at the same time. 

طراحی افزونه پذیر و ماژولار در Asp.net core
اشتراک‌ها
15 کتابخانه LightBox واکنشگرا مناسب برای گوشی های همراه
 Lightbox is one popular way to overlay images on the web. When you click on an image, the Lightbox pops up with some form of animation, and dims the background so your focus is on the image itself. The image is also larger in scale. Most popular Lightbox JavaScript libraries that we have known for years let you do this well on desktop, but not so much on mobile platform
15 کتابخانه LightBox واکنشگرا مناسب برای گوشی های همراه
اشتراک‌ها
Entity Framework Core 8 منتشر شد

EF Core 8, or just EF8, is the successor to EF Core 7. EF8 requires .NET 8. It will not work with .NET 6 or 7, or with any version of .NET Framework. 

Entity Framework Core 8 منتشر شد
اشتراک‌ها
شرکت اینتل 15000 کارمند خود را تعدیل می‌کند

Intel’s on a long, long road to recovery, and over 15,000 workers will no longer be coming along for the ride. The chipmaker just announced it’s downsizing its workforce by over 15 percent as part of a new $10 billion cost savings plan for 2025, which will mean a headcount reduction of greater than 15,000 roles, Intel tells The Verge. The company currently employs over 125,000 workers, so layoffs could be as many as 19,000 people.

شرکت اینتل 15000 کارمند خود را تعدیل می‌کند
اشتراک‌ها
چرا برنامه نویسان باید زبان Golang را یاد بگیرند

Go, also referred to as Golang is a program created by Google. It was designed by Ken Thompson, Rob Pike, and Robert Griesmer. Golang is one of the most rapidly growing languages in terms of popularity. Ken Thompson, Rob Pike, and Robert Griesmer created Go Language to be a language that has numerous cores, implements concurrency easily, works smoothly in a distributed environment and allows the programmer to write programs without too much hustle. Go language also has a lean and user-friendly syntax. 

چرا برنامه نویسان باید زبان Golang را یاد بگیرند
نظرات مطالب
Blazor 5x - قسمت 14 - کار با فرم‌ها - بخش 2 - تعریف فرم‌ها و اعتبارسنجی آن‌ها
یک نکته‌ی تکمیلی: روش سازگار کردن اعتبارسنجی فرم‌های استاندارد Blazor با کلاس‌های CSS بوت استرپ 4 و 5
زمانیکه از EditForm و کامپوننت‌های توکار Blazor استفاده می‌کنیم، اگر کامپوننتی در وضعیت اعتبارسنجی شده قرار داشته باشد، با کلاس valid:
class="modified valid form-control"
و اگر در وضعیت شکست اعتبارسنجی قرارگیرد، با کلاس invalid مزین می‌شود:
class="modified invalid form-control"
اما برای یکپارچه سازی آن با کلاس‌های اعتبارسنجی بوت استرپ 4 و 5، نیاز است از کلاس‌های is-valid و is-invalid بجای valid و invalid استفاده شود. این تغییر نیاز به استفاده از «یک نکته‌ی تکمیلی: امکان اعتبارسنجی دستی فرم‌ها در Blazor» را دارد؛ چون با دسترسی به EditContext است که می‌توان CSS provider آن‌را سفارشی سازی کرد؛ برای مثال:
EditContext = new EditContext(Model);
EditContext.SetFieldCssClassProvider(new BootstrapFieldCssClassProvider());
که سفارشی ساز مخصوص بوت استرپ، به صورت زیر قابل تعریف است:
using System;
using System.Linq;
using Microsoft.AspNetCore.Components.Forms;

namespace BlazorComponents
{
    /// <summary>
    /// Supplies CSS class names for form fields to represent their validation state or other state information from an EditContext.
    /// </summary>
    public class BootstrapFieldCssClassProvider : FieldCssClassProvider
    {
        /// <summary>
        /// Gets a string that indicates the status of the specified field as a CSS class.
        /// </summary>
        public override string GetFieldCssClass(EditContext editContext, in FieldIdentifier fieldIdentifier)
        {
            if (editContext == null)
            {
                throw new ArgumentNullException(nameof(editContext));
            }

            var isValid = !editContext.GetValidationMessages(fieldIdentifier).Any();

            if (editContext.IsModified(fieldIdentifier))
            {
                return isValid ? "is-valid" : "is-invalid";
            }
            return isValid ? "" : "is-invalid";
        }
    }
}
در اینجا در ابتدا بررسی می‌شود که آیا فیلد جاری معتبر است یا خیر و همچنین آیا ویرایش شده‌است یا خیر؟ سپس بر این اساس، کلاس‌های ویژه‌ی بوت استرپ، بجای کلاس‌های پیش‌فرض ارائه خواهند شد.
مطالب
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 }
    );
}

اشتراک‌ها
بایندینگ به شیوه ASP.NET MVC در ASP.NET WEB API

This lets you do things that you can’t do in WebAPI’s default binder, specifically:

  1. ModelBinds everything, including the body. Assumes the body is FormUrl encoded
  2. This means you can do MVC scenarios where a complex type is bound with one field from the query string and one field from the form data in the body.
  3. Allows multiple parameters to be bound from the body. 
بایندینگ به شیوه ASP.NET MVC در ASP.NET WEB API
اشتراک‌ها
انتشار ReSharper Ultimate 2018.3.2

ReSharper 2018.3.2 bug-fix update fixes:

- Many issues in C#, VB.NET, and TypeScript Code Analysis.
- More than a dozen issues related to parameter name hints.
- Missing “Find Code Dependent on Module” item in a context menu for a project node in the Solution Explorer tab.
- Several issues in Unit Testing.
- Some issues related to auto-detect naming style.
 

انتشار ReSharper Ultimate 2018.3.2