اشتراک‌ها
نگاهی بر CQRS و معماری Message-Based
CQRS الگویی است که مدل Command و Query نرم افزار را از هم جدا میکند. این جداسازی می‌تواند فقط در سطح Application بوده و هم می‌تواند در سطح پایگاه داده باشد. پیاده سازی CQRS در یک نرم افزار Enterprise می‌تواند فواید زیادی مانند انعطاف پذیری، مقیاس پذیری، تمرکز جداگانه بر روی مدل‌ها و ...  در برداشته باشد. در این مقاله آقای Dino Esposito به توضیح الگوی CQRS و معماری Message-Based می‌پردازد.
نگاهی بر CQRS و معماری Message-Based
نظرات مطالب
تاثیر فرهنگ جاری سیستم بر روی اعداد در دات نت
ممنون بابت این مقاله .
در یکی از پروژه هایی که چندین سال پیش نوشته شده بود برای قفل نرم افزار  از کدی شبیه به زیر استفاده شده بود :
Math.Sinh(123456.12).ToString();
قطعه کد فوق در ویندوز‌های قبل از 10 مقدار برگشتی Infinity  را داشت ولی در ویندوز 10 خروجی ∞  را بر میگرداند که باعث خطا در نرم افزار میشد.
برای رفع آن همانطور که در مطلب فوق نیز عنوان شده، با استفاده از کد زیر قابل اصلاح می‌باشد :
Math.Sinh(123456.12).ToString(CultureInfo.InvariantCulture);
نظرات مطالب
طراحی گزارش در Stimulsoft Reports.Net – بخش 2
سلام و خسته نباشید
من هنوز در این بحث گزارش گیری کاملا مبتدی هستم. چون می‌خواستم تازه کارم رو شروع کنم دنبال انتخاب انتخاب نرم افزار مناسب برای گزارشگیری C# در محیط ویندوز بودم. یک سری مطالب کپی شده و تکراری در اینترنت رو دیدم، دوست داشتم نظر تخصصی و شخصی خودتون رو بدونم. من اول دنبال کریستال بودم، ولی بعدش دیدم که ظاهرا استیمول هم نرم افزار معروفیه، میشه کمکم کنید؟
بی نهایت ممنون از سایت خوبتون
نظرات مطالب
استفاده از لوسین برای برجسته سازی عبارت جستجو شده در نتایج حاصل
سلام و خسته نباشید. من از طریق سایت شما با این کتابخونه آشنا شدم. دارم باهاش کار می‌کنم اما یه مشکلی باهاش دارم. و اون اینه که قبلا توی سرچ من اگر کلمه "ما" رو سرچ می‌کردم 2600 تا نتیجه برمیگردوند اما الان 20 تا. چرا؟
و سوال بعد من اینه که چطور می‌تونم ایندکس کلمه پیدا شده توی متن رو پیدا کنم؟ چون نرم افزار خواسته شده رو می‌خوان مثه نرم افزار نور باشه.
ممنون میشم راهنماییم کنید.
تشکر
نظرات مطالب
پایان پروژه ASP.NET Ajax Control Toolkit !
با سلام،
تمام این موارد که مبفرمایید درست، من خودم از طرفداران استقاده از jQuery هستم اما یک مسئله برای من هنوز وجود دارد اون هم RAD است. در یکی از کتابخانه های آژاکسی برای asp.net مثل Anthem.Net
این مسئله خیلی خوب رعایت شده و کار توسعه نرم افزار مبنتی بر استفاده از آژاکس به سرعت انجام میشه. این برای من هنوز سواله با jQuery چطور می توان به این سرعت نرم افزار های Full-Ajax را توسعه داد.
مطالب دوره‌ها
اعمال غیر همزمان و چند ریسمانی
تصور عموم بر آن است که اعمال غیر همزمان با چند ریسمانی به یک معنا هستند. این مورد الزاما صحیح نیست. برای مثال دریافت غیرهمزمان یک فایل را از اینترنت درنظر بگیرید. شاید اینطور به نظر برسد که در اینجا یک ترد جدید ایجاد شده و در آن کل کار دریافت فایل آغاز می‌گردد؛ اما خیر. ایجاد یک ترد جدید تنها در قسمت‌های خاصی از یک پروسه انجام می‌شود. همچنین از لحاظ فنی امکان انجام کل کار در یک ترد، بدون بلاک کردن آن وجود دارد. از این جهت که بیشتر زمان، جهت صبر کردن دریافت پاسخی از سرور صرف می‌شود. زمانیکه کلاینت درخواستی را ارسال می‌کند، دیگر کار خاصی را نمی‌تواند انجام دهد تا اینکه پاسخی را دریافت کند.
زمانیکه از یک API غیرهمزمان برای مدیریت چنین عملیاتی استفاده می‌شود، ترد جاری را در این حالت در خواب فرو می‌برد. برای اینکه کار بیشتری برای انجام وجود ندارد. همچنین با اینکه کلاینت درخواستی را ارسال می‌کند یا پاسخی را دریافت، برای مدیریت کل عملیات در اکثر اوقات نیازی به تردها ندارد. این سخت افزار شبکه‌ی نصب شده در سیستم است که عمده‌ی کار را انجام می‌دهد و نه برنامه. زمانیکه برنامه درخواست ارسال اطلاعاتی را بر روی شبکه ارائه می‌دهد، درایور سخت افزار شبکه است که به سخت افزار مرتبط فرمان می‌دهد چه اطلاعاتی را باید ارسال کند. اکثر اینگونه سخت افزارها قادرند اطلاعات را خارج از حافظه‌ی اصلی سیستم دریافت کنند. در اینجا درایور تنها باید به سخت افزار عنوان کند، چه اطلاعاتی را و به کجا باید ارسال کند. بنابراین CPU تنها در طی ارسال این فرمان است که مشغول می‌باشد و نه خارج از آن و این زمان اصلا در مقایسه با زمان ارسال اطلاعات توسط سخت افزار مرتبط، طولانی نیست. CPU  مجددا زمانی درگیر خواهد شد که سخت افزار شبکه، اطلاعاتی را دریافت کرده است و باز هم این زمان در مقایسه با زمان دریافت اطلاعات توسط سخت افزار شبکه بسیار کوتاه است.
اغلب کارهای IO به همین شکل هستند. شبیه به همین روند در حالت دسترسی به سخت دیسک وجود دارد. مدت زمانیکه CPU به دیسک کنترلر اعلام می‌کند چه اطلاعاتی را نیاز دارد در مقایسه با مدت زمانیکه دیسک کنترلر این اطلاعات را واقعا بارگذاری می‌کند، بسیار ناچیز است.
نمونه‌ی دیگر آن کار با بانک‌های اطلاعاتی است. در اغلب اوقات برنامه‌ی ما صرفا یک درخواست را به بانک اطلاعاتی ارائه می‌دهد و اصل عملیات در جایی دیگر و توسط موتور بانک اطلاعاتی، خارج از برنامه پردازش می‌گردد.
بنابراین جهت پردازش یک پروسه‌ی خاص، در بسیاری از مراحل آن تنها یک ترد کافی است و هدف اصلی اعمال غیرهمزمان، کاهش تعداد تردهایی است که برنامه جهت پردازش عملیاتی خاص، نیاز دارد. این نوع الگوریتم‌ها طوری طراحی شده‌اند تا تردها تنها زمانی بکار گرفته شود که واقعا CPU قرار است کار خاصی را انجام دهد و نه برای مثال زمانیکه دیسک کنترلر یا سخت افزار شبکه مشغول به کار هستند (و ویندوز به صورت توکار دارای یک چنین API ایی هست). این مساله در سمت کلاینت، سبب خواهد شد تا ترد UI آزاد شود و بتواند به درخواست‌های رسیده کاربر بهتر پاسخ دهد. همچنین این مساله در سمت سرور نیز بسیار مفید است، زیرا برنامه قادر خواهد شد تا به تعداد بیشتری از درخواست‌ها به صورت همزمان پاسخ دهد. زیرا با کاهش تعداد تردهای درگیر، مقیاس پذیری سیستم افزایش می‌یابد.
مطالب
ضمیمه کردن فایل در RavenDb
یکی از مواردی که در بانک‌های اطلاعاتی امروزه بیشتر مورد استفاده قرار میگیرد، ذخیره فایل‌ها در خود دیتابیس، بجای ذخیره نام یا آدرس آن‌ها بر روی دیسک سخت است. از همان ابتدا که Raven به بازار عرضه شد، امکان ذخیره فایل‌های باینری را با استفاده از افزونه هایی که به همراه داشت برای برنامه نویسان مهیا ساخت.  این امکان از طریق کد زیر برای ذخیره یک فایل کفایت میکرد:
using (var store = new DocumentStore
            {
                Url = "http://localhost:8080"
            }.Initialize())
            {
                using (var session = store.OpenSession())
                {
                    store.DatabaseCommands.PutAttachment(key: "file/1",
                                                         etag: null,
                                                         data: System.IO.File.OpenRead(@"D:\Prog\packages.config"),
                                                         metadata: new RavenJObject
                                                         {
                                                            { "Description", "توضیحات فایل" }
                                                         });
                    var question = new Question
                    {
                        By = "users/Vahid",
                        Title = "Raven Intro",
                        Content = "Test....",
                        FileId = "file/1"
                    };
                    session.Store(question);

                    session.SaveChanges();
                }
            }
