اشتراک‌ها
تزریق وابستگی‌ها در Typescript

InversifyJS is a lightweight  inversion of control (IoC) container for TypeScript and JavaScript apps. A IoC container uses a class constructor to identify and inject its dependencies. InversifyJS has a friendly API and encourage the usage of the best OOP and IoC practices. 

تزریق وابستگی‌ها در Typescript
مطالب
ایجاد Drop Down List های آبشاری توسط Kendo UI
پیشتر مطلبی را در مورد ایجاد Drop Down List‌های به هم پیوسته توسط jQuery Ajax در این سایت مطالعه کرده بودید. شبیه به همان مطلب را اینبار قصد داریم توسط Kendo UI پیاده سازی کنیم.


مدل‌های برنامه

در اینجا قصد داریم لیست گروه‌ها را به همراه محصولات مرتبط با آن‌ها، توسط دو drop down list نمایش دهیم:
public class Category
{
    public int CategoryId { set; get; }
    public string CategoryName { set; get; }
 
    [JsonIgnore]
    public IList<Product> Products { set; get; }
}


public class Product
{
    public int ProductId { set; get; }
    public string ProductName { set; get; }
}
از ویژگی JsonIgnore جهت عدم درج لیست محصولات، در خروجی JSON نهایی تولیدی گروه‌ها، استفاده شده‌است.


منبع داده JSON سمت سرور

پس از مشخص شدن مدل‌های برنامه، اکنون توسط دو اکشن متد، لیست گروه‌ها و همچنین لیست محصولات یک گروه خاص را با فرمت JSON بازگشت می‌دهیم:
using System.Linq;
using System.Text;
using System.Web.Mvc;
using KendoUI12.Models;
using Newtonsoft.Json;
 
namespace KendoUI12.Controllers
{
 
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View(); // shows the page.
        }
 
        [HttpGet]
        public ActionResult GetCategories()
        {
            return new ContentResult
            {
                Content = JsonConvert.SerializeObject(CategoriesDataSource.Items),
                ContentType = "application/json",
                ContentEncoding = Encoding.UTF8
            };
        }
 
        [HttpGet]
        public ActionResult GetProducts(int categoryId)
        {
 
            var products = CategoriesDataSource.Items
                            .Where(category => category.CategoryId == categoryId)
                            .SelectMany(category => category.Products)
                            .ToList();
 
            return new ContentResult
            {
                Content = JsonConvert.SerializeObject(products),
                ContentType = "application/json",
                ContentEncoding = Encoding.UTF8
            };
        }
    }
}
بار اولی که صفحه بارگذاری می‌شود، توسط یک درخواست Ajax ایی، لیست گروه‌ها دریافت خواهد شد. سپس با انتخاب یک گروه، اکشن متد GetProducts جهت بازگرداندن لیست محصولات آن گروه، فراخوانی می‌گردد.
در اینجا به عمد از JsonConvert.SerializeObject استفاده شده‌است تا ویژگی JsonIgnore کلاس گروه‌ها، توسط کتابخانه‌ی JSON.NET مورد استفاده قرار گیرد (ASP.NET MVC برخلاف ASP.NET Web API به صورت پیش فرض از JSON.NET استفاده نمی‌کند).


کدهای سمت کاربر برنامه

کدهای جاوا اسکریپتی Kendo UI را جهت تعریف دو drop down list به هم مرتبط و آبشاری، در ادامه ملاحظه می‌کنید:
<!--نحوه‌ی راست به چپ سازی -->
<div class="k-rtl k-header demo-section">
    <label for="categories">گروه‌ها: </label><input id="categories" style="width: 270px" />
    <label for="products">محصولات: </label><input id="products" disabled="disabled" style="width: 270px" />
</div>
 
