نظرات مطالب
آموزش TypeScript #1
یکی از دلایل محبوبیت زبان JavaScript، راحتی در نوشتن کد با این زبان است. اگر قرار باشد این زبان یک محصول همه منظوره باشد به طور قطع دچار پیچیدگی‌های پیاده سازی شده و این همه محبوبیت به دست نمی‌آورد. هدف اولیه از تولید و توسعه زبان JavaScript، استفاده از آن در پروژه‌های سمت کلاینت بود. اما با مرور زمان و محبوبیت بیش از اندازه، توسعه گران مختلف تصمیم به توسعه این زبان گرفتند که هر محصول برای یک منظور خاص به وجود آمد.  برای مثال Node.Js برای پروژه‌های RealTime استفاه می‌شود و بر مبنای منطق event-driven می‌باشد که خیلی‌ها از آن به عنوان Server side JavaScript یاد می‌کنند یا به عنوان مثال دیگر Dart محصول شرکت گوگل در سال 2011 (طراحی شده بر مبنای Scratch)و TypeScript محصول  شرکت مایکروسافت در سال 2012 (طراحی شده بر مبنای JavaScript)عرضه شدند که هدف اصلی از تولید این زبان‌ها پشتیبانی از مبحث static typing و مباحث OOP برای پیاده سازی پروژه‌های در سطوحی با مقیاس بزرگ بود. JavaScript به عنوان زبان پایه باقی خواهد ماند و نسخه‌های مختلف در شکل سایر زبان‌ها و فریم ورک‌های مختلف عرضه می‌شوند تا هر کدام یک نیاز را برطرف سازند. البته در پایان این نکته را هم متذکر شوم که JavaScript هم روند با توسعه ECMAScript تغییر می‌کند. برای مثال در نسخه ECMASCript 6، امکان تعریف کلاس و ماژول در JavaSCript فراهم شده است.
مطالب
آشنایی با angular.extend در AngularJs
در این مقاله قصد دارم تکنیکی ساده ولی در عین حال موثر را معرفی کنم که در نوشتن کنترلر‌ها بسیار کارآمد است. همانطور که می‌دانید به طور معمول برای تعریف متد‌ها و پراپرتی‌های درون کنترلر و انتقال آن به View، از دو روش انتساب به scope$ و controller as استفاده می‌شود.
در AngularJs متدی به صورت built-in وجود دارد که قادر است یک شیء را درون شیء دیگر کپی کند. این متد در بسیاری از مواقع بسیار کارآمد است که به بررسی آن خواهیم پرداخت. جزئیات بیشتر و دقیق‌تر در مورد angular.extend را می‌توانید در اسناد سایت رسمی AngularJs  مشاهده کنید.
به تکه کد زیر توجه کنید. این کد نمونه‌ای از استفاده‌ی از scope$ است. مشاهده می‌کنید که متغییر‌های thingOne و thingTwo چگونه درون scope$ قرار میگیرد.
app.controller(‘ThingController’, [ ‘$scope’, function($scope) {
   $scope.thingOne = ‘one’;
   $scope.thingTwo = ‘two’;
   $scope.getThings = function() { 
       return $scope.thingOne + ‘ ‘ + $scope.thingTwo; 
   };
}]);
حال ببینیم که متد angular.extend کد فوق را چگونه ساده سازی می‌کند. همانطور که مشاهده می‌کنید توسط extend، تمامی متدها و پراپرتی‌ها به صورت یکجا به scope انتساب داده شده است.
app.controller(‘ThingController’, [ ‘$scope’, function($scope) {
    angular.extend($scope, {
        thingOne: ‘one’,
        thingTwo: ‘two’,
        getThings: function() { 
            return $scope.thingOne + ‘ ‘ + $scope.thingTwo; 
        }
    });
}]);
استفاده از angular.extend باعث می‌شود که تمامی assignmentها به صورت‌‌تر و تمیز درون scope یا this قرار بگیرند. حال اینکه نیازی نیست تا شما تمامی این assingmentها را به صورت یکجا و توسط یک بار صدا زدن extend انجام دهید. شما می‌توانید در نقاط مختلف کنترلر این متد را با مقادیر انتسابی متفاوتی فراخوانی کنید. تکه کد زیر نمونه‌ی تغییر یافته به صورت دو بار فراخوانی extend است:
app.controller(‘ThingController’, [ ‘$scope’, function($scope) {
    // models
    angular.extend($scope, {
        thingOne: ‘one’,
        thingTwo: ‘two’
    });

    // methods
    angular.extend($scope, {
      // in HTML template, something like {{ getThings() }}
       getThings: function() { 
            return $scope.thingOne + ‘ ‘ + $scope.thingTwo; 
        }
    });
}]);
حال قصد داریم تا کمی ساختار کد پیشین را مستحکم‌تر کنیم. در بسیاری از مواقع اطلاعات دریافتی از view به این صورت است که در ابتدا نیاز به تایید صلاحیت دارند. در تکه کد زیر قصد داریم تا به متغیر‌های thingObe و thingTwo دو متد getter و setter را اضافه نماییم و پراپرتی‌ها را از حالت public خارج کنیم. در کد زیر ما، دو متد getter و setter برای هر کدام از متغیر‌ها که به حالت private تعریف شده‌اند، اضافه کرده ایم:
app.controller(‘ThingController’, [ ‘$scope’, function($scope) {
    // private
    var _thingOne = ‘one’,
        _thingTwo = ‘two’;

    // models
    angular.extend($scope, {
        get thingOne() {
        return _thingOne;
        },
        set thingOne(value) {
           if (value !== ‘one’ && value !== ‘two’) {
             throw new Error(‘Invalid value (‘+value+‘) for thingOne’);
        },
        get thingTwo() {
        return _thingTwo;
        },
        set thingTwo(value) {
           if (value !== ‘two’ && value !== ‘three’) {
             throw new Error(‘Invalid value (‘+value+‘) for thingTwo’);
        }
   });

    // methods
    angular.extend($scope, {
       // in HTML template, something like {{ things }}
       get things() { 
            return _thingOne + ‘ ‘ + _thingTwo; 
        }
    });
}]);
و در آخر اینکه با استفاده از این متد می‌توان ارث بری در سرویس‌های Angular را پیاده سازی کرد که جزئیات آن را می‌توانید از اینجا  دریافت کنید.
مطالب
MVVM و فراخوانی متدهای اشیاء View از طریق ViewModel

ما در ViewModel دسترسی مستقیمی به هیچ یک از اشیاء موجود در View نداریم (و درستش هم همین است). الان فرض کنید که می‌خواهیم از طریق ViewModel یک View را ببندیم؛ مثلا متد Close آن پنجره را فراخوانی کنیم. به عبارتی در حالت کلی می‌خواهیم یکی از متدهای تعریف شده یکی از عناصر بصری موجود در View را از طریق ViewModel فراخوانی نمائیم.
برای حل این مساله از فایل‌های همان SDK‌ مرتبط با Expression blend استفاده خواهیم کرد.

ابتدا ارجاعاتی را به اسمبلی‌های System.Windows.Interactivity.dll و Microsoft.Expression.Interactions.dll اضافه می‌کنیم.
سپس دو فضای نام مرتبط هم باید اضافه شوند:

  xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"  
  xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"

یک مثال عملی:
قصد داریم از طریق ViewModel ، پنجره‌ای را ببندیم. کدهای XAML این مثال را در ادامه مشاهده خواهید کرد:

<Window x:Class="WpfCallMethodActionSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:vm="clr-namespace:WpfCallMethodActionSample.ViewModels"
Name="ThisWindow"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<vm:MainWindowViewModel x:Key="vmMainWindowViewModel" />
</Window.Resources>
<Grid DataContext="{Binding Source={StaticResource vmMainWindowViewModel}}">

<Button Content="Save &amp; Close" VerticalAlignment="Top" Margin="5">
<i:Interaction.Triggers>
<!--فراخوانی متدی در ویوو مدل-->
<i:EventTrigger EventName="Click">
<ei:CallMethodAction
TargetObject="{Binding}"
MethodName="SaveButtonClicked" />
</i:EventTrigger>

<!--فراخوانی متدی در شیء جاری از طریق ویوو مدل-->
<i:EventTrigger SourceObject="{Binding}" EventName="CloseMainWindow">
<ei:CallMethodAction
TargetObject="{Binding ElementName=ThisWindow}"
MethodName="Close"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</Grid>
</Window>

همچنین ViewModel تعریف شده نیز همین چند سطر زیر است:

using System;

namespace WpfCallMethodActionSample.ViewModels
{
public class MainWindowViewModel
{
public void SaveButtonClicked()
{
close();
}

public event EventHandler CloseMainWindow;
private void close()
{
if (CloseMainWindow != null) CloseMainWindow(this, EventArgs.Empty);
}
}
}

توضیحات:
اگر به ViewModel دقت کنید خبری از DelegateCommand در آن نیست. بله، به کمک ترکیبی از EventTrigger و CallMethodAction می‌توان جایگزینی را جهت DelegateCommand معرفی شده در قسمت‌های قبل این سری مباحث MVVM ارائه داد.
EventTrigger در اینجا به این معنا است که اگر EventName ذکر شده رخ داد، آنگاه این اعمال را انجام بده. مثلا در اینجا CallMethodAction را فراخوانی کن.
CallMethodAction در اسمبلی Microsoft.Expression.Interactions.dll تعریف شده است و تنها متدی از نوع void و بدون پارامتر را می‌تواند به صورت خودکار فراخوانی کند (محدودیت مهم آن است).
اینکه این متد کجا قرار دارد، توسط TargetObject آن مشخص می‌شود. اگر TargetObject را مساوی Binding قرار دادیم، یعنی به دنبال متدی که در DataContext گرید وجود دارد بگرد. به عبارتی به صورت خودکار به SaveButtonClicked تعریف شده در ViewModel ما متصل خواهد شد و آن‌را فراخوانی می‌کند.

تا اینجا رخداد Click دکمه تعریف شده را به متد SaveButtonClicked موجود در ViewModel سیم کشی کردیم.

در مرحله بعد می‌خواهیم از طریق ViewModel ، متدی را در View فراخوانی کنیم. نکته آن هم پیشتر ذکر شد؛ TargetObject صحیحی را باید انتخاب کرد. در اینجا برای پنجره جاری نام ThisWindow تعریف شده است و از طریق تعریف:

TargetObject="{Binding ElementName=ThisWindow}"

به CallMethodAction خواهیم گفت که قرار است متد Close را در شیء ThisWindow فراخوانی کنی.
همچنین نحوه تعریف EventTrigger ما هم در اینجا برعکس شده است:

<i:EventTrigger SourceObject="{Binding}"  EventName="CloseMainWindow">

قبلا به دنبال مثلا رخداد Click یک دکمه بودیم، اکنون با توجه به SourceObject تعریف شده، در ViewModel به دنبال این رخداد که برای نمونه در اینجا CloseMainWindow نام گرفته خواهیم گشت.

بنابراین View اینبار به رخداد CloseMainWindow تعریف شده در ViewModel سیم کشی خواهد شد. اکنون اگر این رخداد در ViewModel فراخوانی شود، CallMethodAction متناظر فعال شده و متد Close پنجره را فراخوانی می‌کند.

مطالب
استاندارد وب WIA-ARIA
چند روز پیش مطلبی به عنوان اشتراک در سایت جاری معرفی شده که به ما یادآوری می‌کرد، ما تنها استفاده کنندگان سیستم‌های کامپیوتری، به خصوص اینترنت نیستیم و معلولین هم نیازمند استفاده از این فناوری‌ها هستند.
WAI-ARIA  که برگرفته از Web Accessibility Initiative - Accessible Rich internet Application است به معنی برنامه‌ی اینترنتی تعامل گرا با خاصیت دسترسی پذیری بالا می‌باشد و یک راهنماست که توسط کنسرسیوم وب (+ ) معرفی گشته است تا وب سایت‌ها با رعایت این قوانین، دسترسی سایت خود را بالاتر ببرند. این قوانین به خصوص برای سایت‌هایی با محتوای پویا هستند که از فناوری‌هایی چون Ajax,Javascrip, HTML و دیگر فناوری‌های مرتبط استفاده می‌کنند.
امروزه طراحان وب بیش از هر وقتی از فناوری‌های سمت کلاینت چون جاوااسکریپت برای ساخت رابط‌های کاربری استفاده می‌کنند که html به تنها قادر به ایجاد آن‌ها نیست. یکی از تکنیک‌های جاوااسکریپت، دریافت محتوای جدید و به روزآوری قسمتی از صفحات وب است بدون اینکه مجددا کل صفحه از وب سرور درخواست گردد که به این تکنیک  Rich Internet Application هم می‌گویند. تا به اینجای کار هیچ مشکلی نیست و خوب هم هست؛ ولی مشکلی که در این بین وجود دارد این است که این نوع تکنیک‌ها باعث از بین رفتن خاصیت دسترسی پذیری معلولین می‌گردند. معلولینی که از صفحه خوان ها استفاده می‌کنند یا به دلیل معلولیت‌های خود قادر به حرکت دادن ماوس نیستند.
ARIA با استفاده از خصوصیت‌ها Properties، نقش‌ها Roles و وضعیت‌ها States به طراحان برنامه‌های وب و سازندگان فناوری‌های یاری رسان، اجازه می‌دهد که با ابزارهای کمکی معلولان ارتباط برقرار کنیم و یک صفحه‌ی وب ساده را به یک صفحه‌ی پویا تبدیل کنیم. ARIA تنها یک استاندارد برای وب نیست، بلکه یک فناوری چند پلتفرمه است که برای بازی‌های رایانه‌ای، موبایل‌ها، دستگاه‌های سرگرمی و سلامتی و دیگر انواع برنامه‌ها نیز تعریف شده است.



فریمورک ARIA
خود HTML به تنهایی نمی‌تواند نقش‌های هر المان و ارتباط بین آن‌ها را به درستی بیان کند و به این منظور ARIA به کمک می‌آید. با استفاده از نقش‌ها میتوان هدف هر المان را مشخص کرد و با استفاده از خصوصیات ARIA نحوه‌ی عملکرد آن‌ها را تعریف کرد.

نقش ها
نقش‌ها طبق مستندات کنسرسیوم وب بر 4 نوع هستند:
  • Abstract Roles
  • Widget Roles
  • Document Roles
  • Landmark Roles
فریمورک ARIA با استفاده از Landmark Roles یا نقش‌های راهنما، به معرفی بخش‌های ویژوالی می‌پردازد تا فناوری‌های کمکی به آن دسترسی سریعی داشته باشند. هشت نقش راهنما وجود دارد که در زیر آن‌ها را بررسی می‌کنیم.

 Banner این قسمت که عموما برای اجزای مهمی مثل هدر سایت قرار می‌گیرد و شامل معرفی وب سایت هست و در همه‌ی صفحات وجود دارد که شامل لوگو، اطلاعات عمومی سایت و اسپانسرها و ... می‌گردد و بسیار مهم است که تنها یکبار در صفحه‌ی وب به کار برود و تکرار آن پرهیز شود.
 Main  این نقش به محتوای اصلی وب سایت اشاره می‌کند و نباید بیشتر از یکبار در هر صفحه‌ی وب به کار برود و عموما بهتر است این خصوصیت در تگ div قرار گیرد:
<div Role="main"></div>
یا در HTML5 به طور مفهومی ساخته می‌شود:
<main role="main">.....

Navigation اشاره به یک ناحیه پر از المان‌های لینک برای ارتباط با صفحات دیگر
 Complementary  مشخص سازی ناحیه‌ای که اطلاعات اضافی درباره‌ی محتوای اصلی سایت دارد؛ مانند بخش مقالات مرتبط، آخرین کامنت‌ها و ...
 ContentInfo  این نقش که بیشتر برای فوتر مناسب است برای محتوایی به کار می‌رود که در آن به قوانین کپی رایت و ... اشاره می‌شود.
 form  برای اشاره به فرم‌ها که دارای قسمت‌های ورودی کاربر هستند.
 search
 در صورتیکه فرمی دارید و از آن برای گزینه‌ی جست و جو استفاده می‌کنید، از این نقش استفاده کنید.
 application  برای اینکه وب سایت خود را به صورت یک وب اپلیکیشن معرفی کنید؛ تا یک صفحه وب معمولی، استفاده می‌شود و برای وب سایت‌های قدیمی یا با حالت سنتی توصیه نمی‌شود و به برنامه‌های کمکیار معلولین می‌گوند که از حالت عادی به حالت application سوئیچ کنند؛ پس با دقت بیشتری باید از این گزینه استفاده کرد.
 


خصوصیت‌ها و وضعیت ها

در حالیکه از نقش‌ها برای معرفی هر المان یا تگ استفاده می‌کنید؛ خصویت‌ها و وضعیت‌ها به کاربر اطلاعات اضافی می‌دهند که چگونه ز آن استفاده کنند. برای معرفی خصوصیت‌ها و وضعیت‌ها از یک خصوصیت که با -aria شروع می‌شود استفاده کنید. از معروفترین آن‌ها خصوصیت aria-required و وضعیت aria-checked می‌باشند، تا به ترتیب به کاربر اعلام کنید این تگ نیاز به پر شدن دارد، یا المانی نیاز به تغییر وضعیت انتخابی دارد.
نحوه‌ی استفاده از آن‌ها به شکل زیر است:
<div id="some-id" class="some-class" aria-live="assertive"><div>
aria-live سه مقدار می‌پذیرد که عبارتند از Off,Polite,Assertive  و مشخص می‌کنند که المان مورد نظر آپدیت پذیر هست یا خیر و اگر آری، نحوه‌ی به روز شوندگی آن به چه نحوی است.

ساخت ارتباطات میان المان‌ها با خصوصیت‌های ارتباطی

مثال شماره یک
<div role="main" aria-labelledby="some-id">
 
    <h1 id="some-id">This Is A Heading</h1>
 
    Main content...
 
</div>
خصوصیت aria-labelledby به تعریف المان‌هایی با نام جاری می‌پردازد. این خصوصیت معرفی کننده‌ی برچسب هاست. به عنوان مثال بین المان‌ها ورودی و برچسب آنان ارتباط ایجاد می‌کند تا ابزارهای معلولین، مانند صفحه خوان‌ها، در خواندن به مشکل برنخورند.

مثال شماره دو
در این مثال هر گروهی از المان‌ها یک برچسب و بعضی المان‌ها یک برچسب اختصاصی دارند که توسط خصوصیت معرفی شده aria-labelldby کامل شده‌اند:
<div id="billing">Billing Address</div>

<div>
    <div id="name">Name</div>
    <input type="text" aria-labelledby="name billing"/>
</div>
<div>
    <div id="address">Address</div>
    <input type="text" aria-labelledby="address billing"/>
</div>

مثال شماره سه

در این مثال گروهی از radio button‌ها با برچسبشان ارتباط برقرار می‌کنند.
<div id="radio_label">My radio label</div>
<ul role="radiogroup" aria-labelledby="radio_label">
    <li role="radio">Item #1</li>
    <li role="radio">Item #2</li>
    <li role="radio">Item #3</li>
</ul>

خصوصیت‌ها و وضعیت‌های aria را با چرخه‌ی فعالیت‌های صفحه به روز کنید

در صورتیکه چرخه‌ی فعالیت صفحه‌ی شما تغییر می‌کند و تگ‌ها نیاز به مقادیر جدیدی از aria دارند، حتما این مقادیر را هم به نسبت تغییراتی که در صفحه زخ می‌دهد، تغییر دهید تا وضعیت بحرانی برای کاربر به خصوص در حین کار با فرم‌ها و ... پیش نیاید.


هر aria را دوباره استفاده نکنید

امروزه به خصوص با آمدن html5 و ویژگیهایی چون تگ‌های مفهومی، کار بسیار راحت‌تر شده‌است و مرورگر به طور خودکار می‌تواند aria را بر روی بعضی از المان‌ها پیاده کند. به عنوان نمونه:
<form></form>
<form role="form"></form>
همچنین به عنوان مثال با استفاده از خصوصیات HTML مثل hidden کردن یک شیء نیازی به استفاده از وضعیت aria-hidden نمی‌باشد. مرورگر به طور پیش فرض آن را لحاظ می‌کند.

امروزه شاهد پیشرفت فناوری در همه‌ی عرصه‌ها هستیم و همیشه این پیشرفت‌ها ما را ذوق زده کرده‌اند، ولی یکی از بی نظیرترین استفاده‌های فناوری روز، استفاده در صنایع سلامتی است که نه تنها ما را ذوق زده می‌کند، بلکه از لحاظ احساسی هم ما را به وجد می‌آورند و جزء زیباترین نتایج فناوری می‌باشند. بسیاری از شرکت‌ها چون گوگل در این راستا فعالیت‌های زیادی کرده‌اند تا بتوانند سلامت جامعه را کنترل کنند، از ساخت لنز چشمی برای کنترل دیابت گرفته تا ساخت قاشق عذای خوری برای بیماران پارکینسون، ولی استفاده‌های ساده از مسائلی مانند بالا به افراد معلول این مژده را می‌دهد که ما آن‌ها را فراموش نکرده‌ایم.
مطالب
بررسی ORM های مناسب جهت استفاده در اندروید
با آمدن ORM‌ها به دنیای برنامه نویسی، کار برنامه نویسی نسبت به قبل ساده‌تر و راحت‌تر شد. عدم استفاده کوئری‌های دستی، پشتیبانی از چند دیتابیس و از همه مهمتر و اصلی‌ترین هدف این ابزار "تنها درگیری با اشیا و مدل شیء گرایی" کار را پیش از پیش آسان‌تر نمود.
در این بین به راحتی می‌توان چندین نمونه از این ORM‌ها را  نام برد مثل IBatis , Hibernate ,Nhibernate و EF که از معروفترین آن‌ها هستند.
من در حال حاضر قصد شروع یک پروژه اندرویدی را دارم و دوست دارم بجای استفاده‌ی از Sqlitehelper، از یک ORM مناسب بهره ببرم که چند سوال برای من پیش می‌آید. آیا ORM ای برای آن تهیه شده است؟ اگر آری چندتا و کدامیک از آن‌ها بهتر هستند؟ شاید در اولین مورد کتابخانه‌ی Hibernate جاوا را نام ببرید؛ ولی توجه به این نکته ضروری است که ما در مورد پلتفرم موبایل و محدودیت‌های آن صحبت می‌کنیم. یک کتابخانه همانند Hibernate مطمئنا برای یک برنامه اندروید چه از نظر حجم نهایی برنامه و چه از نظر حجم بزرگش در اجرا، مشکل زا خواهد بود و وجود وابستگی‌های متعدد و دارا بودن بسیاری از قابلیت‌هایی که اصلا در بانک‌های اطلاعاتی موبایل قابل اجرا نیست، باعث می‌شود این فریمورک انتخاب خوبی برای یک برنامه اندروید نباشد.

معیارهای انتخاب یک فریم ورک مناسب برای موبایل:
  • سبک بودن: مهمترین مورد سبک بودن آن است؛ چه از لحاظ اجرای برنامه و چه از لحاظ حجم نهایی برنامه
  • سریع بودن: مطمئنا ORM‌های طراحی شده‌ی موجود، از سرعت خیلی بدی برخوردار نخواهند بود؛ اگر سر زبان هم افتاده باشند. ولی باز هم انتخاب سریع بودن یک ORM، مورد علاقه‌ی بسیاری از ماهاست.
  • یادگیری آسان و کانفیگ راحت تر.

OrmLight

این فریمورک مختص اندروید طراحی نشده ولی سبک بودن آن موجب شده‌است که بسیاری از برنامه نویسان از آن در برنامه‌های اندرویدی استفاده کنند. این فریم ورک جهت اتصالات JDBC و Spring و اندروید طراحی شده است.

نحوه معرفی جداول در این فریمورک به صورت زیر است:
@DatabaseTable(tableName = "users")
public class User {
    @DatabaseField(id = true)
    private String username;
    @DatabaseField
    private String password;
 
    public User() {
        // ORMLite needs a no-arg constructor
    }
    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }
 
    // Implementing getter and setter methods
    public String getUserame() {
        return this.username;
    }
    public void setName(String username) {
        this.username = username;
    }
    public String getPassword() {
        return this.password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}
با استفاده از کلمات کلیدی DatabaseTable@ در بالای کلاس و DatabaseField@ در بالای هر پراپرتی به معرفی جدول و فیلدهای جدول می‌پردازیم.
سورس این فریمورک را می‌توان در گیت هاب یافت و مستندات آن در این آدرس قرار دارند.


SugarORM
این فریمورک مختص اندروید طراحی شده است. یادگیری آن بسیار آسان است و به راحتی به یاد می‌ماند. همچنین جداول مورد نیاز را به طور خودکار خواهد ساخت. روابط یک به یک و یک به چند را پشتیبانی می‌کند و عملیات CURD را با سه متد Save,Delete و Find که البته FindById هم جزء آن است، پیاده سازی می‌کند.

برای استفاده از این فریمورک نیاز است ابتدا متادیتا‌های زیر را به فایل manifest اضافه کنید:
<meta-data android:name="DATABASE" android:value="my_database.db" />
<meta-data android:name="VERSION" android:value="1" />
<meta-data android:name="QUERY_LOG" android:value="true" />
<meta-data android:name="DOMAIN_PACKAGE_NAME" android:value="com.my-domain" />
برای تبدیل یک کلاس به جدول هم از کلاس این فریم ورک ارث بری می‌کنیم:
public class User extends SugarRecord<User> {
    String username;
    String password;
    int age;
    @Ignore
    String bio; //this will be ignored by SugarORM
 
    public User() { }
 
    public User(String username, String password,int age){
        this.username = username;
        this.password = password;
        this.age = age;
    }
}
بر خلاف OrmLight که باید فیلد جدول را معرفی می‌کردید، اینجا تمام پراپرتی‌ها به اسم فیلد شناخته می‌شوند؛ مگر اینکه در بالای آن از عبارت Ignore@ استفاده کنید.

باقی عملیات آن از قبیل اضافه کردن یک رکورد جدید یا حذف رکورد(ها) به صورت زیر است:
User johndoe = new User(getContext(),"john.doe","secret",19);
johndoe.save(); //ذخیره کاربر جدید در دیتابیس


//حذف تمامی کاربرانی که سنشان 19 سال است
List<User> nineteens = User.find(User.class,"age = ?",new int[]{19});
foreach(user in nineteens) {
    user.delete();
}
برای اطلاعات بیشتر به مستندات آن رجوع کنید.


GreenDAO
موقعیکه بحث کارآیی و سرعت پیش می‌آید نام GreenDAO هست که می‌درخشد. طبق گفته‌ی سایت رسمی آن این فریمورک میتواند در ثانیه چند هزار موجودیت را اضافه و به روزرسانی و بارگیری نماید. این لیست حاوی برنامه‌هایی است که از این فریمورک استفاده می‌کنند. جدول زیر مقایسه‌ای است بین این کتابخانه و OrmLight که نشان میدهد 4.5 برابر سریعتر از OrmLight عمل می‌کند.

غیر از این‌ها در زمینه‌ی حجم هم حرف‌هایی برای گفتن دارد. حجم این کتابخانه کمتر از 100 کیلوبایت است که در اندازه‌ی APK اثر چندانی نخواهد داشت.

آموزش راه اندازی  آن در اندروید استادیو، سورس آن در گیت هاب و مستندات رسمی آن.


Active Android
این کتابخانه از دو طریق فایل JAR و به شیوه maven قابل استفاده است که می‌توانید روش استفاده‌ی از آن را در این لینک ببینید و سورس اصلی آن هم در این آدرس قرار دارد. بعد از اینکه کتابخانه را به پروژه اضافه کردید، دو متادیتای زیر را که به ترتیب نام دیتابیس و ورژن آن هستند، به manifest اضافه کنید:
<meta-data android:name="AA_DB_NAME" android:value="my_database.db" />
<meta-data android:name="AA_DB_VERSION" android:value="1" />
بعد از آن  عبارت ;()ActiveAndroid.Initialize را در اکتیویتی‌های مدنظر اعمال کنید:
public class MyActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActiveAndroid.initialize(this);
 
        //ادامه برنامه
    }
}
برای معرفی کلاس‌ها به جدول هم از دو اعلان Table و Column مانند کد زیر به ترتیب برای معرفی جدول و فیلد استفاده می‌کنیم.
@Table(name = "User")
public class User extends Model {
    @Column(name = "username")
    public String username;
 