ولی اگر از نسخه سه بعد RavenDb را استفاده کنید، می‌بینید که متد PutAttachment و دیگر خانواده این متد با ویژگی Obsolete (منسوخ شده) مزین شده‌اند و توصیه شده‌است از این پس از قابلیت جدیدی به نام RavenFs استفاده شود.
RavenFS یک فایل سیستم مجازی توزیع شده‌است و برای فایل‌های بزرگ چند گیگابایتی به طور بهینه‌ای طراحی گردیده‌است تا کارآیی بانک اطلاعاتی را بالا ببرد و وجود فایل‌های تکراری، از بین برود. این سیستم جدید شامل سیستم پیش فرض ایندکس گذاری میباشد و به شما این اجازه را میدهد تا بر روی متادیتاهای یک فایل از قبیل حجم، تاریخ آخرین نگارش و حتی متادیتاهای اختصاصی که شما در حین ذخیره سازی به آن اضافه می‌کنید، به جست‌وجو بپردازد. این سیستم جدید همچنین این امکان را به شما میدهد تا این اطلاعات را بین Node‌ها، با کمترین میزان انتقالات جابجا کنید و دسترسی سریعتری را بین نودهای مختلف داشته باشید.

برای ذخیره سازی یک فایل ابتدا باید یک FileStore را همانند آنچه که برای DocumentStore داشتید تعریف کنید. Url که شامل همان رشته اتصالی بوده و DefaultFileSystem هم  همانند DefaultDatabase که نام دیتابیس در آن ذکر میشد، در اینجا نام فایل سیستم ذکر می‌گردد:
 var fileStore = new FilesStore()
            {
                Url = "http://localhost:8080",
                DefaultFileSystem = "SampleFs"
            };
            fileStore.Initialize();

