مطالب دوره‌ها
لیست ها و آرایه ها در #F
برای تعریف لیست در #F فقط کافیست از [] و برای جداسازی آیتم‌های موجود در لیست از عملگر :: (بخوانید cons) استفاده کنید. #F از لیست‌های خالی نیز پشتیبانی می‌کند. به مثال هایی از این دست توجه کنید

#1 let emptyList = []
#2 let oneItem = "one " :: []
#3 let twoItem = "one " :: "two " :: []
#1 تعریف یک لیست خالی
#2 تعریف یک لیست به همراه یک آیتم
#3 تعریف یک لیست به همراه دو آیتم
قبول دارم که دستورالعمل بالا برای مقدار دهی اولیه به لیست کمی طولانی و سخت است. برای همین می‌تونید از روش زیر هم استفاده کنید.
let shortHand = ["apples "; "pears"]
*کد بالا یک لیست با دو آیتم که از نوع رشته ای هستند تولید خواهد کرد.
می‌تونید از عملگر @ برای پیوستن دو لیست به هم نیز استفاده کنید.
let twoLists = ["one, "; "two, "] @ ["buckle "; "my "; "shoe "]

نکته : تمام آیتم‌های موجود در لیست باید از یک نوع باشند. بعنی امکان تعریف لیستی که دارای آیتم هایی با datatype‌های متفاوت باشد باعث تولید خطای کامپایلری می‌شود. اما اگر نیاز به لیستی دارید که باید چند datatype رو هم پوشش دهد می‌تونید از object‌ها استفاده کنید.
let objList = [box 1; box 2.0; box "three"]
در بالا یک لیست از object‌ها رو تعریف کرده ایم. فقط دقت کنید برای اینکه آیتم‌های موجود در لیست رو تبدیل به object کنیم از دستور box قبل از هر آیتم استفاده کردیم.

 در هنگام استفاده از عملگر‌ها @ و :: مقدار لیست تغییر نمی‌کند بلکه یک لیست جدید تولید خواهد شد.
#1 let one = ["one "]
#2 let two = "two " :: one
#3 let three = "three " :: two
#4 let rightWayRound = List.rev three

#5 let main() =
printfn "%A" one
printfn "%A" two
printfn "%A" three
printfn "%A" rightWayRound
#1 تعریف لیستی که دارای یک آیتم است.
#2 تعریف لیستی که دارای دو آیتم است(آیتم دوم لیست خود از نوع لیست است)
#3 تعریف لیستی که دارای سه آیتم است(ایتم دوم لیست خود از نوع لیستی است که دارای دو آیتم است)
# از تابع List.rev برای معکوس کردن آیتم‌های لیست three استفاده کردیم و مقادیر در لیستی به نام  rightWayRound قرار گرفت.
#5 تابع main برای چاپ اطلاعات لیست ها
بعد از اجرا خروجی زیر مشاهده می‌شود.
["one "]
["two "; "one "]
["three "; "two "; "one "]
["one "; "two "; "three "]
تفاوت بین لیست‌ها در #F و لیست و آرایه در دات نت(System.Collection.Generic)

 F#List
Net Array
 Net List
 #1 امکان تغییر در عناصر لیست
 NoYes
 Yes
 #2 امکان اضافه کردن عنصر جدید
 NoNo
 Yes
#3 جستجو
On
O1
O1
#1 در #F بعد از ساختن یک لیست امکان تغییر در مقادیر عناصر آن وجود ندارد.
#2 در #F بعد از ساختن یک لیست دیگه نمی‌تونید یک عنصر جدید به لیست اضافه کنید.
#3 جستجوی در لیست‌های #F به نسبت لیست‌ها و آرایه‌های در دات نت کند‌تر عمل می‌کند.

استفاده از عبارات در لیست ها
برای تعریف محدوده در لیست می‌تونیم به راحتی از روش زیر استفاده کنیم
let rangeList = [1..99]
برای ساخت لیست‌ها به صورت داینامیک استفاده از حلقه‌های تکرار در لیست مجاز است.
let dynamicList = [for x in 1..99 -> x*x]
کد بالا معادل کد زیر در #C  است.
for(int x=0;x<99 ; x++)
{
   myList.Add(x*x);
}
لیست‌ها و الگوی Matching
روش عادی برای کار با لیست‌ها در #F استفاده از الگوی Matching و توابع بازگشتی است.
let listOfList = [[2; 3; 5]; [7; 11; 13]; [17; 19; 23; 29]]

let rec concatList l =
match l with
| head :: tail -> head @ (concatList tail)
| [] -> []

let primes = concatList listOfList

printfn "%A" primes
در مثال بالا ابتدا یک لیست تعریف کردیم که دارای 3 آیتم است و هر آیتم آن خود یک لیست با سه آیتم است.(تمام آیتم‌ها از نوع داده عددی هستند). یک تابع بازگشتی برای پیمایش تمام آیتم‌های لیست نوشتم که در اون از الگوی Matching استفاده کردیم.
خروجی :
[2; 3; 5; 7; 11; 13; 17; 19; 23; 29]
ماژول لیست
در جدول زیر تعدادی از توابع ماژول لیست رو مشاهده می‌کنید.

 نام تابع
 توضیحات
 List.length  تابعی که طول لیست را برمی گرداند
 List.head  تابعی برای برگشت عنصر اول لیست
 List.tail  تمام عناصر لیست را بر میگرداند به جز عنصر اول
 List.init  یک لیست با توجه به تعداد آیتم ایجاد می‌کند و یم تابع را بر روی تک تک عناصر لیست ایجاد می‌کند.
 List.append  یک لیست را به عنوان ورودی دریافت می‌کند و به لیست مورد نظر اضافه می‌کند و مجموع دو لیست را برگشت می‌دهد
 List.filter  فقط عناصری را برگشت می‌دهد که شرط  مورد نظر بر روی آن‌ها مقدار true را برگشت دهد
 List.map  یک تابع مورد نظر را بر روی تک تک عناصر لیست اجرا می‌کند و لیست جدید را برگشت می‌دهد
 List.iter  یک تابع مورد نظر را بر روی تک تک عناصر لیست اجرا می‌کند  
 List.zip 
 مقادیر دو لیست را با هم تجمیع می‌کند و لیست جدید را برگشت می‌دهد. اگر طول 2 لیست ورودی یکی نباشد خطا رخ خواهدداد 
 List.unzip درست برعکس تابع بالا عمل می‌کند
 List.toArray  لیست را تبدیل به آرایه می‌کند
 List.ofArray آرایه را تبدیل به لیست می‌کند
مثال هایی از توابع بالا
 List.head [5; 4; 3]

List.tail [5; 4; 3]

List.map (fun x -> x*x) [1; 2; 3]

List.filter (fun x -> x % 3 = 0) [2; 3; 5; 7; 9]

Sequence Collection