    @Column(name = "password")
    public String password;
 
    public User() {
        super();
    }
 
    public User(String username,String password) {
        super();
        this.username = username;
        this.password = password;
    }
}
جهت اطلاعات بیشتر در مورد این کتابخانه به مستندات آن رجوع کنید.


ORMDroid
 از آن دست کتابخانه‌هایی است که سادگی و کم حجم بودن شعار آنان است و سعی دارند تا حد ممکن همه چیز را خودکار کرده و کمترین کانفیگ را نیاز داشته باشد. حجم فعلی آن حدود 20 کیلوبایت بوده و نمی‌خواهند از 30 کیلوبایت تجاوز کند.

برای استفاده‌ی از آن ابتدا دو خط زیر را جهت معرفی تنظیمات به manifest اضافه کنید:
<meta-data
  android:name="ormdroid.database.name"
  android:value="your_database_name" />

<meta-data
  android:name="ormdroid.database.visibility"
  android:value="PRIVATE||WORLD_READABLE||WORLD_WRITEABLE" />
برای آغاز کار این کتابخانه، عبارت زیر را در هرجایی که مایل هستید مانند کلاس ارث بری شده از Application یا در ابتدای هر اکتیویتی که مایل هستید بنویسید. طبق مستندات آن صدا زدن چندباره این متد هیچ اشکالی ندارد.
ORMDroidApplication.initialize(someContext);
معرفی مدل جدول بانک اطلاعاتی هم از طریق ارث بری از کلاس Entity می‌باشد .
public class Person extends Entity {
  public int id;
  public String name;
  public String telephone;
}

