مطالب
استفاده از Lambda Expression در پروژه های مبتنی بر WCF
نکته : آشنایی با مفاهیم پایه WCF برای فهم بهتر مفاهیم توصیه می‌شود.

امروزه استفاده از WCF در پروژه‌های SOA بسیار فراگیر شده است. کمتر کسی است که در مورد قدرت تکنولوژی WCF نشنیده باشد یا از این تکنولوژی در پروژه‌های خود استفاده نکرده باشد. WCF مدل برنامه نویسی یکپارچه مایکروسافت برای ساخت نرم‌افزارهای سرویس گرا است و برای توسعه دهندگان امکانی را فراهم می‌کند که راهکارهایی امن، و مبتنی بر تراکنش را تولید نمایند که قابلیت استفاده در بین پلتفرم‌های مختلف را دارند. قبل از WCF توسعه دهندگان پروژه‌های نرم افزاری برای تولید پروژه‌های توزیع شده باید شرایط موجود برای تولید و توسعه را در نظر می‌گرفتند. برای مثال اگر استفاده کننده از سرویس در داخل سازمان و بر پایه دات نت تهیه شده بود از .net remoting استفاده می‌کردند و اگر استفاده کننده سرویس از خارج سازمان یا مثلا بر پایه تکنولوژی J2EE بود از Web Service‌ها استفاده می‌شد. با ظهور WCF این تکنولوژی با هم تجمیع شدند(بهتر بگم تبدیل به یک تکنولوژی واحد شدند) و دیگر خبری از net remoting یا web service‌ها نیست.
  WCF با تمام قدرت و امکاناتی که داراست دارای نقاط ضعفی هم می‌باشد که البته این معایب (یا محدودیت) بیشتر جهت سازگار سازی سرویس‌های نوشته شده با سیستم‌ها و پروتکل‌های مختلف است.
برای انتقال داده‌ها از طریق WCF بین سیستم‌های مختلف باید داده‌های مورد نظر حتما سریالایز شوند که مثال هایی از این دست رو در همین سایت می‌تونید مطالعه کنید:
(^ )  و (^ ) و (^ )

با توجه به این که داده‌ها سریالایز می‌شوند، در نتیجه امکان انقال داده هایی که از نوع object  هستند در WCF وجود ندارد. بلکه نوع داده باید صراحتا ذکر شود و این نوع باید قابیلت سریالایز شدن را دارا باشد.برای مثال شما نمی‌تونید متدی داشته باشید که پارامتر ورودی آن از نوع delegate باشد یا کلاسی باشد که صفت [Serializable] در بالای اون قرار نداشته باشد یا کلاسی باشد که صفت DataContract برای خود کلاس و صفت DataMember برای خاصیت‌های اون تعریف نشده باشد. حالا سوال مهم این است اگر متدی داشته باشیم که پارامتر ورودی آن حتما باید از نوع delegate باشد چه باید کرد؟

برای تشریح بهتر مسئله یک مثال می‌زنم؟

سرویسی داریم برای اطلاعات کتاب ها. قصد داریم متدی بنوسیم که پارامتر ورودی آن از نوع Lambda Expression است تا Query مورد نظر کاربر از سمت کلاینت به سمت سرور دریافت کند و خروجی مورد نظر را با توجه به Query ورودی به کلاینت برگشت دهد.( متدی متداول در اکثر پروژه ها). به صورت زیر عمل می‌کنیم.

*ابتدا یک Blank Solution ایجاد کنید.

*یک ClassLibrary به نام Model ایجاد کنید و کلاسی به نام Book در آن بسازید .(همانطور که میبینید کلاس مورد نظر سریالایز شده است):

   [DataContract]
    public class Book
    {
        [DataMember]
        public int Code { get; set; }

        [DataMember]
        public string Title { get; set; }
    }
* یک WCF Service Application ایجاد کنید
یک Contract برای ارتباط بین سرور و کلاینت می‌سازیم:
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.ServiceModel;