seq در #F یک توالی از عناصری است که هم نوع باشند. عموما از sequence‌ها زمانی استفاده میکنیم که یک مجموعه از داده‌ها با تعداد زیاد و مرتب شده داشته باشیم ولی نیاز به استفاده از تمام عناصر آن نیست. کارایی sequence  در مجموعه‌های با تعداد زیاد از list‌ها به مراتب بهتر است. sequence‌‌ها را با تابع  seq می‌شناسند که معادل IEnumerable در دات نت است. بنابر این هر مجمو عه ای که IEnumerable رو در دات نت پیاده سازی کرده باشد در #F با seq قابل استفاده است.

مثال هایی از نحوه استفاده seq

#1 seq بامحدوده 1 تا 100 و توالی 10 
seq { 0 .. 10 .. 100 }
#2 استفاده از حلقه‌های تکرار برای تعریف محدوده و توالی در seq
seq { for i in 1 .. 10 do yield i * i }
#3 استفاده از <- به جای yield
seq { for i in 1 .. 10 -> i * i }
#4 استفاده از حلقه for به همراه شرط برای فیلتر کردن
let isprime n =
    let rec check i =
        i > n/2 || (n % i <> 0 && check (i + 1))
    check 2

let aSequence = seq { for n in 1..100 do if isprime n then yield n }
چگونگی استفاده از توابع seq
در این بخش به ارائه مثال هایی کاربردی‌تر از چگونگی استفاده از seq در #F می‌پردازیم. برای شروع نحوه ساخت یک seq خالی یا empty رو خواهم گفت.
let seqEmpty = Seq.empty
روش ساخت یک seq که فقط یک عنصر را برگشت می‌دهد.
let seqOne = Seq.singleton 10
برای ساختن یک seq همانند لیست‌ها می‌تونیم از seq.init استفاده کنیم. عدد 5 که بلافاصله بعد از تابع seq.init آمده است نشان دهنده تعداد آیتم‌ها موجود در seq خواهد بود. seq.iter هم یک تابع مورد نظر رو بر روی تک تک عناصر seq اجرا خواهد کرد.(همانند list.iter)
let seqFirst5MultiplesOf10 = Seq.init 5 (fun n -> n * 10)
Seq.iter (fun elem -> printf "%d " elem) seqFirst5MultiplesOf10
خروجی مثال بالا
0 10 20 30 40
با استفاده از توابع seq.ofArray , seq.ofList می‌تونیم seq مورد نظر خود را از لیست یا آرایه مورد نظر بسازیم.
let seqFromArray2 = [| 1 .. 10 |] |> Seq.ofArray 
البته این نکته رو هم یادآور بشم که به کمک عملیات تبدیل نوع(type casting) هم می‌تونیم آرایه رو به seq تبدیل کنیم. به صورت زیر
let seqFromArray1 = [| 1 .. 10 |] :> seq<int>
برای مشخص کردن اینکه آیا یک آیتم در seq موجود است یا نه می‌تونیم از seq.exists به صورت زیر استفاده کنیم.
let containsNumber number seq1 = Seq.exists (fun elem -> elem = number) seq1
let seq0to3 = seq {0 .. 3}
printfn "For sequence %A, contains zero is %b" seq0to3 (containsNumber 0 seq0to3)
اگر seq پاس داده شده به تابع exists خالی باشد یا یک ArgumentNullException متوقف خواهید شد.

برای جستجو و پیدا کردن یک آیتم در seq می‌تونیم از seq.find استفاده کنیم.
let isDivisibleBy number elem = elem % number = 0
let result = Seq.find (isDivisibleBy 5) [ 1 .. 100 ]
printfn "%d " result
دقت کنید که اگر هیچ آیتمی در sequence با  predicate مورد نظر پیدا نشود یک KeyNotFoundException رخ خواهد داد. در صورتی که مایل نباشید که استثنا رخ دهد می‌توانید از تابع seq.tryFind استفاده کنید. هم چنین خالی بودن sequence ورودی باعث ArgumentNullExceptionخواهد شد.

استفاده از lambda expression در توابع
lamdaExpressoion از توانایی‌ها مورد علاقه برنامه نویسان دات نت است و کمتر کسی است حاضر به استفاده از آن در کوئری‌های linq نباشد. در #F نیز می‌توانید از lambda Expression استفاده کنید. در ادامه به بررسی مثال هایی از این دست خواهیم پرداخت.

تابع skipWhile
همانند skipWhile در linq عمل می‌کند. یعنی یک predicate مورد نظر را بر روی تک تک عناصر یک لیست اجرا می‌کند و آیتم هایی که شرط برای آن‌ها true باشد نادیده گرفته میشوند و مابقی آیتم‌ها برگشت داده می‌شوند.
let mySeq = seq { for i in 1 .. 10 -> i*i }
let printSeq seq1 = Seq.iter (printf "%A ") seq1; printfn "" 
let mySeqSkipWhileLessThan10 = Seq.skipWhile (fun elem -> elem < 10) mySeq
mySeqSkipWhileLessThan10 |> printSeq
می‌بینید که predicate مورد نظر برای تابع skipWhile به صورت lambda expression است که با رنگ متفاوت نمایش داده شده است.(استفاده از کلمه fun).
 خروجی به صورت زیر است:
16 25 36 49 64 81 100
 برای بازگرداندن یک تعداد مشخص از آیتم‌های seq می‌تونید از توابع seq.take یا seq.truncate استفاده کنید. ابتدا باید تعداد مورد نظر و بعد لیست مورد نظر را به عنوان پارامتر مقدار دهی کنید.
مثال:
let mySeq = seq { for i in 1 .. 10 -> i*i }
let truncatedSeq = Seq.truncate 5 mySeq
let takenSeq = Seq.take 5 mySeq

let printSeq seq1 = Seq.iter (printf "%A ") seq1; printfn "" 
#1 truncatedSeq |> printSeq #3 takenSeq |> printSeq
خروجی
1 4 9 16 25 //truncate
1 4 9 16 25 //take

Tuples
tuples در #F به گروهی از مقادیر بی نام ولی مرتب شده که می‌توانند انواع متفاوت هم داشته باشند گفته می‌شود. ساختار کلی آن به صورت ( element , ... , element )  است که هر element خود می‌تواند یک عبارت نیز باشد.(مشابه کلاس Tuple در #C که به صورت generic استفاده می‌کنیم)
// Tuple of two integers.
( 1, 2 ) 

// Triple of strings.
( "one", "two", "three" ) 

// Tuple of unknown types.
( a, b ) 

// Tuple that has mixed types.
( "one", 1, 2.0 ) 

// Tuple of integer expressions.
( a + 1, b + 1)
نکات استفاده از tuple
#1 می‌تونیم از الگوی Matching برای دسترسی به عناصر tuple استفاده کنیم.
let print tuple1 =
   match tuple1 with
    | (a, b) -> printfn "Pair %A %A" a b
