اشتراک‌ها
کتابخانه های برنامه های Front-End و معماری کامپوننت ها

Component architectures are an important part of ever modern front-end framework. In this article, I’m going to dissect Polymer, React, Rio.js, Vue.js, Aurelia and Angular 2 components. The goal is to make the commonalities between each solution obvious. Hopefully, this will convince you that learning one or the other isn’t all that complex, given that everyone has somewhat settled on a component architecture. 

کتابخانه های برنامه های Front-End و معماری کامپوننت ها
بازخوردهای پروژه‌ها
Fill and FillByObject
متود زیر برای تولید عبارت مبتنی بر الگو زمانی که الگو پیچیده‌تر از این است که بشود با string.Format به راحتی پیاده سازی شود ولی چندان هم پیچیده نیست که ابزارهای حرفه ای‌تری مانند T4 یا Razor به کار بیایند، میتواند مورد استفاده قرار گیرد:
        /// <summary>
        /// Insert values from an object into a string pattern. To specify the object's property you have to use the '{propertyName}'.
        /// </summary>
        /// <remarks>
        /// This method is a replacement to String.Format, but it has two differences:
        /// <list type="simple">
        /// <item>It reverese the order you call the functionality, instead of writing String.Format(pattern, args) you write pattern.FillByObject(args). This makes the code look cleaner.</item>
        /// <item>You supply the pattern with an object and specify insertion points by property names.</item>
        /// </list>
        /// <example>
        /// <![CDATA[
        /// "First name:{firstName}, Sur name:{Surname}".FillByObject(new {firstName = "Sam", lastName="Naseri"});
        /// ]]>
        /// </example>
        /// </remarks>
        /// <seealso cref="Fill"/>
        /// <typeparam name="T">Type of bindingValue.</typeparam>
        /// <param name="bindingPattern">The pattern to fill.</param>
        /// <param name="bindingValue">The object providing values to fill in the pattern.</param>
        /// <returns>The pattern filled with values.</returns>
        public static string FillByObject<T>(this string bindingPattern, T bindingValue)
        {
            var properties = GetProperties(typeof(T)).ToList();
            var values = properties.Select(property => property.GetValue(bindingValue, new object[] { })).ToList();
            var result = bindingPattern;
            for (int index = 0; index < properties.Count; index++)
            {
                var property = properties[index];
                var propPattern = "{" + property.Name + "}";
                var old = result;
                result = result.Replace(propPattern, values[index] != null ? values[index].ToString() : "");
            }
            return result;
        }

پیاده سازی فوق یک پیاده سازی بسیار خام و بسیار کند است و جای بهبود زیادی دارد. من فقط برای سناریوهای ساده که کارایی مطرح نیست استفاده از متود فوق را توصیه میکنم.
متودهای جانبی مورد نیاز:
private static IEnumerable<PropertyInfo> GetProperties(Type t)
{
    return t.GetProperties(BindingFlags.Public | BindingFlags.Instance);
}

همچنین متود زیر هم میتواند نوشتن string.Format را یک خرده ساده‌تر کند:
/// <summary>
/// A simple replacement for String.Format which only makes the codes look nicer.
/// </summary>
/// <param name="pattern">The source string that you want to replace insertion points on it.</param>
/// <param name="args">Values to be replaced in the pattern.</param>
/// <returns></returns>
public static string Fill(this string pattern, params object[] args)
{
    return string.Format(pattern, args);
}

مطالب
CoffeeScript #10

اصطلاحات عمومی CoffeeScript

Destructuring Assignments

با استفاده از Destructuring assignments می‌توانید خصوصیات را از آرایه‌ها یا اشیاء، با هر میزان عمقی استخراج کنید.

someObject = { a: 'value for a', b: 'value for b' }
{ a, b } = someObject
console.log "a is '#{a}', b is '#{b}'"
نتیجه‌ی کامپایل آن می‌شود:
var a, b, someObject;

someObject = {
  a: 'value for a',
  b: 'value for b'
};

a = someObject.a, b = someObject.b;