namespace WcfLambdaExpression
{
    [ServiceContract]
    public interface IBookService
    {
        [OperationContract]
        IEnumerable<Book> GetByExpression( Expression<Func<Book, bool>> expression );
    }
}
متد GetByExpression دارای پارامتر ورودی expression است که نوع آن نیز Lambda Expression  می‌باشد. حال یک سرویس ایجاد می‌کنیم:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace WcfLambdaExpression
{    
    public class BookService : IBookService
    {        
        public BookService()
        {
            ListOfBook = new List<Book>();
        }

        public List<Book> ListOfBook 
        {
            get;
            private set;
        }

        public IEnumerable<Book> GetByExpression( Expression<Func<Book, bool>> expression )
        {
            ListOfBook.AddRange( new Book[] 
            {
                new Book(){Code = 1 , Title = "Book1"},
                new Book(){Code = 2 , Title = "Book2"},
                new Book(){Code = 3 , Title = "Book3"},
                new Book(){Code = 4 , Title = "Book4"},
                new Book(){Code = 5 , Title = "Book5"},
            } );

            return ListOfBook.AsQueryable().Where( expression );
        }       
    }
}
بعد از Build پروژه همه چیز سمت سرور آماده است. یک پروژه دیگر از نوع Console ایجاد کنید و از روش AddServiceReference سعی کنید که سرویس مورد نظر را به پروژه اضافه کنید. در هنگام Add Service Reference برای اینکه سرویس سمت سرور و کلاینت هر دو با یک مدل کار کنند باید از یک Reference assembly استفاده کنند و کافی است از قسمت Advanced گزینه Reuse types in referenced assemblies را تیک بزنید و assembly‌های مورد نظر را انتخاب کنید.( در این پروژه باید Model و System.Xml.Linq را انتخاب کنید)


به طور حتم با خطا روبرو خواهید شد. دلیل آن هم این است که امکان سریالایز کردن برای پارامتر ورودی expression میسر نیست.
خطای مربوطه به شکل زیر خواهد بود:
Type 'System.Linq.Expressions.Expression`1[System.Func`2[WcfLambdaExpression.Book,System.Boolean]]' cannot be serialized. 
Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute.  
If the type is a collection, consider marking it with the CollectionDataContractAttribute.  
See the Microsoft .NET Framework documentation for other supported types
حال چه باید کرد؟
روش‌های زیادی برای بر طرف کردن این محدودیت وجود دارد. اما در این پست روشی رو که خودم از اون استفاده می‌کنم رو براتون شرح می‌دهم.
در این روش باید از XElement استفاده شود که در فضای نام System.Linq.Xml قرار دارد. یعنی آرگومان ورودی سمت کلاینت باید به فرمت Xml سریالایز شود و سمت سرور دوباره دی سریالایز شده و تبدیل به یک Lambda Expression شود. اما سریالایز کردن Lambda Expression واقعا کاری سخت و طاقت فرساست . با توجه به این که در اکثر پروژه‌ها این متد‌ها به صورت Generic نوشته می‌شوند. برای حل این مسئله بعد از مدتی جستجو، کلاسی رو پیدا کردم که این کار رو برام انجام می‌داد. بعد از مطالعه دقیق و مشاهده روش کار کلاس، تغییرات مورد نظرم رو اعمال کردم و الان در اکثر پروژه هام دارم از این کلاس استفاده می‌کنم.
یک مثال از روش استفاده :
برای اینکه از این کلاس در هر دو پروژه (سرور و کلاینت) استفاده می‌کنیم باید یک Class Library جدید به نام Common بسازید و یک ارجاع از اون رو به هر دو پروژه سمت سرور و کلاینت بدید.
سرویس و Contract بالا رو به صورت زیر باز نویسی کنید.
[ServiceContract]
    public interface IBookService
    {
        [OperationContract]
        IEnumerable<Book> GetByExpression( XElement expression );
    }
و سرویس :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Xml.Linq;

namespace WcfLambdaExpression
{
    public class BookService : IBookService
    {
        public BookService()
        {
            ListOfBook = new List<Book>();
        }

        public List<Book> ListOfBook
        {
            get;
            private set;
        }