#2 میتونیم از let  برای تعربف الگوی tuple استفاده کنیم.
let (a, b) = (1, 2)
#3 توابع fst و snd مقادیر اول و دوم هر tuple رو بازگشت می‌دهند
let c = fst (1, 2) // return 1
let d = snd (1, 2)// return 2
#4 تابعی برای بازگشت عنصر سوم یک tuple وجود ندارد ولی این تابع رو با هم می‌نویسیم:
let third (_, _, c) = c
کاربرد tuple در کجاست
زمانی که یک تابع باید بیش از یک مقدار را بازگشت دهد از tuple‌ها استفاده می‌کنیم. برای مثال
let divRem a b = 
   let x = a / b
   let y = a % b
   (x, y)
خروجی تابع divRem از نوع tuple که دارای 2 مقدار است می‌باشد.
مطالب
معماری وب گرا (سبکی از سرویس گرایی)
در ابتدای مقاله، پیش از آن که وارد بحث معماری وب گرا بشوم، یک سوال را مطرح میکنم که شاید برای شما هم جالب باشد. آن سوال اینست : آیا SOA پاسخی برای همه چیز در 
حوزه معماری است؟ شاید اینطور نباشد. به ترکیب زیر دقت کنید :
WOA  / SOA + WWW + REST
ترکیب فوق ما را چند قدم جلوتر برده و کاستی‌های سرویس گرایی را پر می‌کند و ما را یاری می‌کند تا اپلیکیشن‌های کامل end-to-end بسازیم.

اگر چه مفهوم WOA شاید چندان فراگیر نباشد، ولی بسیاری از آنچه تاکنون در سطح اینترنت می‌بینیم شالوده همین تفکر وب گرایی است.

معماری وب گرا یا Web-Oriented Architecture در 2006 توسط  Nick Gall از گروه Gartner ابداع شده است. 
معماری وب گرا یک سبک معماری نرم افزاری است که معماری سرویس گرا (Service-Oriented Architecture) را در راستای اپلیکیشن‌های تحت وب گسترش می‌دهد. 
معماری وب گرا در اصل توسط بسیاری از شبکه‌های اجتماعی و وب سایت‌های شخصی ساخته شده است.

تعریف رسمی Gartner از معماری وب گرا چنین است :
 “معماری وب گرا یا Web-Oriented Architecture سبکی معمارگونه از معماری سرویس گرا یا همان Service-Oriented Architecture می‌باشد که به یکپارچگی سیستم‌ها و کاربران از طریق ابررسانه‌های مرتبط با هم در سطح جهانی بر اساس معماری وب می‌پردازد.
 این نوع معماری بر تمامی اینترفیس‌ها (رابط کاربری و  رابط کاربردی برنامه نویسی) به منظور دستیابی به تاثیرات شبکه‌ی جهانی از طریق پنج عنصر رابط اساسی ذیل تاکید دارد :
  • شناسایی منابع
  • بکارگیری منابع از طریق نمایش آنها (منابع وب)
  • پیام‌های خودتوصیفی
  • ابررسانه بعنوان قلب تپنده موقعیت برنامه
  • درگیر نکردن برنامه “
Nick Gall همچنین فرمولی را برای تعریف معماری وب گرا (WOA) ارائه داده است که بدین شکل است:
WOA = SOA + WWW + REST

Dion Hinchcliffe مدعی است که معماری وب گرا چنین است: 

“مجموعه‌ای از هسته پروتکل‌های وب مانند HTTP, XML است و اینکه تنها تفاوت معماری سرویس گرای سنتی و مفاهیم معماری وب گرا اینست که WOA از REST حمایت می‌کند. REST متدی به طور فزاینده محبوب ، قدرتمند و ساده به منظور اعمال نفوذ پروتکل انتقال ابر متن HTTP بعنوان یک وب سرویس در چارچوب حقوق خودش است.“

پشته‌ی معماری وب گرا WOA شامل چنین مواردی است :
  • توزیع (HTTP , Feeds)
  • ترکیب (Hypermedia , Mashups)
  • امنیت (Open ID, SSL)
  • قابلیت انتقال داده (XML,RDF)
  • قابلیت نمایش داده (ATOM, JSON)
  • متدهای انتقال (REST, HTTP, Bit Torrent)

بطور کل باید گفت WOA هر چیزی است که در اینترنت وجود دارد و هر چیزی که بر مبنای REST می‌باشد والبته سرویس گراست. در کلامی گویا باید گفت امروزه معماری وب گرا پراستفاده‌ترین نوع معماری در جهان تا به امروز بوده است. طبق پیش بینی Gartner در 2014 سبک معماری وب گرای (مبتنی بر REST) در 80% سازمان هایی که سرویس گرایی را دنبال می‌کنند فراگیر خواهد شد. واقعا صحت یا عدم صحت تحقق این پیش بینی Gartner شاید مهم نباشد ؛ چرا که هر کسی می‌بایست WOA را بشناسد.
اما REST چیست ؟ Representational State Transfer سبکی از معماری نرم افزار برای سیستم‌های ابررسانه توزیع شده مانند شبکه جهانی وب است (منبع : ویکی پدیا). با هم اصول REST را مرور کنیم:
  • هر چیزی یک منبع است.
  • هر منبعی یک تمثیل دارد.
  • هر منبعی یک نام بخصوص دارد.
  • انتقال موقعیت نیازمند کشف و شهود (Discovery) است.
  • پروتکل شبکه پایه WOA می‌باشد

بطور خلاصه WOA را بررسی می‌کنیم :
  • اطلاعات در قالب منابع (Resources) نمایش می‌یابند.
  • منابع توسط URI‌ها شناخته می‌شوند.
  • منابع از طریق HTTP اداره می‌شوند.
  • معاهدات به صورت ضمنی در نمایش منابع می‌باشند.
  • رابط‌ها بطور کلی عام هستند.

معماری وب گرای سازمانی
معماری وب گرای سازمانی یا Enterprise Web Oriented Architecture (EWOA) یکی از زیر سبک‌های SOA می‌باشد. EWOA مجموعه ای از عناصر، اصول و فرآیندهای معماری مبتنی بر وب می‌باشد. وب سایت‌ها و برنامه‌های کاربردی جدید مانند Google AdSense, Wikipedia و دیگر سرویس‌های RESTful از WOA استفاده می‌کنند.
مثال حال حاضر WOA را می‌توان Google’s Open Social  یا MindTouch دانست. در حال حاضر Mobile API بنایی اساسی بر تمرکز در استفاده از تکنولوژی WOA را دارند. ساخت چنین سرویس هایی با استفاده از پروتکل‌های ساده شده وب نظیر Rest , JSON بیش از پیش آسان شده است. این پروتکل‌ها برای توسعه دهندگان وب بسیار راحت‌تر است چرا که CPU و پهنای باند کمتری را طلب می‌کنند. این پروتکل‌ها بیشتر بخاطر شبکه‌های اجتماعی بزرگ نظیر فیس بوک ، آمازون ، توییتر و … شناخته شده‌اند.
MindTouch هم یک شرکت اوپن سورس و یک سکوی مستندسازی استراتژیک و نوعی جدید از ECM می‌باشد. از جمله پروژه‌هایی که ارایه کرده‌است می‌توان به موارد ذیل اشاره کرد :
DReAM
SGML Reader
MindTouch Core/2010
در ادامه، بکارگیری REST را در قالب شبکه جهانی وب (W3) در قالب جدول زیر با دیدگاه مقایسه‌ای با تلفیق در وب بررسی می‌کنیم:
{بنده می‌گویم} REST بدون WWW بی معناست. REST با Web است که تکمیل می‌شود و معنا پیدا می‌کند.