console.log("a is '" + a + "', b is '" + b + "'");
این موضوع به خصوص در برنامه‌های کاربردی، وقتی نیاز به ماژول‌های دیگر است، مفید خواهد بود.
{join, resolve} = require('path')

join('/Users', 'Vahid')

External libraries

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

# Use local alias
$ = jQuery

$ ->
  # DOMContentLoaded
  $(".el").click ->
    alert("Clicked!")
نتیجه‌ی کامپایل آن می‌شود:
var $;
$ = jQuery;
$(function() {
  return $(".el").click(function() {
    return alert("Clicked!");
  });
});
از آنجاییکه خروجی همه کدهای CoffeeScript در داخل یک تابع بدون نام قرار می‌گیرد، می‌توانیم از یک متغیر محلی به نام $ به عنوان نام مستعار jQuery استفاده کنیم. این کار به شما کمک می‌کند تا حتی وقتی که حالت jQuery.noConflict نیز فراخوانی شده باشد، $ مجدد تعریف شده و اسکریپت ما به طور کامل اجرا شود.

Private variables

کلمه‌ی کلید do در CoffeeScript به ما اجازه می‌دهد تا توابع را مستقیما اجرا کنیم و این روش یک راه خوب برای کپسوله سازی و حفاظت از متغیرهاست. در مثال زیر متغیر classToType را در context یک تابع بدون نام که به وسیله‌ی do فراخوانی می‌شود، تعریف کرده‌ایم. تابع بدون نام دوم، مقدار نهایی از type است را برمی گرداند. از آنجایی که classToType در context تعریف شده است و هیچ ارجایی به آن نگهداری نمی‌شود، پس امکان دسترسی به آن خارج از این scope وجود ندارد.
# Execute function immediately
type = do ->
  classToType = {}
  for name in "Boolean Number String Function Array Date RegExp Undefined Null".split(" ")
    classToType["[object " + name + "]"] = name.toLowerCase()

  # Return a function
  (obj) ->
    strType = Object::toString.call(obj)
    classToType[strType] or "object"
نتیجه‌ی کامپایل آن می‌شود:
var type;

type = (function() {
  var classToType, i, len, name, ref;
  classToType = {};
  ref = "Boolean Number String Function Array Date RegExp Undefined Null".split(" ");
  for (i = 0, len = ref.length; i < len; i++) {
    name = ref[i];
    classToType["[object " + name + "]"] = name.toLowerCase();
  }
  return function(obj) {
    var strType;
    strType = Object.prototype.toString.call(obj);
    return classToType[strType] || "object";
  };
})();
به بیان دیگر classToType به طور کامل private است و امکان دسترسی به آن از طریق تابع بدون نام اجرا کننده وجود ندارد. این الگو راه بسیار خوب و مناسبی برای کپسوله سازی scope و مخفی سازی متغیرها است.
مطالب
EF Code First #11

استفاده از الگوی Repository اضافی در EF Code first؛‌ آری یا خیر؟!

اگر در ویژوال استودیو، اشاره‌گر ماوس را بر روی تعریف DbContext قرار دهیم، راهنمای زیر ظاهر می‌شود:

A DbContext instance represents a combination of the Unit Of Work and Repository patterns such that 
it can be used to query from a database and group together changes that will then be written back to
the store as a unit. DbContext is conceptually similar to ObjectContext.