بعد از آن باید از طریق Store جدید یک سشن ایجاد شود و فایل مورد نظر را در قالب یک استریم بخوانیم:
 var session = fileStore.OpenAsyncSession();
 var stream = File.OpenRead("D:\\Apocalypse.Now.Redux.1979.BDRip.YIFY.mkv");  

توجه داشته باشید که برای کار با فایل سیستم، همه متدهای session به صورت غیرهمزمان بوده و متد همزمانی وجود ندارد. سپس در مرحله بعد میخواهم متادیتاهای شخصی نیز به آن اضافه کنیم:
  var metadata = new RavenJObject
            {
                {"User", "users/1345"},
              {"Director","Francis Ford Coppola" }, 
                {"Year","1979" }
            };

با استفاده از شیء RavenObject میتوانیم در قالب کلید و مقدار، مقادیر خود را ذخیره کنیم و بعد از آن همه موارد بالا که شامل فایل هدر، استریم و متادیتای اختصاصی است را رجیستر کنیم. اگر هم چندین فایل داریم میتوانید آن‌ها را هم در همینجا رجیستر کنید:
session.RegisterUpload("mkv/sample.mkv", stream, metadata);

در مرحله بعدی تغییرات را تایید و عملیات آپلود آغاز میگردد:
await session.SaveChangesAsync();

همانطور که می‌بینید تمامی متدهای کاربردی این سشن به طور غیرهمزمان طراحی شده‌اند.
کلیه عملیاتی که در بالا انجام شد:
    var fileStore = new FilesStore()
            {
                Url = "http://localhost:8080",
                DefaultFileSystem = "SampleFs"
            };
            fileStore.Initialize();

            var session = fileStore.OpenAsyncSession();
             var stream = File.OpenRead("D:\\Apocalypse.Now.Redux.1979.BDRip.YIFY.mkv"); 
            var metadata = new RavenJObject
            {
                {"User", "users/1345"},
               {"Director","Francis Ford Coppola" }, 
                {"Year","1979" }
            };

            session.RegisterUpload("Mkv/sample.mkv", stream, metadata);
            await session.SaveChangesAsync();