//====================

Person p = Entity.query(Person.class).where("id=1").execute();
p.telephone = "555-1234";
p.save();

// یا

Person person = Entity.query(Person.class).where(eql("id", id)).execute();
p.telephone = "555-1234";
p.save();
کد بالا دقیقا یادآوری به EF هست ولی حیف که از Linq پشتیبانی نمی‌شود.
سورس آن در گیت هاب

در اینجا سعی کردیم تعدادی از کتابخانه‌های محبوب را معرفی کنیم ولی تعداد آن به همین جا ختم نمی‌شود. ORM‌های دیگری نظیر AndRom و سایر ORM هایی که در این لیست معرفی شده اند وجود دارند.


نکته نهایی اینکه خوب می‌شود دوستانی که از این ORM‌های مختص اندروید استفاده کرده اند؛ نظراتشان را در مورد آن‌ها بیان کنند و مزایا و معایب آن‌ها را بیان کنند.
مطالب
بررسی روش آپلود فایل‌ها از طریق یک برنامه‌ی Angular به یک برنامه‌ی ASP.NET Core
پیشنیازها
«بررسی روش آپلود فایل‌ها در ASP.NET Core»
«ارسال فایل و تصویر به همراه داده‌های دیگر از طریق jQuery Ajax»
- در مطلب اول، روش دریافت فایل‌ها از کلاینت، در سمت سرور و ذخیره سازی آن‌ها در یک برنامه‌ی ASP.NET Core بررسی شده‌است که کلیات آن در اینجا نیز صادق است.
- در مطلب دوم، روش کار با FormData استاندارد بررسی شده‌است. هرچند در مطلب جاری از jQuery استفاده نمی‌شود، اما نکات نحوه‌ی کار با شیء FormData استاندارد، در اینجا نیز یکی است.


