مطالب
تعدادی از توابع kendo UI Treeview
kendo ui یکی از جذاب‌ترین و بهترین فریم ورک‌های HTML5 است که استفاده از آن بین برنامه نویسان جا افتاده است و تلریک هم پشتیبانی خوبی از آن به عمل آورده است. من هم به تازگی از شیء treeview آن  استفاده کردم و موقعیکه کارم با شیء Treeview به پایان رسید، یک فایل کوچک جاوااسکریپت به کار اضافه شد که شامل تعدادی از توابع چون حذف گره و ... بود که تصمیم گرفتم بر اساس مستندات و نیازهای عمومی، تعداد این توابع را بالا ببرم که برای استفاده در صفحات و پروژه‌های دیگر و بالا بردن امتیاز استفاده مجدد از کد از آن استفاده کنم. سورس آن در گیت هاب موجود است.
بعد از صدا زدن فایل‌های مورد نیاز کندو، این فایل جاوااسکریپتی را هم به پروژه اضافه کنید. بیشتر توابع تست شده و جواب گرفته و فکر نکنم مشکلی باشد؛ هر چند عیب یابی آن هم ساده است و مشکلی برای برطرف کردن آن وجود ندارد و هر تابع دو یا سه خط بیشتر نیست.

معرفی توابع


    var treeview;

    function FindTreeViewObj(objName) {
        treeview = $(objName).data("kendoTreeView");
    }
اولین و مهمترین تابع می‌باشد که باید قبل از همه در زمان لود پروژه بعد از ایجاد درخت آن را صدا بزنید، در صورتی که صدا زده نشود، بقیه‌ی توابع کار نخواهند کرد. این تابع وظیفه دارد شیء درخت معرفی شده را پیدا کرده و داخل یک متغیر عمومی به اسم treeview قرار دهد:
FindTreeViewObj("#treeview");

    function GetSelectedNode() {
        return treeview.select();
    }
گره انتخابی را باز می‌گرداند:
GetSelectedNode();


    function DisableSelectedNode() {
        treeview.enable(GetSelectedNode(), false);
    }
گره انتخابی را غیرفعال می‌کند:
DisableSelectedNode();

    function EnableSelectedNode() {
        treeview.enable(GetSelectedNode(), true);
    }
گره انتخابی را فعال می‌کند:
EnableSelectedNode();

    function EnableAllNodes() {
        treeview.enable(".k-item");
    }
همه‌ی گره‌ها را فعال می‌کند:
EnableAllNodes();

    function ExpandAllNodes() {
        treeview.expand(".k-item");
    }
همه‌ی گره‌ها را به سمت فرزندان باز می‌کند:
ExpandAllNodes();

    function CollapseAllNodes() {
        treeview.collapse(".k-item");
    }
همه گره‌ها به سمت والد را جمع می‌کند:
CollapseAllNodes();

    function RemoveSelectedNode() {
        treeview.remove(GetSelectedNode());
    }
گره انتخابی را حذف می‌کند:
RemoveSelectedNode()

    function FilterTreeView(filterText) {
        if (filterText !== "") {
            treeview.dataSource.filter({
                field: "text",
                operator: "contains",
                value: filterText
            });
        } else {
            treeview.dataSource.filter({});
        }
    }
گره‌هایی که عبارت مد نظر در آن‌ها باشند، نمایش میابند:
FilterTreeView('my node')

    function SortTreeView(sortType) {
        treeview.dataSource.sort({
            field: "text",
            dir: sortType
        });
    }
گره‌ها را به صورت صعودی یا نزولی مرتب می‌کند. مقادیر پارامتر ورودی آن یا "asc" است یا "desc"
SortTreeView('asc');
SortTreeView('desc');

    function GetSelectedDataItem() {
        return treeview.dataItem(GetSelectedNode());
    }
قسمت اطلاعاتی یک گره که شامل مواردی چون عنوان یا Id است را باز می‌گرداند:
GetSelectedDataItem();

    function GetSelectedNodeId() {
        var data = GetSelectedDataItem();
        return data.id;
    }
Id گره را بر میگرداند:
GetSelectedNodeId();

    function GetSelectedNodeText() {
        var data = GetSelectedDataItem();
        return data.Name;
    }
متن یا مقدار گره را باز میگرداند:
GetSelectedNodeText();

    function SetSelectedNodeText(value) {
        var node = GetSelectedNode();
        treeview.text(node, value);
    }
مقدار گره را به مقدار جدید تغییر می‌دهد:
SetSelectedNodeText('new value');

    function GetNodeByText(text) {
        return treeview.findByText(text);
    }
اولین گره با این متن را باز میگرداند:
GetNodeByText('mynode');

    function GetNodeByText(id) {
        return treeview.findByUid(id);
    }
گره ای با این Id را باز میگرداند:
GetNodeByText(4);

    function InsertAfter(item, nextItem) {
        treeview.insertAfter({ text: "item" }, GetNodeByText(nextItem));
    }
متن دو گره را دریافت می‌کند، گره‌ای را بر اساس متن پارامتر دوم پیدا کرده و بعد از آن گره اول را با مقدار پارامتر اول درج می‌کند.
InsertAfter('new item', 'old item')

    function MoveToAfter(firstItem, secondItem) {
        treeview.insertAfter(GetNodeByText(firstItem), GetNodeByText(secondItem));
    }
مقدار گره‌ها را دریافت می‌کند و بعد از پیدا کردن آن‌ها، گره اول را به بعد از گره دوم انتقال می‌دهد:
MoveToAfter('firstItem', 'secondItem');

    function InsertBefore(item, nextItem) {
        treeview.insertBefore({ text: "item" }, GetNodeByText(nextItem));
    }

    function MoveToBefore(firstItem, secondItem) {
        treeview.insertBefore(GetNodeByText(firstItem), GetNodeByText(secondItem));
    }
دو تابع بعد مثل توابع بالا هستند و فقط به قبل آن اضافه می‌کند یا انتقال می‌دهد.
InsertBefore('new item', 'old item');
MoveToBefore('firstItem', 'secondItem');

    function GetParent(node) {
        return treeview.parent(node);
    }
والد گره انتخابی را بر میگرداند:
GetParent(GetSelectedNode());

    function Toggle(node) {
        treeview.toggle(node);
    }
گره را (در صورت داشتن فرزند)  باز و بسته می‌کند:
Toggle(GetSelectedNode());

    function NewNode(nodeText, nodeValue, selectedNode) {
        treeview.append({
            Name: nodeText,
            Id: nodeValue
        }, selectedNode);
    }
