کتاب رایگان توسعه نرم افزار Agile
Learning new development processes can be difficult, but switching to Agile doesn’t need to be complicated. Explore the theories behind Agile and learn how to make it work for you. In Agile Software Development Succinctly, author Stephen Haunts will guide you to a fuller understanding of Agile, its advantages and disadvantages, and how to get the most out of it.
In a nutshell: jspm combines package management with module loading infrastructure and transpilers to provide a magical experience. You can write code using today’s JavaScript, or tomorrow’s JavaScript (ES6), and use any type of module system you like (ES6, AMD, or CommonJS). jspm figures everything out. By integrating package management with a smart script loader, jspm means less work for us.
دسترسی به داده با NHibernate
One thing that keeps amazing me is how many smart developers still feel the urge to write their own data access layer (DAL). They either do it all manually, or they generate parts of it, or they generate the whole thing. Whichever way you go, there are still various alternative paths you can choose from.
استفاده از Awesomium.NET در برنامههای وب
RavenDB؛ تجربه متفاوت از پایگاه داده
By default RavenDB allow anonymous access only for read requests (HTTP GET), and since we creating data, we need to specify a username and password. You can control this by changing the AnonymousAccess setting in the server configuration file. Enter your username and password of your Windows account and a sample data will be generated for you.
در طی این سالها ویندوز به ناپایداری و پپیچیدگی متهم شده است. صرف نظر از این که ویندوز شایستگی این اتهامات را دارد یاخیر، این اتهامات نتیجهی چند عامل است:
اول از همه برنامهها از dll هایی استفاده میکنند که بسیاری از آنها نوشتهی برنامه نویسانشان نیست و توسط توسعه دهندگان دیگر ارائه شدهاند و توسعه دهندگان مربوطه نمیتوانند صد در صد مطمئن شوند که افراد دیگر، به چه نحوی از dll آنها استفاده میکنند و در عمل ممکن هست باعث دردسرهای زیادی شود که البته این نوع مشکلات عموما از قبل خودشان را نشان نمیدهند، چرا که توسط سازندهی برنامه تست و دیباگ شدهاند.
موقعی کاربرها بیشتر دچار دردسر میگردند که برنامههای خودشان را به روز میکنند و عموما شرکتها در آپدیتها، فایلهای جدید زیادی را روی سیستم کاربر منتقل میکنند که ممکن هست سازگاری با فایلهای قبلی موجود نداشته باشند و از آنجا که همیشه تست این مورد برای توسعه دهنده امکان ندارد، به مشکلاتی بر میخورند و نمیتوانند صد در صد مطمئن باشند که تغییرات جدید باعث تاثیر ناخوشایند نمیشود.
مطمئن هستم شما بسیاری از این مشکلات را دیدهاید که کاربری یک برنامه را نصب میکند و شما متوجه میشوید که یک برنامهی از قبل نصب شده به خاطر آن دچار مشکل میشود و این مورد به DLL hell مشهور هست. این مورد باعث ایجاد ترس و لرز برای کاربر شده تا با دقت بیشتری به نصب برنامهها بپردازد.
دومین مورد مربوط به نصب برنامهها است که متهم به پیچیدگی است. امروزه هر برنامهای که روی سیستم نصب میشود، بر همه جای سیستم تاثیر میگذارد. یک برنامه را نصب میکنید و به هر دایرکتوری تعدادی فایل کپی میشود. تنظیمات ریجستری را آپدیت میکند، یک آیکن روی دسکتاپ و یکی هم start menu یا مترو را اضافه میکند. به این معنی که یک نصب کننده به عنوان یک موجودیت واحد شناخته نمیشود. شما نمیتونید راحت از یک برنامه بکاپ بگیرید. باید فایلهای مختلفش را جمع آوری کنید و تنظیمات ریجیستری را ذخیره کنید. عدم امکان انتقال یک برنامه به یک سیستم دیگر هم وجود دارد که باید مجدد برنامه را نصب کنید و نکتهی نهایی، حذف برنامه که گاهی اوقات حذف کامل نیست و به شکل نامنظم و کثیفی اثراتش را به جا میگذارد.
سومین مورد امنیت هست. موقعی که کاربر برنامهای را نصب میکند انواع فایلها از شرکت و تولید کنندههای مختلف روی سیستم نصب میشوند. گاهی اوقات برنامهها بعضی از فایل هایشان را از روی اینترنت دریافت میکنند و کاربر اصلا متوجه موضوع نمیشود و این فایلها میتوانند هر کاری از حذف فایل از روی سیستم گرفته تا ارسال ایمیل را انجام بدهند که این موارد باعث وحشت کاربرها از نصب یک برنامهی جدید میشود که این مورد را با قرار دادن یک سیستم امنیت داخلی با اجازه و عدم اجازه کاربر میشود تا حدی رفع کرد.
دات نت فریمورک هم این معضل را به طور عادی در زمینهی DLL hellدارد که در فصل آتی حل آن بررسی خواهد شد. ولی بر خلاف COM، نوعهای موجود در دات نت نیازی به ذخیره تنظیمات در ریجستری ندارند؛ ولی متاسفانه لینکهای میانبر هنوز وجود دارند. در زمینه امنیت دات نت شامل یک مدل امنیتی به نام Code Access security میباشد؛ از آنجا که امنیت ویندوز بر اساس هویت کاربر تامین میشود. code access security به برنامههای میزبان مثل sql server اجازه میدهد که مجوز مربوطه را خودشان بدهند تا بدین صورت بر اعمال کامپوننتهای بار شده نظارت داشته باشند که البته این مجوزها در حد معمولی و اندک هست. ولی اگر برنامه خود میزبان که به طور محلی روی سیستم نصب میشوند، باشد دسترسی کاملب به مجوزها را دارد. پس بدین صورت کاربر این اجازه را دارد که بر آن چیزی که روی سیستم نصب یا اجرا میشود، نظارت داشته باشه تا کنترل سیستم به طور کامل در اختیار او باشد.
در قسمت بعدی با نحوه توزیع برنامه آشنا خواهیم شد.
پیشنیازها
- آشنایی با مباحث Migrations در EF Code first
- آشنایی با مباحث الگوی واحد کار
- چگونه مدلهای EF را به صورت خودکار به Context اضافه کنیم؟
- چگونه تنظیمات مدلهای EF را به صورت خودکار به Context اضافه کنیم؟
کدهایی را که در این قسمت مشاهده خواهید کرد، در حقیقت همان برنامهی توسعه یافته «آشنایی با مباحث الگوی واحد کار» است و از ذکر قسمتهای تکراری آن جهت طولانی نشدن مبحث، صرفنظر خواهد شد. برای مثال Context و مدلهای محصولات و گروههای آنها به همراه کلاسهای لایه سرویس برنامهی اصلی، دقیقا همان کدهای مطلب «آشنایی با مباحث الگوی واحد کار» است.
تعریف domain classes مخصوص افزونهها
در ادامهی پروژهی افزونه پذیر فعلی، پروژهی class library جدیدی را به نام MvcPluginMasterApp.Plugin1.DomainClasses اضافه خواهیم کرد. از آن جهت تعریف کلاسهای مدل افزونهی یک استفاده میکنیم. برای مثال کلاس News را به همراه تنظیمات Fluent آن به این پروژهی جدید اضافه کنید:
using System.Data.Entity.ModelConfiguration; namespace MvcPluginMasterApp.Plugin1.DomainClasses { public class News { public int Id { set; get; } public string Title { set; get; } public string Body { set; get; } } public class NewsConfig : EntityTypeConfiguration<News> { public NewsConfig() { this.ToTable("Plugin1_News"); this.HasKey(news => news.Id); this.Property(news => news.Title).IsRequired().HasMaxLength(500); this.Property(news => news.Body).IsOptional().IsMaxLength(); } } }
PM> install-package EntityFramework
مشکل! برنامهی اصلی، همانند مطلب «آشنایی با مباحث الگوی واحد کار» دارای domain classes خاص خودش است به همراه تنظیمات Context ایی که صریحا در آن مدلهای متناظر با این پروژه در معرض دید EF قرار گرفتهاند:
public class MvcPluginMasterAppContext : DbContext, IUnitOfWork { public DbSet<Category> Categories { set; get; } public DbSet<Product> Products { set; get; }
تغییرات اینترفیس Unit of work جهت افزونه پذیری
در ادامه، اینترفیس بهبود یافتهی IUnitOfWork را جهت پذیرش DbSetهای پویا و همچنین EntityTypeConfigurationهای پویا، ملاحظه میکنید:
namespace MvcPluginMasterApp.PluginsBase { public interface IUnitOfWork : IDisposable { IDbSet<TEntity> Set<TEntity>() where TEntity : class; int SaveAllChanges(); void MarkAsChanged<TEntity>(TEntity entity) where TEntity : class; IList<T> GetRows<T>(string sql, params object[] parameters) where T : class; IEnumerable<TEntity> AddThisRange<TEntity>(IEnumerable<TEntity> entities) where TEntity : class; void SetDynamicEntities(Type[] dynamicTypes); void ForceDatabaseInitialize(); void SetConfigurationsAssemblies(Assembly[] assembly); } }
SetDynamicEntities : توسط این متد در ابتدای برنامه، نوعهای مدلهای جدید افزونهها به صورت خودکار به Context اضافه خواهند شد.
SetConfigurationsAssemblies : کار افزودن اسمبلیهای حاوی تعاریف EntityTypeConfigurationهای جدید و پویا را به عهده دارد.
ForceDatabaseInitialize: سبب خواهد شد تا مباحث migrations، پیش از شروع به کار برنامه، اعمال شوند.
در کلاس Context ذیل، نحوهی پیاده سازی این متدهای جدید را ملاحظه میکنید:
namespace MvcPluginMasterApp.DataLayer.Context { public class MvcPluginMasterAppContext : DbContext, IUnitOfWork { private readonly IList<Assembly> _configurationsAssemblies = new List<Assembly>(); private readonly IList<Type[]> _dynamicTypes = new List<Type[]>(); public void ForceDatabaseInitialize() { Database.Initialize(force: true); } public void SetConfigurationsAssemblies(Assembly[] assemblies) { if (assemblies == null) return; foreach (var assembly in assemblies) { _configurationsAssemblies.Add(assembly); } } public void SetDynamicEntities(Type[] dynamicTypes) { if (dynamicTypes == null) return; _dynamicTypes.Add(dynamicTypes); } protected override void OnModelCreating(DbModelBuilder modelBuilder) { addConfigurationsFromAssemblies(modelBuilder); addPluginsEntitiesDynamically(modelBuilder); base.OnModelCreating(modelBuilder); } private void addConfigurationsFromAssemblies(DbModelBuilder modelBuilder) { foreach (var assembly in _configurationsAssemblies) { modelBuilder.Configurations.AddFromAssembly(assembly); } } private void addPluginsEntitiesDynamically(DbModelBuilder modelBuilder) { foreach (var types in _dynamicTypes) { foreach (var type in types) { modelBuilder.RegisterEntityType(type); } } } } }
بهبود اینترفیس IPlugin جهت پذیرش نوعهای پویای EF
در قسمت اول، با اینترفیس IPlugin آشنا شدیم. هر افزونه باید دارای کلاسی باشد که این اینترفیس را پیاده سازی میکند. از آن جهت دریافت تنظیمات و یا ثبت تنظیمات مسیریابی و امثال آن استفاده میشود.
در اینجا متد GetEfBootstrapper آن کار دریافت تنظیمات EF هر افزونه را به عهد دارد.
namespace MvcPluginMasterApp.PluginsBase { public interface IPlugin { EfBootstrapper GetEfBootstrapper(); //...به همراه سایر متدهای مورد نیاز } public class EfBootstrapper { /// <summary> /// Assemblies containing EntityTypeConfiguration classes. /// </summary> public Assembly[] ConfigurationsAssemblies { get; set; } /// <summary> /// Domain classes. /// </summary> public Type[] DomainEntities { get; set; } /// <summary> /// Custom Seed method. /// </summary> public Action<IUnitOfWork> DatabaseSeeder { get; set; } } }
DomainEntities بیانگر لیست مدلها و موجودیتهای هر افزونه است.
DatabaseSeeder کار دریافت منطق متد Seed را بر عهده دارد. برای مثال اگر افزونهای نیاز است در آغاز کار تشکیل جداول آن، دیتای پیش فرض و خاصی را در بانک اطلاعاتی ثبت کند، میتوان از این متد استفاده کرد. اگر دقت کنید این Action یک وهله از IUnitOfWork را به افزونه ارسال میکند. بنابراین در این طراحی جدید، اینترفیس IUnitOfWork به پروژهی MvcPluginMasterApp.PluginsBase منتقل میشود. به این ترتیب دیگر نیازی نیست تا تک تک افزونهها ارجاع مستقیمی را به DataLayer پروژهی اصلی پیدا کنند.
تکمیل متد GetEfBootstrapper در افزونهها
اکنون جهت معرفی مدلها و تنظیمات EF آنها، تنها کافی است متد GetEfBootstrapper هر افزونه را تکمیل کنیم:
namespace MvcPluginMasterApp.Plugin1 { public class Plugin1 : IPlugin { public EfBootstrapper GetEfBootstrapper() { return new EfBootstrapper { DomainEntities = new[] { typeof(News) }, ConfigurationsAssemblies = new[] { typeof(NewsConfig).Assembly }, DatabaseSeeder = uow => { var news = uow.Set<News>(); if (news.Any()) { return; } news.Add(new News { Title = "News 1", Body = "news 1 news 1 news 1 ...." }); news.Add(new News { Title = "News 2", Body = "news 2 news 2 news 2 ...." }); } }; }
همچنین توسط delegate ایی به نام DatabaseSeeder، نحوهی دسترسی به متد Set واحد کار و سپس استفادهی از آن، برای تعریف متد Seed سفارشی نیز تکمیل شدهاست.
تدارک یک راه انداز EF، پیش از شروع به کار برنامه
در پوشهی App_Start پروژهی اصلی یا همان MvcPluginMasterApp، کلاس جدید EFBootstrapperStart را با کدهای ذیل اضافه کنید:
[assembly: PreApplicationStartMethod(typeof(EFBootstrapperStart), "Start")] namespace MvcPluginMasterApp { public static class EFBootstrapperStart { public static void Start() { var plugins = SmObjectFactory.Container.GetAllInstances<IPlugin>().ToList(); using (var uow = SmObjectFactory.Container.GetInstance<IUnitOfWork>()) { initDatabase(uow, plugins); runDatabaseSeeders(uow, plugins); } } private static void initDatabase(IUnitOfWork uow, IEnumerable<IPlugin> plugins) { foreach (var plugin in plugins) { var efBootstrapper = plugin.GetEfBootstrapper(); if (efBootstrapper == null) continue; uow.SetDynamicEntities(efBootstrapper.DomainEntities); uow.SetConfigurationsAssemblies(efBootstrapper.ConfigurationsAssemblies); } Database.SetInitializer(new MigrateDatabaseToLatestVersion<MvcPluginMasterAppContext, Configuration>()); uow.ForceDatabaseInitialize(); } private static void runDatabaseSeeders(IUnitOfWork uow, IEnumerable<IPlugin> plugins) { foreach (var plugin in plugins) { var efBootstrapper = plugin.GetEfBootstrapper(); if (efBootstrapper == null || efBootstrapper.DatabaseSeeder == null) continue; efBootstrapper.DatabaseSeeder(uow); uow.SaveAllChanges(); } } } }
همانطور که ملاحظه میکنید، ابتدا لیست تمام افزونههای موجود، به کمک StructureMap دریافت میشوند. سپس میتوان در متد initDatabase به متد GetEfBootstrapper هر افزونه دسترسی یافت و توسط آن تنظیمات مدلها را یافته و به Context اصلی برنامه اضافه کرد. سپس با فراخوانی ForceDatabaseInitialize تمام این موارد به صورت خودکار به بانک اطلاعاتی اعمال خواهند شد.
کار متد runDatabaseSeeders، یافتن DatabaseSeeder هر افزونه، اجرای آنها و سپس فراخوانی متد SaveAllChanges در آخر کار است.
کدهای کامل این سری را از اینجا میتوانید دریافت کنید:
MvcPlugin
ایجاد Responsive Layered Slider
MongoDB #14
- برای ایمن نگه داری اطلاعات
- دسترسی پذیری بالای اطلاعات (شبانه روزی)
- بازیابی اطلاعات
- نیازی به از کار افتادن هنگام انجام عملیات نگهداری ندارد
- مقایس پذیری خواندن دادهها (کپی برداریهای اضافه برای عمل خواندن)
- کپی اطلاعات برای نرم افزارها شفاف و قابل دستیابی است.
تکثیر در MongoDB چگونه کار میکند
- یک مجموعهی کپی، یک گروه از دویا چند گره است. (عموما حداقل 3 گره نیاز است.)
- در یک مجموعهی کپی، یک گره، گره اصلی است و بقیه گرهها گرههای ثانویه هستند.
- همهی دادهها از گرهی اصلی به گرههای ثانویه تکثیر میشوند.
- هنگام انجام عملیات نگه داری یا ازدسترس خارج شدن سرور، گزینش برای گره اصلی و انتخاب گره اصلی جدید آغاز میشود.
- گره از کار افتاده، بعد از بازیابی دوباره، به مجموعه کپی ملحق میشود و بعنوان یک گره ثانویه کار میکند.
ویژگیهای مجموعهی کپی
- یک کلاستر از N عدد گره
- هر گرهایی میتواند گره اصلی باشد
- همهی عملیات نوشتن بر روی گره اصلی انجام میشود
- عمل ازدسترس خارج شدن سرور و جایگزین شدن یک گره بصورت اتوماتیک
- بازیابی بصورت اتوماتیک
- همراهی و توافق در گزینش گره اصلی
ساختن یک مجموعه کپی
- همهی نمونههای در حال اجرای mongod را در سمت سرور، متوقف کنید.
- اکنون mongod سمت سرور را با سوئیچ –replSet راه اندازی کنید.
mongod --port "PORT" --dbpath "YOUR_DB_DATA_PATH" --replSet "REPLICA_SET_INSTANCE_NAME"
mongod --port 27017 --dbpath "D:\set up\mongodb\data" --replSet rs0
گرامر
>rs.add(HOST_NAME:PORT)
>rs.add("mongod1.net:27017") >