در اینجا تیم EF صراحتا عنوان می‌کند که DbContext در EF Code first همان الگوی Unit Of Work را پیاده سازی کرده و در داخل کلاس‌ مشتق شده از آن، DbSet‌ها همان Repositories هستند (فقط نام‌ها تغییر کرده‌اند؛ اصول یکی است).
به عبارت دیگر با نام بردن صریح از این الگوها، مقصود زیر را دنبال می‌کنند:
لطفا بر روی این لایه Abstraction ایی که ما تهیه دیده‌ایم، یک لایه Abstraction دیگر را ایجاد نکنید!
«لایه Abstraction دیگر» یعنی پیاده سازی الگوهای Unit Of Work و Repository جدید، برفراز الگوهای Unit Of Work و Repository توکار موجود!
کار اضافه‌ای که در بسیاری از سایت‌ها مشاهده می‌شود و ... متاسفانه اکثر آن‌ها هم اشتباه هستند! در ذیل روش‌های تشخیص پیاده سازی‌های نادرست الگوی Repository را بر خواهیم شمرد:
1) قرار دادن متد Save تغییرات نهایی انجام شده، در داخل کلاس Repository
متد Save باید داخل کلاس Unit of work تعریف شود نه داخل کلاس Repository. دقیقا همان کاری که در EF Code first به درستی انجام شده. متد SaveChanges توسط DbContext ارائه می‌شود. علت هم این است که در زمان Save ممکن است با چندین Entity و چندین جدول مشغول به کار باشیم. حاصل یک تراکنش، باید نهایتا ذخیره شود نه اینکه هر کدام از این‌ها، تراکنش خاص خودشان را داشته باشند.
2) نداشتن درکی از الگوی Unit of work
به Unit of work به شکل یک تراکنش نگاه کنید. در داخل آن با انواع و اقسام موجودیت‌ها از کلاس‌ها و جداول مختلف کار شده و حاصل عملیات، به بانک اطلاعاتی اعمال می‌گردد. پیاده سازی‌های اشتباه الگوی Repository، تمام امکانات را در داخل همان کلاس Repository قرار می‌دهند؛ که اشتباه است. این نوع کلاس‌ها فقط برای کار با یک Entity بهینه شده‌اند؛ در حالیکه در دنیای واقعی، اطلاعات ممکن است از دو Entity مختلف دریافت و نتیجه محاسبات مفروضی به Entity سوم اعمال شود. تمام این عملیات یک تراکنش را تشکیل می‌دهد، نه اینکه هر کدام، تراکنش مجزای خود را داشته باشند.
3) وهله سازی از DbContext به صورت مستقیم داخل کلاس Repository
4) Dispose اشیاء DbContext داخل کلاس Repository
هر بار وهله سازی DbContext مساوی است با باز شدن یک اتصال به بانک اطلاعاتی و همچنین از آنجائیکه راهنمای ذکر شده فوق را در مورد DbContext مطالعه نکرده‌اند، زمانیکه در یک متد با سه وهله از سه Repository موجودیت‌های مختلف کار می‌کنید، سه تراکنش و سه اتصال مختلف به بانک اطلاعاتی گشوده شده است. این مورد ذاتا اشتباه است و سربار بالایی را نیز به همراه دارد.
ضمن اینکه بستن DbContext در یک Repository، امکان اعمال کوئری‌های بعدی LINQ را غیرممکن می‌کند. به ظاهر یک شیء IQueryable در اختیار داریم که می‌توان بر روی آن انواع و اقسام کوئری‌های LINQ را تعریف کرد اما ... در اینجا با LINQ to Objects که بر روی اطلاعات موجود در حافظه کار می‌کند سر و کار نداریم. اتصال به بانک اطلاعاتی با بستن DbContext قطع شده، بنابراین کوئری LINQ بعدی شما کار نخواهد کرد.
همچنین در EF نمی‌توان یک Entity را از یک Context به Context‌ دیگری ارسال کرد. در پیاده سازی صحیح الگوی Repository (دقیقا همان چیزی که در EF Code first به صورت توکار وجود دارد)، Context باید بین Repositories که در اینجا فقط نامش DbSet تعریف شده، به اشتراک گذاشته شود. علت هم این است که EF از Context برای ردیابی تغییرات انجام شده بر روی موجودیت‌ها استفاده می‌کند (همان سطح اول کش که در قسمت‌های قبل به آن اشاره شد). اگر به ازای هر Repository یکبار وهله سازی DbContext انجام شود، هر کدام کش جداگانه خاص خود را خواهند داشت.
5) عدم امکان استفاده از تنها یک DbConetext به ازای یک Http Request
هنگامیکه وهله سازی DbContext به داخل یک Repository منتقل می‌شود و الگوی واحد کار رعایت نمی‌گردد، امکان به اشتراک گذاری آن بین Repositoryهای تعریف شده وجود نخواهد داشت. این مساله در برنامه‌های وب سبب کاهش کارآیی می‌گردد (باز و بسته شدن بیش از حد اتصال به بانک اطلاعاتی در حالیکه می‌شد تمام این عملیات را با یک DbContext انجام داد).