گره جدیدی را اضافه می‌کند. پارامتر اول مقدار گره، پارامتر دوم Id گره و پارامتر سوم در صورتی که بخواهید یک زیر گره باشد، باید گره والد را به آن پاس کنید و درصورتی که زیر گره نیست آن را نال مقدار دهی کنید.
NewNode('new node', 1, null);
NewNode('new sub node', 2, GetSelectedNode());
اشتراک‌ها
0.Visual Studio 2017 15.9 منتشر شد

Summary of Notable New Features in 15.9

Top Issues Fixed in 15.9

0.Visual Studio 2017 15.9 منتشر شد
نظرات مطالب
ASP.NET MVC #20
مشکل حل شد.
دستور Install-Package Microsoft.AspNet.WebPages رو در کنسول زدم و سپس System.Web.Helpers.dll رو از پوشه bin لوکال به پوشه bin سرور بردم.
علت رو اما نفهمیدم! چون این فایل از اول هم توی bin لوکال نبود و بعد از اجرای این دستور اضافه شد، پس چطور قبلش صفحه بدرستی نمایش داده میشد؟
مطالب
BloggerToCHM 1.3

نگارش جدید برنامه BloggerToCHM را از اینجا می‌توانید دریافت کنید.
تغییرات حاصل شده:
  • پشتیبانی بهتر از تغییرات open search API که هر از چندگاهی توسط گوگل اعمال می‌شود.
  • رفع مشکل تخریب اعداد فارسی در فایل تولیدی نهایی
  • اضافه شدن چند گزینه جهت کنترل بر روی نمایش قسمت about در فایل نهایی حاصل و همچنین درج نظرات
  • و ...

مطالب
استفاده از #F در پروژه های MVC4
در این پست با روش پیاده سازی پروژه‌های WPF با استفاده از #F آشنا شدید. قصد دارم در طی چند پست روش پیاده سازی پروژه‌های Asp.Net MVC 4  با استفاده از #F را شرح دهم.
»اگر با #F آشنایی ندارید می‌توانید از اینجا شروع کنید.
به صورت کلی برای استفاده گسترده از #F در پروژه‌های وب نیاز به یک سری template‌های آماده داریم در غیر این صورت کار کمی سخت خواهد شد. به تصویر زیر دقت نمایید:

واضح است که با توجه به تصویر بالا کنترلر‌ها و البته مدل‌های app  و هر آنچه که سمت سرور به آن نیاز است باید با استفاده از #F پیاده سازی شوند. اما هنگامی که کنترلر‌ها با استفاده از #F نوشته شوند سیستم مسیر یابی نیز تحت تاثیر قرار خواهد گرفت. علاوه بر آن باید فکری برای بخش Bundling و همچنین فیلتر‌هاو... نمود. در نتیجه با توجه به template پروژه مورد نظر بر خلاف حالت پیش فرض #C آن که در قالب یک پروژه ارائه می‌شود در این جا حداقل به دو پروژه نیاز داریم. خوشبختانه همانند پروژه FSharpX که برای WPF مناسب است برای MVC نیز template آماده موجود است که در ادامه با آن آشنا خواهیم شد.

شروع به کار

ابتدا در VS.Net یک پروژه جدید ایجاد نمایید. از بخش Online Template گزینه FSharp MVC 4 را جستجو کنید. 

بعد از انتخاب نام پروژه و  کلیک بر روی Ok ( و البته دانلود حدود ده MB اطلاعات) صفحه زیر نمایان می‌شود. در این قسمت تنظیمات مربوط به انتخاب View Engine و نوع قالب پروژه را وجود دارد. در صورتی که قصد استفاده از Web Api را دارید گزینه  Web Api Project را انتخاب کنید در غیر این صورت گزینه Empty Project.

البته از Visual Studio 2012 به بعد این بخش به صورت زیر خواهد بود که قسمت Single Page App به آن اضافه شده است:

بعد از کلیک بر روی Ok یک پروژه بر اساس Template مورد نظر ساخته می‌شود. همانند تصویر زیر:

بررسی تغییرات

در یک نگاه به راحتی می‌توان تغییرات زیر را در پروژه Web تشخیص داد:

»پوشه Controller وجود ندارد؛

»پوشه مدل وجود ندارد؛

»فایل Global.asax دیگر فایلی به نام Global.asax.cs را همراه با خود ندارد.

دلیل اصلی عدم وجود موارد بالا این است که تمام این موارد باید به صورت #F پیاده سازی شوند در نتیجه به پروژه #F ساخته شده منتقل شده اند. فایل Global.asax را باز نمایید. سورس زیر قابل مشاهده است:

<%@ Application Inherits="FsWeb.Global" Language="C#" %> <script Language="C#" RunAt="server">
 // Defines the Application_Start method and calls Start in // System.Web.HttpApplication from which Global inherits. protected void Application_Start(Object sender, EventArgs e) { base.Start(); } </script>
تمامی کاری که تکه کد بالا انجام می‌دهد فراخواهی متد Start در فایل Global متناظر در پروژه #F است. اگر به قسمت reference‌های پروژه Web دقت کنید خواهید که به پروژه #F متناظر رفرنس دارد.
حال به بررسی پروژه #F  ساخته شده خواهیم پرداخت. در این پروژه یک فایل  Global.fs وجود دارد که سورس آن به صورت زیر است:

namespace FsWeb

open System
open System.Web
open System.Web.Mvc
open System.Web.Routing

type Route = { controller : string
               action : string
               id : UrlParameter }

type Global() =
    inherit System.Web.HttpApplication() 

    static member RegisterRoutes(routes:RouteCollection) =
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}")
        routes.MapRoute("Default", 
                        "{controller}/{action}/{id}", 
                        { controller = "Home"; action = "Index"
                          id = UrlParameter.Optional } )

    member this.Start() =
        AreaRegistration.RegisterAllAreas()
        Global.RegisterRoutes(RouteTable.Routes)
  در پروژه‌های MVC بر اساس زبان #C،  کلاسی به نام RouteConfig وجود دارد که در فایل Global.asax.cs فراخوانی می‌شود:
RouteConfig.RegisterRoutes(RouteTable.Routes);
و کد‌های مورد نظر جهت تعیین الگوی مسیر یابی کنترلر‌ها و درخواست‌ها در کلاس RouteConfig نیز به صورت زیر می‌باشد:
public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
اما در اینجا بر خلاف #C، تعریف و اجرای سیستم مسیر یابی در یک فایل انجام می‌شود. در بخش اول ابتدا یک type تعریف می‌شود که معادل با تعیین Routing در زبان #C است. علاوه بر آن متد RegisterRoutes جهت تعیین و انتساب Route Type تعریف شده به Route Collection مورد نظر نیز در این فایل می‌باشد. 

//تعریف الکوی مسیر یابی
type Route = { controller : string
               action : string
               id : UrlParameter }