بررسی مزایای WOA
  • ساده سازی توسعه پذیری، مقیاس پذیری
  • کاهش زمان توسعه ویژگی‌های جدید
  • کاهش زمان مهندسی مورد نیاز برای یکپارچه سازی
  • سازنده فرصت‌هایی جدید برای mash-ups و دیگر داستان‌های غیرقابل پیش بینی کاربری
  • اما وضعیت ارتباطی کلاینت‌ها و سرورها در WOA چگونه است ؟
  • سرویس‌ها وابسته به دیگر سرویس‌ها هستند.
  • ارتباطات از طریق HTTP صورت می‌گیرد.
  • کلاینت‌ها حکم منبع و سرویس دهی به دیگر کلاینت‌ها را دارند.
  • مقیاس پذیری ، توسعه پذیری == اتصالات داخی 


بعنوان مثال می‌توان با ترکیب تصاویر و آدرس‌های مختلف دانشگاه‌های تهران، یک map Mashup درست کرد.


برای Photo Mashup ابزار Color Picker هم هست که امکان جستجوی تصاویر را بر اساس رنگ فراهم می‌کند و از سرویس اشتراک گذاری عکس Flickr استفاده می‌کند که در این آدرس قابل استفاده است.


معماری Mashup هم مثل معماری MVC (البته با تفاوت‌های فاحش) سه لایه‌ای است :


لایه نمایش / تعامل کاربر (همان رابط کاربری است)

تکنولوژی‌ها : HTML/XHTML, CSS, Javascript, Asynchronous JS and Xml (Ajax).

وب سرویس‌ها : عملکرد محصول از طریق سرویس‌های API هم قابل دسترسی است

تکنولوژی‌ها : XMLHTTPRequest, XML-RPC, JSON-RPC, SOAP, REST

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

تکنولوژی‌ها : XML , JSON , KML

از نظر معماری  Mashup  دارای 2 سبک است : الف) مبتنی بر وب – ب) مبتنی بر سرور


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


شاید برای شما سوال پیش بیاید که ما در معماری وب گرا بحث می‌کردیم، اصلا چرا وارد مفهوم Mashup شدیم؟


به‌عبارت فنی‌تر چرا معماری وب گرا (WOA) برای Mashups اهمیت دارد ؟

 پاسخ یک کلمه است : REST . همانطور که بالاتر نیز اشاره کردم، Mashup از REST بهره می‌برد. به منظور افزایش اطلاعات در رابطه با REST باید گفت Roy Fielding آنرا بنیان نهاده‌است. میخواهید او را بهتر معرفی کنم؟ وی یکی از خالقان HTTP است و مگر می‌توان وب را بدون HTTP فرض کرد که مهمترین پروتکل انتقال ابر متن در جهان و پروتکل زیربنایی وب است؟! 

REST به خوبی با معماری اینترنت عجین شده است! بپرسید چرا؟ چون پروتکل اصلی اینترنت HTTP است و هر دوی این‌ها از یک ذهن نشات گرفته و او کسی نیست جز Roy Fielding. اما باید بگویم REST یک استاندارد نیست؛ با وجود سادگی بسیار زیاد، تنها یک سبک استفاده از HTTP است.


REST همچنین از متدهای اختصاصی HTTP نظیر GET, PUT , POST , DELETE در بالای یک URL استفاده می‌کند تا نشان دهد چه رویدادی رخ می‌دهد.


در پایان گفته‌ها در رابطه با REST باید بگویم ATOM همان REST است. منظورم از ATOM ویرایشگر معروف متنی نیست که برای نوشتن کدهای برنامه نویسی استفاده قرار می‌گیرد؛ آنرا غالبا به شکل Atom می‌نویسند چرا که مخفف چند کلمه نیست و یک کلمه خاص است  اما ATOM یک استاندارد وب به زبان XML است که برای خوراک وب بعنوان جایگزینی برای RSS استفاده می‌شود. ATOM را با AtomPub یا APP اشتباه نگیرید؛ چرا که APP پروتکل انتشاری است مبتنی بر پروتکل انتقال ابرمتن (HTTP) و برای به روزرسانی محتوی وب مورد استفاده قرار می‌گیرد.


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

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


HTTP + URIs = Web


ظرافت فرمول بالا به اهمیت پروتکل زیربنایی وب یعنی HTTP اشاره دارد. URI هم مجموعه‌ای از رشته‌هاست که برای شناسایی یک منبع خاص تحت وب به کار می‌روند. در شکل زیر رابطه بین URI , URN , URL را بررسی می‌کنیم. URI تشکیل شده‌است از URL و URN .URL متد دسترسی به منبع را مشخص می‌کند، در حالیکه URN تنها مشخص کننده نام منبع می‌باشد و هیچگونه روشی را برای دسترسی به ما ارائه نمی‌دهد. بعنوان مثال یک شماره ISBN کتاب، یک نوع URN است. 





مطالب
ایجاد لینک با یک تصویر بوسیله Html Helper
با Html Helper ما میتوانیم لینک‌های متن دار را ایجاد نماییم. شاید گاهی پیش آید که بجای لینک‌های متنی، از تصویر بجای لینک بخواهید استفاده نمایید. می‌توان هر زمانی، لینکی را که حاوی یک تصویر باشد، ایجاد کنید. اما با Asp.net MVC یکی از راه‌های مناسب برای انجام این کار استفاده از Extension methods است که از تکرار کد نویسی نیز جلو گیری می‌نماید.
همان طور که در کد زیر مشاهد می‌نمایید، این کد تشکیل شده است از نوشته لینک و نام اکشن متد و نام کنترلر آن، همراه با آی دی و تعریف css. کاری که قرار است صورت گیرد همانند ActionLink می‌باشد، با این تفاوت که تصویری هم به لینک ما اضافه خواهد شد:
 @Html.ActionLink("Text to display", "ActionNameHere", "ControllerNameHere", new { id = 123 }, new{@class="myClass"})