تدارک مقدمات مثال این قسمت

این مثال در ادامه‌ی همین سری کار با فرم‌های مبتنی بر قالب‌ها است. به همین جهت ابتدا ماژول جدید UploadFile را به آن اضافه می‌کنیم:
 >ng g m UploadFile -m app.module --routing
همچنین به فایل app.module.ts مراجعه کرده و UploadFileModule را بجای UploadFileRoutingModule در قسمت imports معرفی می‌کنیم. سپس به این ماژول جدید، کامپوننت فرم ثبت یک درخواست پشتیبانی را اضافه خواهیم کرد:
 >ng g c UploadFile/UploadFileSimple
که اینکار سبب به روز رسانی فایل upload-file.module.ts و افزوده شدن UploadFileSimpleComponent به قسمت declarations آن می‌شود.
در ادامه کلاس مدل معادل فرم ثبت نام یک درخواست پشتیبانی را تعریف می‌کنیم:
 >ng g cl UploadFile/Ticket
با این محتوا:
export class Ticket {
  constructor(public description: string = "") {}
}
در اینجا Ticket تعریف شده دارای یک خاصیت توضیحات است و این فرم به همراه فیلد ارسال چندین فایل نیز می‌باشد که نیازی به درج آن‌ها در کلاس فوق نیست:



ایجاد مقدمات کامپوننت UploadFileSimple و قالب آن

پس از ایجاد ساختار کلاس Ticket، یک وهله از آن‌را به نام model ایجاد کرده و در اختیار قالب آن قرار می‌دهیم:
import { Ticket } from "./../ticket";

export class UploadFileSimpleComponent implements OnInit {
  model = new Ticket();
سپس قالب این کامپوننت و یا همان فایل upload-file-simple.component.html را به صورت ذیل تکمیل می‌کنیم:
<div class="container">
  <h3>Support Form</h3>
  <form #form="ngForm" (submit)="submitForm(form)" novalidate>
    <div class="form-group" [class.has-error]="description.invalid && description.touched">
      <label class="control-label">Description</label>
      <input #description="ngModel" required type="text" class="form-control"
        name="description" [(ngModel)]="model.description">
      <div *ngIf="description.invalid && description.touched">
        <div class="alert alert-danger"  *ngIf="description.errors.required">
          description is required.
        </div>
      </div>
    </div>

    <div class="form-group">
      <label class="control-label">Screenshot(s)</label>
      <input #screenshotInput required type="file" multiple (change)="fileChange($event)"
        class="form-control" name="screenshot">
    </div>

    <button class="btn btn-primary" [disabled]="form.invalid" type="submit">Ok</button>
  </form>
</div>
در اینجا ابتدا فیلد توضیحات درخواست جدید، ارائه و به خاصیت model.description متصل شده‌است. همچنین این فیلد با ویژگی required مزین، و اجباری بودن آن بررسی گردیده‌است.
سپس در انتها، فیلد آپلود را مشاهده می‌کنید؛ با این ویژگی‌ها:
الف) ngModel ایی به آن متصل نشده‌است؛ چون روش کار با آن متفاوت است.
ب) یک template reference variable به نام screenshotInput# در آن تعریف شده‌است. از این متغیر، در کامپوننت قالب استفاده خواهیم کرد.
ج) به رخ‌داد change این کنترل، متد fileChange متصل شده‌است که رخ‌داد جاری را نیز دریافت می‌کند.
د) ذکر ویژگی استاندارد multiple را نیز در اینجا مشاهده می‌کنید. وجود آن سبب خواهد شد تا کاربر بتواند چندین فایل را با هم انتخاب کند. اگر نیازی به ارسال چندین فایل نیست، این ویژگی را حذف کنید.


دسترسی به المان ارسال فایل در کامپوننت متناظر

تا اینجا یک المان ارسال فایل را به فرم، اضافه کرده‌ایم. اما چگونه باید به فایل‌های آن برای ارسال به سرور دسترسی پیدا کنیم؟
برای این منظور در ادامه دو روش را بررسی خواهیم کرد:

1) دسترسی به المان ارسال فایل از طریق رخ‌داد change
در تعریف فیلد ارسال فایل، اتصال به رخ‌داد change تعریف شده‌است:
 (change)="fileChange($event)"
معادل آن در سمت کامپوننت متناظر، به صورت ذیل است:
fileChange(event) {
    const filesList: FileList = event.target.files;
    console.log("fileChange() -> filesList", filesList);
}
همانطور که مشاهده می‌کنید، event.target، امکان دسترسی مستقیم به المان متناظری را در قالب کامپوننت میسر می‌کند. سپس می‌توان به خاصیت files آن دسترسی یافت.


در اینجا ساختار شیء استاندارد FileList و اجزای آن‌را مشاهده می‌کنید. برای مثال چون دو فایل انتخاب شده‌است، این لیست به همراه یک خاصیت طول و دو شیء File است.

تعاریف این اشیاء استاندارد، در فایل ذیل قرار دارند و به همین جهت است که VSCode، بدون نیاز به تنظیمات دیگری، آن‌ها را شناسایی و intellisense متناظری را مهیا می‌کند:
 C:\Program Files (x86)\Microsoft VS Code\resources\app\extensions\node_modules\typescript\lib\lib.dom.d.ts
همچنین اگر به فایل tsconfig.json پروژه نیز مراجعه کنید، یک چنین تعاریفی در آن قرار دارند:
{
    "lib": [
      "es2016",
      "dom"
    ]
  }
}
وجود و تعریف کتابخانه‌ی dom است که سبب کامپایل شدن کدهای فوق، بدون بروز هیچگونه خطایی می‌شود.


2) دسترسی به المان آپلود فایل از طریق یک template reference variable
در حین تعریف المان فایل در فرم برنامه، متغیر screenshotInput# نیز ذکر شده‌است. می‌توان به یک چنین متغیرهایی در کامپوننت متناظر به روش ذیل دسترسی یافت:
import { Component, OnInit, ViewChild, ElementRef } from "@angular/core";

export class UploadFileSimpleComponent implements OnInit {
  @ViewChild("screenshotInput") screenshotInput: ElementRef;

  submitForm(form: NgForm) {
    const fileInput: HTMLInputElement = this.screenshotInput.nativeElement;
    console.log("fileInput.files", fileInput.files);
  }
ابتدا یک خاصیت جدید را به نام screenshotInput از نوع ElementRef که در angular/core@ تعریف شده‌است، اضافه می‌کنیم. سپس برای اتصال آن به template reference variable ایی به نام screenshotInput، از ویژگی به نام ViewChild، با پارامتری مساوی نام همین متغیر، استفاده خواهیم کرد.
اکنون خاصیت screenshotInput کامپوننت، به متغیری به همین نام در قالب متناظر با آن متصل شده‌است. بنابراین با استفاده از خاصیت nativeElement آن همانند کدهایی که در متد submitForm فوق ملاحظه می‌کنید، می‌توان به خاصیت files این کنترل ارسال فایل‌ها دسترسی یافت.
نوع جدید و استاندارد HTMLInputElement نیز در فایل lib.dom.d.ts که پیشتر معرفی شد، ثبت شده‌است.


ارسال فرم درخواست پشتیبانی به سرور

تا اینجا فرمی را تشکیل داده و همچنین به فیلد file آن دسترسی پیدا کردیم. اکنون می‌خواهیم این اطلاعات را به سمت سرور ارسال کنیم. برای این منظور، سرویس جدیدی را ایجاد خواهیم کرد:
 >ng g s UploadFile/UploadFileSimple -m upload-file.module
که سبب به روز رسانی خودکار قسمت providers فایل upload-file.module.ts نیز می‌شود.
در ادامه کدهای کامل این سرویس را مشاهده می‌کنید:
import { Http, RequestOptions, Response, Headers } from "@angular/http";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Observable";
import "rxjs/add/operator/do";
import "rxjs/add/operator/catch";
import "rxjs/add/observable/throw";
import "rxjs/add/operator/map";
import "rxjs/add/observable/of";

import { Ticket } from "./ticket";

@Injectable()
export class UploadFileSimpleService {
  private baseUrl = "api/SimpleUpload";

  constructor(private http: Http) {}

  private extractData(res: Response) {
    const body = res.json();
    return body || {};
  }

  private handleError(error: Response): Observable<any> {
    console.error("observable error: ", error);
    return Observable.throw(error.statusText);
  }