        public IEnumerable<Book> GetByExpression( XElement expression )
        {
            ListOfBook.AddRange( new Book[] 
            {
                new Book(){Code = 1 , Title = "Book1"},
                new Book(){Code = 2 , Title = "Book2"},
                new Book(){Code = 3 , Title = "Book3"},
                new Book(){Code = 4 , Title = "Book4"},
                new Book(){Code = 5 , Title = "Book5"},
            } );

             Common.ExpressionSerializer serializer = new Common.ExpressionSerializer();

            return ListOfBook.AsQueryable().Where( serializer.Deserialize( expression ) as Expression<Func<Book, bool>> );
        }
    }
بعد از Build پروژه از روش Add Service Reference استفاده کنید و می‌بینید که بدون هیچ گونه مشکلی سرویس مورد نظر به پروژه Console اضافه شد. برای استفاده سمت کلاینت به صورت زیر عمل کنید.

using System;
using System.Linq.Expressions;
using TestExpression.MyBookService;

namespace TestExpression
{
    class Program
    {
        static void Main( string[] args )
        {
            BookServiceClient bookService = new BookServiceClient();

            Expression<Func<Book, bool>> expression = x => x.Code > 2 && x.Code < 5;

            Common.ExpressionSerializer serializer = new Common.ExpressionSerializer();

            bookService.GetByExpression( serializer.Serialize( expression ) );
        }
    }
}
بعد از اجرای پروژه، در سمت سرور خروجی‌های زیر رو مشاهده می‌کنیم.

خروجی هم به صورت زیر خواهد بود:

دریافت سورس کامل Expression-Serialization
نظرات مطالب
شمسی سازی Date-Picker توکار Angular Material 6x
من این کار رو توی انگیولار 14 انجام دادم و مشکلی نداشتم فقط چندتا نکته دیدم که بهتر دونستم اینجا اعلام کنم شاید به درد کسی بخوره.
اول اینکه توی ورژن‌های جدید انگیولار متریال، DateAdapter  به فولدر angular/material/core  منتقل شده
نسخه قدیمی
import { DateAdapter } from "@angular/material";
نسخه جدید
import { DateAdapter } from "@angular/material/core";

مابقی هم همینطور
import {  DateAdapter,  MAT_DATE_FORMATS,  MAT_DATE_LOCALE } from "@angular/material/core";

یه مشکلی هم که من داشتم این بود که تقویم چپ چین بود و من میخواستم راستچین باشه که با "DIR="RTL حل شد
 <mat-datepicker #picker2 dir="rtl"></mat-datepicker>
مطالب
babel چیست؟ lebab چیست؟
قطعا به عنوان برنامه نویس JavaScript کم و بیش با ecmaScript 6 آشنایی دارید.
با وجود ویژگی‌های منحصر به فردی که دارد شاید تنها دلیلی که برخی از برنامه نویسان هنوز تصمیم به عدم استفاده از این زبان را دارند، مرورگرهایی میباشند که هنوز از es6 پشتیبانی نمیکنند: es6 compatibility table 
اما راهکاری مناسب، برای اینکه بتوان هم از es6 استفاده کرد و هم کاربران را مجبور به استفاده‌ی از مرورگر‌های مدرن نکنیم نیز وجود دارد:به صورت مستقیم میتوان با استفاده از Babel، کد‌های نوشته شده‌ی با es6 را کامپایل و تبدیل به es5 کنیم. برای اینکار معمولا از gulp استفاده میکنیم. 
gulp در وبسایت رسمی آن، خودش را اینچنین تعریف کرده است : automate and enhance your workflow
حال کافیست با چند خط کد es6 شروع به کار کنیم. بنده معمولا از visual studio code استفاده میکنم.
class firstCLs
{
    doFirst(str)
    {
        console.log(str);
    }
}

class secondCls extends firstCLs
{
    doSecond(str)
    {
        super.doFirst(str);
    }
}

let str = 'string';
new secondCls().doSecond(`this is some ${str}`);
فکر میکنم کد‌های فوق احتیاج به توضیح بیشتری نداشته باشند. اکنون فرض کنید نام فایل آن code.js است و در پوشه‌ی src قرار دارد. همانطور که پیشتر عرض کردم، برای تبدیل آن به کدی از نوع es5 از gulp استفاده می‌کنیم.
ابتدا از طریق خط فرمان، خود gulp را نصب میکنیم. 
npm install -g gulp
بعد بر روی پوشه‌ی root پروژه‌تان رفته و با استفاده از خط فرمان، npm init را ارسال کنید تا package.json برای شما ساخته شود.
برای نصب gulp در پروژه‌ی local خود نیز این فرمان را ارسال کنید:
npm install gulp --save-dev
با استفاده از این فرمان، gulp را در مسیر جاری پروژه‌تان و در پوشه‌ی node-modules نصب کرده و همچنین فرمان --save-dev نیز آن را به وابستگی‌های پروژه اضافه میکند.
حال احتیاج به نصب gulp-babel داریم که با استفاده از خط فرمان، خود آن را نصب مینماییم:
npm install --save-dev gulp-babel babel-preset-es2015
حال در مسیر اصلی پروژه، فایل gulpfile.js را ساخته و کدهای زیر را مینویسیم:
const gulp = require('gulp');
const babel = require('gulp-babel');
 
gulp.task('default', () => {
return gulp.src('src/code.js')
.pipe(babel({
presets: ['es2015']
}))
.pipe(gulp.dest('dist'));
});
برای توضیح کد‌های بالا باید عرض کنم در قسمت gulp.task، عملیاتی را که لازم میدانیم gulp برای ما انجام دهد، شرح میدهیم.
gulp.src مسیر فایلی را که تصمیم داریم کامپایل شده و به es5 تبدیل شود، معین می‌کند ( لازم به ذکر است که میتوان بطور مثال همه‌ی اسکریپت‌های درون یک پوشه را انتخاب کرد که توضیح آن در این مقاله نمیگنجد).
بعد در قسمت اولین pipe فوق است که میخواهیم تبدیلی را به es2015 داشته باشیم و در آخرین pipe نیز با استفاده از متد dest، آدرس مسیری را که میخواهیم آن فایل کامپایل شده در آن قرار بگیرد، مینویسیم. بطور مثال من پوشه‌ی dist را به عنوان آدرس قرار داده‌ام.
مراحل انجام شده را save نمایید. خط فرمان خود را باز کرده و دستور gulp را type نمایید. بعد از پایان یافتن عملیات، به پوشه‌ی dist رجوع کنید. فایل مورد نظر مشاهد میشود.

اما حال فرض کنید پروژه ای در اختیار داشته و کد‌ها از نوع es5 میباشند و تصمیم به تبدیل آن‌ها به es6 داشته باشید.
برای اینکار از lebab (که دقیقا عکس نوشتاری bable میباشد) استفاده میکنیم.
ابتدا از طریق خط فرمان خود آن را نصب مینماییم
npm install -g lebab
به صورت مستقیم میتوانیم هر فایلی را که به صورت استاندارد نوشته شده است، کامپایل کرده و تبدیل به es6 نماییم.
کد‌های زیر را در نظر بگیرید
'use strict';

// Let/const
var name = 'Bob', time = 'yesterday';
time = 'today';

// Template string
console.log('Hello ' + name + ', how are you ' + time + '?');

var bob = {
  // Object shorthand
  name: name,
  // Object method
  sayMyName: function () {
    console.log(this.name);
  }
};

// Classes
var SkinnedMesh = function SkinnedMesh() {
};

SkinnedMesh.prototype.update = function (camera) {
  camera = camera || createCamera();
  this.camera = camera;
};

Object.defineProperty(SkinnedMesh.prototype, 'name', {
  set: function (geometry) {
    this.geometry = geometry;
  },
  get: function () {
    return this.geometry;
  }
});

// Commonjs
var lebab = require('lebab');
module.exports = SkinnedMesh;

// Arrow functions
var render = function () {
  // ...
  requestAnimationFrame(render);
};
فرض کنید آن را با نام es5.js در مسیر اصلی پروژه ذخیره کرده‌ایم. با استفاده از خط فرمان خود آن را تبدیل به es6 خواهیم کرد؛ بدین شکل:
lebab es5.js -o es6.js
فایل مورد نظر ما به نام es6.js ذخیره خواهد شد و بدین صورت کامپایل خواهد شد
const name = 'Bob';
let time = 'yesterday';
time = 'today';

// Template string
console.log(`Hello ${name}, how are you ${time}?`);

const bob = {
  // Object shorthand
  name,
  // Object method
  sayMyName() {
    console.log(this.name);
  }
};

class SkinnedMesh {
  update(camera=createCamera()) {
    this.camera = camera;
  }