برای نوشتن این متد جهت تولید لینک‌هایی به همراه تصویر، از کد‌های زیر استفاده می‌کنیم:
public MvcHtmlString ActionImage(this HtmlHelper htmlHelper,
   string controller,
   string action,
   object routeValues,
   string imagePath,
   string alternateText = "",
   object htmlAttributes = null)
{
  var anchorBuilder = new TagBuilder("a");
  var url = new UrlHelper(HtmlHelper.ViewContext.RequestContext);
  anchorBuilder.MergeAttribute("href",url.Action(action,controller,routeValues));
  var imgBuilder = new TagBuilder("img");
  imgBuilder.MergeAttribute("src", url.Content(imagePath));
  imgBuilder.MergeAttribute("alt", alternateText);
  var attributes = (IDictionary<string, object>) HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
  imgBuilder.MergeAttributes(attributes);
  string imgHtml = imgBuilder.ToString(TagRenderMode.SelfClosing);
  anchorBuilder.InnerHtml = imgHtml;
  return MvcHtmlString.Create(anchorBuilder.ToString());
}
اولین پارامتر اجازه گسترش HtmlHelper را می‌دهد و توسط آن می‌توان متد‌های جدید خود را با کلمه کلیدی @Html شروع کنید.
4 پارامتر بعدی، پارامترهای ضروری هستند. یکی  controller، پس از آن Action  routeValues و سپس آدرس تصویر است. در نهایت، ما می‌توانیم در صورت نیاز متن جایگزین و ویژگی‌های اضافی متنی را نیز مشخص نماییم.
 در رابطه با توضیحات مربوط به بدنه متد: ابتدا لینک‌ها را ایجاد خواهد کرد با استفاده از RequestContext و UrlHelper. سپس بخش ساخت تصویر و اضافه کردن آن به لینک است. برای استفاده از میتوان از کد زیر استفاده نمود:
 @Html.ActionImage("Workout", "Delete", new { id = @workout.Id }, "/images/bluetrash.png", "Delete", new { id="deletebutton"})

در شکل بالا خروجی HTML تولید شده را  مشاهد می‌نمایید.
مطالب
بهبود کارآیی برنامه‌های قدیمی که از SQL Server استفاده می‌کنند
برنامه‌های قدیمی، الزاما خیلی قدیمی هم نیستند؛ برنامه‌هایی هستند پر از کوئری‌های ذیل:
 SELECT * FROM table1 WHERE OrderDate ='12 Mar 2004'

SET @SQL = 'SELECT * FROM table2 WHERE OrderDate = ' + '''' + @Var + ''''
EXEC (@SQL)
ویژگی مهم این نوع کوئری‌ها که با جمع زدن رشته‌ها و یا مقدار دهی مستقیم فیلدها تشکیل شده‌اند، «غیر پارامتری» بودن آ‌ن‌ها است.
این نوع مشکلات با بکار گیری ORMها به نحو قابل توجهی کاهش یافته‌است؛ زیرا این نوع واسط‌ها در اغلب موارد، در آخر کار کوئری‌هایی پارامتری را تولید می‌کنند.


مشکل کوئری‌های غیر پارامتری چیست؟

استفاده‌ی وسیع از کوئری‌های غیرپارامتری با SQL Server، مشکلی را پدید می‌آورد به نام «Cache bloat» یا «کش پُف کرده» و این «پُف» به این معنا است که کش کوئری‌های اجرا شده‌ی بر روی SQL Server بیش از اندازه با Query plan‌های مختلف حاصل از بررسی نحوه‌ی اجرای بهینه‌ی آن‌ها پر شده‌است. هر کوئری که به SQL Server می‌رسد، جهت اجرای بهینه، ابتدا پردازش می‌شود و دستور العملی خاص آن، تهیه و سپس در حافظه کش می‌شود. وجود این کش به این خاطر است که SQL Server هربار به ازای هر کوئری رسیده، این عملیات پردازشی را تکرار نکند. مشکل از زمانی شروع می‌شود که SQL Server کوئری‌هایی را که از نظر یک برنامه نویس مانند هم هستند را به علت عدم استفاده‌ی از پارامترها، یکسان تشخیص نداده و برای هر کدام یک Plan جداگانه را محاسبه و کش می‌کند. این مساله با حجم بالای کوئری‌های رسیده دو مشکل را ایجاد می‌کند:
الف) مصرف حافظه‌ی بالای SQL Server که گاهی اوقات این حافظه‌ی اختصاص داده شده‌ی به کش کوئری‌ها به بالای یک گیگابایت نیز می‌رسد.
ب) CPU Usage بالای سیستم


سیستم قدیمی است؛ امکان تغییر کدها را نداریم.

بدیهی است بهترین راه حلی که در اینجا وجود دارد، پارامتری ارسال کردن کوئری‌ها به SQL Server است تا به ازای هر تغییری در مقادیر آن‌ها، این کوئری‌ها باز هم یکسان به نظر برسند و SQL Server سعی در محاسبه‌ی مجدد Plan آن‌ها نکند. اما ... اگر این امکان را ندارید، خود SQL Server یک چنین قابلیت‌هایی را به صورت توکار تدارک دیده‌است که باید فعال شوند.


فعال سازی پارامتری کردن خودکار کوئری‌ها در SQL Server

اگر نمی‌توانید کدهای یک سیستم قدیمی را تغییر دهید، SQL Server می‌تواند به صورت خودکار این‌کار را برای شما انجام دهد. در این حالت فقط کافی است یکی از دو دستور ذیل را اجرا کنید:
  --Forced
ALTER DATABASE dbName SET PARAMETERIZATION FORCED

--Simple
ALTER DATABASE dbName SET PARAMETERIZATION SIMPLE
حالت simple بیشتر جهت پارامتری کردن خودکار کوئری‌های select بکار می‌رود. اگر می‌خواهید تمام کوئری‌های select, insert, update و delete را نیز پارامتری کنید، باید از حالت forced استفاده نمائید.



فعال سازی بهبود کارآیی SQL Server با کوئری‌های Ad-Hoc زیاد

به کوئری‌های غیرپارامتری، کوئری‌های Ad-Hoc نیز گفته می‌شود. اگر سیستم فعلی شما، تعداد زیادی کوئری Ad-Hoc تولید می‌کند، می‌توان فشار کاری SQL Server را برای این مورد خاص، تنظیم و بهینه سازی کرد.
فعال سازی گزینه‌ی ویژه‌ی «Optimize for Ad hoc Workloads» سبب می‌شود تا SQL Server پس از مدتی به صورت خودکار کش Plan کوئری‌هایی را که به ندرت استفاده می‌شوند، حذف کند. همین مساله سبب آزاد شدن حافظه و بهبود کارآیی کلی سیستم می‌گردد. همچنین باید درنظر داشت که کش Plan کوئری‌ها نامحدود نیست و سقفی دارد. به همین جهت آزاد شدن آن، کش کردن کوئری‌هایی را که بیشتر استفاده می‌شوند، ساده‌تر می‌کند.
برای اعمال آن به یک بانک اطلاعاتی خاص، نیاز است دستورات ذیل را اجرا کرد:
 use dbName;