نمونه‌ای از این پیاده سازی اشتباه را در اینجا می‌توانید پیدا کنید. متاسفانه شبیه به همین پیاده سازی، در پروژه MVC Scaffolding نیز بکارگرفته شده است.


چرا تعریف لایه دیگری بر روی لایه Abstraction موجود در EF Code first اشتباه است؟

یکی از دلایلی که حین تعریف الگوی Repository دوم بر روی لایه موجود عنوان می‌شود، این است:
«به این ترتیب به سادگی می‌توان ORM مورد استفاده را تغییر داد» چون پیاده سازی استفاده از ORM، در پشت این لایه مخفی شده و ما هر زمان که بخواهیم به ORM دیگری کوچ کنیم، فقط کافی است این لایه را تغییر دهیم و نه کل برنامه‌ را.
ولی سؤال این است که هرچند این مساله از هزار فرسنگ بالاتر درست است، اما واقعا تابحال دیده‌اید که پروژه‌ای را با یک ORM شروع کنند و بعد سوئیچ کنند به ORM دیگری؟!
ضمنا برای اینکه واقعا لایه اضافی پیاده سازی شده انتقال پذیر باشد، شما باید کاملا دست و پای ORM موجود را بریده و توانایی‌های در دسترس آن را به سطح نازلی کاهش دهید تا پیاده سازی شما قابل انتقال باشد. برای مثال یک سری از قابلیت‌های پیشرفته و بسیار جالب در NH هست که در EF نیست و برعکس. آیا واقعا می‌توان به همین سادگی ORM مورد استفاده را تغییر داد؟ فقط در یک حالت این امر میسر است: از قابلیت‌های پیشرفته ابزار موجود استفاده نکنیم و از آن در سطحی بسیار ساده و ابتدایی کمک بگیریم تا از قابلیت‌های مشترک بین ORMهای موجود استفاده شود.
ضمن اینکه مباحث نگاشت کلاس‌ها به جداول را چکار خواهید کرد؟ EF راه و روش خاص خودش را دارد، NH چندین و چند روش خاص خودش را دارد! این‌ها به این سادگی قابل انتقال نیستند که شخصی عنوان کند: «هر زمان که علاقمند بودیم، ORM مورد استفاده را می‌شود عوض کرد!»

دلیل دومی که برای تهیه لایه اضافه‌تری بر روی DbContext عنوان می‌کنند این است:
«با استفاده از الگوی Repository نوشتن آزمون‌های واحد ساده‌تر می‌شود». زمانیکه برنامه بر اساس Interfaceها کار می‌کند می‌توان آن‌ها را بجای اشاره به بانک اطلاعاتی، به نمونه‌ای موجود در حافظه، در زمان آزمون تغییر داد.
این مورد در حالت کلی درست است اما .... نه در مورد بانک‌های اطلاعاتی!
زمانیکه در یک آزمون واحد، پیاده سازی جدیدی از الگوی Interface مخزن ما تهیه می‌شود و اینبار بجای بانک اطلاعاتی با یک سری شیء قرارگرفته در حافظه سروکار داریم، آیا موارد زیر را هم می‌توان به سادگی آزمایش کرد؟
ارتباطات بین جداول‌را، cascade delete، فیلدهای identity، فیلدهای unique، کلیدهای ترکیبی، نوع‌های خاص تعریف شده در بانک اطلاعاتی و مسایلی از این دست.
پاسخ: خیر! تغییر انجام شده، سبب کار برنامه با اطلاعات موجود در حافظه خواهد شد، یعنی LINQ to Objects.
شما در حالت استفاده از LINQ to Objects آزادی عمل فوق العاده‌ای دارید. می‌توانید از انواع و اقسام متدها حین تهیه کوئری‌های LINQ استفاده کنید که هیچکدام معادلی در بانک اطلاعاتی نداشته و ... به ظاهر آزمون واحد شما پاس می‌شود؛ اما در عمل بر روی یک بانک اطلاعاتی واقعی کار نخواهد کرد.
البته شاید شخصی عنوان که بله می‌شود تمام این‌ها نیازمندی‌ها را در حالت کار با اشیاء درون حافظه هم پیاده سازی کرد ولی ... در نهایت پیاده سازی آن بسیار پیچیده و در حد پیاده سازی یک بانک اطلاعاتی واقعی خواهد شد که واقعا ضرورتی ندارد.