  set name(geometry) {
    this.geometry = geometry;
  }

  get name() {
    return this.geometry;
  }
}

import lebab from 'lebab';
export default SkinnedMesh;

// Arrow functions
const render = () => {
  // ...
  requestAnimationFrame(render);
};
تبدیل es5 به es6 انجام شد؛ اما باید خدمتتان عرض کنم آنچنان هم نباید انتظار داشت که بعد از این تبدیل و فشار دادن دکمه‌ی F5، پروژه‌ی شما بدون هیچ خطایی اجرا شود (البته در صورتیکه هنوز در اوایل پروژه هستید شاید اینگونه شود) اما کمی refactoring برای کد‌های کامپایل شده را به es 6، در خاطر داشته باشید.
مطالب
تخمین مدت زمان خوانده شدن یک مطلب
پس از انتشار مطلب «Pro Agile .NET Development With Scrum - قسمت اول» شاید این سؤال در ابتدای کار برای خواننده پیش بیاید که ... چقدر باید برای خواندن آن وقت بگذارم؟ برای پاسخ به این سؤال باید درنظر داشت که یک انسان معمولی، می‌تواند بین 200 تا 250 کلمه را در دقیقه، مطالعه کند. بنابراین در ابتدا باید محاسبه کرد که یک متن، چه تعدادی کلمه دارد؟
شاید عنوان کنید که کافی است متن ورودی را بر اساس فاصله‌ی بین کلمات تقسیم بندی کرده و سپس تعداد کلمات بدست آمده را محاسبه کنیم:
 var words = text.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
return words.Length;
این روش با آزمون زیر کار نکرده و با شکست مواجه می‌شود:
[TestMethod]
public void TestInvalidChars()
{
    const string data = "To be . ! < > ( ) ! ! , ; : ' ? + -";
    Assert.AreEqual(2, data.WordsCount());
}
در اینجا ! ، و امثال آن نیز یک کلمه درنظر گرفته می‌شوند. برای حل این مشکل کافی است آرایه‌ی split را کمی تکمیل‌تر کنیم تا حروف غیرمجاز را درنظر نگیرد:
 var words = text.Split(
    new[] { ' ', ',', ';', '.', '!', '"', '(', ')', '?', ':', '\'', '«' , '»', '+', '-' },
    StringSplitOptions.RemoveEmptyEntries);
return words.Length;
تا اینجا مشکل !، >< حل شد، اما در مورد متن ذیل چطور؟
[TestMethod]
public void TestSimpleHtmlSpacesWithNewLine()
{
    const string data = "<b>this is&nbsp;a&nbsp;&nbsp;test.</b>\n\r<b>this is&nbsp;a&nbsp;&nbsp;test.</b>";
    Assert.AreEqual(8, data.WordsCount());
}
مطالب ثبت شده، عموما توسط HTML Editorها ثبت می‌شوند. بنابراین دارای انواع و اقسام تگ‌ها بوده و همچنین ممکن است در این بین new line هم وجود داشته باشد که در این حالت، test\n\rtest باید دو کلمه محاسبه شود و نه یک کلمه.
اگر این موارد را در نظر بگیریم، به کلاس ذیل خواهیم رسید:
using System;
using System.Text.RegularExpressions;
 
namespace ReadingTime
{
    public static class CalculateWordsCount
    {
        private static readonly Regex _matchAllTags =
            new Regex(@"<(.|\n)*?>", RegexOptions.IgnoreCase | RegexOptions.Compiled);
 