type Global() =
    inherit System.Web.HttpApplication() 

    static member RegisterRoutes(routes:RouteCollection) =
       //فراخوانی  و انتساب الگوی مسیر یابی به  مسیر‌های تعریف شده
       routes.IgnoreRoute("{resource}.axd/{*pathInfo}")
        routes.MapRoute("Default", 
                        "{controller}/{action}/{id}", 
                        { controller = "Home"; action = "Index"
                          id = UrlParameter.Optional } )
در نهایت نیز تابع RegisterRoute در تابع Start فراخوانی خواهد شد.
Global.RegisterRoutes(RouteTable.Routes)
نتیجه کلی تا اینجا:
در این پست با Template پروژه‌های F# MVC 4 اشنا شدیم و از طرفی مشخص شد که برای پیاده سازی این گونه پروژه‌ها حداقل نیاز به دو پروژه داریم. یک پروژه که از نوع #C است ولی در آن فقط View ‌ها و فایل جاوااسکریپتی و البته Css وجود دارد. از طرف دیگر کنترلر‌ها و مدل‌ها و هر چیز دیگر که مربوط به سمت سرور است در قالب یک پروژه #F پیاده سازی می‌شود.
در پست بعدی با روش تعریف و توسعه کنترلر‌ها و مدل‌ها آشنا خواهیم شد.
مطالب
امکان استفاده‌ی مستقیم از کتابخانه‌های Full .NET Framework در NET Core 2.0.
یکی از مواردی که به همراه NET Core 1.x. وجود دارد، کمبود کتابخانه‌های ثالث مخصوص آن است. برای مثال کتابخانه‌ی log4net در اوایل ارائه‌ی NET Core. نگارش مخصوص به آن‌را نداشت (البته هم اکنون دارد). باید درنظر داشت، این مورد صرفا در حالت توزیع چندسکویی برنامه‌های مبتنی بر NET Core. مشکل ایجاد می‌کرد. از این جهت که می‌توان full .NET framework را به عنوان Target Framework برنامه‌های NET Core. معرفی کرد و در این حالت برنامه بدون هیچگونه مشکلی تنها بر روی ویندوز و سرورهای ویندوزی اجرا می‌شود (و امکان دسترسی به تمامی کتابخانه‌های مخصوص full .NET framework را نیز دارا خواهد بود)؛ اما قابلیت توزیع بر روی لینوکس و مک را از دست خواهد داد.
در NET Core 2.0. از یک اصطلاحا «compatibility shim» مخصوص استفاده می‌شود که امکان افزودن ارجاعات به full framework library‌ها را بدون نیاز به تغییر target framework برنامه میسر می‌کند. یعنی در اینجا می‌توان یک کتابخانه‌ی قدیمی دات نتی را در برنامه‌های مبتنی بر NET Core. بر روی لینوکس نیز اجرا کرد و در این حالت نیازی به تبدیل اجباری این کتابخانه به نسخه‌ی NET Core. آن نیست.


NET Core 2.0. پیاده سازی کننده‌ی NET Standard 2.0. است

NET Standard‌. در حقیقت یک قرار داد است که سکوهای کاری مختلف دات نتی مانند Full .NET Framework ، Xamarin ، Mono ، UWP و غیره می‌توانند آن‌را پیاده سازی کنند. یک نمونه‌ی دیگر این پیاده سازی‌ها نیز NET Core. است. برای مثال دات نت 4.6.1، استاندارد و قرار داد شماره‌ی 2 دات نت را پیاده سازی می‌کند. به همین صورت NET Core 2.0. نیز پیاده سازی کننده‌ی این استاندارد شماره 2 است.
 با تغییرات اخیر، اکنون NuGet می‌تواند کتابخانه‌های مبتنی بر NET Standard 2. را در برنامه‌های مبتنی بر سکوهای کاری که آن‌را پیاده سازی می‌کنند، بدون مشکل اضافه کند. برای مثال می‌توان اسمبلی‌های دات نت 4.6.1 را به برنامه‌های ASP.NET Core 2.0 اضافه کرد (کاری که در نگارش 1x آن به صورت مستقیم میسر نیست) و یا می‌توان اسمبلی‌های کامپایل شده‌ی برای دات نت استاندارد 2 را به برنامه‌های مبتنی بر دات نت 4.6.1 اضافه کرد.


آیا واقعا کتابخانه‌های قدیمی دات نتی توسط برنامه‌های NET Core 2.0. در لینوکس نیز اجرا خواهند شد؟

دات نت استاندارد، بیش از یک قرار داد چیزی نیست و پیاده سازی کنندگان آن می‌توانند سطح بیشتری را نسبت به این قرار داد نیز لحاظ کنند. برای مثال دات نت 4.6.1 شامل سطح API بیشتری از دات نت استاندارد 2 است.
 به همین جهت باید درنظر داشت که امکان اضافه کردن یک بسته‌ی نیوگت از یک کتابخانه‌ی نوشته شده‌ی برای دات نت کامل در برنامه‌های دات نت Core به معنای تضمینی برای کار کردن آن در زمان اجرا نخواهد بود. از این جهت که دات نت کامل، به همراه قسمت‌هایی است که در NET Standard. وجود خارجی ندارند. بنابراین اگر کتابخانه‌ی استفاده شده صرفا این API مشترک را هدف قرار داده‌است، هم قابلیت اتصال و هم قابلیت اجرا را خواهد داشت؛ اما اگر برای مثال کسی بسته‌ی NServiceBus را به پروژه‌ی ASP.NET Core 2.0 اضافه کند، بدون مشکل کامپایل خواهد شد. اما از آنجائیکه این کتابخانه از MSMQ استفاده می‌کند که خارج از میدان دید این استاندارد است، در زمان اجرا با شکست مواجه خواهد شد.


«compatibility shim» در NET Standard 2.0. چگونه کار می‌کند؟

در NET Core.، پیاده سازی Object در System.Runtime قرار دارد و کد تولید شده‌ی توسط آن یک چنین ارجاعی را [System.Runtime]System.Object تولید می‌کند. اما در دات نت کلاسیک، System.Object در mscorlib قرار دارد. به همین جهت زمانیکه سعی کنید اسمبلی‌های دات نت کلاسیک را در NET Core 1.x. استفاده کنید، پیام یافتن نشدن نوع‌ها را دریافت خواهید کرد. اما در NET Core 2.0. یک پیاده سازی صوری (facade) از mscorlib وجود دارد که کار آن هدایت نوع درخواستی، به نوع واقعی پیاده سازی شده‌ی در NET Core. است.


