مطالب
تعریف انبار داده Data Warehouse
در این مقاله در ادامه‌ی مطلبی که تحت عنوان «آموزش مفاهیم Data Warehouse» توسط آقای شاه قلی منتشر شده بود، به بررسی بیشتر مفهوم انبار داده ( Data Warehouse ) پرداخته می‌شود.

مقدمه
در سازمان ها، داده‌ها و اطلاعات معمولاً به دو شکل در سیستم‌ها پیاده سازی می‌گردد:
• سیستم‌های عملیاتی  OLTP:
این سیستم‌ها باعث می‌گردند تا چرخ کسب و کار بگردد. وجود این سیستم‌ها سبب می‌شود تا داده‌های مربوط به کسب و کار، به بانک اطلاعاتی وارد شوند. این سیستم‌ها عموماً:
o به دلیل کوتاهی عملیات دارای سرعت قابل توجهی می‌باشند.
o محیطی جهت ورود داده‌ها می‌باشند.
o معمولاً اپراتورها، استفاده کننده‌های آن هستند.
• سیستم‌های اطلاعاتی OLAP ، DW/BI، DSS :
این سیستم‌ها باعث می‌گردند تا چرخش کسب و کار را بنگرید. فلسفه بکارگیری این سیستم‌ها در سازمان این است که اطلاعات مورد نیاز مدیران، از درون داده‌های سیستم‌های عملیاتی موجود، استخراج گردد. این سیستم‌ها عموماً:
o به دلیل آنالیز حجم انبوهی از داده ها، معمولاً کندتر از سیستم‌های عملیاتی می‌باشند.
o محیطی جهت تولید گزارشات تحلیلی و آماری می‌باشند.
o معمولاً مدیران و تصمیم گیرندگان سازمان ها، استفاده کنندگان آن می‌باشند.
سیستم‌های عملیاتی در جامعه ما سابقه بیشتری داشته و متخصصین فناوری اطلاعات عموماً با طراحی و تولید چنین سیستم هایی آشنایی کافی دارند. متاسفانه جایگاه سیستم‌های اطلاعاتی در جامعه ما کمتر شناخته شده و متخصصین فناوری اطلاعات بندرت با مفاهیم و نحوه پیاده سازی آن آشنایی دارند.
این نکته حائز اهمیت است که سیستم‌های اطلاعاتی یک سیستم یا محصول نیستند که بتوان آنها را خریداری کرد. بلکه یک راهبرد (Solution, Approach) هستند و در حقیقت هر راهبردی مربوط به یک نوع کسب و کار (Business) و یا سازمان می‌باشد و نمی‌توان فرمول واحدی را برای حتی سازمان‌های مشابه، ارائه نمود.

گارتنر در ابتدای سال 2011 گزارشی را منتشر کرده که نشان میدهد بازار BI با 9.7 % رشد، ارزشی بالغ بر 10.8 بیلیون دلار داشته، ولی متاسفانه پروژه‌های آن به طور متوسط با 75% شکست مواجه شده است. در حالیکه 4 سال پیش، این رقم حدود 50% بود. این موسسه BI را پنجمین اولویت مدیران IT ذکر کرده است.

مفاهیم و مباحث مربوط به Data Warehouse به اواسط دهه 1980 برمی گردد، به زمانی که IBM تحقیقاتی را در این زمینه شروع کرد و نتیجه آنرا «Information Warehouse» نامید و هنوز هم در برخی منابع از این واژه بجای Data Warehouse استفاده می‌شود. از این پس برای راحتی از اختصار DW بجای Data Warehouse استفاده می‌شود. انبارهای داده جهت رفع نیاز رو به رشد مدیریت داده‌ها و اطلاعات سازمانی که توسط پایگاه‌های داده سیستم‌های عملیاتی غیر ممکن بود، ساخته شدند.

انبار داده به مجموعه ای از داده‌ها گفته می‌شود که از منابع مختلف اطلاعاتی سازمان جمع آوری، دسته بندی و ذخیره می‌شود. در واقع یک انبار داده مخزن اصلی کلیه داده‌های حال و گذشته یک سازمان می‌باشد که برای همیشه جهت انجام عملیات گزارش گیری و آنالیز در دسترس مدیران می‌باشد. انباره‌های داده حاوی داده هایی هستند که به مرور زمان از سیستم‌های عملیاتی آنلاین سازمان، استخراج می‌شوند. بنابراین سوابق کلیه اطلاعات و یا بخش عظیمی از آنها را می‌توان در انباره داده‌ها مشاهده نمود.
از آنجائیکه انجام عملیات آماری و گزارشات پیچیده دارای بار کاری بسیار سنگینی برای سرورهای پایگاه داده می‌باشند، وجود انبار داده سبب می‌گردد که این گونه عملیات تاثیری بر فعالیت برنامه‌های کاربردی سازمان نداشته باشد.
همانگونه که پایگاه داده سیستم‌های عملیاتی سازمان (برنامه‌های کاربردی) به گونه ای طراحی می‌شوند که انجام تغییر، حذف و اضافه داده به سرعت صورت پذیرد، در مقابل انبار داده‌ها دارای معماری ویژه ای می‌باشند که موجب تسریع انجام عملیات آماری و گزارش گیری می‌شود. در حقیقت می‌توان اینگونه بیان نمود که انباره داده یک مخزن فعال و هوشمند از اطلاعات است که قادر است اطلاعات را از محیط‌های گوناگون جمع آوری و مدیریت کرده و نهایتا پخش نماید و در صورت لزوم نیز سیاست‌های تجاری را روی آنها اجرا نماید.

Bill Inmon:
او را پدر DW می‌نامند، از دیدگاه او DW هسته مرکزی چیزی است که او آنرا CIF اختصار (Corporate Information Factory) می‌نامد، که پایه و اساس BI بر مبنای آن قرار دارد. وی از طرفداران Top-Down Design می‌باشد که معتقد است در زمان طراحی باید با دیدی سازمانی، CIF را مدل سازی، ولی بصورت دپارتمانی پیاده سازی کرد (Think Globally, Implement Locally). در این نوع طراحی از DW به Data Mart خواهیم رسید.

Ralph Kimball Ph.D:
به نظر وی DW چیزی نیست جز یک کپی از داده‌های عملیاتی که به طرز خاصی برای گزارشات و تحلیل‌های آماری، آماده و ساختمند شده است. به بیان دیگر DW سیستمی است جهت استخراج، پالایش، تطبیق و تحویل اطلاعات منابع داده ای به یک بانک اطلاعاتی Dimensional و اجرای Query و گزارشات آماری و تحلیلی برای اهداف تصمیم گیری و استراتژیک سازمان.
وی معرفی کننده یکی از اساسی‌ترین مفاهیم طراحی یعنی Dimensional Modeling است؛ ماحصل چنین ایده ای، اساس شکل گیری مدلی است که امروزه کارشناسان آنرا به نام Cube می‌شناسند. وی از طرفداران Bottom-Up Design است که در این نگرش از Data Mart به DW می‌رسیم. این روش به نظر عملی‌تر از روشی می‌باشد که به یکباره DW جامع و کامل برای اهداف سازمانی طراحی و پیاده سازی گردد.