        public static int WordsCount(this string text)
        {
            if (string.IsNullOrWhiteSpace(text))
            {
                return 0;
            }
 
            text = text.cleanTags().Trim();
            text = text.Replace("\t", " ");
            text = text.Replace("\n", " ");
            text = text.Replace("\r", " ");
 
            var words = text.Split(
                new[] { ' ', ',', ';', '.', '!', '"', '(', ')', '?', ':', '\'', '«' , '»', '+', '-' },
                StringSplitOptions.RemoveEmptyEntries);
            return words.Length;
        }
 
        private static string cleanTags(this string data)
        {
            return data.Replace("\n", "\n ").removeHtmlTags();
        }
 
        private static string removeHtmlTags(this string text)
        {
            return string.IsNullOrEmpty(text) ?
                        string.Empty :
                        _matchAllTags.Replace(text, " ").Replace("&nbsp;", " ");
        }
    }
}
در اینجا حذف تگ‌های HTML و همچنین پردازش خطوط جدید و حروف غیرمجاز درنظر گرفته شده‌اند.

پس از اینکه موفق به شمارش تعداد کلمات یک متن HTML ایی شدیم، اکنون می‌توان این تعداد را تقسیم بر 180 (یک عدد معمول و متداول) کرد تا زمان خواندن کل متن بدست آید. سپس با استفاده از متد toReadableString می‌توان آن‌را به شکل قابل خواندن‌تری نمایش داد.
using System;
 
namespace ReadingTime
{
    public static class CalculateReadingTime
    {
        public static string MinReadTime(this string text, int wordsPerMinute = 180)
        {
            var wordsCount = text.WordsCount();
            var minutes = wordsCount / wordsPerMinute;
            return minutes == 0 ? "کمتر از یک دقیقه" : TimeSpan.FromMinutes(minutes).toReadableString();
        }
 
        private static string toReadableString(this TimeSpan span)
        {
            var formatted = string.Format("{0}{1}{2}{3}",
                span.Duration().Days > 0 ? string.Format("{0:0} روز و ", span.Days) : string.Empty,
                span.Duration().Hours > 0 ? string.Format("{0:0} ساعت و ", span.Hours) : string.Empty,
                span.Duration().Minutes > 0 ? string.Format("{0:0} دقیقه و ", span.Minutes) : string.Empty,
                span.Duration().Seconds > 0 ? string.Format("{0:0} ثانیه", span.Seconds) : string.Empty);
 
            if (formatted.EndsWith("و "))
            {
                formatted = formatted.Substring(0, formatted.Length - 2);
            }
 
            if (string.IsNullOrEmpty(formatted))
            {
                formatted = "0 ثانیه";
            }
            return formatted.Trim();
        }
    }
}

کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید:
ReadingTime.zip
 
مطالب دوره‌ها
مدیریت تغییرات گریدی از اطلاعات به کمک استفاده از الگوی واحد کار مشترک بین ViewModel و لایه سرویس
قالب پروژه WPF Framework به همراه چندین صفحه ابتدایی لازم، برای شروع هر برنامه‌ی تجاری دسکتاپی است؛ مثال مانند صفحه لاگین، صفحه تغییرات مشخصات کاربر وارد شده به سیستم و امثال آن. صفحه‌ای را که در این قسمت بررسی خواهیم کرد، صفحه تعریف کاربران جدید و ویرایش اطلاعات کاربران موجود است.


در این صفحه با کلیک بر روی دکمه به علاوه، یک ردیف به ردیف‌های موجود اضافه شده و در اینجا می‌توان اطلاعات کاربر جدیدی به همراه سطح دسترسی او را وارد و ذخیره کرد و یا حتی اطلاعات کاربران موجود را ویرایش نمود. اگر بخواهیم مانند مراحلی که در قسمت قبل در مورد تعریف یک صفحه جدید در برنامه توضیح داده شد، عمل کنیم، به صورت خلاصه به ترتیب ذیل عمل شده است:
1) ایجاد صفحه تغییر مشخصات کاربر
ابتدا صفحه Views\Admin\AddNewUser.xaml به پروژه ریشه که Viewهای برنامه در آن تعریف می‌شوند، اضافه شده است. به همراه دو دکمه و یک ListView که تطابق بهتری با قالب متروی مورد استفاده دارد.

