مطالب
تغییر PartCreationPolicy پیش فرض در MEF
تشریح مسئله : در MEF به صورت پیش فرض نوع نمونه ساخته شده از اشیا به صورت Singleton است. در صورتی که بخواهیم یک نمونه جدید از اشیا به ازای هر درخواست ساخته شود باید PartCreationPolicyAttribute رو به ازای هر کلاس مجددا تعریف کنیم و نوع اون رو به NonShared تغییر دهیم. در پروژه‌های بزرگ این مسئله کمی آزار دهنده است. برای تغییر رفتار Container در MEF هنگام نمونه سازی Object‌ها باید چه کار کرد؟

نکته: آشنایی با مفاهیم MEF برای درک بهتر مطالب الزامی است.

*در صورتی که با مفاهیم MEF آشنایی ندارید می‌توانید از اینجا شروع کنید.

در MEF سه نوع PartCreationPolicy وجود دارد:
#1 Shared : آبجکت مورد نظر فقط یک بار در کل طول عمر Composition Container ساخته می‌شود.(Singleton)
#2 NonShared : آبجکت مورد نظر به ازای هر درخواست دوباره نمونه سازی می‌شود.
#3 Any : از حالت پیش فرض CompositionContainar برای نمونه سازی استفاده میشود که همان مورد اول است(Shared)

در اکثر پروژه‌ها ساخت نمونه اشیا به صورت Singleton میسر نیست و باعث اشکال در پروژه می‌شود. برای حل این مشکل باید PartCreationPolicy رو برای هر شی مجزا تعریف کنیم. برای مثال
    [Export]
    [PartCreationPolicy( CreationPolicy.NonShared )] 
    internal class ShellViewModel : ViewModel<IShellView>
    {
        private readonly DelegateCommand exitCommand;


        [ImportingConstructor]
        public ShellViewModel( IShellView view )
            : base( view )
        {
            exitCommand = new DelegateCommand( Close );
        }
    }
حال فرض کنید تعداد آبجکت شما در یک پروژه بیش از چند صد تا باشد. در صورتی که یک مورد را فراموش کرده باشید  و  UnitTest قوی و مناسب در پروژه تعبیه نشده باشد قطعا در طی پروژه مشکلاتی به وجود خواهد آمد و امکان Debug سخت خواهد شد.
برای حل این مسئله بهتر است که رفتار Composition Container رو در هنگام نمونه سازی تغییر دهیم. یعنی آبجکت‌ها به صورت پیش فرض به صورت NonShared تولید شوند و در صورت نیاز به نمونه Shared این Attribute رو در کلاس مورد نظر استفاده کنیم. کافیست از کلاس Composition Container که قلب MEF محسوب می‌شود ارث برده و رفتار مورد نظر را Override کنیم. برای نمونه :
public class CustomCompositionContainer : CompositionContainer
{
    public CustomCompositionContainer(ComposablePartCatalog catalog)
        : base(catalog)
    {
    }

    protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition)
    {
        definition = AdaptDefinition(definition);
        
        return base.GetExportsCore(definition);
    }

    private ImportDefinition AdaptDefinition(ImportDefinition definition)
    {
        ContractBasedImportDefinition namedDefinition = definition as ContractBasedImportDefinition;
        if (namedDefinition != null && namedDefinition.RequiredCreationPolicy == CreationPolicy.Any)
        {   
            definition = new ContractBasedImportDefinition(namedDefinition.ContractName,
                                                           namedDefinition.RequiredMetadata,
                                                           namedDefinition.Cardinality,
                                                           namedDefinition.IsRecomposable,
                                                           namedDefinition.IsPrerequisite,
                                                         CreationPolicy.NonShared);
        }

        return definition;
    }
}
مشاهده می‌کنید که متد GetExportCore در کلاس بالا Override شده است و توسط متد AdaptDefinition اگر PartCreationPolicy به صورت Any بود نمونه ساخته شده به صورت NonShared ایجاد می‌شود.
حال فقط کافیست در پروژه به جای استفاده از CompositionContainer از CustomCompositionContainer استفاده کنیم.
مطالب
ویدئوی آموزش مقدمات CodeFirst در قالب یک کلاس آموزشی به همراه مثال
این ویدئو به مدت حدوداً یکساعت و حجمی حدود 50 مگابایت، مربوط به یک کلاس آموزشی است که در ضمن آن به بررسی مقدماتی چگونگی بکاربردن روش CodeFirst برای تولید دیتابیس و جداول آن، پرداخته‌ام. پیشاپیش از نواقص و نارسایی‌های احتمالی آن، پوزش می‌طلبم.
سرفصل مطالبی که بطور مختصر مطرح شده‌اند، عبارتند از:
  • معرفی EF CodeFirst و کاربرد آن
  • استفاده از Nuget Package Manager  برای افزودن EntityFrameWork
  • ایجاد کلاس نمونه  User  و معرفی DbContext جهت معرفی کلاس User  به عنوان جدولی از دیتابیس
  • ایجاد ConnectionString  و نکات مربوط به آن برای ایجاد صحیح جداول  در SQL Server
  • چگونگی ایجاد فیلد کلیدی
  • روش ذخیره سازی اطلاعات در جدول
  • روش ایجاد رابطه یک به چند با ایجاد دو جدول کمکی Log و Work و مرتبط با جدول User
  • روش جستجو  در جداول بدون استفاده مستقیم از SQL Query