در این تصویر استفاده‌ی از یک کتابخانه‌ی ثالث را مشاهده می‌کنید که ارجاعی را به [mscorlib]Microsoft.Win32.RegistryKey دارد (مبتنی بر دات نت کلاسیک است).  همچنین یک mscorlib مشخص شده‌ی به صورت facade را نیز مشاهده می‌کنید. کار آن هدایت درخواست نوع واقع شده‌ی در mscorlib، به نوع موجود [Microsoft.Win32.Registry] Microsoft.Win32.RegistryKey است و تنها زمانی کار خواهد کرد که Microsoft.Win32.RegistryKey.dll وجود خارجی داشته باشد. به این معنا که رجیستری، یک مفهوم ویندوزی است و این کتابخانه بر روی ویندوز بدون مشکل کار می‌کند. اما تحت لینوکس، این قسمت خاص با پیام PlatformNotSupportedException خاتمه خواهد یافت. اما اگر قسمت‌هایی از این کتابخانه را استفاده کنید که در تمام سکوهای کاری وجود داشته باشند، بدون مشکل قادر به استفاده‌ی از آن خواهید بود.


یک مثال: استفاده از کتابخانه‌ی رمزنگاری اطلاعات Inferno

آخرین نگارش کتابخانه‌ی رمزنگاری اطلاعات Inferno مربوط به NET 4.5.2. است. مراحل ذیل را پس از نصب SDK جدید NET Core 2.0. در خط فرمان طی می‌کنیم:
الف) ایجاد پوشه‌ی UseNET452InNetCore2 و سپس ایجاد یک پروژه‌ی کنسول جدید
dotnet new console

ب) افزودن بسته‌ی نیوگت Inferno به پروژه
 dotnet add package Inferno
این بسته بدون مشکل اضافه می‌شود؛ البته پیام اخطار ذیل نیز صادر خواهد شد (چون مبتنی بر NET 4.6.1. که پیاده سازی کننده‌ی NET Standard 2.0. است، نیست):
 log  : Installing Inferno 1.4.0.
warn : Package 'Inferno 1.4.0' was restored using '.NETFramework,Version=v4.6.1' instead of the project target framework '.NETCoreApp,Version=v2.0'. This package may not be fully compatible with your project.
info : Package 'Inferno' is compatible with all the specified frameworks in project 'D:\UseNET452InNetCore2\UseNET452InNetCore2.csproj'.
info : PackageReference for package 'Inferno' version '1.4.0' added to file 'D:\UseNET452InNetCore2\UseNET452InNetCore2.csproj'.
ابتدا پیام می‌دهد که این بسته ممکن است با NET Core 2.0. سازگار نباشد. سپس عنوان می‌کند که سازگاری کاملی را با پروژه‌ی جاری دارد و بسته را اضافه می‌کند.

ج) استفاده از کتابخانه‌ی Inferno جهت تولید یک عدد تصادفی thread safe
using System;
using SecurityDriven.Inferno;

namespace UseNET452InNetCore2
{
    class Program
    {
        static CryptoRandom random = new CryptoRandom();
        static void Main(string[] args)
        {
            Console.WriteLine($"rnd: {random.NextLong()}");
        }
    }
}

د) اجرای برنامه
در ادامه اگر دستور dotnet run را صادر کنیم، ابتدا اخطاری را صادر می‌کند که این بسته ممکن است دارای قسمت‌هایی باشد که با NET core 2.0. سازگار نیست و سپس خروجی نهایی را بدون مشکل اجرا کرده و نمایش می‌دهد.
 >dotnet run
warning NU1701:  This package may not be fully compatible with your project.
rnd: 8167886599578111106
مطالب
کار با Docker بر روی ویندوز - قسمت هفتم - مدیریت اجرای چندین کانتینر به هم وابسته
تا اینجا نحوه‌ی اجرای برنامه‌ها، وب سرورها و حتی بانک‌های اطلاعاتی را توسط داکر بررسی کردیم. در این قسمت می‌خواهیم یک برنامه و بانک اطلاعاتی مخصوص آن‌را داخل یک کانتینر اجرا کنیم و برای این منظور از ابزار ساده کننده‌ی docker-compose استفاده خواهیم کرد.


docker-compose چیست؟

فرض کنید برنامه‌ی ما، از یک قسمت منطق خود برنامه و قسمت دیگر بانک اطلاعاتی آن تشکیل شده‌است. در این حالت برای توزیع آن توسط کانتینرها، نیاز به دو کانتینر مجزا خواهد بود؛ یکی برای برنامه و دیگری برای بانک اطلاعاتی:
dockerrun --name db`
-d `
-p 3306:3306 `
-e MYSQL_ROOT_PASSWORD=my-secret-pw `
-v db:/var/lib/mysql`
mysql

dockerinspect db # extract ipaddress

dockerrun --name web `
-d `
-p 8080:80 `
-e MY_DB_PORT=3306 `
-e MY_DB_HOST=? `
-v /my/php/app:/usr/share/nginx/html `
nginx
تمام این دستورات را به همراه یک ` نیز مشاهده می‌کنید. این روشی است که از آن برای چندسطری کردن دستورات در PowerShell استفاده می‌شود.
- دستور اول مطابق توضیحات قسمت قبل، یک بانک اطلاعاتی MySQL را در پس زمینه، با نام db که در آن، پورت 3306 میزبان به پورت 3306 کانتینر نگاشت شده‌است و همچنین بانک اطلاعاتی آن در یک volume نامدار به نام db با مسیر نگاشت شده‌ی به /var/lib/mysql/ داخل کانتینر ایجاد می‌شود، اجرا می‌کند.
- دستور دوم کار استخراج اطلاعات این کانتینر را انجام می‌دهد که شامل آدرس IP آن نیز می‌باشد. از این IP در برنامه‌ی وب استفاده خواهیم کرد.
- دستور سوم مطابق توضیحات قسمت پنجم، یک وب سرور nginx را برای هاست یک برنامه‌ی PHP که در آن پورت 8080 میزبان به پورت 80 کانتینر نگاشت شده‌است و همچنین فایل‌های آن از مسیر /my/php/app/ میزبان به مسیر /usr/share/nginx/html/ داخل کانتینر نگاشت و تامین می‌شوند، اجرا می‌کند. در اینجا از پارامتر e برای تعریف یک سری متغیر محیطی مانند شماره‌ی پورت و IP کانتینر اجرا کننده‌ی mysql، استفاده شده‌است.