2) تنظیم اعتبارسنجی صفحه اضافه شده
مرحله بعد تعریف هر صفحه‌ای در سیستم، مشخص سازی وضعیت دسترسی به آن است:
/// <summary>
/// افزودن و مدیریت کاربران سیستم
/// </summary>
[PageAuthorization(AuthorizationType.ApplyRequiredRoles, "IsAdmin, CanAddNewUser")]
ویژگی PageAuthorization به فایل Views\Admin\AddNewUser.xaml.cs اعمال شده است. در اینجا تنها کاربرانی که خاصیت‌های IsAdmin و CanAddNewUser آن‌ها true باشند، مجوز دسترسی به صفحه تعریف کاربران را خواهند یافت.

3) تغییر منوی برنامه جهت اشاره به صفحه جدید
در ادامه در فایل منوی برنامه Views\MainMenu.xaml تعریف دسترسی به صفحه Views\Admin\AddNewUser.xaml قید شده است:
                <Button Style="{DynamicResource MetroCircleButtonStyle}"
                        Height="55" Width="55"  
                        Command="{Binding DoNavigate}"
                        CommandParameter="\Views\Admin\AddNewUser.xaml"
                        Margin="2">
                    <Rectangle Width="28" Height="17.25">
                        <Rectangle.Fill>
                            <VisualBrush Stretch="Fill" Visual="{StaticResource appbar_user_add}" />
                        </Rectangle.Fill>
                    </Rectangle>
                </Button>
همانطور که در قسمت قبل نیز توضیح داده شده، تنها کافی است در اینجا CommandParameter را مساوی مسیر فایل AddNewUser.xaml قرار دهیم تا سیستم راهبری به صورت خودکار از آن استفاده کند.

4) ایجاد ViewModel متناظر با صفحه
مرحله نهایی تعریف صفحه AddNewUser، افزودن ViewModel متناظر با آن است که سورس کامل آن‌را در فایل ViewModels\Admin\AddNewUserViewModel.cs پروژه Infrastructure می‌توانید ملاحظه کنید.
نکته مهم این ViewModel، ارائه خاصیت لیست کاربران از نوع ObservableCollection به View و گرید برنامه است:
public ObservableCollection<User> UsersList { set; get; }
اطلاعات آن از IUsersService تزریق شده در سازنده کلاس ViewModel دریافت می‌شود:
        /// <summary>
        /// جهت مقاصد انقیاد داده‌ها در دبلیو پی اف طراحی شده است
        /// لیستی از کاربران سیستم را باز می‌گرداند
        /// </summary>
        /// <param name="count">تعداد کاربر مد نظر</param>
        /// <returns>لیستی از کاربران</returns>
        public ObservableCollection<User> GetSyncedUsersList(int count = 1000)
        {
            _users.OrderBy(x => x.FriendlyName).Take(count)
                  .Load();

            // For Databinding with WPF.
            // Before calling this method you need to fill the context by using `Load()` method.
            return _users.Local;
        }
این کدها را در فایل UsersService.cs لایه سرویس برنامه می‌توانید مشاهده نمائید.
در اینجا از قابلیت خاصیتی به نام Local که یک ObservableCollection تحت نظر EF را بازگشت می‌دهد، استفاده شده است. برای استفاده از این خاصیت، ابتدا باید کوئری خود را تهیه و سپس متد Load را بر روی آن فراخوانی کرد. سپس خاصیت Local بر اساس اطلاعات کوئری قبلی پر و مقدار دهی خواهد شد.
علت انتخاب نام Synced برای این متد، تحت نظر بودن اطلاعات خاصیت Local است تا زمانیکه Context تعریف شده زنده نگه داشته شود. به همین جهت در برنامه جاری از روش زنده نگه داشتن Context به ازای یک ViewModel استفاده شده است.
به Context، توسط اینترفیس IUnitOfWork تزریق شده در سازنده کلاس ViewModel می‌توان دسترسی یافت. چون در اینجا از تزریق وابستگی‌ها استفاده شده است، وهله‌ای که IUnitOfWork کلاس AddNewUserViewModel را تشکیل می‌دهد، دقیقا همان وهله‌ای است که در کلاس UsersService لایه سرویس استفاده شده است. در نتیجه، در گرید برنامه هر تغییری اعمال شود، تحت نظر IUnitOfWork خواهد بود و صرفا با فراخوانی متد uow.ApplyAllChanges آن، کلیه تغییرات تمام ردیف‌های تحت نظر EF به صورت خودکار در بانک اطلاعاتی درج و یا به روز خواهند شد.
همچنین در مورد ViewModelContextHasChanges نیز در قسمت قبل بحث شد. در اینجا پیاده سازی کننده آن صرفا خاصیت uow.ContextHasChanges است. به این ترتیب اگر کاربر، تغییری را در صفحه داده باشد و بخواهد به صفحه دیگری رجوع کند، با پیام زیر مواجه خواهد شد:


از همین خاصیت برای فعال و غیرفعال کردن دکمه ذخیره سازی اطلاعات نیز استفاده شده است:
  /// <summary>
  /// فعال و غیرفعال سازی خودکار دکمه ثبت
  /// این متد به صورت خودکار توسط RelayCommand کنترل می‌شود
  /// </summary>  
  private bool canDoSave()
  {
     // آیا در حین نمایش صفحه‌ای دیگر باید به کاربر پیغام داد که اطلاعات ذخیره نشده‌ای وجود دارد؟
     return ViewModelContextHasChanges;
  }
این متد توسط RelayCommand ایی به نام  DoSave
  /// <summary>
  /// رخداد ذخیره سازی اطلاعات را دریافت می‌کند
  /// </summary>
  public RelayCommand DoSave { set; get; }
که به نحو زیر مقدار دهی شده است، مورد استفاده قرار می‌گیرد:
DoSave = new RelayCommand(doSave, canDoSave);
به ازای هر تغییری در UI، این RelayCommand به نتیجه canDoSave مراجعه کرده و اگر خروجی آن true باشد، دکمه متناظر را به صورت خودکار فعال می‌کند و یا برعکس.
این بررسی نیز بسیار سبک و سریع است. از این جهت که تغییرات Context در حافظه نگهداری می‌شوند و مراجعه به آن مساوی مراجعه به بانک اطلاعاتی نیست.
مطالب
آموزش VC++ از مقدماتی تا پیشرفته
بحثی که بنده قصد آموزش آن را دارم آموزش  ++ C  در IDE  مایکروسافت  visual studio  می‌باشد . آموزش از پروژه‌های Win32 Console Application  شروع شده و قسمت پیشرفته آموزش در پروژه‌های Win32 Project ادامه می‌یابد .
...

اولین پروژه

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

ایجاد اولین پروژه  Win32 Console Application

ویژوال استادیو را اجرا نمایید و از گزینه  File -> New -> Project و سپس طبق عکس زیر پروژه Win32 Console Application را انتخاب نمایید ، دقت کنید که زبان انتخاب شده ++Visual C باشد.

در این مرحله میتوانید محل ذخیره شده پروژه را در قسمت Location  تنظیم نمایید و از قسمت  Name  میتوانید نام دلخواه را وارد کنید در حالت پیش فرض اگر اولین پروژه Win32 Console  در مسیر تعین شده‌ی قسمت  Location  باشد ، نام  ConsoleApplication1  قرار گرفته است . پس از تنظیمات Ok کنید .

در این مرحله Next  را بزنید .

در این مرحله در قسمت Additional options  تیک Empty project را بزنید ، همانند عکس فوق تنظیمات را انجام دهید .

پس از انجام مراحل فوق پروژه بصورت شکل زیر ظاهر میشود .

برای کد نویسی روی نام پروژه که در اینجا ConsoleApplication1 می‌باشد ، راست کلیک میکنیم و گزینه Add و سپس New Item  را انتخاب میکنیم .

طبق عکس زیر فایل با پسوند cpp  را انتخاب و Add  میکنیم .

فایلی که اکنون به پروژه اضافه کردیم خالی و با نام پیش فرض Source.cpp  می‌باشد ، دستورات زیر را در آن تایپ کنید .حال پروژه به شکل زیر خواهد بود .

#include<iostream>

int  main()
{
   std::cout<<"Hello world ...\n";
   return 0;
}

برای اجرای پروژه کلید F5 را فشار دهید و اگر میخواهید نتیجه کار را مشاهده کنید کلید Ctrl + F5  را امتحان کنید .

شما اولین پروژه VC++  را اجرا نمودید ( آفرین ) .

اما توضیحات :