نظرات مطالب
5 دلیل برای استفاده از یک ابزار ORM
سؤال شما به موضوع بحث مرتبط نیست. آیا جایی در مقاله به typed dataset‌ اشاره شده یا کار نقد orm های مختلف صورت گرفته؟ ... بگذریم.

در مورد typed dataset ها ، بله نسبتا تا حدودی و تا حد نازلی بله! شبه ORM هستند که این مشکلات را دارند:
- مشکل Synchronization بین آن‌ها و دیتابیس مساله ساز است که در یک ORM‌ خوب باید این مساله حل شده باشد.
- join table queries در طراح آن کار نمی‌کند!
- query syntax استانداردی نداشته و هنگام کار با دیتابیس‌های مختلف (نوع‌های مختلف) این مورد مساله ساز می‌شود.
- typed dataset کمتر حال و هوای یک ORM واقعی و دنیای شیء گرایی با اشیایی که وابستگی کمی به دیتابیس دارند را ارائه می‌دهد.
- کلا dataset اشیایی با سربار بالا در دات نت فریم ورک مطرح هستند و زمانیکه کارآیی مطرح هست سعی می‌شود به روش‌هایی دیگری کوچ شود.
همچنین از لحاظ مباحث serialization هم بسیار ضعیف و کند عمل می‌کنند.
- زمانیکه از typed dataset استفاده می‌کنید عملا مدل رابطه‌ای دیتابیس خود را با business layer مخلوط کرده‌اید.
مطالب
تهیه پردازنده‌های سفارشی برای HTMLWorker کتابخانه iTextSharp
پیشنیاز
«تبدیل HTML به PDF با استفاده از کتابخانه‌ی iTextSharp»

هرچند کلاس HTMLWorker دیگر توسعه نخواهد یافت (با کتابخانه XML Worker جایگزین شده‌است)، اما برای تبدیل یک سری از کارهای ابتدایی بسیار مناسب است. در این بین اگر تگ خاصی توسط کلاس HTMLWorker پشتیبانی نشود یا پیاده سازی آن ناقص باشد، امکان جایگزین کردن کامل آن با پیاده سازی اینترفیس IHTMLTagProcessor وجود دارد. در کدهای ذیل نحوه جایگزین کردن پردازش کننده تصاویر آن‌را ملاحظه می‌کنید. در اینجا پشتیبانی از تصاویر base64 مدفون شده در صفحات html به آن اضافه شده است:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.html;
using iTextSharp.text.html.simpleparser;
using iTextSharp.text.pdf;

namespace CustomHtmlWorkerTag
{
    /// <summary>
    /// Our custom HTML Tag to add an IElement.
    /// </summary>
    public class CustomImageHTMLTagProcessor : IHTMLTagProcessor
    {
        /// <summary>
        /// Tells the HTMLWorker what to do when a close tag is encountered.
        /// </summary>
        public void EndElement(HTMLWorker worker, string tag)
        {
        }