در این مثال دو کانتینر به هم وابسته را اجرا کرده‌ایم و برای اجرای کانتینر دوم، نیاز است حداقل IP کانتینر اول را دانست و در قسمت MY_DB_HOST مقدار دهی کرد. روش دیگری نیز برای مدیریت ساده‌تر اجرای چندین کانتینر به هم وابسته توسط ابزاری به نام docker-compose وجود دارد. اگر از Dockerfile (که آن‌را در قسمت پنجم معرفی کردیم) جهت ایجاد Imageهای سفارشی بکار می‌رود، فایل docker-compose.yml، کار خودکار سازی ایجاد و اجرای چندین کانتینر را انجام می‌دهد که با قالب YAML تعریف می‌شود:
version: '2'
services:
    db:
         image: mysql
         ports:
             -3306:3306
         environment:
             -MYSQL_ROOT_PASSWORD=my-secret-pw
         volumes:
             -db:/var/lib/mysql

    web:
         image: nginx
         ports:
             -8080:80
         environment:
             -MY_DB_PORT=3306
             -MY_DB_HOST=db
         volumes:
             -/my/php/app:/usr/share/nginx/html
همانطور که مشاهده می‌کنید، هرچند قالب آن اندکی متفاوت شده‌است، اما در اصل با دستورات docker ای که در ابتدا معرفی کردیم، تفاوتی ندارد. محتوای فوق را در یک فایل متنی ویژه به نام docker-compose.yml ذخیره و آن‌را به ابزار خط فرمان دیگری به نام docker-compose معرفی می‌کنیم.
در ابتدای این فایل، شماره نگارش قالب YAML مورد استفاده، مشخص شده‌است. در این نگارش، به کانتینرها، services گفته می‌شود که در اینجا دو سرویس db و web را مشاهده می‌کنید. در فایل‌های yml، فضاهای خالی و indentations مهم هستند و بر این اساس است که کانتینرها و سپس مشخصات این کانتینرها، تمیز داده می‌شوند.


راه اندازی TeamCity به کمک فایل docker-compose.yml آن

در اینجا محتویات فایل docker-compose.yml مخصوص راه اندازی TeamCity را مشاهده می‌کنید که از سه کانتینر تشکیل شده‌است و از بانک اطلاعاتی postgres استفاده می‌کند:
version: '2'
services:
    teamcity:
        image: sjoerdmulder/teamcity
        ports:
            - 8111:8111
    teamcity-agent:
        image: sjoerdmulder/teamcity-agent
        environment:
            - TEAMCITY_SERVER=http://teamcity:8111
    postgres:
        image: postgres
        environment:
            - POSTGRES_DB=teamcity
در این تنظیمات، پورت 8111 میزبان به پورت 8111 کانتینر teamcity نگاشت شده‌است. در ادامه teamcity-agent نیاز به IP این کانتینر را دارد (یک build-server است). زمانیکه چندین کانتینر را توسط فایل docker-compose.yml راه اندازی می‌کنیم، داکر یک شبکه‌ی ایزوله (private network) را نیز برای اینکار مهیا می‌کند. داخل این شبکه‌ی ایزوله، یک DNS سرور توکار نیز وجود دارد که امکان دسترسی به کانتینرهای مختلف را از طریق نام کانتینرهای آن‌ها میسر می‌کند. به همین جهت است که مقدار TEAMCITY_SERVER، به http://teamcity:8111 تنظیم شده‌است و دقیقا از نام کانتینر teamcity برای یافتن IP آن استفاده می‌کند. همچنین باید دقت داشت در این آدرس، عدد 8111 به پورت داخل کانتینر teamcity اشاره می‌کند و نه به پورت میزبان. کانتینرها از طریق آدرس IP و پورت خودشان با هم در تماس هستند. پورت میزبان 8111، صرفا جهت فراخوانی teamcity از طریق سیستم میزبان مشخص شده‌است.


در ادامه برای کار با آن، ابتدا این محتویات را به صورت یک فایل متنی docker-compose.yml ذخیره کنید. سپس از طریق خط فرمان به پوشه‌ی آن وارد شده و دستور docker-compose up را صادر کنید. docker-compose یکی دیگر از ابزارهای خط فرمان نصب شده‌ی به همراه داکر است و پارامتر up آن کار راه اندازی و اجرای کانتینرهای ذکر شده‌ی در فایل yml موجود را انجام می‌دهد. نام پوشه‌ای که این فایل در آن قرار دارد، به عنوان نام پروژه‌ی مشترک بین این کانتینرها در گزارشات آن مورد استفاده قرار می‌گیرد.
پس از صدور این فرمان، ابتدا تمام imageهای ذکر شده‌ی در فایل yml دریافت می‌شوند (سه image در اینجا) و هر سه کانتینر راه اندازی می‌شوند. اکنون می‌توان در سیستم میزبان به آدرس http://localhost:8111 مراجعه کرد و از برنامه‌ی teamcity استفاده نمود. البته صفحه‌ی ابتدایی آن کار تنظیمات بانک اطلاعاتی آن‌را انجام می‌دهد و جائیکه در مورد database type سؤال می‌پرسد می‌توان postgres را انتخاب کرد و سپس در ذیل آن مقدار database host را نیز postgres وارد می‌کنیم. علت آن‌را نیز پیشتر توضیح دادیم. postgres در اینجا نام کانتینر نیز هست و ذکر نام آن، با ذکر IP مرتبط با آن کانتینر، یکی است. نام بانک اطلاعاتی را teamcity وارد کنید (مطابق تنظیمات فایل yml فوق) و نام کاربری آن نیز postgres است؛ بدون کلمه‌ی عبور. البته می‌شد در فایل yml فوق، متغیر محیطی POSTGRES_PASSWORD=xyz را نیز تنظیم کرد و سپس از آن در اینجا استفاده نمود.


docker-compose و ایجاد شبکه‌های ایزوله

توسط دستور docker network ls می‌توان لیست شبکه‌های مجازی ایجاد شده‌ی توسط docker را مشاهده کرد (و همچنین سایر network adapters موجود). اگر این دستور را اجرا کنید، کارت شبکه‌ی مجازی متناظر با شبکه‌ی خصوصی teamcity_default را که پیشتر در مورد آن توضیح داده شد، می‌توانید مشاهده کنید. این teamcity در اینجا همان نام پروژه و یا در اصل نام پوشه‌ای است که فایل docker-compose را از آنجا اجرا کردیم.
برای دریافت اطلاعات بیشتری در مورد این کارت شبکه‌ی به خصوص، می‌توان دستور docker network inspect teamcity_default را صادر کرد. یکی از قسمت‌های خروجی این گزارش، لیست کانتینرهایی است که هم اکنون به این شبکه متصل هستند؛ که در اینجا teamcity و بانک اطلاعاتی آن است.
مزیت ایجاد یک شبکه‌ی خصوصی مخصوص کانتینرهای به هم پیوسته، علاوه بر سادگی تشکیل فایل docker-compose آن‌ها با اشاره‌ی به نام کانتینرها، بجای ذکر مستقیم آدرس IP هر کدام، ایزوله ساختن این شبکه، از شبکه‌ی پیش‌فرض docker و بالا بردن میزان امنیت سایر کانتینرهایی است که هم اکنون از آن شبکه استفاده می‌کنند.