-- Optimizing for Ad hoc Workloads
exec sp_configure 'show advanced options',1;
RECONFIGURE;
go
exec sp_configure 'optimize for ad hoc workloads',1;
RECONFIGURE;
Go


برای مطالعه‌ی بیشتر
Fixing Cache Bloat Problems With Guide Plans and Forced Parameterization
Optimizing ad-hoc workloads
Optimizing for Ad hoc Workloads
مطالب
تغییرات دسترسی به کدها در دات نت 4

دو پروژه‌ی سورس باز XML RPC و Log4Net برای اجرا شدن در برنامه‌های دات نت 4 نیاز به اندکی تغییر در هر دو برنامه‌ی فراخوان و اسمبلی‌های آن‌ها دارند که در ادامه توضیحات مربوطه ارائه خواهند شد.

اگر یک پروژه‌ی جدید دات نت 4 را آغاز کنید و سپس ارجاعی را به یکی از اسمبلی‌های ذکر شده اضافه نمائید، اولین خطایی را که حین استفاده مشاهده خواهید نمود، مورد زیر است:
Could not resolve assembly "System.Web".
The assembly is not in the currently targeted framework ".NETFramework,Version=v4.0,Profile=Client".
Please remove references to assemblies not in the targeted framework or consider retargeting your project.
علت هم اینجا است که در تنظیمات پروژه‌ها‌ی جدید مبتنی بر دات نت 4، پیش فرض Target framework انتخابی توسط VS.NET 2010 از نوع Client profile است؛ که صرفا جهت کاهش حجم دات نت فریم ورک مورد نیاز این نوع برنامه‌ها طراحی شده است. در این پروفایل ساده شده، اسمبلی System.Web وجود ندارد. بنابراین جهت استفاده از کتابخانه‌های XML RPC و یا Log4Net نیاز است تا در خواص پروژه، Target framework را بر روی دات نت فریم ورک 4 کامل قرار داد تا خطای فوق برطرف شود.

خطای دومی که حین کار با کتابخانه‌های XML RPC و یا Log4Net در یک برنامه‌ی دات نت 4 حتما با آن مواجه خواهید شد در ادامه ذکر گردیده است:
Inheritance security rules violated while overriding member:
GetObjectData(System.Runtime.Serialization.SerializationInfo, System.Runtime.Serialization.StreamingContext),
Security accessibility of the overriding method must match the security accessibility of the method being overriden.
متد ISerializable.GetObjectData با ویژگی SecurityCritical در دات نت فریم ورک مزین شده است. با تغییرات امنیتی صورت گرفته در دات نت 4، متدی که این متد را تحریف می‌کند نیز باید با همان سطح دسترسی متد virtual اصلی معرفی گردد و گرنه برنامه اجرا نخواهد شد. البته این مشکل ما نیست؛ مشکل سازندگان کتابخانه‌های ذکر شده است! ولی خوب تا این لحظه برای مثال کتابخانه XML RPC برای دات نت 4 به روز نشده است ولی سورس کامل آن در دسترس است.
برای رفع این مشکل ابتدا سورس این کتابخانه‌ها را دریافت کرده و سپس در فایل AssemblyInfo.cs آن‌ها یک سطر زیر را حذف نموده و پروژه را مجددا کامپایل کنید:
[assembly: AllowPartiallyTrustedCallers]
علت وجود این ویژگی‌ در کتابخانه‌های ذکر شده این است که بتوان از آن‌ها در محیط‌های اصطلاحا partially trusted (برای مثال هر برنامه‌ای که در internet zone یا intranet zone اجرا می‌شود) استفاده کرد. در دات نت 4 با تغییرات انجام شده معنای AllowPartiallyTrustedCallers به security-transparency تغییر کرده است. بنابراین با قید آن یا باید هر جایی که متد GetObjectData ذکر شده در این کتابخانه‌ها تحریف می‌شود، ویژگی SecurityCritical را صریحا اعمال کرد یا اینکه می‌توان AllowPartiallyTrustedCallers را حذف کرده و وظیفه‌ی انجام آن‌را به CLR محول نمود.


برای مطالعه بیشتر:
Using Libraries from Partially Trusted Code
Security Changes in the .NET Framework 4
TypeLoadException based on Security-Transparent Code, Level 2
Making log4net run on .NET 4.0

نظرات مطالب
کتابخانه‌ی انواع و اقسام مدل‌های داده‌ای
سلام
بله. این سایت واقعا مفید است. خیلی ایده می‌شود از آن استخراج کرد.
و یک سری سایت هستند که به صورت تخصصی کار UI انجام می‌دن. برای مثال:
http://www.uxbooth.com/view/blog/
که چندی قبل در مورد آینده رابط‌های کاربری یک سری مطلب جالب منتشر کرده بود:
http://www.uxbooth.com/blog/the-future-of-interface-design/
نظرات نظرسنجی‌ها
در محیط کاری از کدام سورس کنترل استفاده می‌کنید؟
- عموما در محیط کاری برای مدیریت یک تیم، یک سورس کنترلر مرجع بیشتر استفاده نمی‌شود. بنابراین نیازی به چک باکس نیست و عنوان هم این نبوده که در طول روز به چند سورس کنترلر در سراسر دنیا مراجعه می‌کنید.
مطالب
کنترل دسترسی‌ها در Angular با استفاده از Ng2Permission
سناریویی را در نظر بگیرید که در آن بعد از احراز هویت کاربر، لیست دسترسی‌هایی را که کاربر به بخش‌های مختلف خواهد داشت، از سرور دریافت می‌کند. به عنوان مثال کل دسترسی‌های موجود در سیستم به شرح زیر است:
  1. ViewUsers 
  2. CreateUser 
  3. EditUser 
  4. DeleteUser 
حالا فرض کنید، کاربر X بعد از احراز هویت، از لیست دسترسی‌های موجود، تنها دسترسی ViewUsers و EditUser را دریافت می‌کند. یعنی تنها مجاز به مشاهده‌ی لیست کاربران و ویرایش کردن آنها می‌باشد.
در اینجا جهت جلوگیری از دسترسی به ویرایش کاربر، با استفاده از یک Router guard سفارشی می‌توان مسیر users/edit را برای کاربر غیر قابل استفاده کرد؛ به نحوی که اگر کاربر وارد شده مجوز EditUser را نداشت، این مسیر غیر قابل دسترسی باشد. 
از طرفی صفحه‌ی ViewUsers، برای کاربری با تمامی دسترسی‌ها، به شکل زیر خواهد بود: 