و پاسخ صحیح در اینجا و این مساله خاص این است:
لطفا در حین کار با بانک‌های اطلاعاتی مباحث mocking را فراموش کنید. بجای SQL Server، رشته اتصالی و تنظیمات برنامه را به SQL Server CE تغییر داده و آزمایشات خود را انجام دهید. پس از پایان کار هم بانک اطلاعاتی را delete کنید. به این نوع آزمون‌ها اصطلاحا integration tests گفته می‌شود. لازم است برنامه با یک بانک اطلاعاتی واقعی تست شود و نه یک سری شیء ساده قرار گرفته در حافظه که هیچ قیدی همانند شرایط کار با یک بانک اطلاعاتی واقعی، بر روی آ‌ن‌ها اعمال نمی‌شود.
ضمنا باید درنظر داشت بانک‌های اطلاعاتی که تنها در حافظه کار کنند نیز وجود دارند. برای مثال SQLite حالت کار کردن صرفا در حافظه را پشتیبانی می‌کند. زمانیکه آزمون واحد شروع می‌شود، یک بانک اطلاعاتی واقعی را در حافظه تشکیل داده و پس از پایان کار هم ... اثری از این بانک اطلاعاتی باقی نخواهد ماند و برای این نوع کارها بسیار سریع است.


نتیجه گیری:
حین استفاده از EF code first، الگوی واحد کار، همان DbContext است و الگوی مخزن، همان DbSetها. ضرورتی به ایجاد یک لایه محافظ اضافی بر روی این‌ها وجود ندارد.
در اینجا بهتر است یک لایه اضافی را به نام مثلا Service ایجاد کرد و تمام اعمال کار با EF را به آن منتقل نمود. سپس در قسمت‌های مختلف برنامه می‌توان از متدهای این لایه استفاده کرد. به عبارتی در فایل‌های Code behind برنامه شما نباید کدهای EF مشاهده شوند. یا در کنترلرهای MVC نیز به همین ترتیب. این‌ها مصرف کننده نهایی لایه سرویس ایجاد شده خواهند بود.
همچنین بجای نوشتن آزمون‌های واحد، به Integration tests سوئیچ کنید تا بتوان برنامه را در شرایط کار با یک بانک اطلاعاتی واقعی تست کرد.


برای مطالعه بیشتر:
اشتراک‌ها
روش‌های مقابله با مشکل امنیتی Mass Assignment در ASP.NET Core
  • Use BindAttribute on the action method 
  • Use [Editable] or [BindNever] on the model 
  • Use two different models 
  • Use a base class 
  • Use ModelMetadataTypeAttribute 
  • Explicit binding via TryUpdateModelAsync<> 

This was a very quick run down of some of the options available to you to prevent mass assignment. Which approach you take is up to you, though I would definitely suggest using one of the latter 2-model approaches. There are other options too, such as doing explicit binding via TryUpdateModelAsync<> but the options I've shown represent some of the most common approaches. Whatever you do, don't just blindly bind your view models if you have properties that should not be edited by a user, or you could be in for a nasty surprise.

And whatever you do, don't bind directly to your EntityFramework models. Pretty please. 

روش‌های مقابله با مشکل امنیتی Mass Assignment در ASP.NET Core
اشتراک‌ها
افزایش کارایی سرویسها با gRPC در NET 7.0.

With an 800% performance improvement, .NET7 will change the game.
 NET 7 gRPC performance now exceeds popular frameworks like Rust, Go and C++.
 .NET 7 reduces uploading a 100MB file from 26.9 seconds to 4.3 seconds in comparison with .NET 6.
 JSONTranscoding turns gRPC into REST APIs
 Use Server Streaming/Multiplexing to deliver 5M records in less than a minute. 

افزایش کارایی سرویسها با gRPC در NET 7.0.