        /// <summary>
        /// Tells the HTMLWorker what to do when an open tag is encountered.
        /// </summary>
        public void StartElement(HTMLWorker worker, string tag, IDictionary<string, string> attrs)
        {
            Image image;
            var src = attrs["src"];

            if (src.StartsWith("data:image/"))
            {
                // data:[<MIME-type>][;charset=<encoding>][;base64],<data>
                var base64Data = src.Substring(src.IndexOf(",") + 1);
                var imagedata = Convert.FromBase64String(base64Data);
                image = Image.GetInstance(imagedata);
            }
            else
            {
                image = Image.GetInstance(src);
            }

            worker.UpdateChain(tag, attrs);
            worker.ProcessImage(image, attrs);
            worker.UpdateChain(tag);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            using (var pdfDoc = new Document(PageSize.A4))
            {
                PdfWriter.GetInstance(pdfDoc, new FileStream("Test.pdf", FileMode.Create));
                pdfDoc.Open();

                FontFactory.Register("c:\\windows\\fonts\\tahoma.ttf");

                var tags = new HTMLTagProcessors();
                // Replace the built-in image processor
                tags[HtmlTags.IMG] = new CustomImageHTMLTagProcessor();

                var html = "<img alt='' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAodJREFUeNpsk0tME1EUhv87UwlCREhRFpi4cGMMRrTE4MaoxBhAsDyMssFHfCQu3BlXGuNKNy5NmqALoqEEMJWCgEUjYojllSpofIUNBNqmIKU6OnQennunUxvgJF86957z/+d27hkGigMlDJfOAmV7AcYsKGqIZljRSvhNE+CMTwEtXmBy2gQb7mCQJUBKkTIQYtfJYCNMAxO9hzq5CYmFiWFY6ISE9VFLRedc1SONeqwf+uJLuKreNPI9nltbLG0orhpqUCM90DRVoEbJ5MSLho1MMg1O0bHOuyoD9crCcxL+xa0HqwL+rEQHsb/CW89reO1aAyEuq+yp+zXvg66rgng8LrDXSmwYpUc8dZkmDsJNL+NCeVVXbWK+O32cpJ7E6OgkwuEwrl8phaHrVsfYD+x03XTPjN3nzZnD0HGxvPppTSLcLwo0I4lldRFK8jdCoZBlJquAbBnr0BD9GUTRvubahclW5qDukqkpIqlodGQ1At3UxZXaIUvauqsyjBV+jZJEJ3s83HO5j+UWI7E6C4mp2EQCTixyV2CvbbKzNmN2zNfHtbzPM3p4FOy/M5CXtwsOKZmmsOi2IHMvyyFhJhgY4BqutQ/aRRstocEngZzswnQnO+x1lqTjy8hIgNdyDc+x5nomxrKJhpcSp2lSrx48WlZhGArynG5hsLLoE7/jQ59f0aR7ZBkdbf7U6Ge+mKYaBvdx8wwZXjtWvfswfTrp3Over29J8NAXYO1t/v/7csZA5U5/Q35nH+aKt8OMR2POPSUFOyRmorvje3BiCt4b9zBANTmwGvP/aMoZRluJbURB8APmnPlQliNLzk8flxbeh9Du8eId5bYQ2SnxH36b/wQYABNFRsIaESsTAAAAAElFTkSuQmCC' />";

                var styles = new StyleSheet();
                styles.LoadTagStyle(HtmlTags.BODY, HtmlTags.FONTFAMILY, "tahoma");
                styles.LoadTagStyle(HtmlTags.BODY, HtmlTags.ENCODING, "Identity-H");

                PdfPCell pdfCell = new PdfPCell { Border = 0 };
                pdfCell.RunDirection = PdfWriter.RUN_DIRECTION_LTR;

                using (var reader = new StringReader(html))
                {
                    var parsedHtmlElements = HTMLWorker.ParseToList(reader, styles, tags, null);

                    foreach (var htmlElement in parsedHtmlElements)
                    {
                        pdfCell.AddElement(htmlElement);
                    }
                }

                var table1 = new PdfPTable(1);
                table1.AddCell(pdfCell);
                pdfDoc.Add(table1);
            }

            Process.Start("Test.pdf");
        }
    }
}
همانطور که ملاحظه می‌کنید، پس از پیاده سازی اینترفیس IHTMLTagProcessor و تهیه یک پردازش کننده جدید که اینبار می‌تواند تصاویر شروع شده با data:image را مورد استفاده قرار دهد، برای معرفی آن به کتابخانه HTMLWorker فقط کافی است وهله‌ای از HTMLTagProcessors موجود را ایجاد نمائیم و سپس در این Dictionary، نمونه قدیمی را جایگزین کنیم:
var tags = new HTMLTagProcessors();
// Replace the built-in image processor
tags[HtmlTags.IMG] = new CustomImageHTMLTagProcessor();
در ادامه فقط کافی است لیست جدید پردازنده‌ها را به متد ParseToList ارسال نمائیم تا مورد استفاده قرار گیرد:
HTMLWorker.ParseToList(reader, styles, tags, null)