تعریف انبار داده:
W.H.Inmon پدر DW آنرا چنین تعریف می‌کند:
The Data Warehouse is a collection of Integrated, Subject-Oriented databases designed to support the DSS function, where each unit of data is Non-Volatile and relevant to some moment in Time
از تعریف فوق دو مورد دیگر نیز به طور ضمنی استنباط می‌شود:
o انبار داده به طور فیزیکی، کاملاً جدا از سایر سیستم‌های عملیاتی است.
o داده‌های DW مجموعه ای Aggregated و Atomic از داده‌های تراکنش‌های سیستم‌های عملیاتی است که سوای کاربرد آنها در سیستم‌های عملیاتی، برای مقاصد مدیریتی نیز استفاده خواهد شد.

به بیان دیگر DW راهبردی است که دسترسی آسان به اطلاعات درست (Right Information)، در زمانی درست (Right Time) ، به کاربران درست (Right Users)، را فراهم می‌آورد تا «تصمیم گیری سازمانی» قابل انجام باشد. DW صرفاً یک محصول نرم افزاری و یا سخت افزاری نیست که بتوان آنرا خریداری نمود بلکه فراتر از آن و در حقیقت یک محیط پردازشی می‌باشد که کاربران می‌توانند از درون آن اطلاعات مورد نیاز خود را بیابند.
DW اطلاعات خود را از سایر بانک‌های اطلاعاتی از نوع OLTP و یا سایر DW‌های لایه پایین‌تر و به صورت دسته ای (Batch) و یا انبوه (Bulk Loading) جمع آوری می‌کند. یک DW به صورت سنتی باید شامل داده‌های Historic سازمان باشد و می‌توان اینگونه بیان نمود که در DW هرچه داده‌های قدیمی‌تری موجود باشد، اعتبار تحلیل‌های آماری سیستم افزایش خواهد یافت.