همانطور که مشاهده می‌کنید، المنت‌هایی در صفحه وجود دارند که کاربر X نباید آنها را مشاهده کند. از جمله دکمه حذف کاربر و دکمه ایجاد کاربر. برای مخفی کردن آنها چه راه‌حلی را می‌توان ارائه داد؟ شاید بخواهید برای اینکار از ngIf* استفاده کنید. برای اینکار کافی است دست بکار شوید تا مشکلاتی را که در این روش به آنها بر می‌خورید، متوجه شوید. از جمله این مشکلات می‌توان به پیچیدگی بسیار زیاد و وجود کدهای تکراری در هر کامپوننت اشاره کرد (در بهترین حالت هر کامپوننت باید سرویس حاوی دسترسی‌ها را در خود تزریق کرده و با استفاده از توابعی، وجود یا عدم وجود دسترسی را بررسی کند). 

راه‌حل بهتر، استفاده از یک Directive سفارشی است. همچنین ماژول  Ng2Permission  علاوه بر فراهم کردن Directive جهت مدیریت المنت‌های روی صفحه، امکاناتی را جهت نگهداری و تعریف دسترسی‌های جدید و همچنین محافظت از Routeها فراهم کرده است. این ماژول الهام گرفته از ماژول  angular-permission می‌باشد.

کافی است با استفاده از دستور زیر این ماژول را نصب کنید: 

npm install angular2-permission --save

بعد از نصب، ماژول Ng2Permission را در قسمت imports در ماژول اصلی برنامه، اضافه کنید. 

import { Ng2Permission } from 'angular2-permission';
@NgModule({
  imports: [
    Ng2Permission
  ]
})


مدیریت دسترسی‌ها

 برای مدیریت دسترسی‌های کاربر، از سرویس PermissionService، در هرجایی از برنامه می‌توانید استفاده کنید. این سرویس دارای متدهای زیر است.:
توضیحات  امضاء 
 تعریف دسترسی‌های جدید   define(permissions: Array<string>): void
 افزودن دسترسی جدید   add(permission: string ) : void 
 حذف دسترسی مشخص شده   remove(permission: string ) : void 
 برسی اینکه دسترسی قبلا تعریف شده است؟   hasDefined( permission : string ) : boolean 
 برسی اینکه حداقل یکی از دسترسی‌های ورودی قبلا تعریف شده است؟   hasOneDefined(permissions: Array < string > ) : boolean 
 حذف تمامی دسترسی‌ها   clearStore( ) : void 
 دریافت تمامی دسترسی‌های تعریف شده   get store ( ) : Array < string>
 Emitter جهت تغییر در دسترسی‌ها  get permissionStoreChangeEmitter ( ) : EventEmitter< an y>

برای مثال جهت تعریف دسترسی‌های جدید، کافی است سرویس PermissionService را تزریق کرده و با استفاده از متدهای define اقدام به اینکار کنید: 

import { PermissionService } from 'angular2-permission';
@Component({
    […]
})
export class LoginComponent implements OnInit {
    constructor(private _permissionService: PermissionService) { 
        this._permissionService.define(['ViewUsers', 'CreateUser', 'EditUser', 'DeleteUser']);
    }
}

آنچه که واضح است، این است که لیست دسترسی‌ها می‌توانند از سمت سرور تامین شوند.

 

محافظت از مسیرهای تعریف شده

 بعد از تعریف دسترسی‌ها، برای محافظت از مسیر‌های غیر مجاز برای کاربر می‌توانید از PermissionGuard به شکل زیر استفاده کنید: 
import { PermissionGuard, IPermissionGuardModel } from 'angular2-permission';
[…]
const routes: Routes = [
    {
        path: 'login',
        component: LoginComponent,
        children: []
    },
    {
        path: 'users',
        component: UserListComponent,
        canActivate: [PermissionGuard],
        data: {
            Permission: {
                Only: ['ViewUsers'],
                RedirectTo: '403'
            } as IPermissionGuardModel
        },
        children: []
    },
    {
        path: 'users/create',
        component: UserCreateComponent,
        canActivate: [PermissionGuard],
        data: {
            Permission: {
                Only: ['CreateUser'],
                RedirectTo: '403'
            } as IPermissionGuardModel
        },
        children: []
    },
    {
        path: '403',
        component: AccessDeniedComponent,
        children: []
    }
];

@NgModule({
    imports: [RouterModule.forRoot(routes)],
    exports: [RouterModule]
})
export class AppRoutingModule { }
همانطور که مشاهده می‌کنید کافی است canActivate در هر Route را به PermissionGuard تنظیم کنید. همچنین در data از طریق کلید Permission، تنظیمات این Guard را مشخص کنید. کلید Permission در data یک شیء از نوع IPermissionGuardModel را دریافت خواهد کرد که حاوی خصوصیات زیر است:
 
توضیحات     خصوصیت 
 فقط دسترسی‌های تعریف شده در این قسمت، امکان پیمایش به این مسیر را خواهند داشت.   Only 
 تمامی دسترسی‌های تعریف شده، به جز دسترسی‌های تعریف شده در این قسمت، امکان پیمایش به این مسیر را خواهند داشت.   Except 
 در صورتیکه تقاضای غیر مجازی جهت پیمایش به این مسیر صادر شد، کاربر را به این مسیر هدایت می‌کند.   RedirectTo 

نکته ۱: مقدار دهی همزمان Only و Except مجاز نیست.
نکته ۲: ذکر چند دسترسی در هر یک از خصوصیت‌های Only و Except معنی «یا منطقی» دارد. مثلا در قطعه کد زیر، اگر دسترسی Admin باشد «یا» دسترسی CreateUser باشد امکان مشاهده پیمایش صفحه وجود خواهد داشت. 
{
    path: 'users/create',
    component: UserCreateComponent,
    canActivate: [PermissionGuard],
    data: {
        Permission: {
            Only: ['Admin', 'CreateUser'],
            RedirectTo: '403'
        } as IPermissionGuardModel
    },
    children: []
}

محافظت از المنت‌های صفحه

 جهت محافظت از المنت‌های موجود در صفحه، ماژول Ng2Permission دایرکتیوهایی را برای این منظور تدارک دیده است: 
 توضیحات  Input type     Directive 
 فقط دسترسی‌های تعریف شده در این دایرکتیو امکان مشاهده (به صورت پیش فرض) المنت را دارند.   Arrayy<string>   hasPermission 
 تمامی دسترسی‌های موجود، به جز دسترسی‌های تعریف شده در این دایرکتیو امکان مشاهده (به صورت پیش فرض) المنت را دارند.   Array<string>   exceptPermission
 استراتژی برخورد با المنت، هنگامیکه کاربر دسترسی به المنت دارد.   string | Function   onAuthorizedPermission 
 استراتژی برخورد با المنت، هنگامیکه کاربر دسترسی به المنت را ندارد.  string | Function 
 onUnauthorizedPermission 