نظرات مطالب
آپلود فایل توسط فرم‌های پویای jqGrid
این خطا چند علت می‌تواند داشته باشد:
الف) فایل jQuery به صفحه اضافه نشده‌است.
ب) فایل jQuery چندین بار به صفحه اضافه شده‌است. برای مثال یکبار توسط تعریف مستقیم و یکبار توسط تعریفی مانند بوت استرپ و bundling آن. این مورد تداخل ایجاد می‌کند.
ج) ترتیب معرفی اسکریپت‌ها رعایت نشده‌است. برای مثال قسمت render section، قبل از قسمت تعریف اسکریپت‌های اصلی آمده‌است یا اینکه ترتیب تعریف مدخل ajaxfileupload.js، مانند مثال فوق نیست.
مطالب
استفاده از shim و stub برای mock کردن در آزمون واحد
مقدمه:
از آنجایی که در این سایت در مورد shim و stub صحبتی نشده دوست داشتم مطلبی در این باره بزارم. در آزمون واحد ما نیاز داریم که یک سری اشیا را moq کنیم تا بتوانیم آزمون واحد را به درستی انجام دهیم. ما در آزمون واحد نباید وابستگی به لایه‌های پایین یا بالا داشته باشیم پس باید مقلدی از object هایی که در سطوح مختلف قرار دارند بسازیم.
شاید برای کسانی که با آزمون واحد کار کردند، به ویژه با فریم ورک تست Microsoft، یک سری مشکلاتی با mock کردن اشیا با استفاده از Mock داشته اند که حالا می‌خواهیم با معرفی فریم ورک‌های جدید، این مشکل را حل کنیم.
برای اینکه شما آزمون واحد درستی داشته باشید باید کارهای زیر را انجام دهید:
1- هر objectی که نیاز به mock کردن دارد باید حتما یا non-static باشد، یا اینترفیس داشته باشد.
2- شما احتیاج به یک فریم ورک تزریق وابستگی‌ها دارید که به عنوان بخشی از معماری نرم افزار یا الگوهای مناسب شی‌ءگرایی مطرح است، تا عمل تزریق وابستگی‌ها را انجام دهید.
3- ساختارها باید برای تزریق وابستگی در اینترفیس‌های object‌های وابسته تغییر یابند.

Shims و Stubs:
نوع stub همانند فریم ورک mock می‌باشد که برای مقلد ساختن اینترفیس‌ها و کلاس‌های non-sealed virtual یا ویژگی ها، رویدادها و متدهای abstract استفاده می‌شود. نوع shim می‌تواند کارهایی که stub نمی‌تواند بکند انجام دهد یعنی برای مقلد ساختن کلاس‌های static یا متدهای non-overridable استفاده می‌شود. با مثال‌های زیر می‌توانید با کارایی بیشتر shim و stub آشنا شوید.
یک پروژه mvc ایجاد کنید و نام آن را FakingExample بگذارید. در این پروژه کلاسی با نام CartToShim به صورت زیر ایجاد کنید:
namespace FakingExample
{
    public class CartToShim
    {
        public int CartId { get; private set; }
        public int UserId { get; private set; }
        private List<CartItem> _cartItems = new List<CartItem>();
        public ReadOnlyCollection<CartItem> CartItems { get; private set; }
        public DateTime CreateDateTime { get; private set; }
 
        public CartToShim(int cartId, int userId)
        {
            CartId = cartId;
            UserId = userId;
            CreateDateTime = DateTime.Now;
            CartItems = new ReadOnlyCollection<CartItem>(_cartItems);
        }
 
        public void AddCartItem(int productId)
        {
            var cartItemId = DataAccessLayer.SaveCartItem(CartId, productId);
            _cartItems.Add(new CartItem(cartItemId, productId));
        }
    }
}
و همچنین کلاسی با نام CartItem به صورت زیر ایجاد کنید:
public class CartItem
    {
        public int CartItemId { get; private set; }
        public int ProductId { get; private set; }
 
        public CartItem(int cartItemId, int productId)
        {
            CartItemId = cartItemId;
            ProductId = productId;
        }
    }
حالا یک پروژه unit test را با نام FakingExample.Tests اضافه کرده و نام کلاس آن را CartToShimTest بگذارید. یک reference از پروژه FakingExample تان به پروژه‌ی تستی که ساخته اید اضافه کنید. برای اینکه بتوانید کلاس‌های پروژه FakingExample را shim و یا stub کنید باید بر روی Reference پروژه تان راست کلیک کنید و گزینه Add Fakes Assembly را انتخاب کنید. وقتی این گزینه را می‌زنید، پوشه ای با نام Fakes در پروژه تست ایجاد شده و FakingExample.fakes در داخل آن قرار دارد همچنین در reference‌های پروژه تست، FakingExample.Fakes نیز ایجاد می‌شود.
اگر بر روی فایل fakes که در reference ایجاد شده دوبار کلیک کنید می‌توانید کلاس‌های CartItem و CartToShim را مشاهده کنید که هم نوع stub شان است و هم نوع shim آنها که در تصویر زیر می‌توانید مشاهده کنید.

ShimDataAccessLayer را که مشاهده می‌کنید یک متد SaveCartItem دارد که به دیتابیس متصل شده و آیتم‌های کارت را ذخیره می‌کند.

حالا می‌توانیم تست خود را بنویسیم. در زیر یک نمونه از تست را مشاهده می‌کنید:

[TestMethod]
        public void AddCartItem_GivenCartAndProduct_ThenProductShouldBeAddedToCart()
        {
            //Create a context to scope and cleanup shims
            using (ShimsContext.Create())
            {
                int cartItemId = 42, cartId = 1, userId = 33, productId = 777;
 
                //Shim SaveCartItem rerouting it to a delegate which 
                //always returns cartItemId
                Fakes.ShimDataAccessLayer.SaveCartItemInt32Int32 = (c, p) => cartItemId;
 
                var cart = new CartToShim(cartId, userId);
                cart.AddCartItem(productId);
 
                Assert.AreEqual(cartId, cart.CartItems.Count);
                var cartItem = cart.CartItems[0];
                Assert.AreEqual(cartItemId, cartItem.CartItemId);
                Assert.AreEqual(productId, cartItem.ProductId);
            }
        }
همانطور که در بالا مشاهده می‌کنید کدهای تست ما در اسکوپی قرار گرفته اند که محدوده shim را تعیین می‌کند و پس از پایان یافتن تست، تغییرات shim به حالت قبل بر می‌گردد. متد SaveCartItemInt32Int32 را که مشاهده می‌کنید یک متد static است و نمی‌توانیم با mock ویا stub آن را مقلد کنیم. تغییر اسم متد SaveCartItem به SaveCartItemInt32Int32 به این معنی است که متد ما دو ورودی از نوع Int32 دارد و به همین خاطر fake این متد به این صورت ایجاد شده است. مثلا اگر شما متد Save ای داشتید که یک ورودی Int و یک ورودی String داشت fake آن به صورت SaveInt32String ایجاد می‌شد.

به این نکته توجه داشته باشید که حتما برای assert کردن باید assert‌ها را در داخل اسکوپ ShimsContext قرار گرفته باشد در غیر این صورت assert شما درست کار نمی‌کند.

این یک مثال از shim بود؛ حالا می‌خواهم مثالی از یک stub را برای شما بزنم. یک اینترفیس با نام ICartSaver به صورت زیر ایجاد کنید:

public interface ICartSaver
    {
        int SaveCartItem(int cartId, int productId);
    }
برای shim کردن ما نیازی به اینترفیس نداشتیم اما برای استفاده از stub و یا Mock ما حتما به یک اینترفیس نیاز داریم تا بتوانیم object موردنظر را مقلد کنیم. حال باید یک کلاسی با نام CartSaver برای پیاده سازی اینترفیس خود بسازیم:
public class CartSaver : ICartSaver
    {
        public int SaveCartItem(int cartId, int productId)
        {
            using (var conn = new SqlConnection("RandomSqlConnectionString"))
            {
                var cmd = new SqlCommand("InsCartItem", conn);
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.AddWithValue("@CartId", cartId);
                cmd.Parameters.AddWithValue("@ProductId", productId);
 
                conn.Open();
                return (int)cmd.ExecuteScalar();
            }
        }
    }
حال تستی که با shim انجام دادیم را با استفاده از Stub انجام می‌دهیم:
[TestMethod]
        public void AddCartItem_GivenCartAndProduct_ThenProductShouldBeAddedToCart()
        {
            int cartItemId = 42, cartId = 1, userId = 33, productId = 777;
 
            //Stub ICartSaver and customize the behavior via a 
            //delegate, ro return cartItemId
            var cartSaver = new Fakes.StubICartSaver();
            cartSaver.SaveCartItemInt32Int32 = (c, p) => cartItemId;
 
            var cart = new CartToStub(cartId, userId, cartSaver);
            cart.AddCartItem(productId);
 
            Assert.AreEqual(cartId, cart.CartItems.Count);
            var cartItem = cart.CartItems[0];
            Assert.AreEqual(cartItemId, cartItem.CartItemId);
            Assert.AreEqual(productId, cartItem.ProductId);
        }
امیدوارم که این مطلب برای شما مفید بوده باشد.
مطالب
فیلدهای پویا در NHibernate

یکی از قابلیت‌های جالب NHibernate امکان تعریف فیلدها به صورت پویا هستند. به این معنا که زیرساخت طراحی یک برنامه "فرم ساز" هم اکنون در اختیار شما است! سیستمی که امکان افزودن فیلدهای سفارشی را دارا است که توسط برنامه نویس در زمان طراحی اولیه آن ایجاد نشده‌اند. در ادامه نحوه‌ی تعریف و استفاده از این قابلیت را توسط Fluent NHibernate بررسی خواهیم کرد.

در اینجا کلاسی که قرار است توانایی افزودن فیلدهای سفارشی را داشته باشد به صورت زیر تعریف می‌شود:
using System.Collections;

namespace TestModel
{
public class DynamicEntity
{
public virtual int Id { get; set; }
public virtual IDictionary Attributes { set; get; }
}
}