docker-compose و ایجاد DNS Server توکار

همانطور که عنوان شد، در این شبکه‌ی خصوصی ویژه‌ی کانتینرهای به هم پیوسته که توسط docker-compse اجرا و مدیریت شده‌اند، می‌توان از نام containerها بجای آدرس IP آن‌ها استفاده کرد و این مورد با وجود یک DNS Server توکار در این شبکه میسر شده‌است. برای آزمایش بیشتر این قابلیت، ابتدا دستور docker ps را صادر می‌کنیم تا نام کانتینرهای در حال اجرا را بدست بیاوریم. سپس سعی می‌کنیم پروسه‌ی bash shell داخل کانتینر بانک اطلاعاتی را اجرا کنیم:
docker ps
docker exec -it teamcity_postgres_1 bash
#exit
استفاده از docker exec یک روش است برای دسترسی به shell این کانتینر در حال اجرا؛ روش دیگر، استفاده از خود docker-compse می‌باشد که در این حالت، کار با آن ساده‌تر است:
 docker-compose exec postgres bash
در اینجا نیازی به ذکر سوئیچ it نیست؛ چون مقدار پیش‌فرض آن است و همچنین دیگر نیازی به اجرای docker ps برای یافتن نام کانتینری هم نیست و مستقیما می‌توان از نام‌های سرویس‌هایی که در فایل docker-compose.yml تعریف شده‌اند، استفاده کرد.
پس از دسترسی به شل، دستور زیر را اجرا کنید:
#ping teamcity
#exit
مشاهده خواهید کرد که این کانتینر می‌تواند کانتینر دیگری را صرفا با ذکر نام آن، ping کند.

یک نکته: اگر بخواهیم از وضعیت بانک‌های اطلاعاتی postgres توسط برنامه‌ی psql آن گزارش بگیریم نیز روش اجرای آن به همین صورت است:
docker-compose exec postgres psql -U postgres
postgres=#\l
postgres=#\q


اتصال یک کانتینر خارج از شبکه‌ی مجازی ایجاد شده‌ی توسط docker-compose به آن

فرض کنید می‌خواهید کانتینر کم حجم لینوکس alpine را اجرا کنید و توسط آن به شبکه‌ی مجازی ایجاد شده‌ی توسط docker-compose متصل شوید. روش آن به صورت زیر است:
 docker run --name apline -it --rm --net teamcity_default alpine sh
در اینجا توسط سوئیچ net، می‌توان نام شبکه‌ی مجازی را که نیاز است به آن متصل شویم، ذکر کرد. نام teamcity_default نیز از طریق اجرای دستور docker netwrok ls بدست آمده‌است.
این دستور، کانتینر لینوکس alpine را در حالت interactive جهت اجرای shell آن، راه اندازی می‌کند. سپس به شبکه‌ی مجازی teamcity_default متصل می‌شود. برای آزمایش این اتصال، در این shell راه اندازی شده، دستور ping teamcity را می‌توان صادر کرد. همچنین از داخل کانتینر teamcity نیز می‌توان این کانتینر را با نام آن ping کرد.


راه اندازی مجدد کانتینرها توسط docker-compose

اگر دستور docker-compose ps را دقیقا در پوشه‌ای که فایل yml آن قرار دارد اجرا کنیم، می‌توان گزارشی را صرفا از وضعیت کانتینرهای مرتبط با این فایل yml بدست آورد. دستور docker ps، لیست وضعیت تمام کانتینرهای در حال اجرای موجود را بر می‌گرداند. اکنون فرض کنید یکی از کانتینرهای اجرای شده‌ی توسط docker-compose، دیگر در حال اجرا نیست. برای راه اندازی مجدد آن می‌توان از دستور docker-compose start teamcity-agent استفاده کرد. همچنین دستور docker-compose logs teamcity-agent، لیست آخرین لاگ‌های مرتبط با یک کانتینر را بر می‌گرداند که می‌تواند برای رفع اشکال بسیار مفید باشد.


حذف کانتینرهای به هم پیوسته‌ی ایجاد شده‌ی توسط docker-compose

در ذیل ابتدا یک سری دستور را جهت مشاهده‌ی وضعیت سیستم مشاهده می‌کنید. سپس دستور docker-compose stop، کار متوقف کردن کانتینرهای مرتبط با فایل yml آن‌را انجام می‌دهد. دستور docker-compose rm -v، علاوه بر حذف این کانتینرها، volumeهای بانک‌های اطلاعاتی مرتبط را نیز حذف می‌کند. در آخر دستور docker-compose down، شبکه‌ی مجازی مرتبط را نیز حذف خواهد کرد. سپس مجددا از وضعیت سیستم گزارش گیری شده‌است.
 docker ps
docker-compose ps
docker volume ls
docker network ls

docker-compose stop
docker-compose rm -v
docker-compose down

docker ps -a
docker volume ls
docker network ls


اجرای پروژه‌ی ASP.NET Core Music Store توسط docker-compose

پروژه‌ی معروف Music Store مایکروسافت را به همراه فایل docker-compose.windows.yml آن، در اینجا می‌توانید مشاهده کنید. محتوای این فایل نیز به صورت زیر است:
version: '3'
services:
  db:
    image: microsoft/mssql-server-windows-developer
    environment:
      sa_password: "Password1"
      ACCEPT_EULA: "Y"
    ports:
      - "1433:1433" # REMARK: This is currently required, needs investigation
    healthcheck:
      test: [ "CMD", "sqlcmd", "-U", "sa", "-P", "Password1", "-Q", "select 1" ]
      interval: 1s
      retries: 30
web:
    build:
      context: .
      dockerfile: Dockerfile.windows
    environment:
      - "Data:DefaultConnection:ConnectionString=Server=db,1433;Database=MusicStore;User Id=sa;Password=Password1;MultipleActiveResultSets=True"
    depends_on:
      - db
    ports:
      - "5000:5000"