داده‌های سیستم عملیاتی را نمی‌توان بلافاصله درون بانک اطلاعاتی DW لود نمود، چنین داده هایی باید آماده سازی، پالایش و همگون گردند تا شرایط لود در DW را داشته باشند. حداقل کاری که انتظار داریم یک DW در مورد داده‌ها برای ما برآورده سازد شامل موارد زیر است:
o استخراج داده‌ها از منابع مختلف (مبدإ)
o تبدیل داده‌ها به فرمتی یکسان
o لود داده‌ها به جداول مربوطه (مقصد)
با هر با اجرای پروسه فوق یکی از سه مورد زیر، بسته به نیاز طراحی و محدودیت‌های تکنولوژی رخ خواهد داد:
o تمام داده‌ها در DW با داده‌های جدید جایگزین خواهند گردید(Full Load, Initial Load, Full Refresh).
o داده‌های جدید به داده‌های موجود اضافه خواهند گردید (Incremental Load (Inserted data.
o نسخه جدیدی از داده‌های کنونی به سیستم اضافه خواهند گردید (Incremental Load (Updated data.


ویژگی‌های داده‌های درون DW
داده‌های DW از نگاه Inmon دارای 4 ویژگی اصلی زیر هستند:
o فقط خواندنی (Non-Volatile):
هیچ رکوردی و یا داده ای Update نخواهد شد و صرفاً رکوردهایی که محتوای مقادیر جدید داده‌ها هستند، به سیستم اضافه خواهند شد.
o موضوع گرا (Subject-Oriented):
منظور از «موضوع» پایه‌های اساسی یک کسب و کار هستند، به شکلی که با حذف یکی از این پایه ها، شاید ماهیت آن کسب و کار از ریشه دگرگون شود. برای مثال موضوعاتی چون «مشتری» و یا «بیمه نامه» برای شرکت‌های بیمه.
o جامع (Integrated):
باید تمامی کدهایی که در سیستم‌های عملیاتی وجود دارند و معانی یکسانی دارند، برای مثال کد جنسیت، در DW به یک روش ذخیره و نمایش داده شوند.
o زمانگرا (Time Variant):
هر رکورد باید حاوی فیلد و یا کلیدی باشد که نمایانگر این باشد که این رکورد در چه زمانی ایجاد، استخراج و ذخیره شده است. از آنجا که داده‌های درون سیستم‌های عملیاتی آخرین و به روز‌ترین داده هر سیستم میباشد، نیازی به وجود چنین عنصری در سیستم‌های OLTP احساس نمی‌گردد، ولی چون در DW تمام داده‌های نسخ قدیمی داده‌های سیستم‌های عملیاتی موجود می‌باشد، باید حتماً مشخص گردد که هر داده ای در سیستم‌های عملیاتی در چه زمانی، چه مقادیری داشته است. این عنصر زمانی کمک می‌کند تا بتوانیم:
o گذشته را آنالیز کنیم.
o اطلاعات مربوط به حال حاضر را بدست آوریم.
o آینده را پیش بینی کنیم.

منبع: کتاب آقای خشایار جام سحر با عنوان بانک داده تجمیعی
Comparison  Kimball vs. Inmon

Inmon
Continuous & Discrete Dimension Management
Define data management via dates in your data
Continuous time  
  When is a record active
Start and end dates
Discrete time  
 A point in time
  Snapshot
 
Kimball
Slowly Changing Dimension Management
Define data management via versioning
Type I  
  Change record as required
  No History
Type II  
  Manage all changes
 History is recorded
Type III  
  Some history is parallel
  Limit to defined history


Kimball 
Inmon 
Business-Process-Oriented
Stresses Dimensional Model, Not E-R
Subject-Oriented
Integrated
Non-Volatile
Time-Variant
Bottom-Up and Evolutionary 
Top-Down 
Integration Achieved via Conformed Dimensions 
Integration Achieved via an Assumed Enterprise Data Model 
Star Schemas Enforce Query Semantics 
Characterizes Data marts as Aggregates 
Kimball
Inmon

Bottom-up
Top-down
Overall approach
Data marts model a business process;enterprise is achieved with conformed dims
Enterprise-wide DW feeds departmental DBs
Architectural structure
Fairly simple
Quite complex
Complexity of method
Process oriented
Subject or data driven
Data orientation
Dimensional modeling; departs from traditional relational modeling
Traditional  ERDs and DIS
Tools
High
Low
End user accessibility
Slowly Changing
Continuous & Discrete
Timeframe
Dimension keys
Timestamps
Methods
نظرات مطالب
مقدمه‌ای بر داکر، قسمت سوم
پوشه node_modules رو بهتر است به فایل dockerignore. اضافه کنید تا وابستگی‌ها داخل کانتینر نصب شوند؛ یکسری پکیج‌ها مشکل cross platform بودن دارند که بهتر است در سیستم مقصد npm i صورت بگیرد تا وابستگی متناسب با سیستم‌عامل نصب شود.
اشتراک‌ها
افزونه رایگان فونت ایران برای زیباسازی وب سایت‌های فارسی

ابتدا افزونه را نصب کنید سپس روی آیکون افزونه کلیک کرده و فونت مورد نظر را انتخاب نمایید تا فونت روی سایت اعمال شود.

در حال حاضر پرکاربردترین وب سایت‌ها، شبکه‌های اجتماعی و سرویس‌های تحت وب می‌توانند از این افزونه بهره ببرند.

وب سایت: ویکی‌پدیا و گوگل

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

سرویس‌های تحت وب: واتس آپ، تلگرام و ترلو 

دانلود برای موزیلا

افزونه رایگان فونت ایران برای زیباسازی وب سایت‌های فارسی
مطالب
استفاده از Kendo UI templates
در مطلب «صفحه بندی، مرتب سازی و جستجوی پویای اطلاعات به کمک Kendo UI Grid» در انتهای بحث، ستون IsAvailable به صورت زیر تعریف شد:
columns: [
               {
                   field: "IsAvailable", title: "موجود است",
                   template: '<input type="checkbox" #= IsAvailable ? checked="checked" : "" # disabled="disabled" ></input>'
                }
]
Templates، جزو یکی از پایه‌های Kendo UI Framework هستند و توسط آن‌ها می‌توان قطعات با استفاده‌ی مجدد HTML ایی را طراحی کرد که قابلیت یکی شدن با اطلاعات جاوا اسکریپتی را دارند.
همانطور که در این مثال نیز مشاهده می‌کنید، قالب‌های Kendo UI از Hash (#) syntax استفاده می‌کنند. در اینجا قسمت‌هایی از قالب که با علامت # محصور می‌شوند، در حین اجرا، با اطلاعات فراهم شده جایگزین خواهند شد.
برای رندر مقادیر ساده می‌توان از # =# استفاده کرد. از # :# برای رندر اطلاعات HTML-encoded کمک گرفته می‌شود و #  # برای رندر کدهای جاوا اسکریپتی کاربرد دارد. از حالت HTML-encoded برای نمایش امن اطلاعات دریافتی از کاربران و جلوگیری از حملات XSS استفاده می‌شود.
اگر در این بین نیاز است # به صورت معمولی رندر شود، در حالت کدهای جاوا اسکریپتی به صورت #\\ و در HTML ساده به صورت #\ باید مشخص گردد.


مثالی از نحوه‌ی تعریف یک قالب Kendo UI

    <!--دریافت اطلاعات از منبع محلی-->
    <script id="javascriptTemplate" type="text/x-kendo-template">
        <ul>
            # for (var i = 0; i < data.length; i++) { #
            <li>#= data[i] #</li>
            # } #
        </ul>
    </script>

    <div id="container1"></div>
    <script type="text/javascript">
        $(function () {
            var data = ['User 1', 'User 2', 'User 3'];
            var template = kendo.template($("#javascriptTemplate").html());
            var result = template(data); //Execute the template
            $("#container1").html(result); //Append the result
        });
    </script>
این قالب ابتدا در تگ script محصور می‌شود و سپس نوع آن مساوی text/x-kendo-template قرار می‌گیرد. در ادامه توسط یک حلقه‌ی جاوا اسکریپتی، عناصر آرایه‌ی فرضی data خوانده شده و با کمک Hash syntax در محل‌های مشخص شده قرار می‌گیرند.
در ادامه باید این قالب را رندر کرد. برای این منظور یک div با id مساوی container1 را جهت تعیین محل رندر نهایی اطلاعات مشخص می‌کنیم. سپس متد kendo.template بر اساس id قالب اسکریپتی تعریف شده، یک شیء قالب را تهیه کرده و سپس با ارسال آرایه‌ای به آن، سبب اجرای آن می‌شود. خروجی نهایی، یک قطعه کد HTML است که در محل container1 درج خواهد شد.
همانطور که ملاحظه می‌کنید، متد kendo.template، نهایتا یک رشته را دریافت می‌کند. بنابراین همینجا و به صورت inline نیز می‌توان یک قالب را تعریف کرد.


کار با منابع داده راه دور

فرض کنید مدل برنامه به صورت ذیل تعریف شده‌است:
namespace KendoUI04.Models
{
    public class Product
    {
        public int Id { set; get; }
        public string Name { set; get; }
        public decimal Price { set; get; }
        public bool IsAvailable { set; get; }
    }
}
و لیستی از آن توسط یک ASP.NET Web API کنترلر، به سمت کاربر ارسال می‌شود:
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using KendoUI04.Models;

namespace KendoUI04.Controllers
{
    public class ProductsController : ApiController
    {
        public IEnumerable<Product> Get()
        {
            return ProductDataSource.LatestProducts.Take(10);
        }
    }
}
در سمت کاربر و در View برنامه خواهیم داشت:
    <!--دریافت اطلاعات از سرور-->
    <div>
        <div id="container2"><ul></ul></div>
    </div>

    <script id="template1" type="text/x-kendo-template">
        <li> #=Id# - #:Name# - #=kendo.toString(Price, "c")#</li>
    </script>

    <script type="text/javascript">
        $(function () {
            var producatsTemplate1 = kendo.template($("#template1").html());

            var productsDataSource = new kendo.data.DataSource({
                transport: {
                    read: {
                        url: "api/products",
                        dataType: "json",
                        contentType: 'application/json; charset=utf-8',
                        type: 'GET'
                    }
                },
                error: function (e) {
                    alert(e.errorThrown);
                },
                change: function () {
                    $("#container2 > ul").html(kendo.render(producatsTemplate1, this.view()));
                }
            });
            productsDataSource.read();
        });
    </script>
ابتدا یک div با id مساوی container2 جهت تعیین محل نهایی رندر قالب template1 در صفحه تعریف می‌شود.
هرچند خروجی دریافتی از سرور نهایتا یک آرایه از اشیاء Product است، اما در template1 اثری از حلقه‌ی جاوا اسکریپتی مشاهده نمی‌شود. در اینجا چون از متد kendo.render استفاده می‌شود، نیازی به ذکر حلقه نیست و به صورت خودکار، به تعداد عناصر آرایه دریافتی از سرور، قطعه HTML قالب را تکرار می‌کند.
در ادامه برای کار با سرور از یک Kendo UI DataSource استفاده شده‌است. قسمت transport/read آن، کار تعریف محل دریافت اطلاعات را از سرور مشخص می‌کند. رویدادگران change آن اطلاعات نهایی دریافتی را توسط متد view در اختیار متد kendo.render قرار می‌دهد. در نهایت، قطعه‌ی HTML رندر شده‌ی نهایی حاصل از اجرای قالب، در بین تگ‌های ul مربوط به container2 درج خواهد شد.
رویدادگران change زمانیکه data source، از اطلاعات راه دور و یا یک آرایه‌ی جاوا اسکریپتی پر می‌شود، فراخوانی خواهد شد. همچنین مباحث مرتب سازی اطلاعات، صفحه بندی و تغییر صفحه، افزودن، ویرایش و یا حذف اطلاعات نیز سبب فراخوانی آن می‌گردند. متد view ایی که در این مثال فراخوانی شد، صرفا در روال رویدادگردان change دارای اعتبار است و آخرین تغییرات اطلاعات و آیتم‌های موجود در data source را باز می‌گرداند.


یک نکته‌ی تکمیلی: فعال سازی intellisense کدهای جاوا اسکریپتی Kendo UI

اگر به پوشه‌ی اصلی مجموعه‌ی Kendo UI مراجعه کنید، یکی از آن‌ها vsdoc نام دارد که داخل آن فایل‌های min.intellisense.js و vsdoc.js مشهود هستند.
اگر از ویژوال استودیوهای قبل از 2012 استفاده می‌کنید، نیاز است فایل‌های vsdoc.js متناظری را به پروژه اضافه نمائید؛ دقیقا در کنار فایل‌های اصلی js موجود. اگر از ویژوال استودیوی 2012 و یا بالاتر استفاده می‌کنید باید از فایل‌های intellisense.js متناظر استفاده کنید. برای مثال اگر از kendo.all.min.js کمک می‌گیرید، فایل متناظر با آن kendo.all.min.intellisense.js خواهد بود.
بعد از اینکار نیاز است فایلی به نام references.js_ را به پوشه‌ی اسکریپت‌های خود با این محتوا اضافه کنید (برای VS 2012 به بعد):
/// <reference path="jquery.min.js" />
/// <reference path="kendo.all.min.js" />
نکته‌ی مهم اینجا است که این فایل به صورت پیش فرض از مسیر Scripts/_references.js/~ خوانده می‌شود. برای اضافه کردن مسیر دیگری مانند js/_references.js/~ باید آن‌را به تنظیمات ذیل اضافه کنید:
 Tools menu –> Options -> Text Editor –> JavaScript –> Intellisense –> References
گزینه‌ی Reference Group را به (Implicit (Web تغییر داده و سپس مسیر جدیدی را اضافه نمائید.


کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید:
KendoUI04.zip
مطالب دوره‌ها
استفاده از async و await در برنامه‌های ASP.NET Web forms 4.5
سؤال: چه زمانی از متدهای async و چه زمانی از متدهای همزمان بهتر است استفاده شود؟

از متدهای همزمان متداول برای انجام امور ذیل استفاده نمائید:
- جهت پردازش اعمالی ساده و سریع
- اعمال مدنظر بیشتر قرار است بر روی CPU اجرا شوند و از مرزهای IO سیستم عبور نمی‌کنند.

و از متدهای غیرهمزمان برای پردازش موارد زیر کمک بگیرید:
- از وب سرویس‌هایی استفاده می‌کنید که متدهای نگارش async را نیز ارائه داده‌اند.
- عمل مدنظر network-bound و یا I/O-bound است بجای CPU-bound. یعنی از مرزهای IO سیستم عبور می‌کند.
- نیاز است چندین عملیات را به موازات هم اجرا کرد.
- نیاز است مکانیزمی را جهت لغو یک عملیات طولانی ارائه دهید.


مزایای استفاده از متدهای async در ASP.NET

استفاده از await در ASP.NET، ساختار ذاتی پروتکل HTTP را که اساسا یک synchronous protocol، تغییر نمی‌دهد. کلاینت، درخواستی را ارسال می‌کند و باید تا زمان آماده شدن نتیجه و بازگشت آن از طرف سرور، صبر کند. نحوه‌ی تهیه‌ی این نتیجه، خواه async باشد و یا حتی همزمان، از دید مصرف کننده کاملا مخفی است. اکنون سؤال اینجا است که چرا باید از متدهای async استفاده کرد؟
- پردازش موازی: می‌توان چند Task را مثلا توسط Task.WhenAll به صورت موازی با هم پردازش کرده و در نهایت نتیجه را سریعتر به مصرف کننده بازگشت داد. اما باید دقت داشت که این Taskها اگر I/O bound باشند، ارزش پردازش موازی را دارند و اگر compute bound باشند (اعمال محاسباتی)، صرفا یک سری ترد را ایجاد و مصرف کرده‌اید که می‌توانسته‌اند به سایر درخواست‌های رسیده پاسخ دهند.
- خالی کردن تردهای در حال انتظار: در اعمالی که disk I/O و یا network I/O دارند، پردازش موازی و اعمال async به شدت مقیاس پذیری سیستم را بالا می‌برند. به این ترتیب worker thread جاری (که تعداد آن‌ها محدود است)، سریعتر آزاد شده و به worker pool بازگشت داده می‌شود تا بتواند به یک درخواست دیگر رسیده سرویس دهد. در این حالت می‌توان با منابع کمتری، درخواست‌های بیشتری را پردازش کرد.


ایجاد Asynchronous HTTP Handlers در ASP.Net 4.5

در نگارش‌های پیش از دات نت 4.5، برای نوشتن فایل‌های ashx غیرهمزمان می‌بایستی اینترفیس IHttpAsynchHandler پیاده سازی می‌شد که نحوه‌ی کار با آن از مدل APM پیروی می‌کرد؛ نیاز به استفاده از یک سری callback داشت و این عملیات باید طی دو متد پردازش می‌شد. اما در دات نت 4.5 و با معرفی امکانات async و await، نگارش سازگاری با پیاده سازی کلاس پایه HttpTaskAsyncHandler فراهم شده است.
برای آزمایش آن، یک برنامه‌ی جدید ASP.NET Web forms نگارش 4.5 یا بالاتر را ایجاد کنید. سپس از منوی پروژه، گزینه‌ی Add new item یک Generic handler به نام LogRequestHandler.ashx را به پروژه اضافه نمائید.
زمانیکه این فایل به پروژه اضافه می‌شود، یک چنین امضایی را دارد:
 public class LogRequestHandler : IHttpHandler
IHttpHandler آن‌را اکنون به HttpTaskAsyncHandler تغییر دهید. سپس پیاده سازی ابتدایی آن به شکل زیر خواهد بود:
using System;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace Async14
{
    public class LogRequestHandler : HttpTaskAsyncHandler
    {
        public override async Task ProcessRequestAsync(HttpContext context)
        {
            string url = context.Request.QueryString["rssfeedURL"];
            if (string.IsNullOrWhiteSpace(url))
            {
                context.Response.Write("Rss feed URL is not provided");
            }

            using (var webClient = new WebClient {Encoding = Encoding.UTF8})
            {
                webClient.Headers.Add("User-Agent", "LogRequestHandler 1.0");
                var rssfeed = await webClient.DownloadStringTaskAsync(url);
                context.Response.Write(rssfeed);
            }
        }

        public override bool IsReusable
        {
            get { return true; }
        }

        public override void ProcessRequest(HttpContext context)
        {
            throw new Exception("The ProcessRequest method has no implementation.");
        }
    }
}
واژه‌ی کلیدی async را نیز جهت استفاده از await به نسخه‌ی غیرهمزمان آن اضافه کرده‌ایم.
در این مثال آدرس یک فید RSS از طریق کوئری استرینگ rssfeedURL دریافت شده و سپس محتوای آن به کمک متد DownloadStringTaskAsync دریافت و بازگشت داده می‌شود.
برای آزمایش آن، مسیر ذیل را درخواست دهید:
 http://localhost:4207/LogRequestHandler.ashx?rssfeedURL=https://www.dntips.ir/feed/latestchanges
کاربردهای فایل‌های ashx برای مثال ارائه فید‌های XML ایی یک سایت، ارائه منبع نمایش تصاویر پویا از بانک اطلاعاتی، ارائه JSON برای افزونه‌های auto complete جی‌کوئری و امثال آن است. مزیت آن‌ها سربار بسیار کم است؛ زیرا وارد چرخه‌ی طول عمر یک صفحه‌ی aspx معمولی نمی‌شوند.


صفحات async در ASP.NET 4.5

در قسمت‌های قبل مشاهده کردیم که در برنامه‌های دسکتاپ، به سادگی می‌توان امضای روال‌های رخداد گردان را به async تغییر داد و ... برنامه کار می‌کند. به علاوه از مزیت استفاده از واژه کلیدی await نیز در آن‌ها برخوردار خواهیم شد. اما ... هرچند این روش در وب فرم‌ها نیز صادق است (مثلا public void Page_Load را به  public async void Page_Load می‌توان تبدیل کرد) اما اعضای تیم ASP.NET آن‌را در مورد برنامه‌های وب فرم توصیه نمی‌کنند:
Async void event handlers تنها در مورد تعداد کمی از روال‌های رخدادگردان ASP.NET Web forms کار می‌کنند و از آن‌ها تنها برای تدارک پردازش‌های ساده می‌توان استفاده کرد. اگر کار در حال انجام اندکی پیچیدگی دارد، «باید» از PageAsyncTask استفاده نمائید. علت اینجا است که Async void یعنی fire and forget (کاری را شروع کرده و فراموشش کنید). این روش در برنامه‌های دسکتاپ کار می‌کند، زیرا این برنامه‌ها مدل طول عمر متفاوتی داشته و تا زمانیکه برنامه از طرف OS خاتمه نیابد، مشکلی نخواهند داشت. اما برنامه‌های بدون حالت وب متفاوتند. اگر عملیات async پس از خاتمه‌ی طول عمر صفحه پایان یابد، دیگر نمی‌توان اطلاعات صحیحی را به کاربر ارائه داد. بنابراین تا حد ممکن از تعاریف async void در برنامه‌های وب خودداری کنید.

تبدیل روال‌های رخدادگردان متداول وب فرم‌ها به نسخه‌ی async شامل دو مرحله است:
الف) از متد جدید RegisterAsyncTask که در کلاس پایه Page قرار دارد برای تعریف یک PageAsyncTask استفاده کنید:
using System;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web.UI;

namespace Async14
{
    public partial class _default : Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            RegisterAsyncTask(new PageAsyncTask(LoadSomeData));
        }

        public async Task LoadSomeData()
        {
            using (var webClient = new WebClient { Encoding = Encoding.UTF8 })
            {
                webClient.Headers.Add("User-Agent", "LogRequest 1.0");
                var rssfeed = await webClient.DownloadStringTaskAsync("url");

                //listcontacts.DataSource = rssfeed;
            }
        }
    }
}
با استفاده از System.Web.UI.PageAsyncTask می‌توان یک async Task را در روال‌های رخدادگردان ASP.NET مورد استفاده قرار داد.

ب) سپس در کدهای فایل aspx، نیاز است خاصیت async را نیز true نمائید:
 <%@ Page Language="C#" AutoEventWireup="true"
Async="true"
  CodeBehind="default.aspx.cs" Inherits="Async14._default" %>


تغییر تنظیمات IIS برای بهره بردن از پردازش‌های Async

اگر از ویندوزهای 7، ویستا و یا 8 استفاده می‌کنید، IIS آن‌ها به صورت پیش فرض به 10 درخواست همزمان محدود است.
بنابراین تنظیمات ذیل مرتبط است به یک ویندوز سرور و نه یک work station :
به IIS manager مراجعه کنید. سپس برگه‌ی Application Pools آن‌را باز کرده و بر روی Application pool برنامه خود کلیک راست نمائید. در اینجا گزینه‌ی Advanced Settings را انتخاب کنید. در آن Queue Length را به مثلا عدد 5000 تغییر دهید. همچنین در دات نت 4.5 عدد 5000 برای MaxConcurrentRequestsPerCPU نیز مناسب است. به علاوه عدد connectionManagement/maxconnection را نیز به 12 برابر تعداد هسته‌های موجود تغییر دهید.
اشتراک‌ها
آموزش استفاده از گوگل وب مستر Google Webmaster

سرویس Webmaster Tools گوگل یکی از قدرتمندترین و کاربردی‌ترین ابزارهای مدیریت و آنالیز وب سایت برای وبمسترهاست. استفاده از این ابزار قدرتمند امکان بررسی روزانه وضعیت وبسایت را به شما می‌دهد .

آموزش استفاده از گوگل وب مستر Google Webmaster
مطالب
ایجاد نصاب یک قالب پروژه جدید چند پروژه‌ای در ویژوال استودیو
در ویژوال استودیو ذیل منوی File، گزینه‌ای وجود دارد به نام  Export template که کار آن تهیه یک قالب، بر اساس ساختار پروژه جاری است. این قابلیت جهت تهیه قالب‌های سفارشی، برای کاهش زمان تهیه پروژه‌ها بسیار مفید است. به این ترتیب می‌توان بسیاری از نکات مدنظر را، در یک قالب ویژه لحاظ کرد و به دفعات بدون نیاز به copy/paste مداوم فایل‌ها و تنظیمات اولیه، بسیار سریع یک پروژه جدید دلخواه را ایجاد نمود.
اما ... این قالب تهیه شده، صرفا بر اساس یکی از چندین پروژه Solution جاری تهیه می‌شود و همچنین نصب و توزیع آن نیز دستی است. در ادامه قصد داریم با نحوه تهیه یک قالب جدید پروژه متشکل از چندین پروژه، به همراه تهیه فایل VSI نصاب آن، آشنا شویم.


تهیه یک ساختار نمونه

یک پروژه جدید کنسول را به نام MyConsoleApplication ایجاد کنید. سپس به Solution جاری، یک Class library جدید را به نام مثلا MyConsoleApplication.Tests اضافه نمائید. تا اینجا به شکل زیر خواهیم رسید:


اکنون قصد داریم از این پروژه خاص، یک قالب تهیه کنیم؛ تا هربار نخواهیم یک چنین مراحلی را تکرار کنیم.


تهیه قالب به ازای هر پروژه در Solution

در همین حال که Solution باز است، به منوی File و گزینه Export template مراجعه کنید.


در اینجا تنها امکان انتخاب یک پروژه وجود دارد. به همین جهت این مرحله را باید به ازای هر تعداد پروژه موجود در Solution یکبار تکرار کرد.


اکنون در پوشه My Documents\Visual Studio 2010\My Exported Templates دو فایل zip به نام‌های MyConsoleApplication.zip و MyConsoleApplication.Tests.zip وجود دارند. هر دو فایل را توسط برنامه‌های مخصوص گشودن فایل‌های Zip گشوده و تبدیل به دو پوشه باز شده MyConsoleApplication و MyConsoleApplication.Tests کنید.



افزودن فایل MyTemplate.vstemplate چند پروژه‌ای

در همین پوشه جاری که اکنون حاوی دو پوشه باز شده است، یک فایل متنی جدید را با محتوای ذیل به نام MyTemplate.vstemplate ایجاد کنید:
<VSTemplate Version="3.0.0" Type="ProjectGroup"
xmlns="http://schemas.microsoft.com/developer/vstemplate/2005">
  <TemplateData>
    <Name>MyConsoleApplication</Name>
    <Description>MyConsoleApplication Desc</Description>
    <ProjectType>CSharp</ProjectType>
  </TemplateData>
  <TemplateContent>
    <ProjectCollection>
      <ProjectTemplateLink ProjectName="MyConsoleApplication">
      MyConsoleApplication\MyTemplate.vstemplate</ProjectTemplateLink>
      <ProjectTemplateLink ProjectName="MyConsoleApplication.Tests">
      MyConsoleApplication.Tests\MyTemplate.vstemplate</ProjectTemplateLink>
    </ProjectCollection>
  </TemplateContent>
</VSTemplate>
در اینجا به ازای هر پروژه، یک ProjectTemplateLink ایجاد خواهد شد که به فایل MyTemplate.vstemplate موجود در قالب آن اشاره می‌کند.
در ادامه این دو پوشه باز شده و فایل MyTemplate.vstemplate فوق را انتخاب کرده:


و همگی را تبدیل به یک فایل zip جدید کنید؛ مثلا به نام MyConsoleApplicationTemplates.zip.


تهیه فایل نصاب از قالب پروژه جدید

تا اینجا موفق شدیم، چندین قالب پروژه تهیه شده را به هم متصل کرده و تبدیل به یک فایل zip نهایی کنیم. مرحله بعد ایجاد فایلی است متنی به نام MyConsoleApplicationTemplates.vscontent با محتویات زیر:
<VSContent xmlns="http://schemas.microsoft.com/developer/vscontent/2005">
  <Content>
    <FileName>MyConsoleApplicationTemplates.zip</FileName>
    <DisplayName>MyConsoleApplication</DisplayName>
    <Description>A C# project that ...</Description>
    <FileContentType>VSTemplate</FileContentType>
    <ContentVersion>1.0</ContentVersion>
    <Attributes>
      <Attribute name="ProjectType" value="Visual C#" />
      <Attribute name="ProjectSubType" value="Web" />
      <Attribute name="TemplateType" value="Project" />
    </Attributes>
  </Content>
</VSContent>
در اینجا توسط قسمت Attributes مشخص می‌کنیم که قالب پروژه جدید باید در صفحه new project، در کدام مدخل قرار گیرد. بنابراین مطابق تنظیمات فوق، قالب جدید ذیل پروژه‌های وب سی‌شارپ قرار خواهد گرفت. مقدار FileName آن دقیقا معادل نام فایل zip ایی است که در مرحله قبل ایجاد کردیم.

مرحله بعد انتخاب دو فایل MyConsoleApplicationTemplates.vscontent و MyConsoleApplicationTemplates.zip و تبدیل ایندو به یک فایل zip جدید است. پس از ایجاد فایل جدید، پسوند آن‌را به VSI تغییر دهید؛ برای مثال نام آن‌را به MyConsoleApplicationTemplates.vsi تغییر دهید. اکنون این فایل نهایی با دوبار کلیک بر روی آن قابلیت اجرا و نصب خودکار را پیدا می‌کند.


پس از نصب، بلافاصله ذیل قسمت پروژه‌های وب قابل دسترسی و استفاده خواهد بود:



بنابراین به صورت خلاصه:
1) به ازای هر پروژه، یک فایل قالب zip معادل آن باید تهیه شود.
2) تمام این فایل‌های zip را گشوده و تبدیل به پوشه‌های متناظری کنید.
3) یک فایل MyTemplate.vstemplate را در پوشه ریشه مرحله 2 جهت تعریف ProjectTemplateLink‌ها اضافه کنید.
4) فایل جدید MyTemplate.vstemplate مرحله 3 و تمام پوشه‌های قالب‌های باز شده مرحله 2 را zip کنید.
5) سپس یک فایل vscontent نصاب را تهیه و آن‌را با فایل zip مرحله 4 مجددا zip کرده و پسوند آن‌را به VSI تغییر دهید.
اکنون می‌توان این فایل VSI را توزیع کرد.
مطالب
آشنایی و بررسی ابزار Version Manager
در مطلبی با نسخه بندی و چرخه انتشار نرم افزار آشنا شدید. اما کمبود ابزاری کارآمد و حرفه ای در ویژوال استادیو من را بر آن داشت تا افزونه‌ای را تهیه و در دسترس تمامی توسعه دهندگان قرار دهم. پس از مطالعه و بررسی روش‌های نگارش بندی نرم افزار و ابزار‌های موجود، دو روش عمده نسخه بندی نرم افزار وجود دارد که در زیر آورده شده است.
  • نسخه بندی معنایی
  • نسخه بندی استاندارد مایکروسافت