Attributes در عمل همان فیلدهای سفارشی مورد نظر خواهند بود. جهت معرفی صحیح این قابلیت نیاز است تا نگاشت آن‌را از نوع dynamic component تعریف کنیم:
using FluentNHibernate.Automapping;
using FluentNHibernate.Automapping.Alterations;

namespace TestModel
{
public class DynamicEntityMapping : IAutoMappingOverride<DynamicEntity>
{
public void Override(AutoMapping<DynamicEntity> mapping)
{
mapping.Table("tblDynamicEntity");
mapping.Id(x => x.Id);
mapping.IgnoreProperty(x => x.Attributes);
mapping.DynamicComponent(x => x.Attributes,
c =>
{
c.Map(x => (string)x["field1"]);
c.Map(x => (string)x["field2"]).Length(300);
c.Map(x => (int)x["field3"]);
c.Map(x => (double)x["field4"]);
});
}
}
}
و مهم‌ترین نکته‌ی این بحث هم همین نگاشت فوق است.
ابتدا از IgnoreProperty جهت ندید گرفتن Attributes استفاده کردیم. زیرا درغیراینصورت در حالت Auto mapping ، یک رابطه چند به یک به علت وجود IDictionary به صورت خودکار ایجاد خواهد شد که نیازی به آن نیست (یافتن این نکته نصف روز کار برد ....! چون مرتبا خطای An association from the table DynamicEntity refers to an unmapped class: System.Collections.Idictionary ظاهر می‌شد و مشخص نبود که مشکل از کجاست).
سپس Attributes به عنوان یک DynamicComponent معرفی شده است. در اینجا چهار فیلد سفارشی را اضافه کرده‌ایم. به این معنا که اگر نیاز باشد تا فیلد سفارشی دیگری به سیستم اضافه شود باید یکبار Session factory ساخته شود و SchemaUpdate فراخوانی گردد و خوشبختانه با وجود Fluent NHibernate ، تمام این تغییرات در کدهای برنامه قابل انجام است (بدون نیاز به سر و کار داشتن با فایل‌های XML نگاشت‌ها و ویرایش دستی آن‌ها). از تغییر نام جدول که برای مثال در اینجا tblDynamicEntity در نظر گرفته شده تا افزودن فیلدهای دیگر در قسمت DynamicComponent فوق.
همچنین باتوجه به اینکه این نوع تغییرات (ساخت دوبار سشن فکتوری) مواردی نیستند که قرار باشد هر ساعت انجام شوند، بنابراین سربار آنچنانی را به سیستم تحمیل نمی‌کنند.
   drop table tblDynamicEntity

create table tblDynamicEntity (
Id INT IDENTITY NOT NULL,
field1 NVARCHAR(255) null,
field2 NVARCHAR(300) null,
field3 INT null,
field4 FLOAT null,
primary key (Id)
)

اگر با SchemaExport، اسکریپت خروجی معادل با نگاشت فوق را تهیه کنیم به جدول فوق خواهیم رسید. نوع و طول این فیلدهای سفارشی بر اساس نوعی که برای اشیاء دیکشنری مشخص می‌کنید، تعیین خواهند شد.

چند مثال جهت کار با این فیلدهای سفارشی یا پویا :

نحوه‌ی افزودن رکوردهای جدید بر اساس خاصیت‌های سفارشی:
//insert
object savedId = 0;
using (var session = sessionFactory.OpenSession())
{
using (var tx = session.BeginTransaction())
{
var obj = new DynamicEntity();
obj.Attributes = new Hashtable();
obj.Attributes["field1"] = "test1";
obj.Attributes["field2"] = "test2";
obj.Attributes["field3"] = 1;
obj.Attributes["field4"] = 1.1;

savedId = session.Save(obj);
tx.Commit();
}
}

با خروجی
INSERT
INTO
tblDynamicEntity
(field1, field2, field3, field4)
VALUES
(@p0, @p1, @p2, @p3);
@p0 = 'test1' [Type: String (0)], @p1 = 'test2' [Type: String (0)], @p2 = 1
[Type: Int32 (0)], @p3 = 1.1 [Type: Double (0)]

نحوه‌ی کوئری گرفتن از این اطلاعات (فعلا پایدارترین روشی را که برای آن یافته‌ام استفاده از HQL می‌باشد ...):
//query
using (var session = sessionFactory.OpenSession())
{
using (var tx = session.BeginTransaction())
{
//using HQL
var list = session
.CreateQuery("from DynamicEntity d where d.Attributes.field1=:p0")
.SetString("p0", "test1")
.List<DynamicEntity>();

if (list != null && list.Any())
{
Console.WriteLine(list[0].Attributes["field2"]);
}
tx.Commit();
}
}
با خروجی:
    select