در اینجا تعریف دو کانتینر را مشاهده می‌کنید:
- کانتینر db که بر اساس image مخصوص mssql-server-windows-developer راه اندازی می‌شود. تنظیمات آن نیز بسیار شبیه به مطلب «کار با Docker بر روی ویندوز - قسمت ششم - کار با بانک‌های اطلاعاتی درون Containerها» است که پیشتر در مورد آن بحث کردیم.
- کانتینر web آن که از فایل Dockerfile.windows برای build سپس publish و در آخر run خودکار این برنامه‌ی ASP.NET Core، کمک می‌گیرد. در اینجا context به پوشه‌ی جاری اشاره می‌کند. در قسمت تنظیمات بانک اطلاعاتی آن، استفاده‌ی از نام کانتینر db را در قسمت رشته‌ی اتصالی مشاهده می‌کنید. قسمت depends_on آن ترتیب اجرای این کانتینرها را مشخص می‌کند. یعنی ابتدا باید کانتینر db اجرا شود و سپس web.
محتوای فایل Dockerfile.windows آن نیز به صورت زیر است که بر اساس دستورات NET Core CLI. تهیه شده‌است:
FROM microsoft/dotnet-nightly:2.0-sdk-nanoserver
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
ENV NUGET_XMLDOC_MODE skip
ENV DOTNET_SKIP_FIRST_TIME_EXPERIENCE 1
RUN New-Item -Path \MusicStore\samples\MusicStore -Type Directory
WORKDIR app
ADD samples/MusicStore/MusicStore.csproj samples/MusicStore/MusicStore.csproj
ADD build/dependencies.props build/dependencies.props
ADD NuGet.config .
RUN dotnet restore --runtime win10-x64 .\samples\MusicStore
ADD samples samples
RUN dotnet publish --output /out --configuration Release --framework netcoreapp2.0 --runtime win10-x64 .\samples\MusicStore
FROM microsoft/dotnet-nightly:2.0-runtime-nanoserver
WORKDIR /app
COPY --from=0 /out .
EXPOSE 5000
ENV ASPNETCORE_URLS http://0.0.0.0:5000
CMD dotnet musicstore.dll
روش اجرای آن‌را نیز به صورت زیر بیان کرده‌است:
docker-compose -f .\docker-compose.windows.yml build
docker-compose -f .\docker-compose.windows.yml up
البته باید دقت داشت که اجرای فرمان up، به صورت خودکار کار build را هم انجام می‌دهد. پس از اجرای آن، برنامه را بر روی پورت 5000 می‌توانید مشاهده کنید.
مطالب
آشنایی با SQL Server Data Tools
مقدمه
یکی از امکانات اضافه شده در Sql Server 2012 ابزار Sql Server Data Tools یا به اختصار SSDT می‌باشد. این ابزار در واقع جایگزین ابزار Business Intelligence Development Studio می باشد که همه امکانات قبلی را داشته و همچنین قابلیت‌های جدیدی نیز به آن اضافه شد است. اما کاربرد این ابزار ایجاد محیطی یکپارچه برای طراحی و توسعه تمامی نسخه‌های پایگاه داده Sql Server با استفاده از Visual Studio می‌باشد. در این مقاله من به بیشتر بر روی امکانات زیر تمرکز دارم:
  • Installation
  • Creating a SQL Server Database Project
  • Modify Database Schema
  • Schema Compare and Update
  • Snapshot Project
  • Publish
  1. نصب Sql Server Data Tools
    آخرین نسخه این ابزار را از این آدرس دانلود کنید یا زمان نصب Sql Server 2012 گزینه آن را انتخاب کنید


  2. ایجاد یک پروژه جدید از نوع  SQL Server Database Project
    پس از نصب SSDT شما از طریق Visual Studio 2012 Shell که همراه SqlServer 2012 نصب می‌شود یا با Visual Stadio 2012 یک پروژه جدید از نوع SQL Server Database Project ایجاد کنید.

     Server Database Project Project به شما امکان توسعه پایگاه داده Sql Server را با استفاده  از محیط یکپارچه Visual Studio با در اختیار گذاشتن ابزار‌های همچون navigation, intellisense, validation, debugging, declarative editing و غیره را می‌دهد. شی پایگاه داده شما در پروژه و فایل‌های مجزا ذخیره می‌شود مثل آن که شما در حال توسعه برنامه #C یا VB.NET هستید.
  3. ورود پایگاه داده موجود به پروژه SQL Server Database
    شما می‌توانید شمای پایگاه داده موجود یا SQL Server DAC Package File (.dacpac) یا هر T-SQL دیگری را با راست کلیک بر روی پروژه و انتخاب گزینه Import به پروژه خود اضافه و تغییرات لازم را اعمال نماید شکل زیر پنجره Import Database  را نشان می‌دهد:
     

      پنجره 
    Solution Explorer امکانات زیر را در اختیار شما قرارمی دهد:

    - اضافه کردن اشیای همچون Table، View  و غیره با راست کیلک کردن بر روی پروژه و انتخاب گزینه Add
    - ویرایش اشیا موجود با دبل کیلک کردن بر روی اشیا
    - مقایسه شمای پایگاه داده با پایگاه داده دیگر و یا Microsoft SQL Server DAC Package File کافیست بر روی پروژه راست کیلک و گزینه Schema Compare را         انتخاب نمایید.
    - ایجاد یک Snapshot از شمای پایگاه داده در یک Microsoft SQL Server DAC Package File . یک snapshot برای ایجاد یک پایگاه داده یا ورود در پروژه ای دیگر یا در مقایسه دو پایگاه داده کاربرد دارد.
    - انتشار پایگاه داده که امکان ایجاد پایگاه داده یر روی یک سرور SQL Server را فراهم می‌نماید.  

  4. مقایسه شمای دو پایگاه داده با هم
    SSDT ابزاری برای مقایسه دو پایگاه داده و بروز رسانی پایگاه داده مقصد از روی شمای منبع از طریق ایجاد یک Script یا به صورت مستقیم را می‌دهد.



  5. انتشار پروژه با استفاده از SQL Server Data Tools
    این ابزار امکان گسترش پروژه شما بر روی SQL Server 2005, 2008, 2008 R2, 2012, یا SQL Azure instance را می‌دهد. برای انتشار کافیت از پنجره Solution Explorer  بر روی پروژه راست کیلک و گزینه Publish را انتخاب کنید.

  6. پنجره SQL Server Object Explorer
    این پنجره با اتصال به سرور SQL Server  امکان دسترسی و مدیریت پایگاه داده را به ما می‌دهد. علاوه بر دسترسی به اجزای یک پایگاه داده امکان مدیریت پوشه‌های Security , Server Objects نیز فراهم می‌باشد. همچنین امکان اتصال به Sql Server Express , localdb نیز وجود دارد. 


  7.   
نظرات مطالب
BulkInsert در EF CodeFirst
- کار ما رفع باگ‌های پروژه‌های ثالث نیست. باید این مساله را در issue tracker آن‌ها پیگیری کنید. این مشکل باید در پروژه‌ی اصلی برطرف شود و نه اینجا.
- در کل اگر به فایل providerBase آن مراجعه کنید، چنین تعریفی را دارد:
        protected virtual string ConnectionString
        {
            get
            {
                return (string)DbConnection.GetPrivateFieldValue("_connectionString");
            }
        }