در روش معنایی چهار قسمت نسخه بندی Major.Minor.Build.Revision به صورت زیر افزایش و تغییر می‌یابد:
  1. Revision تا 1000 افزایش می‌یابد
  2. در اجرای بعدی به 0 تنظیم شده و قسمت Build بعلاوه 1 می‌شود.
  3. Build تا 100 افزایش می‌یابد
  4. در اجرای بعدی Build به 0 تنظیم شده و قسمت Minor بعلاوه 1 می‌شود و Revision هم 0 می‌شود.
  5. Minor تا 10 افزایش می‌یابد.
  6. در اجرای بعدی Minor به 0 تنطیم شده، قسمت Major بعلاوه 1 می‌شود و قسمت‌های قبل همه 0 می‌شوند. 
در روش استاندارد ماکروسافت مقادیر قسمت‌های Build و Revision از الگوریتم زیر محاسبه می‌شود.
  1. مقدار Build از مجموع روزهای که از تاریخ پروژه گذشته است بدست می‌آید.
  2. مقدار Revision از مجموع ثانیه‌های که از نیمه شب محلی روز جاری تا زمان اجرای پروژه تقسم بر دو بدست می‌آید.
  3. مقادیر Major و Minor هم با توجه تولید نسخه جدید و تغییرات عمده در نرم افزار بصورت دستی تغییر می‌یابد.
