طراحی دیتابیس یک Workflow Engine
بررسی متد Array.prototype.includes
تصویر فوق، یکی از تصویرهایی است که شاید از طریق ایمیلهایی تحت عنوان "فقط در ایران!" به دست شما هم رسیده باشد. تصور کاربر نهایی (که این ایمیل را با تعجب ارسال کرده) این است که در اینجا به او گفته شده مثلا "مرتضی" را جستجو نکنید و امثال آن. چون برای او تفاوتی بین ی و ی وجود ندارد. همچنین بکار بردن "اقلامی" هم کمی غلط انداز است و بیشتر ذهن را به سمت کلمه سوق میدهد تا حرف.
در ادامهی بحث آلرژی مزمن به وجود انواع "ی" و "ک" در بانک اطلاعاتی (+ و + و +)، اینبار قصد داریم این اطلاعات را به NHibernate بسط دهیم. شاید یک روش اعمال یک دست سازی "ی" و "ک" این باشد که در کل برنامه هر جایی که قرار است update یا insert ایی صورت گیرد، خواص رشتهای را یافته و تغییر دهیم. این روش "کار میکنه" ولی ایده آل نیست؛ چون حجم کار تکراری در برنامه زیاد خواهد شد و نگهداری آن هم مشکل میشود. همچنین امکان فراموش کردن اعمال آن هم وجود دارد.
در NHibernate یک سری EventListener وجود دارند که کارشان گوش فرا دادن به یک سری رخدادها مانند مثلا update یا insert است. این رخدادها میتوانند پیش یا پس از هرگونه ثبت یا ویرایشی در برنامه صادر شوند. بنابراین بهترین جایی که جهت اعمال این نوع ممیزی (Auditing) بدون بالا بردن حجم برنامه یا اضافه کردن بیش از حد یک سری کد تکراری در حین کار با NHibernate میتوان یافت، روالهای مدیریت کنندهی همین EventListener ها هستند.
کلاس YeKeAuditorEventListener نهایی با پیاده سازی IPreInsertEventListener و IPreUpdateEventListenerبه شکل زیر خواهد بود:
using NHibernate.Event;
namespace NHYeKeAuditor
{
public class YeKeAuditorEventListener : IPreInsertEventListener, IPreUpdateEventListener
{
// Represents a pre-insert event, which occurs just prior to performing the
// insert of an entity into the database.
public bool OnPreInsert(PreInsertEvent preInsertEvent)
{
var entity = preInsertEvent.Entity;
CorrectYeKe.ApplyCorrectYeKe(entity);
return false;
}
// Represents a pre-update event, which occurs just prior to performing the
// update of an entity in the database.
public bool OnPreUpdate(PreUpdateEvent preUpdateEvent)
{
var entity = preUpdateEvent.Entity;
CorrectYeKe.ApplyCorrectYeKe(entity);
return false;
}
}
}
تا اینجا فقط تعریف YeKeAuditorEventListener انجام شده است. اما NHibernate چگونه از وجود آن مطلع خواهد شد؟
برای تزریق کلاس YeKeAuditorEventListener به تنظیمات برنامه باید به شکل زیر عمل کرد:
using System;
using System.Linq;
using FluentNHibernate.Cfg;
using NHibernate.Cfg;
namespace NHYeKeAuditor
{
public static class MappingsConfiguration
{
public static FluentConfiguration InjectYeKeAuditorEventListener(this FluentConfiguration fc)
{
return fc.ExposeConfiguration(configListeners());
}
private static Action<Configuration> configListeners()
{
return
c =>
{
var listener = new YeKeAuditorEventListener();
c.EventListeners.PreInsertEventListeners =
c.EventListeners.PreInsertEventListeners
.Concat(new[] { listener })
.ToArray();
c.EventListeners.PreUpdateEventListeners =
c.EventListeners.PreUpdateEventListeners
.Concat(new[] { listener })
.ToArray();
};
}
}
}
کدهای NHYeKeAuditor را از اینجا میتوانید دریافت کنید.
- استفاده از شبیه سازها مانند Virtual Box یا VMWare
- استفاده از نسخه دستکاری شده که بتوانید بر روی سیستم سخت افزاری خود نصب کنید
- استفاده از فایل ISO همانند ویندوز
- استفاده از فایل VMDK آماده
- ایجاد ایمیج از روی فایل DMG
در مراحل مختلف، سوالات متعددی برای آماده سازی ماشین مجازی از شما پرسیده خواهد شد. نام آن را Mac قرار دهید. از کادر انتخابی Type، گزینه Mac OS را انتخاب کرده و نسخه 10.13 High Sierra را انتخاب کنید.
در صفحه بعدی شما میزان RAM ای را که به سیستم عامل میهمان اختصاص میدهید، باید مشخص کنید. حداقل 4 گیگابایت رم به سیستم عامل میهمان اختصاص دهید. دقت داشته باشید که میزان آن 50 الی 65 درصد از کل رم سیستم تان باشد.
در مرحله بعدی شما باید تنظیمات مربوط به هارد دیسک را انجام دهید. گزینه “use an existing virtual hard disk file” را انتخاب کنید. سپس فایلی را که در مرحله قبلی با پسوند VMDK دانلود کردهاید، انتخاب کنید.
نهایتا بر روی Finish کلیک کنید تا ماشین میهمان ساخته شود.
مرحله چهارم: ویرایش تنظیمات مربوط به ماشین مجازی
ماشین مجازی را که در مرحله قبلی ایجاد کردهاید، باز کنید و بر روی دکمهی Setting کلیک کنید. در دسته بندی System بر روی تب Motherboard کلیک کنید. گزینه انتخابی Enable EFI را فعال کنید و Chipset را به IHC9 و یا PIIX3 تغییر دهید.
در تب Processor گزینه Enable PAE/NX را فعال کرده و Coreها را به نصف Coreهای سیستم فعلی خود ارتقاء دهید.
در دسته Display، گزینه Video Memory را به 128 مگابایت ارتقا دهید.
شما میتوانید سایر گزینهها را نیز بسته به نیاز خود تغییر دهید.
بر روی تب Storage کلیک کرده و گزینه Use Host I/O Cache را فعال کنید.
مرحله پنجم: استفاده از خط فرمان برای اضافه کردن دستورات خاص
خط فرمان (CMD) را به عنوان Administrator باز کنید.
دستورات زیر را وارد کنید. دقت داشته باشید که بجای Your VM Name؛ نام ماشین مجازی خود را وارد کنید؛ در مثال ما Mac
cd "C:\Program Files\Oracle\VirtualBox\" VBoxManage.exe modifyvm "Your VM Name" --cpuidset 00000001 000106e5 00100800 0098e3fd bfebfbff VBoxManage setextradata "Your VM Name" "VBoxInternal/Devices/efi/0/Config/DmiSystemProduct" "iMac11,3" VBoxManage setextradata "Your VM Name" "VBoxInternal/Devices/efi/0/Config/DmiSystemVersion" "1.0" VBoxManage setextradata "Your VM Name" "VBoxInternal/Devices/efi/0/Config/DmiBoardProduct" "Iloveapple" VBoxManage setextradata "Your VM Name" "VBoxInternal/Devices/smc/0/Config/DeviceKey" "ourhardworkbythesewordsguardedpleasedontsteal(c)AppleComputerInc" VBoxManage setextradata "Your VM Name" "VBoxInternal/Devices/smc/0/Config/GetKeyFromRealSMC" 1
VirtualBox را قبل از اجزای این دستورات ببندید و سپس این دستورات را اجرا کنید.
مرحله ششم: اجرای سیستم عامل مک نسخه 10.14 بر روی Virtual Box
ماشین مجازی را که ایجاد کرده اید، باز کنید و بر روی start کلیک کنید:
صفحه فوق را باید مشاهده کنید. در صورت بروز هر گونه مشکلی، سوال خود را ذیل این مطلب مطرح کنید.
تنظیمات اولیه و نام کاربری سیستم عامل را وارد کنید و تمام!
دقت داشته باشید که استفاده از این روش ممکن است با تجربه کاری یک مک بر روی سخت افزار اصلی به کلی متفاوت باشد. ما از این روش برای جبران محدودیت خود برای توسعه استفاده میکنیم.
خوشبختانه برای کار با Xamarin.iOS شما مجبور به کد نویسی بر روی مک نخواهید بود و تنها پروسه بیلد پروژه بر روی آن انجام خواهد شد. لذا مشکلات کارآیی آن بر روی روند کار شما تاثیر چندانی نخواهد داشت. البته برای نصب این سیستم عامل به صورت مجازی توصیه میشود از هارد SSD استفاده کنید.
نحوهی رفع مشکلات سخت افزاری و درایوری
در صورتیکه در مراحل نصب و یا پس از نصب سیستم عامل، کیبرد و یا ماوس کار نمیکنند، میتوانید مراحل زیر را انجام دهید:
به سایت VirtualBox.org رفته و آخرین نسخهی Extension Pack را دانلود کنید.
سپس VirtualBox را باز کنید و از منوی فایل، گزینهی Preferences را انتخاب کنید:
بر روی برگهی Extensions کلیک کرده و گزینهی Add را انتخاب کنید:
در مرورگر فایل باز شده، فایلی را که دانلود کردهاید، انتخاب کنید. سپس بر روی Install کلیک کنید. در صفحهی توافقنامه نمایش داده شده، به پایین متن اسکرول کنید و I Agree را انتخاب کنید.
در صورتی که بعد از اعمال تغییرات فوق، مشکل همچنان باقی بود، میتوانید در تنظیمات VM خود در تب USB، گزینهی USB 3.0 (xHCI) Controller. را انتخاب کنید.
در صورتیکه مشکلات دیگری نظیر شناسایی درایورها و یا سایر موارد را داشتید، میتوانید زیر همین مطلب، سؤالات خود و یا بازخورد خود در رابطه با این مقاله را مطرح کنید.
حرکت دادن المانها در صفحه
ابتدا قطعه کد HTML زیر را درنظر بگیرید:
<body> <h2>Flavors</h2> <ul class="flavors"> <li>chocolate</li> <li>strawberry</li> <li>vanilla</li> </ul> <h2>Types</h2> <ul class="types"> <li>frozen yogurt</li> <li>custard</li> <li>Italian ice</li> </ul> <ul class="unassigned"> <li>rocky road</li> <li>gelato</li> </ul> </body>
<body> <h2>Types</h2> <ul class="types"> <li>frozen yogurt</li> <li>Italian ice</li> <li>custard</li> <li>gelato</li> </ul> <h2>Flavors</h2> <ul class="flavors"> <li>chocolate</li> <li>vanilla</li> <li>rocky road</li> <li>strawberry</li> </ul> <ul class="unassigned"> </ul> </body>
حرکت دادن المانها توسط jQuery
var $flavors = $('.flavors'); var $chocolate = $flavors.find('li').eq(0); var $vanilla = $flavors.find('li').eq(2); $chocolate.after($vanilla);
در ادامه میخواهیم لیست types را به همراه عنوان آن، به قبل از لیست flavors منتقل کنیم:
var $typesHeading = $('h2').eq(1); $typesHeading.prependTo('body'); $typesHeading.after($('.types'));
سپس در لیست unassigned ابتدا rocky road آنرا یافته و به بالای strawberry در لیست flavors اضافه میکنیم. همچنین gelato آنرا نیز یافته و به انتهای لیست types اضافه خواهیم کرد:
var $unassigned = $('.unassigned'); var $rockyRoad = $unassigned.find('li').eq(0); var $gelato = $unassigned.find('li').eq(1); $vanilla.after($rockyRoad); $gelato.appendTo($('.types'));
حرکت دادن المانها توسط جاوا اسکریپت خالص (سازگار با IE 8.0 به بعد)
در ابتدا میخواهیم المان vanilla را به قبل از المان strawberry حرکت دهیم. برای اینکار میتوان از متد استاندارد insertBefore استفاده کرد:
var flavors = document.querySelector('.flavors'); var strawberry = flavors.children[1]; var vanilla = flavors.children[2]; flavors.insertBefore(vanilla, strawberry);
سپس کار انتقال عنوان لیست types و خود آن به قبل از لیست flavors صورت میگیرد:
var headings = document.querySelectorAll('h2'); var flavorsHeading = headings[0]; var typesHeading = headings[1]; var typesList = document.querySelector('.types'); document.body.insertBefore(typesHeading, flavorsHeading); document.body.insertBefore(typesList, flavorsHeading);
در آخر میخواهیم آیتمهای لیست unassigned را به لیستهای مرتبط با آنها انتقال دهیم:
flavors.insertBefore(document.querySelector('.unassigned > li'), strawberry); document.querySelector('.types').appendChild(document.querySelector('.unassigned > li'));
در سطر دوم، چون هم اکنون المان rocky road از لیست unassigned حذف شدهاست، متد querySelector فراخوانی شده، اولین عنصر لیست یا همان gelato را بازگشت میدهد. این المان را توسط متد appendChild به انتهای لیست types اضافه خواهیم کرد. متد appendChild نیز همانند متد insertBefore نیاز به یک والد دارد که همان عنصری است که قرار است المانها به آن افزوده شوند.
کپی کردن المانها
<ol class="numbers"> <li>one</li> <li>two</li> </ol>
// deep clone: return value is an exact copy $('.numbers').clone();
و در جاوا اسکریپت خالص (سازگار با IE 8.0 به بعد) برای کپی کردن المانها دو روش shallow و deep وجود دارد:
// shallow clone: return value is an empty <ol> document.querySelector('.numbers').cloneNode(); // deep clone: return value is an exact copy of the tree document.querySelector('.numbers').cloneNode(true);
باید دقت داشت که متد cloneNode آنچه را که مشاهده میکنید یا همان اصل markup را کپی میکند. بنابراین اگر از طریق جاوا اسکریپت تغییراتی را در آن شیء داده باشید در متد cloneNode لحاظ نمیشود.
بدیهی است المانهای clone شده تا زمانیکه با متدهایی مانند insertBefore و یا appendChild به صفحه اضافه نشوند، در صفحه نمایان نخواهند شد.
ایجاد و حذف المانها
فرض کنید میخواهیم به لیست flavors مثال ابتدای بحث، دو مورد جدید را اضافه کنیم.
روش افزودن المانهای جدید توسط جیکوئری:
var $flavors = $('.flavors'); // add two new flavors $('<li>pistachio</li>').appendTo($flavors); $('<li>neapolitan</li>').appendTo($flavors);
// remove the "gelato" type $('.types li:last').remove();
روش افزودن المانهای جدید توسط جاوا اسکریپت خالص:
var flavors = document.querySelector('.flavors'); // add two new flavors flavors.insertAdjacentHTML('beforeend', '<li>pistachio</li>') flavors.insertAdjacentHTML('beforeend', '<li>neapolitan</li>')
// remove the "gelato" type document.querySelector('.types li:last-child').remove();
روش دیگر انجام اینکار به صورت زیر توسط متد removeChild است:
var gelato = document.querySelector('.types li:last-child'); // remove the "gelato" type gelato.parentNode.removeChild(gelato);
کار با المانهای متنی
در جیکوئری متد ()text آن امکان دریافت محتوای متنی و همچنین به روز رسانی آنرا میسر میکند:
$('.types li').eq(1).text('italian ice');
در جاوا اسکریپت خالص، دو خاصیت textContent و همچنین innerText برای خواندن و یا به روز رسانی محتوای متنی عناصر مورد استفاده قرار میگیرند. برای مثال معادل قطعه کد جیکوئری فوق که از متد text استفاده میکند با جاوا اسکریپت خالص به صورت زیر است:
document.querySelectorAll('.types li')[1].textContent = 'italian ice';
خاصیت innerText هرچند بر روی اینترفیس HTMLElement تعریف شدهاست، اما جزء هیچکدام از استانداردهای وب نیست؛ ولی توسط تمام مرورگرهای امروزی پشتیبانی میشود. در این حالت به روز رسانی متن توسط آن با خاصیت textContent دقیقا یکی است؛ اما خروجی آن برعکس حالتهای قبل، متن رندر شدهی المانها را بازگشت میدهد. برای مثال در اینجا شامل فاصلههای پیش از این المانها در markup نمیشود.
برای مثال این قسمتی از خروجی خاصیت textContent است:
Flavors chocolate vanilla rocky road strawberry
Flavors chocolate vanilla rocky road strawberry
گاهی از اوقات از سرور قطعهای کد HTML ایی را دریافت میکنیم (که هنوز به صورت المان یا المانهای DOM در نیامدهاست) و در سمت کلاینت میخواهیم آنرا به قسمتی از صفحه اضافه کنیم. روش انجام اینکار در jQuery به صورت زیر است:
var container = '<h2>Containers</h2><ul><li>cone</li><li>cup</li></ul>'; $('<div>').html(container).appendTo('body');
روش دریافت محتوای رشتهای HTML قابل ارسال به سرور نیز به صورت زیر است:
var contents = $('body').html();
var div = document.createElement('div'); div.innerHTML = container; document.body.appendChild(div);
روش خواندن این محتوای نهایی نیز به صورت زیر است:
var contents = document.body.innerHTML;
پشتیبانی توکار از GDPR در ASP.NET Core 2.1
services.ConfigureApplicationCookie(options => { options.LoginPath = "/Users/Login"; // ... options.Cookie = new CookieBuilder { // ... IsEssential = true // this cookie will always be stored regardless of the user's consent }; }); // The following code makes a cookie essential: context.Response.Cookies.Append("Test", "Value", new CookieOptions { IsEssential = true }); // TempData cookies are non-essentials too + Session state cookies services.Configure<CookieTempDataProviderOptions>(options => { options.Cookie.IsEssential = true; });
try { // some code to check ... } catch (InvalidOperationException ex) { // do your handling for invalid operation ... } catch (IOException ex) { // do your handling for IO error ... }
catch (SomeException ex) when (someConditionIsMet) { // Your handler logic }
علاوه بر این در اینجا میتوان چندین بدنهی catch مجزا را به ازای یک نوع استثنای مشخص به همراه whenهای متفاوتی نیز تعریف کرد و از این لحاظ محدودیتی وجود ندارد. فقط در این حالت باید به تقدم و تاخرها دقت داشت. برای نمونه در مثال ذیل، ترکیب چندین شرط متفاوت را بر اساس یک نوع مشخص استثناء، مشاهده میکنید. در اینجا اگر برای نمونه شرط ذکر شدهی در قسمت when مربوط به catch اولی صادق باشد، همینجا کار خاتمه مییابد و سایر catchها بررسی نمیشوند:
catch (SomeDependencyException ex) when (condition1 && condition2) { } catch (SomeDependencyException ex) when (condition1) { } catch (SomeDependencyException ex) { }
catch (SomeDependencyException ex) { } catch (SomeDependencyException ex) when (condition1 && condition2) { } catch (SomeDependencyException ex) when (condition1) { }
لاگ کردن استثناءها در C# 6 بدون مدیریت آنها
به مثال ذیل دقت کنید:
try { DoSomethingThatMightFail(s); } catch (Exception ex) when (Log(ex, "An error occurred")) { // this catch block will never be reached } ... static bool Log(Exception ex, string message, params object[] args) { Debug.Print(message, args); return false; }
تفاوت C# 6 - Exception Filtering با if/else نوشتن در بدنهی catch چیست؟
تا اینجا به این نتیجه رسیدیم که کدهای if/else دار داخل بدنهی catch کدهای قدیمی را مانند کد ذیل:
try { var request = WebRequest.Create("http://www.google.coom/"); var response = request.GetResponse(); } catch (WebException we) { if (we.Status == WebExceptionStatus.NameResolutionFailure) { //handle DNS error return; } if (we.Status == WebExceptionStatus.ConnectFailure) { //handle connection error return; } throw; }
try { var request = WebRequest.Create("http://www.google.coom/"); var response = request.GetResponse(); } catch (WebException we) when (we.Status == WebExceptionStatus.NameResolutionFailure) { //Handle NameResolutionFailure Separately } catch (WebException we) when (we.Status == WebExceptionStatus.ConnectFailure) { //Handle ConnectFailure Separately }
به این معنا که exception filters سبب Stack unwinding نمیشوند. با هربار ورود به بدنهی catch، اصطلاحا عملیات Stack unwinding صورت میگیرد. یعنی اطلاعات stack مربوط به متدهای پیش از فراخوانی متدی که سبب بروز استثناء شدهاست، از بین میروند. به این ترتیب تشخیص مقادیر متغیرهایی که سبب بروز این استثناء شدهاند نیز میسر نخواهد بود و دیگر نمیتوان با قطعیت عنوان کرد که چه مقادیری و چه اطلاعاتی سبب بروز این مشکل شدهاند. اما در حالت exception filters در قسمت when آن هنوز وارد بدنهی catch نشدهایم. در اینجا دسترسی کاملی به اطلاعات stack جاری و مقادیر متغیرهای محلی که سبب بروز این استثناء شدهاند وجود دارد.
تفاوت stack با stack trace چیست؟ stack قطعهای از حافظهاست که اطلاعاتی در مورد نحوهی فراخوانی متدها، آدرس بازگشتی آنها، آرگومان و همچنین متغیرهای محلی آنها را دارا است. اما stack trace تنها یک رشتهاست و بیانگر نام متدهایی است که هم اکنون بر روی stack قرار دارند. احتمالا پیشتر خوانده بودید که فراخوانی throw داخل بدنهی catch سبب حفظ stack trace میشود و اگر throw ex صورت گیرد، این اطلاعات از دست میروند و بازنویسی میشوند. اما در C# 6 امکان حفظ کل اطلاعات stack به همراه exception filtering میسر شدهاست.
.NET Core SDK | .NET Core Runtime | Compatible Visual Studio | MSBuild | Notes |
---|---|---|---|---|
2.1.5nn | 2.1 | 2017 | 15 | Installed as part of VS 2017 version 15.9 |
2.1.6nn | 2.1 | 2019 | 16 | Installed as part of VS 2019 |
2.2.1nn | 2.2 | 2017 | 15 | Installed manually |
2.2.2nn | 2.2 | 2019 | 16 | Installed as part of VS 2019 |
3.0.1nn | 3.0 (Preview) | 2019 | 16 | Installed manually |
Visual Studio 2017 cannot work with .NET Core SDK 2.1.6nn or 2.2.2nn.
تفکر درباره mvc 5,mvc 6,mvc flash 3
Over five years ago I released MvcFlash, and soon after I released the second iteration MvcFlash2. Don't let the terrible naming and versioning fool you, this is one of my favorite creations. As ASP.NET 5 starts to take root and MVC 6 blossoms, I begin to feel more confident about creating the next version of MvcFlash. Honestly, I can't see developing an MVC application without it. Before I do, I thought I would muse about the possible challenges ahead.