سورس را دریافت کنید و مورد فوق را به نحو ذیل تغییر دهید:
protected virtual string ConnectionString {
  get {
    return (string)DbConnection.ConnectionString;
  }
}
مطالب
تولید MiniDump در حین کرش برنامه‌های دات نت
با مطالعه‌ی سورس‌های محصولات اخیرا سورس باز شده‌ی مایکروسافت، نکات جالبی را می‌توان استخراج کرد. برای نمونه اگر سورس پروژه‌ی Orleans را بررسی کنیم، در حین بررسی اطلاعات استثناءهای رخ داده‌ی در برنامه، متد TraceLogger.CreateMiniDump نیز بکار رفته‌است. در این مطلب قصد داریم، این متد و نحوه‌ی استفاده‌ی از حاصل آن‌را بررسی کنیم.


تولید MiniDump در برنامه‌های دات نت


خلاصه‌ی روش تولید MiniDump در پروژه‌ی Orleans به صورت زیر است:
الف) حالت‌های مختلف تولید فایل دامپ که مقادیر آن قابلیت Or شدن را دارا هستند:
    [Flags]
public enum MiniDumpType
{
    MiniDumpNormal = 0x00000000,
    MiniDumpWithDataSegs = 0x00000001,
    MiniDumpWithFullMemory = 0x00000002,
    MiniDumpWithHandleData = 0x00000004,
    MiniDumpFilterMemory = 0x00000008,
    MiniDumpScanMemory = 0x00000010,
    MiniDumpWithUnloadedModules = 0x00000020,
    MiniDumpWithIndirectlyReferencedMemory = 0x00000040,
    MiniDumpFilterModulePaths = 0x00000080,
    MiniDumpWithProcessThreadData = 0x00000100,
    MiniDumpWithPrivateReadWriteMemory = 0x00000200,
    MiniDumpWithoutOptionalData = 0x00000400,
    MiniDumpWithFullMemoryInfo = 0x00000800,
    MiniDumpWithThreadInfo = 0x00001000,
    MiniDumpWithCodeSegs = 0x00002000,
    MiniDumpWithoutManagedState = 0x00004000
}

ب) متد توکار ویندوز برای تولید فایل دامپ
public static class NativeMethods
{
    [DllImport("Dbghelp.dll")]
    public static extern bool MiniDumpWriteDump(
        IntPtr hProcess,
        int processId,
        IntPtr hFile,
        MiniDumpType dumpType,
        IntPtr exceptionParam,
        IntPtr userStreamParam,
        IntPtr callbackParam);
}

ج) فراخوانی متد تولید دامپ در برنامه
در اینجا نحوه‌ی استفاده از enum و متد MiniDumpWriteDump ویندوز را مشاهده می‌کنید:
public static class DebugInfo
{
    public static void CreateMiniDump(
        string dumpFileName, MiniDumpType dumpType = MiniDumpType.MiniDumpNormal)
    {
        using (var stream = File.Create(dumpFileName))
        {
            var process = Process.GetCurrentProcess();
            // It is safe to call DangerousGetHandle() here because the process is already crashing.
            NativeMethods.MiniDumpWriteDump(
                            process.Handle,
                            process.Id,
                            stream.SafeFileHandle.DangerousGetHandle(),
                            dumpType,
                            IntPtr.Zero,
                            IntPtr.Zero,
                            IntPtr.Zero);
        }
    }
 
    public static void CreateMiniDump(MiniDumpType dumpType = MiniDumpType.MiniDumpNormal)
    {
        const string dateFormat = "yyyy-MM-dd-HH-mm-ss-fffZ"; // Example: 2010-09-02-09-50-43-341Z
        var thisAssembly = Assembly.GetEntryAssembly() ?? Assembly.GetCallingAssembly();
        var dumpFileName = string.Format(@"{0}-MiniDump-{1}.dmp",
                    thisAssembly.GetName().Name,
                    DateTime.UtcNow.ToString(dateFormat, CultureInfo.InvariantCulture));
 
        var path = Path.Combine(getApplicationPath(), dumpFileName);
        CreateMiniDump(path, dumpType);
    }
 
    private static string getApplicationPath()
    {
        return HttpContext.Current != null ?
            HttpRuntime.AppDomainAppPath :
            Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    }
}
متد MiniDumpWriteDump نیاز به اطلاعات پروسه‌ی جاری، به همراه هندل فایلی که قرار است اطلاعات را در آن بنویسد، دارد. همچنین dump type آن نیز می‌تواند ترکیبی از مقادیر enum مرتبط باشد.

یک مثال:
class Program
{
    static void Main(string[] args)
    {
        try
        {
            var zero = 0;
            Console.WriteLine(1 / zero);
        }
        catch (Exception ex)
        {
            Console.Write(ex);
            DebugInfo.CreateMiniDump(dumpType:
                                MiniDumpType.MiniDumpNormal |
                                MiniDumpType.MiniDumpWithPrivateReadWriteMemory |
                                MiniDumpType.MiniDumpWithDataSegs |
                                MiniDumpType.MiniDumpWithHandleData |
                                MiniDumpType.MiniDumpWithFullMemoryInfo |
                                MiniDumpType.MiniDumpWithThreadInfo |
                                MiniDumpType.MiniDumpWithUnloadedModules);
 
            throw;
        }
    }
}
در اینجا نحوه‌ی فراخوانی متد CreateMiniDump را در حین کرش برنامه مشاهده می‌کنید. پارامترهای اضافی دیگر سبب خواهند شد تا اطلاعات بیشتری از حافظه‌ی جاری سیستم، در دامپ نهایی قرار گیرند. اگر پس از اجرای برنامه، به پوشه‌ی bin\debug مراجعه کنید، فایل dmp تولیدی را مشاهده خواهید کرد.


نحوه‌ی بررسی فایل‌های dump


الف) با استفاده از Visual studio 2013

از به روز رسانی سوم VS 2013 به بعد، فایل‌های dump را می‌توان داخل خود VS.NET نیز آنالیز کرد (^ و ^ و ^). برای نمونه تصویر ذیل، حاصل کشودن فایل کرش مثال فوق است:


در اینجا اگر بر روی لینک debug managed memory کلیک کنید، پس از چند لحظه، آنالیز کامل اشیاء موجود در حافظه را در حین تهیه‌ی دامپ تولیدی، می‌توان مشاهده کرد. این مورد برای آنالیز نشتی‌های حافظه‌ی یک برنامه بسیار مفید است.


ب) استفاده از برنامه‌ی Debug Diagnostic Tool

برنامه‌ی Debug Diagnostic Tool را از اینجا می‌توانید دریافت کنید. این برنامه نیز قابلیت آنالیز فایل‌های دامپ را داشته و اطلاعات بیشتری را پس از آنالیز ارائه می‌دهد.


برای نمونه پس از آنالیز فایل دامپ تهیه شده توسط این برنامه، خروجی ذیل حاصل می‌شود:



کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید:
MiniDumpTest.zip