با سلام و تشکر؛ لطفا در مورد اجرای پروژههای دات نت کور بر روی سرویس دهندههای ریموت هم توضیح بفرمایید.فرض میکنیم سورس یک پروژه وب دات نت کور وجود دارد و قرار است بر روی کانتینرهای ریموت (مثلا ابر آروان یا سرویس دهندههای خارجی) اجر شود. آیا امکان دارد که مستقیم سورس پروژه روی داکر ریموت (نه Docker Desktop ) بیلد و اجرا شود؟
مطالب دورهها
ماژول ها و فضای نام(namespace)
در #F ماژول به گروهی از کدها، توابع، انواع دادهها و شناسهها گفته میشود و کاربرد اصلی آن برای قرارگیری کدها مرتبط به هم در یک فایل است و هم چنین از تناقص نامها جلوگیری میکند. در #F در صورتی که توسط برنامه نویس ماژول تعریف نشود هر source file یک ماژول در نظر گرفته میشود. برای مثال:
بعد از کامپایل تبدیل به کد زیر میشود.
هم چنین امکان تعریف چند ماژول در یک source file نیز میسر است. به این صورت که باید برای هر ماژول محلی یک نام اختصاص دهید. در مثال بعدی دو تا ماژول را در یک فایل به نام mySourceFile قرار میدهیم.
در آخرین خط همان طور که مشاهده میکنید با استفاده از نام ماژول میتوانیم به تعاریف موجود در ماژول دسترسی داشته باشیم.(
MyModule1.module1Function
).
استفاده از یک ماژول در فایلهای دیگر.
گاهی اوقات نیاز به استفاده از تعاریف و توابع موجود در ماژولی داریم که در یک فایل دیگر قرار دارد. در این حالت باید به روش زیر عمل کنیم.
فرض بر این است ماژول زیر در یک فایل به نام ArithmeticFile قرار دارد.
حال قصد استفاده از توابع بالا رو در یک فایل و ماژول دیگر داریم.
#1 روش اول (دقیقا مشابه روش قبل از نام ماژول استفاه میکنیم)
#2 روش دوم(استفاده از open)
ماژولهای تودرتو
در #F میتوانیم بک ماژول را درون ماژول دیگر تعریف کنیم یا به عبارت دیگر میتوانیم ماژولی داشته باشیم که خود شامل چند تا ماژول دیگر باشد. مانند:
روش تعریف ماژولهای تودرتو در #F در نگاه اول کمی عجیب به نظر میرسه. جداسازی ماژولهای تودرتو به وسیله دندانه گذاری یا تورفتگی انجام میشود. ماژول Z در مثال بالا به اندازه چهار فضای خالی جلوتر نسبت به ماژول Y قرار دارد در نتیجه به عنوان ماژول داخلی Y معرفی میشود.
در مثال بالا به دلیل اینکه ماژول Z و Y از نظر فضای خالی در یک ردیف قرار دارند در نتیجه ماژول تودرتو نیستند. حال به مثال بعدی توجه کنید.
در این مثال ماژول X به عنوان ماژول داخلی Y حساب میشود. دلیلش هم این است که ماژول Y بدنه ندارد درنتیجه مازول Z بلافاصله بعد از آن قرار میگیرد که کامپایلر اونو به عنوان مازول داخلی حساب میکنه. اما برای اینکه مطمئن شود که قصد شما تولید ماژول تودرتو بود یک Warning میدهد. برای اینکه Warningv رو مشاهده نکنیم می تونیم کد بالا رو به صورت زیر بازنویسی کنیم:
فضای نام (namespace)
مفهوم فضای نام کاملا مشابه مفهوم فضای نام در #C است و راهی است برای کپسوله سازی کدها در برنامه. مفهوم namespace با مفهوم module کمی متفاوت است.
ساختار کلی
چند نکته درباره namespace
#1 اگر قصد داشته باشید که از فضای نام در کدهای خود استفاده کنید باید اولین تعریف در source file برنامه تعریف namespace باشد.
#2 امکان تعریف شناسه یا تابع به صورت مستقیم در namespace وجود ندارد بلکه این تعاریف باید در ماژولها یا typeها نظیر تعریف کلاس قرار گیرند.
#3 امکان تعریف فضای نام با استفاده از تعاریف ماژول نیز وجود دارد( در ادامه به بررسی یک مثال در این زمینه میپردازیم)
تعریف namespace به صورت مستقیم:
تعریف namepsace به صورت غیر مستقیم(استفاده از module)
فضای نامهای تودرتو
همانند ماژولها امکان تعریف فضای نام تودرتو نیز وجود دارد. یک مثال در این زمینه:
همانند فضای نامهای در #C با استفاده از (.) میتوانیم فضای نامهای تودرتو ایجاد کنیم. در مثال بالا فضای نام Inner به عنوان فضای نام داخلی Outer تعریف شد است. برای دسترسی به کلاس InnerMyClass باید تمام مسیر فضای نام رو ذکر کنیم.
// In the file program.fs. let x = 40
module Program let x = 40
module MyModule1 = let module1Value = 100 let module1Function x = x + 10 // MyModule2 module MyModule2 = let module2Value = 121 let module2Function x = x * (MyModule1.module1Function module2Value)
استفاده از یک ماژول در فایلهای دیگر.
گاهی اوقات نیاز به استفاده از تعاریف و توابع موجود در ماژولی داریم که در یک فایل دیگر قرار دارد. در این حالت باید به روش زیر عمل کنیم.
فرض بر این است ماژول زیر در یک فایل به نام ArithmeticFile قرار دارد.
module Arithmetic let add x y = x + y let sub x y = x - y
#1 روش اول (دقیقا مشابه روش قبل از نام ماژول استفاه میکنیم)
let result1 = Arithmetic.add 5 9
open Arithmetic let result2 = add 5 9
در #F میتوانیم بک ماژول را درون ماژول دیگر تعریف کنیم یا به عبارت دیگر میتوانیم ماژولی داشته باشیم که خود شامل چند تا ماژول دیگر باشد. مانند:
module Y = let x = 1 module Z = let z = 5
module Y = let x = 1 module Z = let z = 5
module Y = module Z = let z = 5
module Y = module Z = let z = 5
مفهوم فضای نام کاملا مشابه مفهوم فضای نام در #C است و راهی است برای کپسوله سازی کدها در برنامه. مفهوم namespace با مفهوم module کمی متفاوت است.
ساختار کلی
namespace [parent-namespaces.]identifier
#1 اگر قصد داشته باشید که از فضای نام در کدهای خود استفاده کنید باید اولین تعریف در source file برنامه تعریف namespace باشد.
#2 امکان تعریف شناسه یا تابع به صورت مستقیم در namespace وجود ندارد بلکه این تعاریف باید در ماژولها یا typeها نظیر تعریف کلاس قرار گیرند.
#3 امکان تعریف فضای نام با استفاده از تعاریف ماژول نیز وجود دارد( در ادامه به بررسی یک مثال در این زمینه میپردازیم)
تعریف namespace به صورت مستقیم:
namespace Model type Car = member this.Name = "BMW" module SetCarName = let CarName = "Pride"
module Model.Car module SetCarName = let CarName = "Pride"
همانند ماژولها امکان تعریف فضای نام تودرتو نیز وجود دارد. یک مثال در این زمینه:
namespace Outer type OuterMyClass() = member this.X(x) = x + 1 namespace Outer.Inner type InnerMyClass() = member this.Prop1 = "X"
Outer.Inner.InnerMyClass
بازخوردهای دوره
بوت استرپ (نگارش 3) چیست؟
- همانطور که عنوان شد، در سایت اصلی دریافت بوت استرپ، امکان سفارشی سازی و کار پویا با نگارش LESS آن وجود دارد. برای مثال قسمت تغییر پویای پیش فرضهای navbar در اینجا
- اگر خودتان مستقیما میخواهید این موارد را تغییر دهید، کلیه فایلهای LESS آن در مخزن اصلی کدهای بوت استرپ موجود هستند. در اینجا . برای نمونه فایل navbar.less آن.
اگر به فایلهای less آن دقت کنید، تمام آنها پارامتری هستند و هیچکدام دارای مقدار پیش فرضی نیستند. مقادیر پیش فرض مورد استفاده در فایل variables.less تعریف شدهاند. برای تغییر کلی فایل CSS نهایی فقط کافی است که مقادیر این فایل را تغییر دهید.
فایل نهایی که سبب کامپایل تمام تغییرات خواهد شد، فایل bootstrap.less است.
- استفاده از فایلهای LESS در نگارشهای جدید VS.NET سادهاست و به صورت توکار و خودکار، تغییرات را کامپایل کرده و فایل CSS نهایی را تولید میکند:
روی فایل bootstrap.less دوبار کلیک کنید (تمام فایلهای پوشه less سورس بوت استرپ به VS.NET اضافه شدهاند). اندکی صبر کنید تا کار کامپایل تمام شود. در صفحهای که باز میشود، دو ستون قابل مشاهده است. ستون سمت چپ، فایل less اصلی است و ستون سمت راست، خروجی CSS کامپایل شده نهایی.
- اگر خودتان مستقیما میخواهید این موارد را تغییر دهید، کلیه فایلهای LESS آن در مخزن اصلی کدهای بوت استرپ موجود هستند. در اینجا . برای نمونه فایل navbar.less آن.
اگر به فایلهای less آن دقت کنید، تمام آنها پارامتری هستند و هیچکدام دارای مقدار پیش فرضی نیستند. مقادیر پیش فرض مورد استفاده در فایل variables.less تعریف شدهاند. برای تغییر کلی فایل CSS نهایی فقط کافی است که مقادیر این فایل را تغییر دهید.
فایل نهایی که سبب کامپایل تمام تغییرات خواهد شد، فایل bootstrap.less است.
- استفاده از فایلهای LESS در نگارشهای جدید VS.NET سادهاست و به صورت توکار و خودکار، تغییرات را کامپایل کرده و فایل CSS نهایی را تولید میکند:
روی فایل bootstrap.less دوبار کلیک کنید (تمام فایلهای پوشه less سورس بوت استرپ به VS.NET اضافه شدهاند). اندکی صبر کنید تا کار کامپایل تمام شود. در صفحهای که باز میشود، دو ستون قابل مشاهده است. ستون سمت چپ، فایل less اصلی است و ستون سمت راست، خروجی CSS کامپایل شده نهایی.
اگر در moduleهای دیگر برنامه بخواهیم به اطلاعات شخصی که وارد سیستم شده دسترسی داشته باشیم، باید AuthService را به provider آن ماژول اضافه کنیم؟ یا همین که در CoreModule هست کافی هست؟
ممنون از جوابتون و وقتی که میذارید ولی من دقیقا جوابمو نگرفتم اینطور که شما میگید در شرایط پروژه من:
- استفاده از Visual studio Full
- پروژه از نوع MVC 5.0
- استفاده از سورس کنترل
باید با کامند بیرون از محیط Angular-CL رو روی پوشه پروژه MVC ای که دارم نصب کنم و بیخیال فایل هایی بشم که کنار فایل .sln ساخته میشه بشم.
- پروژه از نوع MVC 5.0
- استفاده از سورس کنترل
باید با کامند بیرون از محیط Angular-CL رو روی پوشه پروژه MVC ای که دارم نصب کنم و بیخیال فایل هایی بشم که کنار فایل .sln ساخته میشه بشم.
افزونه چیست؟
افزونهها جزء مهمترین قسمتهای یک مرورگر توسعه پذیر به شمار میآیند. افزونهها سعی دارند تا قابلیت هایی را به مرورگر شما اضافه کنند. افزونهها از آخرین فناوریهای html,CSS و جاوااسکریپت تا به آنجایی که مرورگر آنها را پشتیبانی کند، استفاده میکنند.
در این سری سعی خواهیم کرد برای هر مرورگر شناخته شده، یک افزونه ایجاد کنیم و ابتدا از آنجا که خودم از کروم استفاده میکنم، اولین افزونه را برای کروم خواهم نوشت.
این افزونه قرار است چه کاری انجام دهد؟
کاری که برای این افزونه تدارک دیدهام این است: موقعیکه سایت dotnettips.info به روز شد مرا آگاه کند. این آگاه سازی را از طریق یک نوتیفیکیشن به اطلاع کاربر میرسانیم. صفحه تنظیمات این افزونه شامل گزینههای "آخرین مطالب"،"نظرات آخرین مطالب"،"آخرین اشتراک ها"و"آخرین نظرات اشتراک ها" خواهد بود که به طور پیش فرض تنها گزینه اول فعال خواهد بود و همچنین یک گزینه نیز برای وارد کردن یک عدد صحیح جهت اینکه به افزونه بگوییم هر چند دقیقه یکبار سایت را چک کن. چک کردن سایت هم از طریق فید RSS صورت میگیرد.
فایل manifest.json
این فایل برای ذخیره سازی اطلاعاتی در مورد افزونه به کار میرود که شامل نام افزونه، توضیح کوتاه در مورد افزونه و ورژن و ... به کار میرود که همه این اطلاعات در قالب یا فرمت json نوشته میشوند و در بالاترین حد استفاده برای تعریف اهداف افزونه و اعطای مجوز به افزونه از آن استفاده میکنیم. این فایل بخشهای زیر را در یک افزونه تعریف میکند که به مرور با آن آشنا میشویم.
کد زیر را در فایل manifest.json مینویسیم:
{ "manifest_version": 2, "name": "Dotnettips Updater", "description": "This extension keeps you updated on current activities on dotnettips.info", "version": "1.0", "icons": { "16": "icon.png", "48": "icon.png", "128": "icon.png" }, "browser_action": { "default_icon": "icon.png", "default_popup": "popup.html" }, "permissions": [ "activeTab", "https://www.dntips.ir" ] }
"default_icon": { // optional "19": "images/icon19.png", // optional "38": "images/icon38.png" // optional }
قسمت popup برای نمایش تنظیمات به کار میرود و درست کردن این صفحه همانند صفحه همیشگی html هست و خروجی آن روی پنجره popup افزونه رندر خواهد شد.
گزینه default_title نیز یکی از دیگر خصیصههای مهم و پرکاربرد این قسمت هست که متن tooltip میباشد و موقعی که که کاربر، اشارهگر را روی آیکن ببرد نمایش داده میشود و در صورتی که نوشته نشود، کروم نام افزونه را نمایش میدهد؛ برای همین ما هم چیزی ننوشتیم.
صفحات پسزمینه
اگر بخواهید برای صفحه popup کد جاوااسکریت بنویسید یا از jquery استفاده کنید، مانند هر صفحهی وبی که درست میکنید آن را کنار فایل popup قرار داده و در popup آنها را صدا کرده و از آنها استفاده کنید. ولی برای پردازش هایی که نیاز به UI وجود ندارد، میتوان از صفحات پس زمینه استفاده کرد. در این حالت ما دو نوع صفحه داریم:
- صفحات مصر یا Persistent Page
- صفحات رویدادگرا یا Events Pages
اولین نوع صفحه، همواره فعال و در حال اجراست و دومی موقعی فعال میشود که به استفاده از آن نیاز است. گوگل توصیه میکند که تا جای ممکن از نوع دوم استفاده شود تا مقدار حافظه مصرفی حفظ شود و کارآیی مروگر بهبود بخشیده شود. کد زیر یک صفحه پس زمینه را از نوع رویدادگرا میسازد. به وضوح روشن است در صورتی که خاصیت Persistent با true مقداردهی شود، این صفحه مصرانه در تمام وقت باز بودن مرورگر، فعال خواهد بود:
"background": { "scripts": ["background.js"], "persistent": false }
Content Script یا اسکریپت محتوا
در صورتی که بخواهید با هر صفحهای که باز یا رفرش میشود، به DOM آن دسترسی پیدا کنید، از این خصوصیت استفاده کنید. در کد زیر برای پردازش اطلاعات DOM از فایل جاوااسکریپت بهره برده و در قسمت matches میگویید که چه صفحاتی باید از این کد استفاده کنند که در اینجا از پروتکلهای HTTP استفاده میشود و اگر مثلا نوع FTP یا file صدا زده شود کد مورد نظر اجرا نخواهد شد. در مورد اینکه matches چگونه کار میکند و چگونه میتوان آن را نوشت، از این صفحه استفاده کنید.
"content_scripts": [ { "matches": ["http://*/*", "https://*/*"], "js": ["content.js"] } ]
آغاز کدنویسی (رابطهای کاربری)
اجازه دهید بقیه موارد را در حین کدنویسی تجربه کنیم و هر آنچه ماند را بعدا توضیح خواهیم داد. در اینجا من از یک صفحه با کد HTML زیر بهره برده ام که یک فرم دارد به همراه چهار چک باکس و در نهایت یک دکمه جهت ذخیره مقادیر. نام صفحه را popup.htm گذاشته ام و یک فایل popup.js هم دارم که در آن کد jquery نوشتم. قصد من این است که بتوان یک action browser به شکل زیر درست کنم:
کد html آن به شرح زیر است:
<html> <head> <meta charset="utf-8"/> <script src="jquery.min.js"></script> <!-- Including jQuery --> <script type="text/javascript" src="popup.js"></script> </head> <body style="direction:rtl;width:250px;"> <form > <input type="checkbox" id="chkarticles" value="" checked="true">آخرین مطالب سایت</input><br/> <input type="checkbox" id="chkarticlescomments" value="" >آخرین نظرات مطالب سایت</input><br/> <input type="checkbox" id="chkshares" value="" >آخرین اشتراکهای سایت</input><br/> <input type="checkbox" id="chksharescomments" value="" >آخرین نظرات اشتراکهای سایت</input><br/> <input id="btnsave" type="button" value="ذخیره تغییرات" /> <div id="messageboard" style="color:green;"></div> </form> </body> </html>
$(document).ready(function () { $("#btnsave").click(function() { var articles = $("#chkarticles").is(':checked'); var articlesComments = $("#chkarticlescomments").is(':checked'); var shares = $("#chkshares").is(':checked'); var sharesComments = $("#chksharescomments").is(':checked'); chrome.storage.local.set({ 'articles': articles, 'articlesComments': articlesComments, 'shares': shares, 'sharesComments': sharesComments }, function() { $("#messageboard").text( 'تنظیمات جدید اعمال شد'); }); }); });
اولین مورد جدیدی که در بالا دیدیم، کلمهی کلیدی chrome است. کروم برای توسعه دهندگانی که قصد نوشتن افزونه دارند api هایی را تدارک دیده است که میتوانید با استفاده از آنها به قسمتهای مختلف مرورگر مثل بوک مارک یا تاریخچه فعالیتهای مرورگر و ... دست پیدا کنید. البته برای اینکار باید در فایل manifest.json هم مجوز اینکار را درخواست نماییم. این ویژگی باید برای برنامه نویسان اندروید آشنا باشد. برای آشنایی هر چه بیشتر با مجوزها این صفحه را ببینید.
برای دریافت مجوز، کد زیر را به manifest اضافه میکنیم:
"permissions": [ "storage" ]
chrome.storage.sync.set
{ "manifest_version": 2, "name": "Dotnettips Updater", "description": "This extension keeps you updated on current activities on dotnettips.info", "version": "1.0", "browser_action": { "default_icon": "icon.png", "default_popup": "popup.html" }, "permissions": [ "storage" ] }
chrome://extensions
الان باید مانند تصویر بالا یک آیکن کنار نوار آدرس یا به قول گوگل، Omni box ببینید. گزینهها را تیک بزنید و روی دکمه ذخیره کلیک کنید. باید پیام مقادیر ذخیره شدند، نمایش پیدا کند. الان یک مشکل وجود دارد؛ دادهها ذخیره میشوند ولی موقعی که دوباره تنظیمات افزونه را باز کنید حالت اولیه نمایش داده میشود. پس باید تنظیمات ذخیره شده را خوانده و به آنها اعمال کنیم. کد زیر را جهت دریافت مقادیر ذخیره شده مینویسیم. اینبار به جای استفاده از متد set از متد get استفاده میکنیم. به صورت آرایه، رشته نام مقادیر را درخواست میکنیم و در تابع callback، مقادیر به صورت آرایه برای ما برگشت داده میشوند.
chrome.storage.local.get(['articles', 'articlesComments', 'shares', 'sharesComments'], function ( items) { console.log(items[0]); $("#chkarticles").attr("checked", items["articles"]); $("#chkarticlescomments").attr("checked", items["articlesComments"]); $("#chkshares").attr("checked", items["shares"]); $("#chksharescomments").attr("checked", items["sharesComments"]); });
حالا برای اینکه افزونهی شما متوجه تغییرات شود، به تب extensions رفته و در لیست افزونهها به دنبال افزونه خود بگردید و گزینه Reload را انتخاب نمایید تا افزونه تغییرات را متوجه شود و صفحه را تست کنید.
Page Action روش دیگر برای ارائه یک رابط کاربری، page action هست. این روش دقیقا مانند روش قبلی است، ولی جای آیکن عوض میشود. قبلا بیرون از نوار آدرس بود، ولی الان داخل نوار آدرس قرار میگیرد. جالبترین نکته در این مورد این است که این آیکن در ابتدا مخفی شده است و شما تصمیم میگیرید که این آیکن چه موقع نمایش داده شود. مثلا آیکن RSS تنها موقعی نمایش داده میشود که وب سایتی که باز شده است، دارای محتوای RSS باشد یا بوک مارک کردن یک آدرس برای همهی سایتها باز باشد و سایر موارد.
کد زیر نحوهی تعریف یک page action را در manifest نشان میدهد. ما در این مثال یک page action را به طور موقت اضافه میکنیم و موقعی هم آن را نشان میدهیم که سایت dotnettips.info باز باشد. دلیل اینکه موقت اضافه میکنیم این است که باید یکی از دو گزینه رابط کاربری که تا به حال گفتیم، استفاده شود. در غیر این صورت کروم در هنگام خواندن فایل manifest در هنگام افزودن افزونه به مرورگر، پیام خطا خواهد داد و این مطلب را به شما گوشزد میکند. پس نمیتوان دو گزینه را همزمان داشت و من میخواهم افزونه را در حالت browser action ارائه کنم. پس در پروژه نهایی، این مطلب page action نخواهد بود. برای داشتن یک page action کد زیر را در manifest بنویسید.
"page_action": { "default_icon": { "19": "images/icon19.png", "38": "images/icon38.png" }, "default_popup": "popup.html"
"background": { "scripts": ["page_action_validator.js"] }
تا اینجا فایل جاوااسکریپت معرفی شد که کد زیر را دارد و در پس زمینه شروع به اجرا میکند.
function UrlValidation(tabId, changeInfo, tab) { if (tab.url.indexOf('dotnettips.info') >-1) { chrome.pageAction.show(tabId); } }; chrome.tabs.onUpdated.addListener(UrlValidation);
یک listener برای tabها ایجاد کردهایم که اگر تب جدید ایجاد شد، یا تب قبلی به آدرس جدیدی تغییر پیدا کرد تابع UrlValidation را اجرا کند و در این تابع چک میکنیم که اگر url این تب شامل نام وب سایت میشود، page action روی این تب ظاهر شود. پس از انجام تغییرات، مجددا افزونه را بارگذاری میکنیم و تغییرات اعمال شده را میبینیم. سایت dotnettips را باز کنید یا صفحه را مجددا رفرش کنید تا تغییر اعمال شده را ببینید.
تغییرات موقت را حذف و کدها را به حالت قبلی یعنی browser action بر میگردانم.
OmniBox
omnibox یک کلمه کلیدی است که در نوار آدرس مرورگر وارد میشود و در واقع میتوانیم آن را نوع دیگری از رابط کاربری بنامیم. موقعی که شما کلمه کلیدی رزرو شده را وارد میکنید، در نوار آدرس کلماتی نشان داده میشود که کاربر میتواند یکی از آنها را انتخاب کند تا عملی انجام شود. ما هم قرار است این کار را انجام دهیم. به این مثال دقت کنید:
میخواهیم موقعی که کاربرکلمه net. را تایپ میکند، 5 عبارت آخرین مطالب و آخرین اشتراکها و آخرین نظرات مطالب و آخرین نظرات اشتراکها و صفحه اصلی سایت نمایش داده شود و با انتخاب هر کدام، کاربر به سمت آن صفحه هدایت شود.
برای افزودن کلمه کلیدی در manifest خطوط زیر را اضافه کنید:
"omnibox": { "keyword" : ".net" }
در این حین میتوانیم همزمان با تایپ کاربر، دستوراتی را به آن نشان بدهیم. من دوست دارم موقعی که کاربر حرفی را وارد کرد، لیستی از نام صفحات نوشته شود.
برای اینکار باید کدنویسی کنیم ، پس یک فایل پس زمینه را به manifest معرفی کنید:
"background": { "scripts": ["omnibox.js"]
chrome.omnibox.onInputChanged.addListener(function(text, suggest) { suggest([ {content: ".net tips Home Page", description: "صفحه اصلی"}, {content: ".net tips Posts", description: "آخرین مطالب"}, {content: ".net tips News", description: "آخرین نظرات مطالب"}, {content: ".net tips Post Comments", description: "آخرین اشتراک ها"}, {content: ".net tips News Comments", description: "آخرین نظرات اشتراک ها"} ]); });
onInputStarted | بعد از اینکه کاربر کلمه کلیدی را وارد کرد اجرا میشود |
onInputChanged | بعد از وارد کردن کلمه کلیدی هربار که کاربر تغییری در ورودی نوارد آدرس میدهد اجرا میشود. |
onInputEntered | کاربر ورودی خود را تایید میکند. مثلا بعد از وارد کردن، کلید enter را میفشارد |
onInputCancelled | کاربر از وارد کردن ورودی منصرف شده است؛ مثلا کلید ESC را فشرده است. |
با نوشتن chrome.omnibox.onInputChanged.addListener ما یک listener ساختهایم تا هر بار کاربر ورودی را تغییر داد، یک تابع callback که دو آرگومان را دارد، صدا بزند. این آرگومانها یکی متن ورودیاست و دیگری آرایهی suggest که شما با تغییر آرایه میتوانید عباراتی که همزمان با تایپ به کاربر پیشنهاد میشود را نشان دهید. البته میتوانید با تغییر کد کاری کنید تا بر اساس حروفی که تا به حال تایپ کردهاید، دستورات را نشان دهد؛ ولی من به دلیل اینکه 5 دستور بیشتر نبود و کاربر راحت باشد، چنین کاری نکردم. همچنین وقتی شما برای هر یک description تعریف کنید، به جای نام پیشنهادی، توضیح آن را نمایش میدهد.
حالا وقت این است که کد زیر را جهت اینکه اگر کاربر یکی از کلمات پیشنهادی را انتخاب کرد، به صفحهی مورد نظر هدایت شود، اضافه کنیم:
chrome.omnibox.onInputEntered.addListener(function (text) { var location=""; switch(text) { case ".net tips Posts": location="https://www.dntips.ir/postsarchive"; break; case ".net tips News": location="https://www.dntips.ir/newsarchive"; break; case ".net tips Post Comments": location="https://www.dntips.ir/commentsarchive"; break; case".net tips News Comments": location="https://www.dntips.ir/newsarchive/comments"; break; default: location="https://www.dntips.ir/"; } chrome.tabs.getSelected(null, function (tab) { chrome.tabs.update(tab.id, { url: location }); }); });
Context Menu
یکی دیگر از رابطهای کاربری، منوی کانتکست هست که توسط chrome.contextmenus ارائه میشود و به مجوز "contextmenus" نیاز دارد. فعال سازی منوی کانتکست در قسمتهای زیر ممکن است:
all, page, frame, selection, link, editable, image, video, audio
من گزینهی dotenettips.info را برای باز کردن سایت، به Contextmenus اضافه میکنم. کد را در فایلی به اسم contextmenus.js ایجاد میکنم و در قسمت background آن را معرفی میکنم. برای باز کردن یک تب جدید برای سایت، نیاز به chrome.tabs داریم که البته نیاز به مجوز tabs هم داریم.
محتوای فایل contextmenus.js
var root = chrome.contextMenus.create({ title: 'Open .net tips', contexts: ['page'] }, function () { var Home= chrome.contextMenus.create({ title: 'Home', contexts: ['page'], parentId: root, onclick: function (evt) { chrome.tabs.create({ url: 'https://www.dntips.ir' }) } }); var Posts = chrome.contextMenus.create({ title: 'Posts', contexts: ['page'], parentId: root, onclick: function (evt) { chrome.tabs.create({ url: 'https://www.dntips.ir/postsarchive/' }) } }); });
تا به اینجا ما قسمت ظاهری کار را آماده کرده ایم و به دلیل اینکه مطلب طولانی نشود، این مطلب را در دو قسمت ارائه خواهیم کرد. در قسمت بعدی نحوه خواندن RSS و اطلاع رسانی و دیگر موارد را بررسی خواهیم کرد.
نظرات اشتراکها
میزبانی مخازن گیت در هاست سی پنل
ممنون از معرفی این روش که نسبت به vps هم خیلی کم هزینه است. اخیرا مخازن کد ما که بر روی ابر آروان روی vps قرار داشت از دست رفت. الان بر روی سرویس لیارا از Gitea استفاده میکنیم با هزینه ماهانه حدود 76 هزار تومان. بصورت روزانه پشتیبان گیری هم از دیسک هم از پایگاه داده توسط خود سرویس انجام میشه. شاید این روش هم مناسب ما ایرانیها باشه.
آشنایی با کتابخانه NHibernate Validator
پروژه جدیدی به پروژه NHibernate Contrib در سایت سورس فورج اضافه شده است به نام NHibernate Validator که از آدرس زیر قابل دریافت است:
این پروژه که توسط Dario Quintana توسعه یافته است، امکان اعتبار سنجی اطلاعات را پیش از افزوده شدن آنها به دیتابیس به دو صورت دستی و یا خودکار و یکپارچه با NHibernate فراهم میسازد؛ که امروز قصد بررسی آنرا داریم.
کامپایل پروژه اعتبار سنجی NHibernate
پس از دریافت آخرین نگارش موجود کتابخانه NHibernate Validator از سایت سورس فورج، فایل پروژه آنرا در VS.Net گشوده و یکبار آنرا کامپایل نمائید تا فایل اسمبلی NHibernate.Validator.dll حاصل گردد.
بررسی مدل برنامه
در این مدل ساده، تعدادی پزشک داریم و تعدادی بیمار. در سیستم ما هر بیمار تنها توسط یک پزشک مورد معاینه قرار خواهد گرفت. رابطه آنها را در کلاس دیاگرام زیر میتوان مشاهده نمود:
به این صورت پوشه دومین برنامه از کلاسهای زیر تشکیل خواهد شد:
namespace NHSample5.Domain
{
public class Patient
{
public virtual int Id { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
}
}
using System.Collections.Generic;
namespace NHSample5.Domain
{
public class Doctor
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Patient> Patients { get; set; }
public Doctor()
{
Patients = new List<Patient>();
}
}
}
ساختار کلی این پروژه را در شکل زیر مشاهده میکنید:
اطلاعات این برنامه بر مبنای NHRepository و NHSessionManager ایی است که در قسمتهای قبل توسعه دادیم و پیشنیاز ضروری مطالعه آن میباشند (سورس پیوست شده شامل نمونه تکمیل شده این موارد نیز هست). همچنین از قسمت ایجاد دیتابیس از روی مدل نیز صرفنظر میشود و همانند قسمتهای قبل است.
تعریف اعتبار سنجی دومین با کمک ویژگیها (attributes)
فرض کنید میخواهیم بر روی طول نام و نام خانوادگی بیمار محدودیت قرار داده و آنها را با کمک کتابخانه NHibernate Validator ، اعتبار سنجی کنیم. برای این منظور ابتدا فضای نام NHibernate.Validator.Constraints به کلاس بیمار اضافه شده و سپس با کمک ویژگیهایی که در این کتابخانه تعریف شدهاند میتوان قیود خود را به خواص کلاس تعریف شده اعمال نمود که نمونهای از آن را مشاهده مینمائید:
using NHibernate.Validator.Constraints;
namespace NHSample5.Domain
{
public class Patient
{
public virtual int Id { get; set; }
[Length(Min = 3, Max = 20,Message="طول نام باید بین 3 و 20 کاراکتر باشد")]
public virtual string FirstName { get; set; }
[Length(Min = 3, Max = 60, Message = "طول نام خانوادگی باید بین 3 و 60 کاراکتر باشد")]
public virtual string LastName { get; set; }
}
}
مثالی دیگر:
جهت اجباری کردن و همچنین اعمال Regular expressions برای اعتبار سنجی یک فیلد میتوان دو ویژگی زیر را به بالای آن فیلد مورد نظر افزود:
[NotNull]
[Pattern(Regex = "[A-Za-z0-9]+")]
تعریف اعتبار سنجی با کمک کلاس ValidationDef
راه دوم تعریف اعتبار سنجی، کمک گرفتن از کلاس ValidationDef این کتابخانه و استفاده از روش fluent configuration است. برای این منظور، پوشه جدیدی را به برنامه به نام Validation اضافه خواهیم کرد و سپس دو کلاس DoctorDef و PatientDef را به آن به صورت زیر خواهیم افزود:
using NHibernate.Validator.Cfg.Loquacious;
using NHSample5.Domain;
namespace NHSample5.Validation
{
public class DoctorDef : ValidationDef<Doctor>
{
public DoctorDef()
{
Define(x => x.Name).LengthBetween(3, 50);
Define(x => x.Patients).NotNullableAndNotEmpty();
}
}
}
using NHSample5.Domain;
using NHibernate.Validator.Cfg.Loquacious;
namespace NHSample5.Validation
{
public class PatientDef : ValidationDef<Patient>
{
public PatientDef()
{
Define(x => x.FirstName)
.LengthBetween(3, 20)
.WithMessage("طول نام باید بین 3 و 20 کاراکتر باشد");
Define(x => x.LastName)
.LengthBetween(3, 60)
.WithMessage("طول نام خانوادگی باید بین 3 و 60 کاراکتر باشد");
}
}
}
استفاده از قیودات تعریف شده به صورت دستی
میتوان از این کتابخانه اعتبار سنجی به صورت مستقیم نیز اضافه کرد. روش انجام آنرا در متد زیر مشاهده مینمائید.
/// <summary>
/// استفاده از اعتبار سنجی ویژه به صورت مستقیم
/// در صورت استفاده از ویژگیها
/// </summary>
static void WithoutConfiguringTheEngine()
{
//تعریف یک بیمار غیر معتبر
var patient1 = new Patient() { FirstName = "V", LastName = "N" };
var ve = new ValidatorEngine();
var invalidValues = ve.Validate(patient1);
if (invalidValues.Length == 0)
{
Console.WriteLine("patient1 is valid.");
}
else
{
Console.WriteLine("patient1 is NOT valid!");
//نمایش پیغامهای تعریف شده مربوط به هر فیلد
foreach (var invalidValue in invalidValues)
{
Console.WriteLine(
"{0}: {1}",
invalidValue.PropertyName,
invalidValue.Message);
}
}
//تعریف یک بیمار معتبر بر اساس قیودات اعمالی
var patient2 = new Patient() { FirstName = "وحید", LastName = "نصیری" };
if (ve.IsValid(patient2))
{
Console.WriteLine("patient2 is valid.");
}
else
{
Console.WriteLine("patient2 is NOT valid!");
}
}
در اینجا اگر سعی در اعتبار سنجی یک پزشک نمائیم، نتیجهای حاصل نخواهد شد زیرا هنگام استفاده از کلاس ValidationDef، باید نگاشت لازم به این قیودات را نیز دقیقا مشخص نمود تا مورد استفاده قرار گیرد که نحوهی انجام این عملیات را در متد زیر میتوان مشاهده نمود.
public static ValidatorEngine GetFluentlyConfiguredEngine()
{
var vtor = new ValidatorEngine();
var configuration = new FluentConfiguration();
configuration
.Register(
Assembly
.GetExecutingAssembly()
.GetTypes()
.Where(t => t.Namespace.Equals("NHSample5.Validation"))
.ValidationDefinitions()
)
.SetDefaultValidatorMode(ValidatorMode.UseExternal);
vtor.Configure(configuration);
return vtor;
}
FluentConfiguration آن مجزا است از نمونه مشابه کتابخانه Fluent NHibernate و نباید با آن اشتباه گرفته شود (در فضای نام NHibernate.Validator.Cfg.Loquacious تعریف شده است).
در این متد کلاسهای قرار گرفته در پوشه Validation برنامه که دارای فضای نام NHSample5.Validation هستند، به عنوان کلاسهایی که باید اطلاعات لازم مربوط به اعتبار سنجی را از آنان دریافت کرد معرفی شدهاند.
همچنین ValidatorMode نیز به صورت External تعریف شده و منظور از External در اینجا هر چیزی بجز استفاده از روش بکارگیری attributes است (علاوه بر امکان تعریف این قیودات در یک پروژه class library مجزا و مشخص ساختن اسمبلی آن در اینجا).
اکنون جهت دسترسی به این موتور اعتبار سنجی تنظیم شده میتوان به صورت زیر عمل کرد:
/// <summary>
/// استفاده از اعتبار سنجی ویژه به صورت مستقیم
/// در صورت تعریف آنها با کمک
/// ValidationDef
/// </summary>
static void WithConfiguringTheEngine()
{
var ve2 = VeConfig.GetFluentlyConfiguredEngine();
var doctor1 = new Doctor() { Name = "S" };
if (ve2.IsValid(doctor1))
{
Console.WriteLine("doctor1 is valid.");
}
else
{
Console.WriteLine("doctor1 is NOT valid!");
}
var patient1 = new Patient() { FirstName = "وحید", LastName = "نصیری" };
if (ve2.IsValid(patient1))
{
Console.WriteLine("patient1 is valid.");
}
else
{
Console.WriteLine("patient1 is NOT valid!");
}
var doctor2 = new Doctor() { Name = "شمس", Patients = new List<Patient>() { patient1 } };
if (ve2.IsValid(doctor2))
{
Console.WriteLine("doctor2 is valid.");
}
else
{
Console.WriteLine("doctor2 is NOT valid!");
}
}
نکته مهم:
فراخوانی GetFluentlyConfiguredEngine نیز باید یکبار در طول برنامه صورت گرفته و سپس حاصل آن بارها مورد استفاده قرار گیرد. بنابراین نحوهی صحیح دسترسی به آن باید حتما از طریق الگوی Singleton که در قسمتهای قبل در مورد آن بحث شد، انجام شود.
استفاده از قیودات تعریف شده و سیستم اعتبار سنجی به صورت یکپارچه با NHibernate
کتابخانه NHibernate Validator زمانیکه با NHibernate یکپارچه گردد دو رخداد PreInsert و PreUpdate آنرا به صورت خودکار تحت نظر قرار داده و پیش از اینکه اطلاعات ثبت و یا به روز شوند، ابتدا کار اعتبار سنجی خود را انجام داده و اگر اعتبار سنجی مورد نظر با شکست مواجه شود، با ایجاد یک exception از ادامه برنامه جلوگیری میکند. در این حالت استثنای حاصل شده از نوع InvalidStateException خواهد بود.
برای انجام این مرحله یکپارچه سازی ابتدا متد BuildIntegratedFluentlyConfiguredEngine را به شکل زیر باید فراخوانی نمائیم:
/// <summary>
/// از این کانفیگ برای آغاز سشن فکتوری باید کمک گرفته شود
/// </summary>
/// <param name="nhConfiguration"></param>
public static void BuildIntegratedFluentlyConfiguredEngine(ref Configuration nhConfiguration)
{
var vtor = new ValidatorEngine();
var configuration = new FluentConfiguration();
configuration
.Register(
Assembly
.GetExecutingAssembly()
.GetTypes()
.Where(t => t.Namespace.Equals("NHSample5.Validation"))
.ValidationDefinitions()
)
.SetDefaultValidatorMode(ValidatorMode.UseExternal)
.IntegrateWithNHibernate
.ApplyingDDLConstraints()
.And
.RegisteringListeners();
vtor.Configure(configuration);
//Registering of Listeners and DDL-applying here
ValidatorInitializer.Initialize(nhConfiguration, vtor);
}
SingletonCore()
{
Configuration cfg = DbConfig.GetConfig().BuildConfiguration();
VeConfig.BuildIntegratedFluentlyConfiguredEngine(ref cfg);
//با همان کانفیگ تنظیم شده برای اعتبار سنجی باید کار شروع شود
_sessionFactory = cfg.BuildSessionFactory();
}
از این لحظه به بعد، نیاز به فراخوانی متدهای Validate و یا IsValid نبوده و کار اعتبار سنجی به صورت خودکار و یکپارچه با NHibernate انجام میشود. لطفا به مثال زیر دقت بفرمائید:
/// <summary>
/// استفاده از اعتبار سنجی یکپارچه و خودکار
/// </summary>
static void tryToSaveInvalidPatient()
{
using (Repository<Patient> repo = new Repository<Patient>())
{
try
{
var patient1 = new Patient() { FirstName = "V", LastName = "N" };
repo.Save(patient1);
}
catch (InvalidStateException ex)
{
Console.WriteLine("Validation failed!");
foreach (var invalidValue in ex.GetInvalidValues())
Console.WriteLine(
"{0}: {1}",
invalidValue.PropertyName,
invalidValue.Message);
log4net.LogManager.GetLogger("NHibernate.SQL").Error(ex);
}
}
}
/// <summary>
/// استفاده از اعتبار سنجی یکپارچه و خودکار
/// </summary>
static void tryToSaveValidPatient()
{
using (Repository<Patient> repo = new Repository<Patient>())
{
var patient1 = new Patient() { FirstName = "Vahid", LastName = "Nasiri" };
repo.Save(patient1);
}
}
نکته:
اگر کار ساخت database schema را با کمک کانفیگ تنظیم شده توسط کتابخانه اعتبار سنجی آغاز کنیم، طول فیلدها دقیقا مطابق با حداکثر طول مشخص شده در قسمت تعاریف قیود هر یک از فیلدها تشکیل میگردد (حاصل از اعمال متد ApplyingDDLConstraints در متد BuildIntegratedFluentlyConfiguredEngine ذکر شده میباشد).
public static void CreateValidDb()
{
bool script = false;//آیا خروجی در کنسول هم نمایش داده شود
bool export = true;//آیا بر روی دیتابیس هم اجرا شود
bool dropTables = false;//آیا جداول موجود دراپ شوند
Configuration cfg = DbConfig.GetConfig().BuildConfiguration();
VeConfig.BuildIntegratedFluentlyConfiguredEngine(ref cfg);
//با همان کانفیگ تنظیم شده برای اعتبار سنجی باید کار شروع شود
new SchemaExport(cfg).Execute(script, export, dropTables);
}
دریافت سورس کامل قسمت دهم
نظرات مطالب
پیاده سازی UnitOfWork به وسیله MEF
اگر امکان دارد سورس مثال را در سایت قرار دهید.
با تشکر
با تشکر
در مورد تنظیمات دستی IIS Express که یک نسخهی سبک IIS 7.5 قابل اجرا بر روی ویندوز XP نیز میباشد، پیشتر در این سایت مطلبی را مطالعه کردهاید (+). اکنون که سرویس پک یک VS 2010 ارائه شده (+)، دیگر نیازی به آن تنظیمات دستی نبوده و امکان استفاده یکپارچه و خودکار از این نسخهی ساده شده IIS 7.5 به شرح زیر وجود دارد:
ابتدا نیاز است تا هر دو مورد سرویس پک یک VS 2010 و همچنین IIS Express به صورت جداگانه نصب شوند. سپس:
الف) ابتدا از منوی Tools ، گزینهی Options را انتخاب کنید. در صفحهی باز شده در قسمت Projects and solutions ذیل گزینهی Web projects نیاز است تا یکبار مجوز استفاده از IIS express صادر شود:
ب) اکنون بر روی نام پروژه در Solution explorer موجود در Visual studio کلیک راست کرده و گزینهی Use IIS Express را انتخاب نمائید:
به این صورت تنظیمات لازم به صورت خودکار اعمال خواهد گردید و جهت مشاهده آنها میتوان به خواص پروژه، برگهی Web مراجعه کرد:
نکته مهم:
نسخهی RTM ویژوال استودیوی 2010 تنظیمات فوق را که در تصویر ملاحظه میکنید، ندارد. به عبارتی پس از اعمال تغییرات فوق باید دقت داشت سایرینی که قرار است از پروژهی شما استفاده کنند نیز باید پیشنیازهای ذکر شده را رعایت نمایند و یا جهت توزیع سورس میتوان مجددا بر روی نام پروژه کلیک راست کرده و اینبار گزینهی Use Visual Studio Development Server قدیمی را انتخاب کرد.