@section JavaScript
{
    <script type="text/javascript">
        $(function () {
            $("#categories").kendoDropDownList({
                optionLabel: "انتخاب گروه...",
                dataTextField: "CategoryName",
                dataValueField: "CategoryId",
                dataSource: {
                    transport: {
                        read: {
                            url: "@Url.Action("GetCategories", "Home")",
                            dataType: "json",
                            contentType: 'application/json; charset=utf-8',
                            type: 'GET'
                        }
                    }
                }
            });
 
            $("#products").kendoDropDownList({
                autoBind: false, // won’t try and read from the DataSource when it first loads
                cascadeFrom: "categories", // the id of the DropDown you want to cascade from
                optionLabel: "انتخاب محصول...",
                dataTextField: "ProductName",
                dataValueField: "ProductId",
                dataSource: {
                    // When the serverFiltering is disabled, then the combobox will not make any additional requests to the server.
                    serverFiltering: true, // the DataSource will send filter values to the server
                    transport: {
                        read: {
                            url: "@Url.Action("GetProducts", "Home")",
                            dataType: "json",
                            contentType: 'application/json; charset=utf-8',
                            type: 'GET',
                            data: function () {
                                return { categoryId: $("#categories").val() };
                            }
                        }
                    }
                }
            });
        });
    </script>
 
    <style scoped>
        .demo-section {
            width: 100%;
            height: 100px;
        }
    </style>
}
دراپ داون اول، به صورت متداولی تعریف شده‌است. ابتدا فیلدهای Text و Value هر ردیف آن مشخص و سپس منبع داده آن به اکشن متد GetCategories تنظیم گردیده‌است. به این ترتیب با اولین بار مشاهده‌ی صفحه، این دراپ داون پر خواهد شد.
سپس دراپ دوم که وابسته‌است به دراپ داون اول، با این نکات طراحی شده‌است:
الف) خاصیت autoBind آن به false تنظیم شده‌است. به این ترتیب این دراپ داون در اولین بار نمایش صفحه، به سرور جهت دریافت اطلاعات مراجعه نخواهد کرد.
ب) خاصیت cascadeFrom آن به id دراپ داون اول تنظیم شده‌است.
ج) در منبع داده‌ی آن دو تغییر مهم وجود دارند:
- خاصیت serverFiltering به true تنظیم شده‌است. این مورد سبب خواهد شد تا آیتم گروه انتخاب شده، به سرور ارسال شود.
- خاصیت data نیز تنظیم شده‌است. این مورد پارامتر categoryId اکشن متد GetProducts را تامین می‌کند و مقدار آن از مقدار انتخاب شده‌ی دراپ داون اول دریافت می‌گردد.

اگر برنامه را اجرا کنیم، برای بار اول لیست گروه‌ها دریافت خواهند شد:


سپس با انتخاب یک گروه، لیست محصولات مرتبط با آن در دراپ داون دوم ظاهر می‌گردند:



کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید.
اشتراک‌ها
معرفی SQL Server بر روی Linux

 Today I’m excited to announce our plans to bring SQL Server to Linux as well. This will enable SQL Server to deliver a consistent data platform across Windows Server and Linux, as well as on-premises and cloud. 

معرفی SQL Server بر روی Linux
اشتراک‌ها
کتاب رایگان Building Cloud Apps with Microsoft Azure

 Greetings! We’re happy to release a free ebook today: Building Cloud Apps with Microsoft Azure: Best practices for DevOps, data storage, high availability, and more, by Scott Guthrie, Mark Simms, Tom Dykstra, Rick Anderson, and Mike Wasson

کتاب رایگان Building Cloud Apps with Microsoft Azure
نظرات مطالب
طراحی یک گرید با Angular و ASP.NET Core - قسمت دوم - پیاده سازی سمت کلاینت
در راهنمای کدنویسی Angular  توصیه شده از اینترفیس‌ها برای تعریف نوع مدل‌ها استفاده شود:

Consider using a class instead of an interface for services and declarables (components, directives, and pipes)

Consider using an interface for data models

البته این مورد موافق‌ها و مخالف‌هایی هم دارد.
در کل سلیقه‌ای است و بهتر است یکنواختی و یک‌دستی کد مدنظر باشد.
اشتراک‌ها
نحوه‌ استفاده از قالب Typescript library starter

Have you ever written a library in JavaScript or TypeScript? Are you planning to do it? If so, you must try Typescript library starter, a starter kit that will make easy to get started while providing all features you know to write a library in Typescript. 