  postTicket(ticket: Ticket, filesList: FileList): Observable<any> {
    if (!filesList || filesList.length === 0) {
      return Observable.throw("Please select a file.");
    }

    const formData: FormData = new FormData();

    for (const key in ticket) {
      if (ticket.hasOwnProperty(key)) {
        formData.append(key, ticket[key]);
      }
    }

    for (let i = 0; i < filesList.length; i++) {
      formData.append(filesList[i].name, filesList[i]);
    }

    const headers = new Headers();
    headers.append("Accept", "application/json");
    const options = new RequestOptions({ headers: headers });

    return this.http
      .post(`${this.baseUrl}/SaveTicket`, formData, options)
      .map(this.extractData)
      .catch(this.handleError);
  }
}
توضیحات تکمیلی:
روش کار با فرم‌هایی که فیلدهای ارسال فایل را به همراه دارند، متفاوت است با روش کار با فرم‌های معمولی. در فرم‌های معمولی، اصل شیء Ticket را به متد this.http.post واگذار می‌کنیم. مابقی آن خودکار است. در اینجا باید شیء استاندارد FormData را تشکیل داده و سپس اطلاعات را از طریق آن ارسال کنیم:
الف) افزودن مقادیر خواص شیء Ticket به FormData
  postTicket(ticket: Ticket, filesList: FileList): Observable<any> {
    const formData: FormData = new FormData();

    for (const key in ticket) {
      if (ticket.hasOwnProperty(key)) {
        formData.append(key, ticket[key]);
      }
    }
با استفاده از حلقه‌ی for می‌توان بر روی خواص یک شیء جاوا اسکریپتی حرکت کرد. به این ترتیب می‌توان نام و مقدار آن‌ها را یافت و سپس به formData به صورت key/value افزود.

ب) افزودن فایل‌ها به شیء FormData
پس از افزودن اطلاعات ticket به FormData، اکنون نوبت به افزودن فایل‌های فرم است:
    for (let i = 0; i < filesList.length; i++) {
      formData.append(filesList[i].name, filesList[i]);
    }
این مورد نیز به سادگی تشکیل یک حلقه، بر روی خاصیت files المان آپلود فایل است. به همین جهت بود که به دو روش سعی کردیم، به این خاصیت دسترسی پیدا کنیم.

یک نکته: چون در اینجا کلید اضافه شده، نام فایل است، دیگر نمی‌توان در سمت سرور از روش model binding استفاده کرد. چون این نام دیگر ثابت نیست و هربار می‌تواند متغیر باشد (در حالت model binding دقیقا مشخص است که کلید مشخصی قرار است به سرور ارسال شود و بر همین اساس، نام خاصیت یا پارامتر سمت سرور تعیین می‌گردد). به همین جهت در سمت سرور برای دسترسی به این مجموعه، از روش Request.Form.Files استفاده می‌کنیم.

ج) ارسال اطلاعات نهایی به سرور
اکنون که formData را بر اساس اطلاعات اضافی ticket و فایل‌های متصل به آن تشکیل دادیم، روش ارسال آن به سرور همانند قبل است:
    const headers = new Headers();
    headers.append("Accept", "application/json");
    const options = new RequestOptions({ headers: headers });

    return this.http
      .post(`${this.baseUrl}/SaveTicket`, formData, options)
      .map(this.extractData)
      .catch(this.handleError);

یک نکته: در اینجا در روش استفاده از formData نباید Content-Type را به multipart/form-data  تنظیم کرد. در غیراینصورت خطای Missing content-type boundary error را دریافت می‌کنید.


تکمیل کامپوننت ارسال درخواست پشتیبانی

پس از تکمیل سرویس ارسال اطلاعات به سمت سرور، اکنون نوبت به استفاده‌ی از آن در کامپوننت ارسال فرم درخواست پشتیبانی است. بنابراین ابتدا این سرویس جدید را به سازنده‌ی UploadFileSimpleComponent تزریق می‌کنیم:
import { UploadFileSimpleService } from "./../upload-file-simple.service";

export class UploadFileSimpleComponent implements OnInit {
  constructor(private uploadService: UploadFileSimpleService  ) {}
و سپس متد submitForm چنین شکلی را پیدا می‌کند:
  submitForm(form: NgForm) {
    const fileInput: HTMLInputElement = this.screenshotInput.nativeElement;
    console.log("fileInput.files", fileInput.files);

    this.uploadService
      .postTicket(this.model, fileInput.files)
      .subscribe(data => {
        console.log("success: ", data);
      });
  }
در اینجا this.model حاوی اطلاعات شیء ticket است (برای مثال اطلاعات توضیحات آن) و fileInput.files امکان دسترسی به اطلاعات فایل‌های انتخابی توسط کاربر را می‌دهد. پس از آن فراخوانی متدهای this.uploadService.postTicket و subscribe، سبب ارسال این اطلاعات به سمت سرور می‌شوند.


دریافت فرم درخواست پشتیبانی در سمت سرور و ذخیره‌ی فایل‌های آن‌

کدهای کامل SimpleUpload که در سرویس فوق مشخص شده‌است، به صورت ذیل هستند. ابتدا مدل Ticket مشخص شده‌است:
namespace AngularTemplateDrivenFormsLab.Models
{
    public class Ticket
    {
        public int Id { set; get; }
        public string Description { set; get; }
    }
}
و سپس کنترلر ذخیره سازی اطلاعات Ticket را مشاهده می‌کنید:
using System.IO;
using System.Threading.Tasks;
using AngularTemplateDrivenFormsLab.Models;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;

namespace AngularTemplateDrivenFormsLab.Controllers
{
    [Route("api/[controller]")]
    public class SimpleUploadController : Controller
    {
        private readonly IHostingEnvironment _environment;
        public SimpleUploadController(IHostingEnvironment environment)
        {
            _environment = environment;
        }

        [HttpPost("[action]")]
        public async Task<IActionResult> SaveTicket(Ticket ticket)
        {
            //TODO: save the ticket ... get id
            ticket.Id = 1001;

            var uploadsRootFolder = Path.Combine(_environment.WebRootPath, "uploads");
            if (!Directory.Exists(uploadsRootFolder))
            {
                Directory.CreateDirectory(uploadsRootFolder);
            }

            var files = Request.Form.Files;
            foreach (var file in files)
            {
                //TODO: do security checks ...!

                if (file == null || file.Length == 0)
                {
                    continue;
                }

                var filePath = Path.Combine(uploadsRootFolder, file.FileName);
                using (var fileStream = new FileStream(filePath, FileMode.Create))
                {
                    await file.CopyToAsync(fileStream).ConfigureAwait(false);
                }
            }

            return Created("", ticket);
        }
    }
}
توضیحات تکمیلی
- تزریق IHostingEnvironment در سازنده‌ی کلاس کنترلر، سبب می‌شود تا از طریق خاصیت WebRootPath آن، به مسیر wwwroot سایت دسترسی پیدا کنیم و فایل‌های نهایی را در آنجا ذخیره سازی کنیم.
- همانطور که ملاحظه می‌کنید، هنوز هم model binding کار کرده و می‌توان شیء Ticket را به نحو متداولی دریافت کرد:
 SaveTicket(Ticket ticket)
اما همانطور که عنوان شد، چون در حلقه‌ی افزودن فایل‌ها در سمت کلاینت، کلید نام این فایل‌ها هربار متفاوت است:
 formData.append(filesList[i].name, filesList[i]);
مجبور هستیم در سمت سرور بر روی Request.Form.Files یک حلقه را تشکیل داده و تمام فایل‌های رسیده را پردازش کنیم:
var files = Request.Form.Files;
foreach (var file in files)



کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید.
مطالب دوره‌ها
یکپارچه سازی اعتبارسنجی EF Code first با امکانات WPF و حذف کدهای تکرای INotifyPropertyChanged
در لابلای توضیحات قسمت‌های قبل، به نحوه استفاده از کلاس‌های پایه‌ای که اعتبارسنجی یکپارچه‌ای را با WPF و EF Code first در قالب پروژه WPF Framework ارائه می‌دهند، اشاره شد. در این قسمت قصد داریم جزئیات بیشتری از پیاده سازی آن‌ها را بررسی کنیم.

بررسی سطح بالای مکانیزم‌های اعتبارسنجی و AOP بکارگرفته شده

در حین کار با قالب پروژه WPF Framework، هنگام طراحی Modelهای خود (تفاوتی نمی‌کند که Domain model باشند یا صرفا Model متناظر با یک View)،  نیاز است دو مورد را رعایت کنید:
 [ImplementPropertyChanged] // AOP
public class LoginPageModel : DataErrorInfoBase
الف) کلاس مدل شما باید مزین به ویژگی ImplementPropertyChanged شود.
ب) از کلاس پایه DataErrorInfoBase مشتق گردد