حالا اگر به نسخه سرور ravenDb مراجعه کنید می‌بینید که فایل طبق فایل هدر داده شده قرار گرفته است و اطلاعات مربوط به آن ذخیره شده است:



{
    "User": "users/1345",
    "Country": "Iran",
    "City": "Kashan",
    "Raven-Synchronization-History": [
        {
            "Version": 4,
            "ServerId": "42d0cccb-103d-4bf0-9f3d-6f635b1c8ba4"
        },
        {
            "Version": 5,
            "ServerId": "42d0cccb-103d-4bf0-9f3d-6f635b1c8ba4"
        }
    ],
    "Raven-Synchronization-Version": "6",
    "Raven-Synchronization-Source": "42d0cccb-103d-4bf0-9f3d-6f635b1c8ba4"
}

برای خواندن هم به شیوه زیر عمل میکنیم:
 از طریق Store ایجاد شده، یک سشن جدید را باز می‌کنیم و فایل مورد نظر را از طریق یکی از متادیتاهای تعریف شده بازیابی میکنیم:
var fileStore = new FilesStore()
            {
                Url = "http://localhost:8080",
                DefaultFileSystem = "SampleFs"
            };
            fileStore.Initialize();

            var session = fileStore.OpenAsyncSession();
            var file = await session.Query()
                   .WhereEquals("Year", "1979")
                   .FirstOrDefaultAsync();
سپس با آدرس دهی فایل هدر، فایل باینری را داخل استریم قرار می‌دهیم:
var stream = await session.DownloadAsync("mkv/"+file.Name);

سپس استریم را روی دیسک سخت دخیره یا به هر مکانی که مد نظر است ارسال می‌کنیم:
   var fs = File.Create("D:\\file2.mkv");
            stream.CopyTo(fs);
            fs.Flush();
            fs.Close();
البته از آنجائیکه عملیات بازیابی توسط بانک اطلاعاتی به صورت غیرهمزمان انجام می‌گیرد، بهتر هست که باقی عملیات هم به صورت غیرهمزمان انجام شود:
await stream.CopyToAsync(fs);

سپس کل کد بازیابی را به شکل زیر می‌نویسیم:
            var fileStore = new FilesStore()
            {
                Url = "http://localhost:8080",
                DefaultFileSystem = "SampleFs"
            };
            fileStore.Initialize();

            var session = fileStore.OpenAsyncSession();
            var file = await session.Query()
                   .WhereEquals("Year", "1979")
                   .FirstOrDefaultAsync();

            var stream = await session.DownloadAsync("mkv/"+file.Name);

            var fs = File.Create("D:\\file2.mkv");

            await stream.CopyToAsync(fs);