dynamicent0_.Id as Id1_,
dynamicent0_.field1 as field2_1_,
dynamicent0_.field2 as field3_1_,
dynamicent0_.field3 as field4_1_,
dynamicent0_.field4 as field5_1_
from
tblDynamicEntity dynamicent0_
where
dynamicent0_.field1=@p0;
@p0 = 'test1' [Type: String (0)]

استفاده از HQL هم یک مزیت مهم دارد: چون به صورت رشته قابل تعریف است، به سادگی می‌توان آن‌را داخل دیتابیس ذخیره کرد. برای مثال یک سیستم گزارش ساز پویا هم در این کنار طراحی کرد ....

نحوه‌ی به روز رسانی و حذف اطلاعات بر اساس فیلدهای پویا:
//update
using (var session = sessionFactory.OpenSession())
{
using (var tx = session.BeginTransaction())
{
var entity = session.Get<DynamicEntity>(savedId);
if (entity != null)
{
entity.Attributes["field2"] = "new-val";
tx.Commit(); // Persist modification
}
}
}

//delete
using (var session = sessionFactory.OpenSession())
{
using (var tx = session.BeginTransaction())
{
var entity = session.Get<DynamicEntity>(savedId);
if (entity != null)
{
session.Delete(entity);
tx.Commit();
}
}
}

اشتراک‌ها
کپی کردن فایل mdf و ldf در حالی که سیستم در حال اجرا می‌باشد

برای کپی کردن فایل mdf و فایل ldf ، یک بانک اطلاعاتی ، بدون این که سرویس SQL Server را متوقف کنیم و یا این که آن بانک اطلاعاتی را Detach کنیم ، می‌توانیم از نرم افزار HoboCopy.exe استفاده نمایید . برای این کار ابتدا این فایل را در یک مسیری کپی نمایید . به طور مثال آن را در مسیر C:\Windows\System32 کپی کنید . سپس وارد PowerShell شوید . البته باید به صورت Run as administrator این کار را انجام دهید .
سپس در آن مسیر نام فایل اجرای HoboCopy و سپس آدرس فایل مبداء (آدرس فایل‌های بانک اطلاعاتی) و در نهایت آدرس فولدری که بناست اطلاعات mdf و ldf در آنجا کپی شوند . i:\MyDB آدرس مبداء می‌باشد و آدرس i:\My ، آدرس مقصد می‌باشد . 

کپی کردن فایل mdf و ldf در حالی که سیستم در حال اجرا می‌باشد
مطالب
بررسی امکانات Bootstrap 4
دنیای وب کلاینت، در اواخر سال میلادی جاری دستخوش تغییرات بسیاری خواهد شد. از جهتی JavaScript با بروز رسانی موتور خود با نام و نسخه‌ی javascript ecmascript 6 ظاهرا قصد دارد تا تغییرات شگرفی را در دنیای اسکریپتی آشفته‌ی کلاینت بدهد. به همین علت فریم ورک‌های SPA یا single page app همانند AngularJs نیز با به‌روز رسانی نسخه‌ی جاوااسکریپت، ظاهرا مجبورند تا هسته‌ی فریم ورک‌های خود را یک آب و جاروی اساسی کنند. البته AngularJs در نسخه‌های 1.X مشکلاتی داشته است که در نسخه‌ی 2.0 غالب آنها رفع خواهند شد. از طرفی این اتفاقات تنها شامل فریم‌ورک‌های مبتنی بر جاوا‌اسکریپت نمی‌شود و Twitter نیز قصد دارد تا نسخه‌ی جدید Bootstrap را ارائه کند. چند وقتی هست که وب‌سایت رسمی Bootstrap در بالای صفحه‌ی اصلی خود پیغام Aww yeah, Bootstrap 4 is coming را مبنی بر آمدن نسخه‌ی 4 منتشر کرده است.
در این مقاله قصد داریم تا به بررسی امکانات Bootstrap 4 بپردازیم. اطلاعاتی که بنده قصد دارم در اختیار شما قرار دهم، مطالبی است که از چند بلاگ مانند وبلاگ رسمی Bootstrap برداشت شده است.
در ابتدای مطب معرفی Bootstrap 4 alpha این نوشته فروتنانه، شما را مجذوب خود خواهد کرد:
Bootstrap 4 در واقع یک اقدام بزرگ بود که پس از یک سال توسعه، بزرگی این اقدام در خط به خط کدها احساس می‌گردد. تصمیم گرفتیم تا نسخه‌ی اولیه‌ی آن را به اشتراک بگذاریم و انتقادات و پیشنهادات شما را بشنویم. برای بهبود و پیشرفت در این زمینه، بسیاری از اخبار مرتبط را در اختیار شما قرار می‌دهیم. امیدواریم که ما را در بهتر شدن یاری کنید.