در مثال زیر فقط کاربرانی که دسترسی DeleteUser را داشته باشند، امکان مشاهده دکمه حذف را خواهند داشت.
<button type="button" [hasPermission]="['DeleteUser']">
  <span aria-hidden="true"></span>
  Delete
</button>

در صورتیکه بیش از یک دسترسی مد نظر باشد، با کاما از هم جدا خواهند شد.

<button type="button" [hasPermission]="[ 'Admin', 'DeleteUser']">
  <span aria-hidden="true"></span>
  Delete
</button>
در مثال بالا درصورتیکه کاربر دسترسی Admin « یا » دسترسی DeleteUser را داشته باشد، امکان مشاهده (به صورت پیش فرض) المنت را خواهد داشت. مثال زیر یعنی تمامی کاربران با هر دسترسی امکان مشاهده المنت را خواهند داشت؛ بجز دسترسی GeustUser. 
<button type="button" [exceptPermission]="['GeustUser']">
  <span aria-hidden="true"></span>
  Delete
</button>
به صورت پیش فرض هنگامیکه کاربری دسترسی به المنتی را نداشته باشد، دایرکتیو، این المنت را مخفی خواهد کرد (با تنظیم استایل display به none). شاید شما بخواهید بجای مخفی/نمایش المنت، مثلا از فعال/غیرفعال کردن المنت استفاده کنید. برای این کار از خصوصیت onAuthorizedPermission و onUnauthorizedPermission به شکل زیر استفاده کنید:
<button type="button" 
  [hasPermission]="['GeustUser']"
  onAuthorizedPermission="enable"
  onUnauthorizedPermission="disable">
  <span aria-hidden="true"></span>
  Delete
</button>
تمامی استراتژی‌های از قبل تعریف شده و قابل استفاده برای خصوصیت onAuthorizedPermission و onUnauthorizedPermission به شرح زیر است:
 رفتار   مقدار 
 حذف خصوصیت disabled از المنت   enable 
افزودن خصوصیت disabled به المنت     disable 
 تنظیم استایل display به inherit   show 
 تنظیم استایل display به none   hide 

در صورتیکه هیچ‌کدام از این استراتژی‌ها، پاسخگوی نیاز شما جهت برخورد با المنت نبود، می‌توانید بجای ارسال یک رشته ثابت به خصوصیت onAuthorizedPermission و onUnauthorizedPermission، یک تابع را ارسال کنید تا عملی که می‌خواهید، بر روی المنت انجام دهد. به عنوان مثال می‌خواهیم در صورتیکه کاربر مجاز به استفاده از المنتی نبود، المنت را از طریق تنظیم استایل visibility به hidden، مخفی کنیم و در صورتیکه کاربر مجاز به استفاده از المنت بود، استایل visibility به inherit تنظیم شود. 
با این فرض، کدهای کامپوننت به شکل زیر:
@Component({
    selector: 'app-user-list',
    templateUrl: './user-list.component.html',
    styleUrls: ['./user-list.component.css']
})
export class UserListComponent {

  constructor() { }

  OnAuthorizedPermission(element: ElementRef) {
    element.nativeElement.style.visibility ="inherit";
  }

  OnUnauthorizedPermission(element: ElementRef) {
    element.nativeElement.style.visibility = "hidden";    
  }
}
و تگهای Html زیر: 
<button 
  [hasPermission]="['CreateUser']"
  [onAuthorizedPermission]="OnAuthorizedPermission"
  [onUnauthorizedPermission]="OnUnauthorizedPermission">
  <span aria-hidden="true"></span>
  Add New User
</button>
نکته:  هر تغییر در لیست دسترسی‌ها در لحظه سبب اجرای دوباره دایرکتیوها خواهد شد و تغییرات، در همان لحظه در لایه نمایش قابل مشاهده خواهند بود. 
نظرات مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 1 - NET Core. چیست؟
نکته تکمیلی :

فناور‌هایی که به زودی به NET Core. منتقل می‌شوند


یکسری از فناوری‌ها مانند XAML هنوز معادل NET Core. ندارند و لیست زیر قرار است از طرف مایکروسافت سورس باز شده و همچنین به NET Core. منتقل شود:
System.Data
System.DirectoryServices
System.Drawing
System.Transactions
.
.
.

در حال حاضر می‌توانید با استفاده از بسته‌ی زیر نیاز خودتان را نسبت به گزینه Bold شده (
System.Drawing  )، برطرف کنید :

"CoreCompat.System.Drawing": "1.0.0-beta006"

بنده برای تولید Captcha موجود در این پست از بسته مذکور استفاده کردم و بدون مشکل نیاز را تامین کرده است.

جزییات کامل را در این مخزن دنبال کنید.
اشتراک‌ها
معرفی فریمورک متن باز رابط کاربری HandyControl برای WPF

یک سالی میشود که روی یک فریمورک رابط کاربری بصورت متن باز به اسم HandyControl مشارکت دارم، این فریمورک در درجه اول مخصوص برنامه نویس‌های چین طراحی شده بود اما با بازخوردهایی که دریافت کرد، جامعه انگلیسی زبان را هم پشتیبانی میکند. بدلیل اینکه هدف این فریمورک ارائه کنترل‌های ساده و بدور از پیچیدگی هست، Nabian با اضافه کردن کنترل‌های پیچیده مخالف هست. به همین دلیل تصمیم گرفتم تا شاخه جدایی از این پروژه را ایجاد کنم و کنترل‌ها و ویژگی‌های مختلفی که سازگار با برنامه نویس‌های ایرانی باشد را اضافه کنم. درحال حاضر تقویم شمسی، ساعت_تقویم شمسی، پشتیبانی از کد ملی، حروف فارسی در نوع ورودی TextBox ،استایل‌های جدید بارگذاری، کنترل BusyIndicator، کنترل سرعت شمار (SpeedoMeter) و چندین کلاس هلپر جهت کار با رجیستری، رمزنگاری و... را به پروژه اضافه کردم.(لیست ویژگی‌های اضافه شده را میتوانید از این قسمت مشاهده کنید) (جهت مشاهده کنترل‌ها و ویژگی‌های اضافه شده در نسخه شخصی سازی شده بعد از اجرای دمو از بخش Controls بخش PersianToolkit را انتخاب کنید)

صفحات پروژه اصلی===> سورس برنامه | صفحه ناگت | صفحه مارکت پلیس مستندات چینی | مستندات انگلیسی | مستندات ویکی

 اگر پیشنهادی برای اضافه کردن کدهای کاربردی یا کنترل‌های کاربردی دارید لطفا در نظرات اعلام کنید و یا اگر خودتان توانایی آن را دارید در گیتهاب PR ارسال کنید.
 

معرفی فریمورک متن باز رابط کاربری HandyControl برای WPF