نحوه‌ استفاده از قالب Typescript library starter
مطالب
Microbenchmark
What Is Micro Benchmark? Micro benchmark is a benchmark designed to measure the performance of a very small and specific piece of code. (^)
البته این موضوع امروزه بیشتر در Java مطرحه تا دات نت (^ و ^ و ^) اما مفاهیم اصلی مختص یک زبان یا پلتفرم نیست.
وقتی در مورد آزمایش بار برای مقایسه کارایی کلاس StrigBuilder تحقیق میکردم به مطلب جالبی برخورد کردم. خلاصش این میشه که برای تست بار قسمتهایی از کدتون میتونین زمان موردنیاز برای اجرای اون کد رو بررسی کنین و چون ممکنه انجام این کار چندین بار نیاز بشه بهتره از متد زیر برای اینکار استفاده کنین:
static void Profile(string description, int iterations, Action func) {
    // clean up
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();

    // warm up 
    func();

    var watch = Stopwatch.StartNew();
    for (int i = 0; i < iterations; i++) {
        func();
    }
    watch.Stop();
    Console.Write(description);
    Console.WriteLine(" Time Elapsed {0} ms", watch.ElapsedMilliseconds);
}
سه خط اول متد بالا برای آماده‌سازی حافظه جهت اجرای تست موردنظر است. برای آشنایی بیشتر با نحوه عملکرد Garbage Collector (^ و ^ و ^) خوندن کتاب فوق العاده CLR via C# - 3rd ed رو پیشنهاد میکنم (فصلهای 21 و 22).
سپس یکبار اکشن موردنظر (که حاوی قطعه کد موردنظره) اجرا میشه تا مسائل مربوطه به بارگذاری‌های اولیه در نتیجه تست تاثیر نزاره (warm up).
در نهایت هم آزمایش بار برای تعداد تکرار درخواست شده انجام میشه و زمان اجرای اون در خروجی چاپ میشه.
برای استفاده از متد فوق میشه از کد زیر استفاده کرد:
Profile("a descriptions", how_many_iterations_to_run, () =>
{
   // ... code being profiled
});
و برای استفاده از این متد در آزمایش کارایی کلاس StringBuilder میشه از کدی شبیه به کد زیر استفاده کزد:
var iterations = 10000000;
var testString = ".NET Tips is awesme!";
do
{
  var sb1 = new StringBuilder(testString);
  var sb2 = new StringBuilder(testString) { Capacity = testString.Length * iterations };
  try
  {
    Profiler.Profile("StringBuilder Profiler", iterations, () => sb1.Append(testString));
    Profiler.Profile("StringBuilder Capacity Profiler", iterations, () => sb2.Append(testString));
  }
  catch (Exception ex)
  {
    Console.WriteLine(ex.Message);
  }
  finally
  {
    Console.WriteLine("----------------------------------------------------------------");
    sb1.Clear();
    sb2.Clear();
  }
} while (Console.ReadKey(true).Key == ConsoleKey.C); // C = continue
البته برای اینکه عملیات مقدار دهی خاصیت Capacity در قسمت warm up متد profile نتایج رو تحت تاثیر قرار نده برای این تست من اون قسمت رو کامنت کردم (اگر این کار رو نکنین زمانهای بدست اومده برای هر دو مورد یکی خواهد بود). اجرای کد بالا نتایج زیر رو تو سیستم من ارائه داد:

می‌بینین که نتایج استفاده از متد موردبحث کمی فرق داره و افزایش کارایی در حالت استفاده از پراپرتی Capacity دیگه حدود 3 برابر نیست و حدود 2 دو برابره. البته زمان بدست اومده برای هر دو مورد نسبت به قبل کاهش داشته که بیشترش میتونه مربوطه به عدم درنظر گرفتن زمان موردنیاز برای ایجاد کلاس StringBuilder در این تست جدید باشه (چون بعید میدونم عملیات پاکسازی حافظه توسط GC تو این تست تاثیر چندانی داشته باشه). درهر حال نتایج این تست بیشتر به واقعیت نزدیکه!