راهنمای نصب و اجرا:
ابتدا افزونه Version Manager را از سایت ویژوال استادیو گالری دریافت و نصب کنید.
سپس از منوی View > Other Windows > Version Manager را انتخاب کنید.

پس از باز شدن پنجره Version Manager پروژه‌های Solution جاری بارگذاری و  Assembly Version و File Version هر پروژه را می‌توانید به راحتی مشاهده و یا تغییر دهید.

اگر بخواهید بصورت خودکار بر اساس شمای انتخاب شده، نسخه نرم افزار را افزایش دهید، شمای نسخه بندی را انتخاب کنید. در دو زمان Build و یا Rebuild پروژه می توان نسخه را افزایش داد.

Semantic Versioning:

  1. گزینه Semantic Versioning را از قسمت Version Style انتخاب کنید.
  2. گزینه Increment Action قسمتی از نگارش که می‌خواهید شمای  نسخه بندی بر روی آن اعمال شود را مشخص می‌کند. که دو گزینه Build یا Revision وجود دارد
  3. گزینه Increment Event زمان رویداد اعمال شمای انتخاب شده را مشخص می‌سازد.
  4. تنظیمات را ذخیره و پروژه خود را Rebuild نمایید.
  5. در پنجره Output نسخه جدید نشان داده می‌شود.

