using System.Collections.Generic;
using BLL = DotNetTipsBLLLayer;//نام مستعار برای فضای نام using EmployeeDomain = DotNetTipsBLLLayer.Employee;//نام مستعار برای یک نوع داده
using (var sqlConnection = new SqlConnection()) { //کد }
using static System.Console; using static System.Math; namespace dotnettipsUsingStatic { class Program { static void Main(string[] args) { Write(" *** Cal Area *** "); int r = int.Parse(ReadLine()); var result = Pow(r, 2) * PI; Write($"Area is : {result}"); ReadKey(); } } }
enum Gender { Male, Female }
تا قبل از سی شارپ 6 برای استفادهی از نوع داده شمارشی بدین شکل عمل میکردیم:
var gender = Gender.Male;
و اکنون بازنویسی استفادهی ازEnum به کمک ویژگی جدید static using statement :
در قسمت معرفی فضاهای نام بدین شکل عمل میکنیم:
using static dotnettipsUsingStatic.Gender;
و در برنامه کافیست مستقیما نام اعضای Enum را ذکر کنیم .
var gender = Male;//تخصیص نوع داده شمارشی WriteLine($"Employee Gender is : {Male}");//استفاده مستقیم از نوع داده شمارشی
استفاده از ویژگی using static و متدهای الحاقی :
تا قبل از ارائه سی شارپ 6 اگر نیاز به استفادهی از یک متد الحاقی خاص همچون where در فضای نام System.Linq.Enumeable داشتیم میبایستی فضای نام System.Linq را به طور کامل اضافه میکردیم و راهی برای اضافه کردن یک فضای نام خاص درون فضای نام بزرگتر وجود نداشت.
اما با قابلیت جدید اضافه شده میتوانیم بخشی از یک فضای نام را اضافه کنیم:
متدهای استاتیک و متدهای الحاقی در زمان استفاده از ویژگی using static:
فرض کنید کلاس static ای بنام MyStaticClass داشته باشیم که متد Print1 و Print2 در آن تعریف شده باشند:
public static class MyStaticClass { public static void Print1(string parameter) { WriteLine(parameter); } public static void Print2(this string parameter) { WriteLine(parameter); } }
برای استفاده از متدهای تعریف شده به شکل زیر عمل میکنیم :
//فراخوانی تابع استاتیک Print1("Print 1");//روش اول MyStaticClass.Print1("Prtint 1");//روش دوم //فراخوانی متد الحاقی استاتیک MyStaticClass.Print2("Print 2"); "print 2".Print2();
ویژگیهای جدید ارائه شده در سی شارپ 6 برای افزایش خوانایی برنامهها و تمیزتر شدن کدها اضافه شدهاند. در مورد ویژگیهای ارائه شده در مقالهی جاری این نکته مهم است که گاهی قید کردن نام کلاسها خود سبب افزایش خوانایی کدها میشود .
angular-translate دایرکتیو و فیلتر هایی را به صورت کامپوننت عرضه کرده است که شما میتوانید به وسیلهی آنها پروژه خود را به زبانهای گوناگون localize کنید. آنچه که در تصویر فوق مشاهده میکنید در حقیقت ساختار ماژول angular-translate را نمایش میدهد. به این صورت که در اولین لایه دایرکتیو translate قرار گرفته است.
سطح بعدی شاید کمی جذابتر به نظر برسد. هر دو بخش دایرکتیو و فیلتر از سرویس تزریق شده translate$ استفاده میکنند. این بدین معنی است که در هنگام تغییر یک زبان به زبان دیگر به وسیله دایرکتیوهایی که در view نوشته شده است، در حقیقت شما این دایرکتیوها را به سطح فیلتر انتقال دادهاید و پس از آن، فیلتر آن را به لایه سرویس برده و سرویس کار اصلی را انجام میدهد.
در سطح بعدی لایه Interpolator قرار گرفته است که وظیفه تغییر DOMها را بر عهده دارد. این فرآیند متغیرهایی را که در ریسورس قرار دادهایم، درایه به درایه در view و در مکانهای هم نام قرار میدهد. این فرآیند به وسیله راهکارهای گوناگونی از قبیل Message Format و یا Angular Core Interpolation Service امکان پذیر است.
جعبه خاکستری رنگ بخش missing translation handler را نشان میدهد. این handlerها زمانی فراخوانی میگردند که translator به دنبال یک key میگردد که تعریف نشده باشد. angular-translate خود شامل یک logging service میباشد که به صورت extension باید آن را به پروژه خود اضافه نمایید که در بخشهای بعدی در مورد آن مفصلتر بحث میکنیم.
بخش asynchronous loader شما را قادر میسازد که دادههای زبانهای متفاوت را به صورت غیر هم زمان بارگذاری نمایید. angular-translate از ماژولهای asynchronous loader پشتیبانی میکند. روش معرفی شده در سایت مرجع در مورد بارگذاری غیر همزمان urlLoader و staticFilesLoader هستند که در بخشهای بعدی به آن خواهیم پرداخت.
angular-translate برای ذخیره سازی دادههای بازگذاری شده و نگه داشتن زبان سایت در صورت reload شدن صفحه راهکارهای متفاوتی را ارائه نموده است. این قابلیت در ابتدا چک میکند که ریسورسهای زبان درون یک local storage قرار گرفتهاند یا خیر. این عملیات طی یک فرآیند جستجوی key-value صورت میگیرد و در نهایت فایلهای ریسورس زبان مورد نظر که درون کوکی یا localStorage ذخیره شدهاند بارگذاری میشوند. angular-translate به صورت توکار دارای دو راهکار localStorage و cookieStorage برای ذخیره سازی ریسورسها میباشد.
در بخش بعدی در مورد نحوهی ذخیره سازی دادهها به دو روش cookieStorage و localStorage بیشتر صحبت خواهیم کرد.
گریس مانکی یکی از افزونههای فایرفاکس است که توسط آن میتوان اسکریپتهایی را بر روی صفحات وب در حال مشاهده، جهت تغییر آنها اجرا کرد. این نوع تغییرات بیشتر در جهت بالا بردن کارآیی یا خوانایی سایتها صورت میگیرد. مثلا بررسی وجود لینکهای ارائه شده در یک صفحه وب (قبل از اینکه به آنها رجوع کنیم، مشخص شود که آیا وجود دارند یا خیر) و هزاران مثال شبیه به این که در سایت اسکریپتهای آن قابل دریافت هستند.
گریس مانکی به خودی خود کار خاصی را انجام نمیدهد و فقط میزبان اجرایی اسکریپتهایی است که برای آن تهیه شده اند. به این اسکریپتها user scripts گفته میشود و جهت تهیه آنها از زبان جاوا اسکریپت استفاده میگردد.
مطابق اصول نامگذاری آن، فایل این اسکریپتها حتما باید به .user.js ختم شود تا توسط افزونه گریس مانکی قابل شناسایی باشد.
اسکریپت سلام دنیای گریس مانکی!
// ==UserScript==
// @name Hello World
// @namespace http://diveintogreasemonkey.org/download/
// @description example script to alert "Hello world!" on every page
// @include *
// @exclude http://diveintogreasemonkey.org/*
// @exclude http://www.diveintogreasemonkey.org/*
// ==/UserScript==
alert('Hello world!');
در پایان مثلا نام آنرا hello.user.js خواهیم گذاشت (همانطور که ذکر شد قسمت user.js آن باید رعایت شود). برای نصب آن فقط کافی است این فایل را به درون پنجره فایر فاکس کشیده و رها کنیم (drag & drop).
استفاده از jQuery در اسکریپتهای گریس مانکی
عمده کاربردهای اسکریپتهای گریس مانکی در جهت اعمال تغییرات بر روی document object model صفحه (DOM) هستند. کتابخانه jQuery اساسا برای این منظور تهیه و بهینه سازی شده است.
مثال:
فرض کنید قصد داریم به نتایج خروجی جستجوی گوگل، fav icon سایتهای یافت شده را اضافه کنیم (در کنار هر لینک، آیکون سایت مربوطه را نمایش دهیم). گوگل اینکار را انجام نداده است. اما ما علاقمند هستیم که این قابلیت را اضافه کنیم!
// ==UserScript==
// @name Google FavIcon
// @namespace http://userscripts.org
// @description Shows favicon for Google searches results
// @include http://*.google.*/search?*
// ==/UserScript==
loadJquery();
$(document).ready(function(){
$("h3.r > a.l").each(function(){
var $a = $(this);
var href = $a.attr("href");
var domain = href.replace(/<\S[^><]*>/g, "").split('/')[2];
var image = '<img src="http://' + domain + '/favicon.ico" style="border:0;padding-right:4px;" />';
//GM_log(">image:> " + image);
$(this).prepend(image);
});
});
دریافت سورس این مثال
در اینجا ابتدا لینکهای حاصل از جستجو پیدا میشوند. سپس نام دومین مربوطه استخراج میگردد (با استفاده از regular expressions) و در ادامه از این نام دومین یک آدرس استاندارد http://domain/favico.ico ساخته شده و از آن یک تگ img درست میشود. در آخر این تگ به قبل از لینکهای گوگل اضافه میشود.
شاید سؤال بپرسید از کجا مشخص شد که باید به دنبال h3.r > a.l گشت؟ به تصویر زیر دقت نمائید (نمایی است از یکی از تواناییهای افزونه fireBug فایرفاکس).
هنگامیکه صفحه بارگذاری شد، بر روی آیکون سوسک موجود در status bar فایرفاکس کلیک کنید تا FireBug ظاهر شود (البته من اینجا سوسک دیدم شاید موجود دیگری باشد :) )
سپس بر روی دکمه inspect در نوار ابزار آن کلیک کنید. در همین حال اشارهگر ماوس را به یکی از لینکهای نتیجه جستجوی گوگل نزدیک کنید. بلافاصله تگها و کلاسهای مورد استفاده آن به شکل زیبایی ظاهر خواهند شد. به این صورت صرفه جویی قابل ملاحظهای در وقت صورت خواهد گرفت.
نتیجه اجرای اسکریپت فوق (پس از نصب) به صورت زیر است:
نکته: نحوه دیباگ کردن اسکریپتهای گریس مانکی
اگر نیاز به مشاهده مقدار متغیرها در لحظه اجرای اسکریپت داشتید، یکی از راهحلهای موجود استفاده از تابع GM_log مربوط به API گریس مانکی است که خروجی آنرا در قسمت messages مربوط به error console فایرفاکس میتوان دید.
برای تولید چنین نموداری از میتوانیم Mermaid استفاده کنیم. یکی از انواع دیاگرامهایی را که پشتیبانی میکند، Gitgraph میباشد. دیاگرامها در Mermaid با کمک یک DSL ساخته میشوند. سینکس آن نیز خیلی ساده است؛ ابتدا نوع دیاگرامی را که میخواهیم ترسیم کنیم، تعیین میکنیم و سپس محتویات را براساس نوع دیاگرام، تعیین میکنیم. به عنوان مثال برای Gitgraph سینتکس آن به این صورت است:
gitGraph commit commit branch develop checkout develop commit commit checkout main merge develop commit commit
در ساختار فوق ابتدا دو کامیت بر روی برنچ اصلی (main) انجام شدهاست؛ سپس یک برنچ جدید را با نام develop، ایجاده کردهایم و بلافاصله به آن checkout کردهایم. در ادامه تعدادی کامیت را بر روی این برنچ انجام داده و در نهایت برنچ موردنظر را بر روی main، مرج کردهایم. در نهایت نیز دو کامیت دیگر را بر روی main ایجاد کردهایم. تعریف فوق، منجر به ساخت چنین نموداری خواهد شد:
از ادیتور آنلاین Mermaid نیز میتوانید برای تست سینکس استفاده کنید. در ادامه میخواهیم با کمک PowerShell، از روی یک پروژهی گیت، DSL موردنیاز برای ساخت دیاگرام را ایجاد کنیم. برای اینکار ابتدا توسط تابع زیر یک پروژهی گیت را با تعدادی فایل نمونه ایجاد خواهیم کرد:
Function New-RandomRepo { Function RandomFiles($branch = "main") { 1..3 | ForEach-Object { New-Item -ItemType File -Name "file_$($_).txt" Set-Content -Path "file_$($_).txt" -Value "This is file $($_) on branch $branch" git add . git commit -m "Commit $($_) on branch $branch" } } Set-Location ~/Desktop New-Item -ItemType Directory "random_git_repo" Set-Location "random_git_repo" git init -b main Write-Output "This is the main branch" | Set-Content -Path "main.txt" git add . git commit -m "Initial commit" 1..3 | ForEach-Object { git checkout -b "branch_$($_)" RandomFiles "branch_$($_)" git checkout main } }
در ادامه تابع New-GitRepoDiagram را برای تولید ساختار مورد نیاز نوشتهایم:
Function New-GitRepoDiagram { $commitIds = @() $branches = git branch | ForEach-Object { $default = $false $activeBranch = git symbolic-ref --short HEAD $currentBranch = ($_.Replace("* ", " ")).Trim() if ($currentBranch -eq $activeBranch) { $default = $true } @{ name = $currentBranch isMainBranch = $default } | ConvertTo-Json } | ConvertFrom-Json $defaultBranch = $branches | Where-Object { $_.isMainBranch -eq $true } | Select-Object -ExpandProperty name $mermaidFile = "%%{init: { 'gitGraph': {'mainBranchName': '$defaultBranch' } } }%%" + [Environment]::NewLine $mermaidFile += 'gitGraph' + [Environment]::NewLine foreach ($branch in ($branches | Sort-Object -Property isMainBranch -Descending)) { $name = $branch.name $notIncludeTheMainCommits = $name -ne $defaultBranch ? "--not $(git merge-base $defaultBranch $name)" : "" $notIncludeTheMainCommits $logs = git log --pretty=format:'{"commit": "%h", "author": "%an", "message": "%s"}' --reverse $name | ConvertFrom-Json if ($name -ne $defaultBranch) { $mermaidFile += ' branch "$name"'.Replace('$name', $name) + [Environment]::NewLine } foreach ($log in $logs) { $commit = $log.commit if ($commitIds -contains $commit) { continue } $commitToAdd = ' commit id: "$commit"'.Replace('$commit', $commit) + [Environment]::NewLine $mermaidFile += $commitToAdd $commitIds += $commit } if ($name -ne $defaultBranch) { $mermaidFile += ' checkout main' + [Environment]::NewLine } } Write-Host $mermaidFile }
توضیحات:
- در تابع فوق، ابتدا یک آرایهی خالی برای ذخیرهی کامیت آیدیها، اضافه شده؛ از این آرایه برای جلوگیری از اضافه شدن کامیت تکراری در هر برنچ استفاده شدهاست.
- سپس با کمک دستور git branch، لیست تمام برنچها، دریافت شدهاست (همانطور که در قسمت قبل بررسی شد +).
- برای هر برنچ، تابع تعیین میکند که آیا برنچ جاری است یا خیر. اینکار با کمک دستور git symbolic-ref انجام شدهاست.
- در ادامه متغیر mermaidFile$ برای ایجاد یک گراف جدید Git مقداردهی میشود. در اینجا نام برنچ اصلی برابر با نام برنچ پیشفرض، تنظیم میشود.
- سپس لیست کامیتهای هر برنچ را با کمک دستور git log (همان سینتکسی که در قسمتهای قبل بررسی شد +) استخراج میکنیم.
- و در نهایت به ازای هر کامیت، یک commit id تولید کردهایم.
با فراخوانی تابع فوق، اینچنین ساختاری برایمان تولید خواهد شد:
%%{init: { 'gitGraph': {'mainBranchName': 'main' } } }%% gitGraph commit id: "765100f" branch "branch_1" commit id: "c88c441" commit id: "44149d9" commit id: "a660fe3" checkout main branch "branch_2" commit id: "2dcb572" commit id: "b043ad1" commit id: "92cafc0" checkout main branch "branch_3" commit id: "559e381" commit id: "f72957f" commit id: "c066e72" checkout main
خروجی فوق دقیقاً دیاگرامی است که در ابتدای مطلب نشان داده شد:
آموزش توسعه یک بلاگ با Blazor Server
Build a Complete Blog App with Blazor Server - Step-by-Step Tutorial from Scratch by Abhay Prince
You will learn about fundamentals of Blazor Server, Routing, Shared Reusable Components, Custom Authentication, EF Core Code First, Passing data from parent to child components and vice versa, Passing events from child to parent components, Forms validations and submissions, styling components, using javascript with blazor. third party components integration with blazor, blazor lifecycle events, authentication and authorization in blazor server, programtically navigating between component pages, multiple routes paths for single component page, dynamic routes and getting data from routes, authorized view and much more...
مروری بر کاربردهای Action و Func - قسمت دوم
برای خواندن اطلاعات از کش سیستم، این الگوی تکراری در هرجایی از برنامه باید انجام شود:
الف) ابتدا باید به شیء Cache مراجعه شود. شاید بر اساس یک key مفروض، اطلاعاتی در آن موجود باشد.
ب) اگر نبود (قطعه if تعریف شده)، باید به یک منبع داده مشخص، مراجعه و اطلاعات دریافت شود. سپس این اطلاعات در کش برای دفعات مراجعه بعدی ثبت گردد.
ج) اطلاعات نهایی بازگشت داده شود.
در اینجا قسمت مراجعه به منبع داده، توسط Func به استفاده کننده از متد CacheRead واگذار شده است. به این صورت ما فقط میدونیم که یک تابع در اختیار این متد قرار خواهد گرفت که در زمان مناسب میشود آن را فراخوانی کرد.
مثلا در مثالی که در انتهای بحث است یک نمونه از کاربرد آنرا مشاهده میکنید.
این مثال شبیه به مثال بررسی وجود نام کاربر با استفاده از jQuery Ajax است که از ذکر توضیحات مشابه آن، در اینجا خودداری خواهد شد.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="TestBrokenImages.aspx.cs"
Inherits="testWebForms87.TestBrokenImages" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>detecting broken images</title>
<script src="jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
function errorReplace(arg) {
//ارسال پیغام خطا
$.ajax({
type: "POST",
url: "TestBrokenImages.aspx/GetErros",
data: "{'image': '" + arg.src + "','page':'" + location.href + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json"
});
//نمایش تصویری دلخواه بجای نمونه مفقود
$(arg).attr('src', 'missing.png');
}
//بررسی وضعیت تک تک تصاویر پس از بارگذاری کامل صفحه
$(document).ready(function() {
$(window).bind('load', function() {
$('img').each(function() {
if (!this.complete || (!$.browser.msie && (typeof this.naturalWidth == "undefined" || this.naturalWidth == 0))) {
errorReplace(this);
}
});
})
});
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<img src="img1.png" />
<img src="img2.png" />
</div>
</form>
</body>
</html>
using System;
using System.IO;
using System.Web.Services;
namespace testWebForms87
{
public partial class TestBrokenImages : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
[WebMethod]
public static void GetErros(string image,string page)
{
//ارسال ایمیل به مسؤول سایت و یا ذخیره خطاها در دیتابیس
}
}
}
در این مثال زمانیکه صفحه کاملا بارگذاری شد، وضعیت تک تک تصاویر بررسی میشود، اگر تصویر مفقودی وجود داشت (با اکثر مرورگرها سازگار است)، اطلاعات آن به تابع errorReplace ارسال خواهد شد.
در این تابع با استفاده از jQuery Ajax ، اطلاعات تصویر مفقود و صفحه مربوطه به وب متد GetErros ما ارسال میشود. سپس در این متد میتوان یا آرگومانهای دریافتی را به صورت یک ایمیل به مسؤول سایت ارسال نمود و یا آنها را جهت بررسی آتی در یک دیتابیس ذخیره کرد.
بدیهی است بجای قرار دادن وب متد فوق در صفحه جاری، میتوان یک وب سرویس را نیز ایجاد و متد را در آن قرار داد تا نیازی نباشد به ازای هر صفحه سایت یکبار این متد تکرار شود.
اگر موفق به اجرای این مثال نشدید، برای مثال یک break point داخل متد GetErrors قرار دهید و برنامه را در حالت دیباگ در ویژوال استودیو شروع کنید، اگر اتفاق خاصی رخ نداد و به این break point نرسیدید، احتمالا تنظیمات وب کانفیگ شما مناسب نیست. قسمت مربوط به system.web.extensions ، webServices و jsonSerialization باید در وب کانفیگ موجود باشد که VS 2008 این موارد را به صورت خودکار اضافه میکند.
- جایگزین آن ViewComponet است و از لحاظ دسترسی به منابع و سرویسها محدودیتی ندارد. یک مثال
- هنوز هم اگر صرفا نیاز به رندر یک پارشال View را به صورت Ajax ایی دارید، روش زیر کار میکند:
جایی که میخواستید Html.RenderAction را قرار دهید، قطعه کد Ajax ایی زیر را فراخوانی کنید:
<div id="dynamicContentContainer"></div> <script> $.get('@Url.Action("GetData", "Home")', {id : 1}, function(content){ $("#dynamicContentContainer").html(content); }); </script>
[HttpGet] public IActionResult GetData(int id) { return PartialView(id); }
@model int <span>Values from controler :</span> @Model