البته اگر به کلاس‌های  Domain model برنامه مراجعه کنید، صرفا مشتق شدن از BaseEntity را ملاحظه می‌کنید:
 public class User : BaseEntity
علت این است که دو نکته یاد شده در کلاس پایه BaseEntity پیشتر پیاده سازی شده‌اند:
 [ImplementPropertyChanged] // AOP
public abstract class BaseEntity : DataErrorInfoBase //پیاده سازی خودکار سیستم اعتبارسنجی یکپارچه

بررسی جزئیات مکانیزم AOP بکارگرفته شده

بسیار خوب؛ این‌ها چطور کار می‌کنند؟!
ابتدا نیاز است مطلب «معرفی پروژه NotifyPropertyWeaver» را یکبار مطالعه نمائید. خلاصه‌ای جهت تکرار نکات مهم آن:
ویژگی ImplementPropertyChanged به ابزار Fody اعلام می‌کند که لطفا کدهای تکراری INotifyPropertyChanged را پس از کامپایل اسمبلی جاری، بر اساس تزریق کدهای IL متناظر، به اسمبلی اضافه کن. این روش از لحاظ کارآیی و همچنین تمیز نگه داشتن کدهای نهایی برنامه، فوق العاده است.
برای بررسی کارکرد آن نیاز است اسمبلی مثلا Models را دی‌کامپایل کرد:


همانطور که ملاحظه می‌کنید، کدهای تکراری INotifyPropertyChanged به صورت خودکار به اسمبلی نهایی اضافه شده‌اند.
البته بدیهی است که استفاده از Fody الزامی نیست. اگر علاقمند هستید که این اطلاعات را دستی اضافه کنید، بهتر است از کلاس پایه BaseViewModel قرار گرفته در مسیر MVVM\BaseViewModel.cs پروژه Common استفاده نمائید.
در این کلاس، پیاده سازی‌های NotifyPropertyChanged را بر اساس متدهایی که یک رشته را به عنوان نام خاصیت دریافت می‌کنند و یا متدی که امکان دسترسی strongly typed به نام رشته را میسر ساخته است، ملاحظه می‌کنید.
   /// <summary>
  /// تغییر مقدار یک خاصیت را اطلاع رسانی خواهد کرد
  /// </summary>
  /// <param name="propertyName">نام خاصیت</param>
  public void NotifyPropertyChanged(string propertyName)

  /// <summary>
  /// تغییر مقدار یک خاصیت را اطلاع رسانی خواهد کرد
  /// </summary>
  /// <param name="expression">نام خاصیت مورد نظر</param>
  public void NotifyPropertyChanged(Expression<Func<object>> expression)
برای مثال در اینجا خواهیم داشت:
public class AlertConfirmBoxViewModel : BaseViewModel
    {
        AlertConfirmBoxModel _alertConfirmBoxModel;
        public AlertConfirmBoxModel AlertConfirmBoxModel
        {
            set
            {
                _alertConfirmBoxModel = value;
                NotifyPropertyChanged("AlertConfirmBoxModel");
                // ویا ....
                NotifyPropertyChanged(()=>AlertConfirmBoxModel);
            }
            get { return _alertConfirmBoxModel; }
        }
هر دو حالت استفاده از متدهای NotifyPropertyChanged به همراه کلاس پایه BaseViewModel در اینجا ذکر شده‌اند. حالت استفاده از Expression به علت اینکه تحت نظر کامپایلر است، در دراز مدت نگه‌داری برنامه را ساده‌تر خواهد کرد.


بررسی جزئیات اعتبارسنجی‌های تعریف شده

EF دارای یک سری ویژگی مانند Required و امثال آن است. WPF دارای اینترفیسی است به نام IDataErrorInfo. این دو را باید به نحوی به هم مرتبط ساخت که پیاده سازی‌های مرتبط با آن‌ها را در مسیرهای WpfValidation\DataErrorInfoBase.cs و WpfValidation\ValidationHelper.cs پروژه Common می‌توانید ملاحظه نمائید.
 <TextBox Text="{Binding Path=ChangeProfileData.UserName, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,
 NotifyOnValidationError=true, ValidatesOnExceptions=true, ValidatesOnDataErrors=True, TargetNullValue=''}"  />
برای نمونه در اینجا خاصیت Text یک TextBox به خاصیت UserName شیء ChangeProfileData تعریف شده در ViewModel تغییر اطلاعات کاربری برنامه مقید شده است.
همچنین حالت‌های بررسی اعتبارسنجی آن نیز به PropertyChanged تنظیم گردیده است. در این حالت WPF به تعاریف شیء ChangeProfileData مراجعه کرده و برای نمونه اگر این شیء اینترفیس IDataErrorInfo را پیاده سازی کرده بود، نام خاصیت جاری را به آن ارسال و از آن خطاهای اعتبارسنجی متناظر را درخواست می‌کند. در اینجا وقت خواهیم داشت تا بر اساس ویژگی‌ها و Data annotaions اعمالی، کار اعتبارسنجی را انجام داده و نتیجه را بازگشت دهیم.
خلاصه‌ی تمام این اعمال و کلاس‌ها، در کلاس پایه DataErrorInfoBase این قالب پروژه قرار گرفته‌اند. بنابراین تنها کاری که باید صورت گیرد، مشتق کردن کلاس مدل مورد نظر از آن می‌باشد.
همچنین باید دقت داشت که نمایش اطلاعات خطاهای حاصل از اعتبارسنجی در این قالب پروژه بر اساس امکانات قالب متروی MahApps.Metro انجام می‌گیرد (این مورد از Silverlight toolkit به ارث رسیده است) و در حالت کلی خودکار نیست؛ اما در اینجا نیازی به کدنویسی اضافه‌تری ندارد.

به علاوه باید دقت داشت که این مورد ویژه را باید بر اساس آخرین Build کتابخانه MahApps.Metro که به‌روزتر است دریافت و استفاده کرد. در اینجا با پارامتر Pre ذکر شده است.

PM> Install-Package MahApps.Metro -Pre
مطالب
کنترلرهای تو در تو در angularJs و نحوه ارث بری متدها و property ها در آن - بخش دوم
در بخش قبلی به چگونگی ساخت کنترلرهای تو در تو در AngularJs پرداختیم. همچنین بررسی نمودیم که propertyهای تعریف شده در کنترلر ما چگونه قابل استفاده توسط کنترلر فرزند میباشند.
حال روشی دیگر را برای ارث بری تابع‌ها و propertyها، در کنترلر‌های تو در تو معرفی می‌نماییم. لازم به ذکر است که سورس پروژه را می‌توانید از لینک زیر دریافت نمایید:
 کد جاوااسکریپت زیر سه کنترلر تو در تو را پیاده سازی می‌کند:
var firstControllerObj = function ($scope) {
    // Initialize the model object
    $scope.firstModelObj = {
        firstName: "John"
    };
};

var secondControllerObj = function ($scope) {
    // Initialize the model object
    $scope.secondModelObj = {
        lastName: "Doe"
    };

    // Define utility functions
    $scope.getFullName = function () {
        return $scope.firstModelObj.firstName + " " +
          $scope.secondModelObj.lastName;
    };
};