Microsoft DateTime:

  1. گزینه Microsoft DateTime را از قسمت Version Style انتخاب کنید.

  2. تاریخ شروع پروژه بصورت خودکار خوانده و نمایش داده می‌شود یا تاریخ شروع پروژه را انتخاب کنید
  3. با توجه به انتخاب Increment Action نسخه جدید محاسبه می‌شود.
  4. پروژه را Rebuild و نسخه جدید را مشاهده نمایید.

    همچنین از پروژه‌های #C و VB.NET و C++ Managed  پشتیبانی می‌کند

    این ابزار هنوز در نگارش بتا است و ممکن است باگ‌هایی داشته باشد.

    نظرات و پیشنهادات شما توسعه دهندگان عزیز می‌تواند موجب هر چه بهتر و کامل‌تر شدن این ابزار باشد.

مطالب
MVVM و نمایش دیالوگ‌ها

بسیاری از برنامه‌های دسکتاپ نیاز به نمایش پنجره‌های دیالوگ استاندارد ویندوز مانند OpenFileDialog و SaveFileDialog را دارند و سؤال اینجا است که چگونه اینگونه موارد را باید از طریق پیاده سازی صحیح الگوی MVVM مدیریت کرد؛ از آنجائیکه خیلی راحت در فایل ViewModel می‌توان نوشت new OpenFileDialog و الی آخر. این مورد هم یکی از دلایل اصلی استفاده از الگوی MVVM را زیر سؤال می‌برد : این ViewModel دیگر قابل تست نخواهد بود. همیشه شرایط آزمون‌های واحد را به این صورت در نظر بگیرید:
سروری وجود دارد در جایی که به آن دسترسی نداریم. روی این سرور با اتوماسیونی که راه انداخته‌ایم، آخر هر روز آزمون‌های واحد موجود به صورت خودکار انجام شده و یک گزارش تهیه می‌شود (مثلا یک نوع continuous integration سرور). بنابراین کسی دسترسی به سرور نخواهد داشت تا این OpenFileDialog ظاهر شده را مدیریت کرده، فایلی را انتخاب و به برنامه آزمون واحد معرفی کند. به صورت خلاصه ظاهر شدن هر نوع دیالوگی حین انجام آزمون‌های واحد «مسخره» است!
یکی از روش‌های حل این نوع مسایل، استفاده از dependency injection یا تزریق وابستگی‌ها است و در ادامه خواهیم دید که چگونه WPF‌ بدون نیاز به هیچ نوع فریم ورک تزریق وابستگی خارجی، از این مفهوم پشتیبانی می‌کند.