امکانات جدید Bootstrap

انتقال از Less به Sass

در نسخه‌ی جدید، شما با استفاده از Sass قادر هستید تا بجای Less، کدهای استایل خود را به این صورت کامپایل و شخصی‌سازی نمایید. البته در Bootstrap 3 این امکان وجود نداشت ولی به صورت جداگانه و البته رسمی منتشر و در GitHub قرار داده شده بود.

بهبود grid system مبتنی بر "rems"

استفاده از سیستم grid همچنان با همان syntax پیشین استفاده می‌شود، اما کمی تغییر در معماری آن حاصل شده است. به عنوان مثال شما هنوز هم قادر به پیاده سازی سیستم مبتنی بر 12 ستون با استفاده از grid، یا تغییر عرض صفحه با استفاده از container و یا سیستم nested rows هستید.
اما چیز جدیدی که اضافه شده در container و یا به نوعی تغییر کلی در گرید بندی بنا به سایز دستگاههای مختلف است. بگذارید با یک مثال ببینیم که کار جدید صورت گرفته به چه شکلی است. در این مثال در Codepen چگونگی تغییر فونت سایز و سپس تغییر container را مشاهده می‌کنید. تا کنون شما قطعا از px، em  و pt برای تغییر ابعاد استفاده کرده‌اید. در bootstrap 4 تمام این اندازه‌ها مبتنی بر واحدی با نام rem است. این مفهوم خیلی آسان و قابل درک است. به این صورت که با استفاده از rem، تمامی font-sizeها وابسته به root element خواهند شد. بنابراین اگر شما یک وب سایت مبتنی بر Bootstrap 4 را Inspect کنید، خواهید دید که HTML tag دارای فونت سایز 16px است و باقی تگ‌ها بر این مقیاس وابسته هستند. به عنوان مثال تگ p دارای فونت سایز 1em است، یعنی همان 16px. و یا تگ h1 به صورت زیر خواهد بود:
h1 { /* 16 * 2.5 = 40px */
}
شاید بتوان گفت که مهم‌ترین دلیل این حرکت، ساده‌تر کردن فرایند بزرگ و کوچک کردن scale برای دستگاه‌های مختلف است. شما به سادگی قادرید که HTML tag را به سایز کوچک‌تر یا بزرگ‌تر تغییر دهید تا تمامی محتویات نیز به همان مقدار تغییر کنند. البته این نکته قابل توجه است که این تغییر از px به واحد rem تنها شامل font-sizeها نبوده و شامل تمامی scalingها مانند margin، padding و ... نیز می‌شود.

تغییر panel و wells به cards

در Bootstrap جدید، مجموعه‌ی پنل‌ها و wellها به یک ساختار جامع‌تر به نام Cards تبدیل گشته‌اند. این مجموعه به عنوان یک container محتویات که هم قابل انعطاف و هم قابل توسعه است معرفی شده است. همانطور که در اسناد مربوط به این مجموعه مشاهده می‌کنید، چندین مجموعه مانند list box‌ها و thumbnailها نیز در Card قرار گرفته‌اند. در این مجموعه، optionهای متفاوتی برای header و footer، و یا حالات متفاوت قرارگیری محتوا، حالت‌های مختلف back ground در نظر گرفته شده است.

Reset Component جایگزینی برای normalize.css

قبلا Bootstrap از Normalize.css جهت reset کردن محتویات css خود استفاده می‌کرد. Normalize در حقیقت یک مجموعه از قوانین CSS مینیفای شده است که تمامی استایل‌های پیش‌فرض مرورگر‌ها را به یک حالت پایدار reset می‌کند. معمولا همه‌ی مرورگر‌ها یک stylesheet از پیش تعریف شده‌ای دارند که برای وب‌سایت‌هایی که هیچ استایلی ندارند معمولا قابل مشاهده است. به عنوان مثال غالب مرورگرها به صورت پیش‌فرض لینک‌ها را به صورت آبی رنگ با underline نمایش می‌دهند و اینکه یک border خاص به جداول می‌دهند. با استفاده از css reset ها، تمامی استایل‌های از پیش تعیین شده‌ی مرورگرها null می‌شوند. این قابلیت به ما کمک می‌کند که راحت‌تر بتوانیم یک صفحه‌ی cross-browser ایجاد نماییم.
حال اینکه در Bootstrap جدید نوعی دیگر جایگزین Normalize شده است که reboot نام نهاده شده و محتویات آن در GitHub  موجود است. به نوعی می‌توان گفت که یک سری base style و resetها در این یک فایل ریخته شده که reboot نام دارد. این امر می‌تواند کمک بسیاری در Customize کردن موارد توسط خود توسعه دهنده کند.
ادامه دارد...