خط اول برنامه یک راهنمای پیش پردازنده است ، کاراکتر # که نشان میدهد این خط یک راهنمای پیش پردازنده است و بعد عبارت include  و نام یک فایل کتابخانه ای که بین علامت <> قرار داده شده ،  فایل سرآیند استفاده شده در اینجا  iostream  میباشد . (به فایل‌های کتابخانه ای ، فایلهای سرآیند (Header Files) نیز گفته میشود. ) راهنمای پیش پردازنده خطی است که به کامپایلر اطلاع میدهد در برنامه موجودیتی است که تعریف آن را در فایل سرآیند مذکور جستجو کند . در این برنامه از std::cout  استفاده شده ، که کامپایلر در مورد آن چیزی نمیداند لذا به فایل iostream  مراجعه نموده ، تعریف آن را می‌یابد و آن را اجرا میکند . 

خط 3 :

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

خط 5 :

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

خط 6 :

که ;0 return میباشد مقدار برگشتی تابع را مشخص میکند در حقیقت این خط که مقدار 0 را برمیگرادند نشان دهنده اتمام موفقیت آمیز برنامه می‌باشد .

به مرور زمان نسبت به موارد بالا بیشتر و مفصل صحبت خواهیم نمود .

نظرات مطالب
Blazor 5x - قسمت یازدهم - مبانی Blazor - بخش 8 - کار با جاوا اسکریپت
برای دستیابی به متدهای غیر استاتیکی سی شارپ در کامپوننت‌ها از طریق کدهای جاوااسکریپتی و بدون فراخوانی آنها توسط IJSRuntime میتوان از روش زیر استفاده کرد.
var object;

window.JsFunctionHelper = {MapSuccessResponse: function (instance, address) {
       object = instance;
       return instance.invokeMethodAsync("GetAddress", valuesFromApi);
       }
 };

 function getValuesFromApi() {
      .
      .
      .

      object.invokeMethodAsync("GetAddress", valuesFromApi);
 }
در این مثال API گوگل مپ جزییات یک آدرس درخواست شده را به یک فایل js برمیگرداند، و میخواهم این مقادیر را به کامپوننت برای پرازش ارسال کنم. ابتدا یک متغیر با دسترسی global تعریف میکنیم و آن را برابر با  ارجاعی که از وهله‌ی کامپوننت جاری ساخته شده قرار میدهیم. در نهایت شی  invokeMethodAsync از این روش برای فراخوانی متد به همراه پارامتر در کامپوننت در دسترس است.
نحوه امکان فراخوانی کدهای #C از طریق کدهای جاوااسکریپت در برنامه‌های Blazor به عنوان یک نکته تکمیلی در بخش نظرات همین پست آمده.

نظرات مطالب
شروع کار با Angular Material ۲
از نسخه 2.0.beta-11، ماژول  MaterialModule حذف شده است. این ماژول تمامی کامپوننتهای پیاده سازی شده را جهت استفاده وارد می‌کرد. از این نسخه به بعد بایستی کامپوننتهای مورد استفاده یکی یکی وارد شوند. به عنوان مثال اگر در برنامه خود فقط از کامپوننت دکمه و چک باکس استفاده می‌کنیم، به شکل زیر عمل میکنیم. 
import {
  MatButtonModule,
  MatCheckboxModule
} from "@angular/material";
به جهت جلوگیری از شلوغی ماژول اصلی برنامه بهتر است ماژول دیگری به شکل زیر تعریف کنیم که کامپوننتهای مورد استفاده در برنامه را مدیریت میکند و ماژول اصلی برنامه تنها از این ماژول استفاده خواهد کرد. (این روش در راهنمای استفاده از Angular Material Design به عنوان یک روش مطرح شده است.)
import {MatButtonModule, MatCheckboxModule} from '@angular/material';

@NgModule({
  imports: [MatButtonModule, MatCheckboxModule],
  exports: [MatButtonModule, MatCheckboxModule],
})
export class MyOwnCustomMaterialModule { }
در این صورت کافی است در AppModule فقط MyOwnCustomMaterialModule را در قسمت imports ذکر کنیم.
نظرات مطالب
اعمال تزریق وابستگی‌ها به مثال رسمی ASP.NET Identity
سلام مجدد
یه سوالی داشتم. آیا Dependencr Resolver برای کنترلرهای از نوع Web Api در این مثال گنجانده شده، چون الان وقتی دو تا اکشن متد از نوع WebApi  و با Verb از نوع httpPostداخل کنترلر AccountApi تعریف میکنیم هنگام فراخوانی و ارسال json به آن‌ها به مشکل برخورده و ارور زیر را نمایش می‌دهد:
exceptionMessage": "An error occurred when trying to create a controller of type 'AccountApiController'. Make sure that the controller has a parameterless public constructor.",
"innerException": {
    "message": "An error has occurred.",
    "exceptionMessage": "Type 'MyProject.Web.Controllers.AccountApiController' does not have a default constructor",
    "exceptionType": "System.ArgumentException",