مروری مقدماتی بر تزریق وابستگی‌ها
امکان نوشتن آزمون واحد برای new OpenFileDialog وجود ندارد؟ اشکالی نداره، یک Interface بر اساس نیاز نهایی برنامه درست کنید (نیاز نهایی برنامه از این ماجرا فقط یک رشته LoadPath است و بس) سپس در ViewModel با این اینترفیس کار کنید؛ چون به این ترتیب امکان «تقلید» آن فراهم می‌شود.

یک مثال عملی:
ViewModel نیاز دارد تا مسیر فایلی را از کاربر بپرسد. این مساله را با کمک dependency injection در ادامه حل خواهیم کرد.
ابتدا سورس کامل این مثال:

ViewModel برنامه (تعریف شده در پوشه ViewModels برنامه):

namespace WpfFileDialogMvvm.ViewModels
{
public interface IFilePathContract
{
string GetFilePath();
}

public class MainWindowViewModel
{
IFilePathContract _filePathContract;
public MainWindowViewModel(IFilePathContract filePathContract)
{
_filePathContract = filePathContract;
}

//...

private void load()
{
string loadFilePath = _filePathContract.GetFilePath();
if (!string.IsNullOrWhiteSpace(loadFilePath))
{
// Do something
}
}
}
}

دو نمونه از پیاده سازی اینترفیس IFilePathContract تعریف شده (در پوشه Dialogs برنامه):

using Microsoft.Win32;
using WpfFileDialogMvvm.ViewModels;

namespace WpfFileDialogMvvm.Dialogs
{
public class OpenFileDialogProvider : IFilePathContract
{
public string GetFilePath()
{
var ofd = new OpenFileDialog
{
Filter = "XML files (*.xml)|*.xml"
};
string filePath = null;
bool? dialogResult = ofd.ShowDialog();
if (dialogResult.HasValue && dialogResult.Value)
{
filePath = ofd.FileName;
}
return filePath;
}
}

public class FakeOpenFileDialogProvider : IFilePathContract
{
public string GetFilePath()
{
return @"c:\path\data.xml";
}
}
}

و View برنامه:

<Window x:Class="WpfFileDialogMvvm.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:WpfFileDialogMvvm.ViewModels"
xmlns:dialogs="clr-namespace:WpfFileDialogMvvm.Dialogs"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ObjectDataProvider x:Key="mainWindowViewModel"
ObjectType="{x:Type vm:MainWindowViewModel}">
<ObjectDataProvider.ConstructorParameters>
<dialogs:OpenFileDialogProvider/>
</ObjectDataProvider.ConstructorParameters>
</ObjectDataProvider>
</Window.Resources>
<Grid DataContext="{Binding Source={StaticResource mainWindowViewModel}}">

</Grid>
</Window>

توضیحات:
ما در ViewModel نیاز داریم تا مسیر نهایی فایل را دریافت کنیم و این عملیات نیاز به فراخوانی متد ShowDialog ایی را دارد که امکان نوشتن آزمون واحد خودکار را از ViewModel ما سلب خواهد کرد. بنابراین بر اساس نیاز برنامه یک اینترفیس عمومی به نام IFilePathContract را طراحی می‌کنیم. در حالت کلی کلاسی که این اینترفیس را پیاده سازی می‌کند، قرار است مسیری را برگرداند. اما به کمک استفاده از اینترفیس، به صورت ضمنی اعلام می‌کنیم که «برای ما مهم نیست که چگونه». می‌خواهد OpenFileDialogProvider ذکر شده باشد، یا نمونه تقلیدی مانند FakeOpenFileDialogProvider. از نمونه واقعی OpenFileDialogProvider در برنامه اصلی استفاده خواهیم کرد، از نمونه تقلیدی FakeOpenFileDialogProvider در آزمون واحد و نکته مهم هم اینجا است که ViewModel ما چون بر اساس اینترفیس IFilePathContract پیاده سازی شده، با هر دو DialogProvider یاد شده می‌تواند کار کند.
مرحله آخر نوبت به وهله سازی نمونه واقعی، در View برنامه است. یا می‌توان در Code behind مرتبط با View نوشت:

namespace WpfFileDialogMvvm
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel(new OpenFileDialogProvider());
}
}
}

و یا از روش ObjectDataProvider توکار WPF هم می‌شود استفاده کرد؛ که مثال آن‌را در کدهای XAML مرتبط با View ذکر شده می‌توانید مشاهده کنید. ابتدا دو فضای نام vm و dialog تعریف شده (با توجه به اینکه مثلا در این مثال، دو پوشه ViewModels و Dialogs وجود دارند). سپس کار تزریق وابستگی‌ها به سازنده کلاس MainWindowViewModel،‌ از طریق ObjectDataProvider.ConstructorParameters انجام می‌شود:

<ObjectDataProvider x:Key="mainWindowViewModel" 
ObjectType="{x:Type vm:MainWindowViewModel}">
<ObjectDataProvider.ConstructorParameters>
<dialogs:OpenFileDialogProvider/>
</ObjectDataProvider.ConstructorParameters>
</ObjectDataProvider>

مطالب
استفاده از کنترل‌های Active-X در WPF

گاهی از اوقات شاید نیاز شود تا از یک کنترل Active-X در WPF استفاده شود؛ مثلا هیچ نمایش دهنده‌ی PDF ایی را در ویندوز نمی‌توان یافت که امکانات و کیفیت آن در حد Acrobat reader و Active-X آن باشد. یک روش استفاده از آن‌را به کمک کنترل WebBrowser در WPF پیشتر در این سایت مطالعه کرده‌اید. روش معرفی شده برای WinForm هم در WPF قابل استفاده است که در ادامه شرح آ‌ن‌ خواهد آمد.

الف) بجای اضافه کردن یک User control مخصوص WPF یک user control از نوع WinForms را به یک پروژه WPF اضافه کنید.


سپس مراحل مشابهی را مانند حالت WinForms، باید طی کرد:
ب) در VS.NET‌ از طریق منوی Tools گزینه‌ی Choose toolbox items ، برگه‌ی Com components را انتخاب کنید.
ج) سپس گزینه‌ی Adobe PDF reader را انتخاب نمائید و بر روی دکمه‌ی OK‌ کلیک کنید.


د) اکنون این کنترل جدید را بر روی فرم user control قسمت الف برنامه قرار دهید. به صورت خودکار COMReference های متناظر هم به پروژه اضافه می‌شوند.
پس از اینکه کنترل بر روی فرم قرار گرفت بهتر است به خواص آن مراجعه کرده و خاصیت Dock آن‌را با Fill مقدار دهی کرد تا کنترل به صورت خودکار در هر اندازه‌ای کل ناحیه‌ی متناظر را پوشش دهد.


کد‌های مرتبط با نمایش فایل PDF این کنترل هم به شرح زیر است:

using System.Windows.Forms;

namespace WpfPdfViewer.Controls
{
public partial class AcroReader : UserControl
{
public AcroReader(string fileName)
{
InitializeComponent();
ShowPdf(fileName);
}

public void ShowPdf(string fileName)
{
if (string.IsNullOrWhiteSpace(fileName)) return;
axAcroPDF1.LoadFile(fileName);
axAcroPDF1.setShowToolbar(true);
axAcroPDF1.Show();
}
}
}


خوب، ما تا اینجا یک کنترل Active-X را از طریق یک User controls مخصوص WinForms به پروژه‌ی WPF جاری اضافه کرده‌ایم. برای اینکه بتوانیم این کنترل را درون مثلا یک User control از جنس WPF و XAML نمایش دهیم باید از کنترل WindowsFormsHost استفاده کرد. برای این منظور نیاز است تا ارجاعی را به اسمبلی WindowsFormsIntegration اضافه کنیم. پس از آن کنترل یاد شده قابل استفاده خواهد بود.


برای نمونه کدهای XAML پنجره اصلی برنامه می‌تواند به صورت زیر باشد:

<Window x:Class="WpfPdfViewer.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<WindowsFormsHost x:Name="WindowsFormsHost1" />
</Grid>
</Window>

سپس جهت استفاده از کنترل WindowsFormsHost خواهیم داشت:

using WpfPdfViewer.Controls;

namespace WpfPdfViewer
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
WindowsFormsHost1.Child = new AcroReader(@"PageSummary.pdf");
}
}
}

فقط کافی است شیء Child این کنترل را با وهله‌ای از یوزرکنترل AcroReader اضافه شده به برنامه مقدار دهی کنیم.

سؤال: این روش زیاد MVVM friendly نیست. به عبارتی Child را نمی‌توان از طریق Binding مقدار دهی کرد. آیا راهی برای آن وجود دارد؟
پاسخ: بله. روش متداول برای حل این نوع مشکلات، نوشتن یک DependencyObject و Attached property مناسب می‌باشد که به آن‌ها Behaviors هم می‌گویند. برای مثال یک نمونه از این پیاده سازی را در ذیل مشاهده می‌کنید:

using System;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Forms.Integration;

namespace WpfPdfViewer.Behaviors
{
public class WindowsFormsHostBehavior : DependencyObject
{
public static readonly DependencyProperty BindableChildProperty =
DependencyProperty.RegisterAttached("BindableChild",
typeof(Control),
typeof(WindowsFormsHostBehavior),
new UIPropertyMetadata(null, BindableChildPropertyChanged));

public static Control GetBindableChild(DependencyObject obj)
{
return (Control)obj.GetValue(BindableChildProperty);
}

public static void SetBindableChild(DependencyObject obj, Control value)
{
obj.SetValue(BindableChildProperty, value);
}

public static void BindableChildPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var windowsFormsHost = o as WindowsFormsHost;
if (windowsFormsHost == null)
throw new InvalidOperationException("This behavior can only be attached to a WindowsFormsHost.");

var control = (Control)e.NewValue;
windowsFormsHost.Child = control;
}
}
}

که نهایتا برای استفاده از آن خواهیم داشت:

<WindowsFormsHost 
Behaviors:WindowsFormsHostBehavior.BindableChild="{Binding ...}" />

و در ViewModel برنامه هم مانند مثال فوق، فقط کافی است یک وهله از new AcroReader به این خاصیت قابل انقیاد از نوع Control، انتساب داده شود.
یا حتی می‌توان بجای نوشتن یک BindableChild، برای مثال مسیر فایل pdf را به DependencyObject تعریف شده ارسال کرد و سپس در همانجا این وهله سازی و انتسابات صورت گیرد (بجای ViewModel برنامه که اینبار فقط مسیر را تنظیم می‌کند).