var thirdControllerObj = function ($scope) {
    // Initialize the model object
    $scope.thirdModelObj = {
        middleName: "Al",
        lastName: "Smith"
    };

    // Define utility functions
    $scope.getFullName = function () {
        return $scope.firstModelObj.firstName + " " +
          $scope.thirdModelObj.middleName + " " +
          $scope.thirdModelObj.lastName;
    };
};
کد html زیر هم از کنترلر‌های تعریف شده‌ی در بالا، به صورت زیر استفاده کرده است. نگاهی کوتاه و مختصر به این فایل و سپس به شرح فرآیند ارث بری property‌ها می‌پردازیم:
    <div ng-controller="firstControllerObj">
        <h3>First controller</h3>
        <strong>First name:</strong> {{firstModelObj.firstName}}<br />
        <br />
        <label>Set the first name: <input type="text" ng-model="firstModelObj.firstName" /></label><br />
        <br />
        
        
        <div ng-controller="secondControllerObj">
            <h3>Second controller (inside First)</h3>
            <strong>First name (from First):</strong> {{firstModelObj.firstName}}<br />
            <strong>Last name (from Second):</strong> {{secondModelObj.lastName}}<br />
            <strong>Full name:</strong> {{getFullName()}}<br />
            <br />
            <label>Set the first name: <input type="text" ng-model="firstModelObj.firstName" /></label><br />
            <label>Set the last name: <input type="text" ng-model="secondModelObj.lastName" /></label><br />
            <br />
            

            <div ng-controller="thirdControllerObj">
                <h3>Third controller (inside Second and First)</h3>
                <strong>First name (from First):</strong> {{firstModelObj.firstName}}<br />
                <strong>Middle name (from Third):</strong> {{thirdModelObj.middleName}}<br />
                <strong>Last name (from Second):</strong> {{secondModelObj.lastName}}<br />
                <strong>Last name (from Third):</strong> {{thirdModelObj.lastName}}<br />
                <strong>Full name (redefined in Third):</strong> {{getFullName()}}<br />
                <br />
                <label>Set the first name: <input type="text" ng-model="firstModelObj.firstName" /></label><br />
                <label>Set the middle name: <input type="text" ng-model="thirdModelObj.middleName" /></label><br />
                <label>Set the last name: <input type="text" ng-model="thirdModelObj.lastName" /></label>
            </div>
        </div>
    </div>
اگر نگاهی به کنترلرهای فوق بیاندازیم می‌بینیم که در firstControllerObj تنها یک شیء درون scope قرار داده شده که firstModelObj نامیده شده است و این شی تنها دارای یک property با نام firstName است. در کنترلر دوم نیز یک شیء جدید با نام secondModelObj ساخته شده است؛ با این تفاوت که property آن lastName نام دارد. حال به بدنه‌ی فایل html دو کنترلر توجه کنیم. می‌بینیم که در کنترلر دوم مستقیما پراپرتی firstName از شیء درون کلاس اول فراخوانی شده است. با اجرای پروژه‌ی نمونه خواهیم دید که با تغییر input شامل firstName در کنترلر دوم، این مدل در کنترلر اول نیز تغییر خواهد کرد.
بنابراین ما می‌توانیم در کنترلر فرزند به objectهای درون کنترلر والد دسترسی داشته باشیم و مقادیر آنرا تغییر دهیم. باید توجه داشت که این نوع تعریف مدل با آنچه که در بخش اول گفته شد، تفاوتی اساسی دارد. در بخش قبل با تغییر مدل توسط کنترلر فرزند، آن مدل در کنترلر والد تغییری نمی‌کرد؛ اما در روشی که در این مقاله شرح داده شد مشاهده نمودیم که با تغییر مدل در کنترلر فرزند مقدار مدل در کنترلر والد نیز تغییر می‌کند. 
مطالب
انتخاب پویای فیلد ها در LINQ

LINQ یک DLS  بر مبنای .NET  می باشد که برای پرس و جو در منابع داده ای مانند پایگاه‌های داده ، فایل‌های XML و یا لیستی از اشیاء درون حافظه کاربرد دارد.

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

LINQ  از 2 نوع نمادگذاری پشتیبانی می‌کند:

  • Inline LINQ یا query expressions : 
var result = 
    from product in dbContext.Products
    where product.Category.Name == "Toys"
    where product.Price >= 2.50
    select product.Name;
  • Fluent Syntax : 
var result = dbContext.Products
    .Where(p => p.Category.Name == "Toys" && p.Price >= 250)
    .Select(p => p.Name);

در پرس و چو‌های بالا فیلد‌های مورد نیاز در قسمت Select در زمان Compile شناخته شده هستند . اما گاهی ممکن است فیلد‌های مورد نیاز در زمان اجرا مشخص شوند.

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

این مدل را در نظر داشته باشید :

    public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Field1 { get; set; }
        public string Field2 { get; set; }
        public string Field3 { get; set; }


        public static IEnumerable<Student> GetStudentSource()
        {
            for (int i = 0; i < 10; i++)
            {
                yield return new Student
                                 {
                                     Id = i,
                                     Name = "Name " + i,
                                     Field1 = "Field1 " + i,
                                     Field2 = "Field2 " + i,
                                     Field3 = "Field3 " + i
                                 };
            }
        }
    }

ستون‌های کلاس Student  را در رابط کاربری برنامه جهت انتخاب به کاربر نمایش می‌دهیم. سپس کاربر یک یا چند ستون را انتخاب می‌کند که قسمت Select  کوئری برنامه باید  بر اساس فیلد‌های مورد نظر کاربر مشخص شود.

یکی از روش هایی که می‌توان از آن بهره برد استفاده از کتاب خانه Dynamic LINQ معرفی شده در اینجا می باشد.

این کتابخانه جهت سهولت در نصب به کمک NuGet در این آدرس قرار دارد.

فرض بر این است که فیلد‌های انتخاب شده توسط کاربر با "," از یکدیگر جدا شده اند. 

    public class Program
    {
        private static void Main(string[] args)
        {
            System.Console.WriteLine("Specify the desired fields : ");
            string fields = System.Console.ReadLine();
            IEnumerable<Student> students = Student.GetStudentSource();
            IQueryable output = students.AsQueryable().Select(string.Format("new({0})", fields));
            foreach (object item in output)
            {
                System.Console.WriteLine(item);
            }
          
            System.Console.ReadKey();
        }
  
    }

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

این روش مزایا و معایب خودش را دارد ، به عنوان مثال خروجی یک لیست از شیء Student  نیست یا این Select  فقط برای روی یک شیء IQueryable  قابل انجام است.

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

    public  class SelectBuilder <T>
    {
        public static Func<T, T> CreateNewStatement(string fields)
        {
            // input parameter "o"
            var xParameter = Expression.Parameter(typeof(T), "o");


            // new statement "new T()"
            var xNew = Expression.New(typeof(T));

            // create initializers
            var bindings = fields.Split(',').Select(o => o.Trim())
                .Select(o =>
                {

                    // property "Field1"
                    var property = typeof(T).GetProperty(o);

                    // original value "o.Field1"
                    var xOriginal = Expression.Property(xParameter, property);

                    // set value "Field1 = o.Field1"
                    return Expression.Bind(property, xOriginal);
                }
            ).ToList();

            // initialization "new T { Field1 = o.Field1, Field2 = o.Field2 }"
            var xInit = Expression.MemberInit(xNew, bindings);

            // expression "o => new T { Field1 = o.Field1, Field2 = o.Field2 }"
            var lambda = Expression.Lambda<Func<T, T>>(xInit, xParameter);

            // compile to Func<T, T>
            return lambda.Compile();
        }
    }
برای استفاده از متد CreateNewStatement باید اینگونه عمل کرد :  
       IEnumerable<Student> result = students.Select(SelectBuilder<Student>.CreateNewStatement("Field1, Field2")).ToList();

            foreach (Student student in result)
            {
                System.Console.WriteLine(student.Field1);
            }
خروجی یک لیست از Student  می باشد.
 نحوه‌ی کارکرد CreateNewStatement :

ابتدا فیلد‌های انتخابی کاربر که با "," جدا شده اند به ورودی پاس داده می‌شود سپس یک statement  خالی ایجاد می‌شود

o=>new Student()
فیلد‌های ورودی از یکدیگر تفکیک می‌شوند و به کمک Reflection پراپرتی معادل فیلد رشته ای در کلاس Student پیدا می‌شود :  
var property = typeof(T).GetProperty(o);
سپس عبارت Select و تولید شیء جدید بر اساس فیلد‌های ورودی تولید می‌شود و برای استفاده Compile  به Func می‌شود. در نهایت Func  تولید شده به Select پاس داده می‌شود و لیستی از Student  بر مبنای فیلد‌های انتخابی تولید می‌شود. 

دریافت مثال : DynamicSelect.zip 
بازخوردهای دوره
جلوگیری از deadlock در برنامه‌های async
در این حالت خاص ضرورتی به استفاده از متدهای Async نیست و اگر ASP.NET Identity نمونه‌ی غیر async ارائه نداده‌است، خودتان ایجاد کنید. برای مثال در کلاس ApplicationUserManager ، شیء this.Users معادل همان ()<users = _uow.Set<ApplicationUser_ است.