نظرات مطالب
تفاوت Desktop Application با Web Application
به نظر من این بحث به همین سادگی نیست و انتخاب پلتفرم اجرای پروژه به پارامترها و ویژگی‌های زیادی مرتبط هست. بطور مثال سرعت توسعه برنامه‌های ویندوز حداقل در قسمت طراحی رابط کاربری سریعتر و ساده‌تر از وب هست. و یا در مثال دیگر رفتار غیر یکسان مرورگرها مشکلاتی را در طراحی نرم افزار‌های بزرگ ایجاد می‌کنه و مشکل ساز میشه من بعد از سال‌ها طراحی سیستم‌های سازمانی روش استفاده ترکیبی از پلتفرم‌های مختلف را انتخاب کردم بطور مثال قسمت مدیریت یک سیستم را بصورت ویندوزی و قسمت رابط ماربری را با وب و... طراحی کردم. متاسفانه طراحی اولیه زبان HTML با هدف نمایش اطلاعات بوده و بهبود‌های اخیر از جمله وب 2 پاسخی منطقی به نیاز به توسعه نرم افزارهای Cross Platform بوده ولی هنوز هم با پیچیدگی‌های زیادی روبروست. به نظر قابلیت‌های نرم افزار تحت وب بیش از واقعیت بزرگ نمایی شده و هنوز هم در برخی راه کار‌ها استفاده از نرم افزار‌های تحت ویندوز گزینه مناسب‌تری خواهد بود اما این به معنی چشم پوشی بر مزایای منحصر به فرد وب نخواهد بود و هنوز انتخاب پلتفرم بستگی زیادی به نیازمندی‌ها و امکانات پروژه خواهد داشت. 
مطالب
مفاهیم پایه سیستم های کنترل نسخه؛ قسمت دوم : SVN
در قسمت قبلی، اهمیت استفاده از سیستم‌های کنترل نسخه را بیان کردیم و مفاهیم پایه‌ای گیت را مورد بررسی قرار دادیم. در این قسمت مفاهیم پایه‌ای SVN را مورد بررسی قرار می‌دهیم.
SVN مخفف عبارت SubVersion هست و یک سیستم کنترل نسخه‌ی رایگان و متن باز است که توسط شرکت  کلاب نت حمایت می‌شود. به تعدادی از این سیستم‌ها، سیستم‌های «مدیریت پیکربندی نرم افزار»   (Software Configuration Manager (SCM هم اطلاق می‌شود.
در این سیستم فایل‌ها در یک مخزن Repository مرکزی ذخیره می‌شوند و با هر تغییری که در فایل‌ها و دایرکتوری‌ها ایجاد می‌شود، آن‌ها را ثبت می‌کند. این امکان به ما این اجازه را می‌دهد که نسخه‌ی قدیمی فایل‌ها را بازیابی کرده و تاریخچه‌ی اینکه فایل‌ها چگونه و چه موقع و توسط چه کسی تغییر کرده‌اند، به ما نشان دهد. تصویر سلسله مراتبی زیر به خوبی نحوه ارتباط کلاینت‌ها را به این مخزن نشان می‌دهد.
SVN برای مدیریت چندین نسخه از فایل ها، از مدل «کپی، ویرایش، ادغام» Copy-Modify-Merge استفاده می‌کند. در این مدل که هر کاربری در مخزن عمل خواندن را انجام می‌دهد، یک کپی جداگانه و کاملا شخصی برای او گرفته شده و سپس کپی‌های شخصی خودش را ویرایش می‌کند. بعد از اینکه ویرایش تکمیل شد، کپی شخصی خودش را با یک فایل جدید و نهایی ادغام می‌کند.
این روش به شدت از روش «قفل کردن، ویرایش، آزادسازی» »Lock-Modify-Unlock کارآمدتر است و دیگر نیازی نیست که یک کاربر در یک زمان به این ساختار دسترسی داشته باشد و آن را ویرایش کند.

در تصویر بالا هری و سالی، یک کپی از مخزن موجود را گرفته و سپس هر کدام جداگانه بر روی کپی‌های خودشان مشغول به کار می‌شوند. سپس سالی کارش را زودتر به اتمام رسانده و مخزن را به روز می‌کند. بعد از آن، هری هم کارش به پایان می‌رسد و قصد به روز کردن مخزن را دارد ولی سیستم به او اجازه این کار را نمی‌دهد؛ چون این مخزن آن مخزن نیست که هری قبلا از آن کپی گرفته است. آن مخزن بعد از به روزرسانی سالی تغییر یافته است. پس او مجبور است تا تغییرات جدید مخزن را دریافت کرده و کپی خودش را به روز کند. پس از آن می‌تواند کپی خودش را بر روی مخزن اعمال کند (با فرض اینکه تغییرات جدید هیچ تصادمی با تغییراتی که روی کپی خودش اعمال کرده است ندارند).


سناریو بالا با احتساب وجود تصادم

اگر همین سناریوی بالا را فرض کنیم که تغییراتی که هری روی فایل‌ها داده است همان تغییراتی است که سالی قبلا روی مخزن اصلی روی همان فایل‌ها  اعمال کرده است، آیا در این حالت دریافت به روزرسانی‌های جدید باعث ایجاد تصادم می‌شود؟

هری درخواست ادغام آخرین تغییرات مخزن را با کپی خودش می‌کند. از آنجا که فایل A تصادم دارد یک فلگ flag از این وضعیت می‌گیرد. حال هری میتواند تفاوت‌های ایجاد شده را ببیند و بین آن‌ها یکی را انتخاب کند. در این وضعیت هری همپوشانی‌های کدها را برطرف می‌کند و شاید هم بحثی در مورد این تصادم با سالی داشته باشد تا بهترین تغییر کد انتخاب گردد و نهایتا به روشی کاملا امن و مطمئن، با مخزن اصلی ادغام می‌شود.

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