نظرات مطالب
آشنایی با الگوی MVP
سلام.
آقای نصیری هنگامی که می خواستم این آدرس رو باز کنم صحفه منتظر پاسخ از بلاگر می مونه :
https://www.dntips.ir/2009/08/mvp.html#disqus_thread
----------------------
در مورد این لینک جدید ام وی پی من برای دانلود فریمورک
webformsmvp
به این صحفه رسیدم
http://nuget.org/List/Packages/WebFormsMvp
اما با وجود ثبت نام در این سایت موفق به دانلود نمیشم.
یعنی هیچ جایی برای دانلود پیدا نکردم.
در سایت پروژه در کد پلکس هم چیزی برای دانلود نبود.
اگر فرصت داشتید راهنمایی کنید.
ممنون
پ ن : قبلا می شد کامنت راست به چپ نوشت الان انگار این امکان وجود نداره؟
مطالب
آشنایی بیشتر با AngularJS Directive

در مطلب آشنایی با Directive‌ها در AngularJS با نحوه‌ی ایجاد Directive آشنا شدیم. هدف از این مطلب، آشنایی بیشتر با Directive در AngularJS است؛ یکی از بهترین فریم ورک‌های جاوااسکریپتی، با قابلیت ایجاد کتابخانه‌هایی از کامپوننت‌ها که می‌توانند به HTML اضافه شوند .

کتابخانه‌های جاوااسکریپتی زیادی وجود دارند. به عنوان مثال Bootstrap یکی از محبوب‌ترین "front-end framework" ها است که امکان تغییر در ظاهر المنت‌ها را فراهم می‌کند و شامل تعدادی کامپوننت جاوااسکریپتی نیز می‌باشد. مشکل کار، در هنگام استفاده از کامپوننت ها است. شخصی که در حال توسعه‌ی HTML است باید در کد جاوااسکریپتی خود از  jQuery استفاده کند و بعنوان مثال یک Popover  را فعال یا غیر فعال کند و این، یک فرآیند خسته کننده و مستعد خطا است. 


یک مثال ساده از Directives AngularJS و بررسی آن

var m = angular.module("myApp");
 
myApp.directive("myDir", function() {
  return {
  restrict: "E",   
  scope: {     
   name: "@",   
   amount: "=",  
   save: "&"    
  },
  template:    
   "<div>" +
   "  {{name}}: <input ng-model='amount' />" +
   "  <button ng-click='save()'>Save</button>" +
   "</div>",
  replace: true,   
  transclude: false, 
  controller: [ "$scope", function ($scope) { …  }],
  link: function (scope, element, attrs, controller) {…}
  }
});

به الگوی نامگذاری directive دقت کنید. پیشوند my شبیه به یک namespace است. بنابراین اگر یک Application از دایرکتیوهای قرار گرفته در Module ‌های متفاوت استفاده کند، به راحتی می‌توان محل تعریف یک directive را تشخیص داد. این نام می‌تواند نشان دهنده‌ی این باشد که این directive را خودتان توسعه داده‌اید یا از یک directive توسعه داده شده توسط شخص دیگری در حال استفاده هستید. به هر حال این نحوه‌ی نام گذاری یک اجبار نیست و به عنوان یک پیشنهاد است.

سازنده directive یک شیء را با تعدادی خاصیت باز می‌گرداند که تمامی آنها در سایت AngularJS توضیح داده شده‌اند. در اینجا قصد داریم تا توضیحی مختصر در مورد کاری که این خصوصیات انجام می‌دهند داشته باشیم.

· restrict : تشخیص می‌دهد که آیا directive در HTML استفاده خواهد شد. گزینه‌های قابل استفاده ‘A’ ،  ‘E’ ، ‘C’ برای attribute ، element ، class و یا comment است . پیش فرض ‘A’ برای attribute است. اما ما بیشتر علاقه به استفاده از ویژگی element برای ایجاد المنت‌های UI داریم.

· scope : ایجاد یک scope ایزوله که متعلق به directive است و موجب ایزوله شدن آن از scope صدا زننده directive می‌شود. متغیرهای scope پدر از طریق خصوصیات تگ directive ارسال می‌شوند. این ایزوله کردن زمانی کاربردی است که در حال ایجاد کامپوننت هایی با قابلیت استفاده مجدد هستیم، که نباید متکی به scope پدر باشند. شیء scope در directive نام و نوع متغیرهای scope را تعیین می‌کنند. در مثال بالا سه متغیر برای scope تعریف شده است:

-   name: "@" (by value, one-way) : علامت @ مشخص می‌کند که مقدار متغیر ارسال می‌شود. Directive یک رشته را دریافت می‌کند که شامل مقدار ارسال شده از scope پدر می‌باشد. Directive می‌تواند از آن استفاده کند، اما نمی‌تواند مقدار آن را در scope پدر تغییر دهد.

-   amount: "=" (by reference, two-way) : علامت = مشخص می‌کند این متغیر با ارجاع ارسال می‌شود. Directive یک ارجاع به مقدار متغیر در scope اصلی دریافت می‌کند. مقدار می‌تواند هر نوع داده ای، شامل یک شیء complex یا یک آرایه باشد. Directive می‌تواند مقدار را در scope پدر تغییر دهد. این نوع متغیر، زمانیکه نیاز باشد directive مقدار را در scope پدر تغییر دهد، استفاده می‌شود.

-   save: "&" (expression) : علامت & مشخص می‌کند این متغیر یک expression را که در scope پدر اجرا می‌شود، نگهداری می‌کند. اکنون directive قابلیت انجام کارهایی فراتر از تغییر یک مقدار را دارد. به عنوان مثال می‌توان یک تابع را از scope پدر فراخوانی و نتیجه‌ی اجرا را دریافت کرد.

· template :  الگوی رشته ای که جایگزین المنت تعریف شده می‌شود. فرآیند جایگزینی تمامی خصوصیات را از المنت قدیمی به المنت جدید انتقال می‌دهد. به نحوه استفاده از متغیر‌های تعریف شده در scope ایزوله دقت کنید. این مورد به شما امکان تعریف directive های macro-style را می‌دهد که نیاز به کد اضافه‌ای، ندارند. اگرچه در بیشتر موارد الگو  یک تگ ساده <div> است که از کد‌های link که در زیر توضیح داده شده است استفاده می‌کند.

· replace : تعیین می‌کند که آیا الگوی directive باید جایگزین المنت شود. مقدار پیش فرض false است.

· transclude : تعیین کننده این است که محتوای directive باید در المنت کپی شود یا خیر. در مثال زیر المنت tab شامل المنت‌های HTML دیگر است پس transclude برابر true است.  

<body ng-app="components">
  <h3>BootStrap Tab Component</h3>
    <tabs>
       <pane title="First Tab">
          <div>This is the content of the first tab.</div>
       </pane>
       <pane title="Second Tab">
          <div>This is the content of the second tab.</div>
       </pane>
    </tabs>
</body>
 

· link : این تابع بیشتر منطق directive را شامل می‌شود. Link وظیفه دستکاری DOM ، ایجاد event listener ‌ها و... را دارد. تابع Link پارامترهای زیر را دریافت می‌کند:

-   scope : ارجاع به scope ایزوله شده directive دارد.

-   element : ارجاع به المنت‌های DOM که directive را تعریف کرده اند. تابع link معمولا برای دستکاری المنت از jQuery استفاده می‌کند. (یا از Angular's jqLite در صورتی که jQuery بارگذاری نشده باشد)

-   controller : در مواقعی که از دایرکتیو‌های تو در تو استفاده می‌شود کاربرد دارد. این پارامتر یک directive فرزند با ارجاعی به پدر را فراهم می‌کند، بنابراین موجب ارتباط  directive ‌ها می‌شود.

به عنوان مثال،  این directive  که پیاده سازی bootstrap tab را انجام داده است، می‌توانید مشاهده نمایید.

موفق باشید

مطالب
مدیریت فایلهای یک پروژه نرم افزاری با استفاده از Subversion
کتابچه‌ای را درباره‌ی کار با SVN تهیه کرده‌ام که از آدرس زیر قابل دریافت است:
دریافت فایل

خلاصه‌ای از مقدمه کتاب:
آیا شما هم جزو آن دسته از برنامه نویسانی هستید که هنوز به ازای هر نگارش از برنامه، سورس‌کدهای خود را فشرده کرده و آنها را بر اساس تاریخ آرشیو می‌کنند؟ آیا می‌توانید گزارشی مقایسه‌ای را از تغییرات انجام شده در سورس کدهای دو نگارش اخیر برنامه خود ارائه دهید؟ آیا می‌دانید فایلی را که هم اکنون بر روی آن مشغول به کار هستید در نگارش قبلی آن چه وضعیتی داشته و مقایسه آن با فایل فعلی شامل چه موارد و تغییراتی خواهد شد؟ آیا امکان بازگشت سریع و تبدیل سورس کدهای جاری برنامه را به سه نگارش قبل که از نظر شما پایدارتر هستند، بدون اضطراب و تشنج عصبی و با سرعت هرچه تمام‌تر و بدون خطا دارید؟ آیا می‌دانید بر روی یک فایل ویژه پروژه چه کسانی کار کرده‌اند و چه تغییراتی را اعمال نموده‌اند؟ آیا می‌توانید در یک تیم برنامه نویسی در کنار سایر برنامه‌نویس‌ها بر روی یک پروژه واحد کار کنید و به‌سادگی تداخلات رخ داده را مرتفع و یا آخرین تغییرات انجام شده را ادغام نمائید؟ آیا می‌توانید همواره آخرین نگارش تائید شده پروژه را به سرعت و با دقت تمام به افراد تیم نرم افزاری خود تحویل دهید؟ آیا مکان مجتمعی را جهت نگهداری سورس‌کدهای پروژه‌های مختلف، در سازمان خود دارید؟

نظرات مطالب
EF Code First #12
در صورتی که بخواهیم Context را به ازای هر ویندوز فرم زنده نگه داریم در WinForm، پیاده سازی زیر صحیح است:
static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Database.SetInitializer<LoanContext>(null);

            // تنظیمات اولیه برنامه که فقط یکبار باید در طول عمر برنامه انجام شود
            ObjectFactory.Initialize(x =>
            {
                x.For<IUnitOfWork>().Use<LoanContext>();
                x.For<IEmployeeService>().Use<EmployeeService>();
            });

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new frmMain());
        }
    }
و در frmMain به شکل زیر پیاده سازی را انجام دهیم:
 public partial class frmMain : Form
    {
        private IContainer _container;
        private IUnitOfWork _uow;

        public frmMain()
        {
            InitializeComponent();

            _container = ObjectFactory.Container.GetNestedContainer();
            _uow = _container.GetInstance<IUnitOfWork>();
        }

        private void btnHomeLoanRequest_Click(object sender, System.EventArgs e)
        {
            var employeeService = _container.GetInstance<IEmployeeService>();
            .
            .
            .
            _uow.SaveChanges();
        }
        private void btnEditLoan_Click(object sender, System.EventArgs e)
        {
            var categoryService = container.GetInstance<ICategoryService>();
            .
            .
            .
            _uow.SaveChanges();
        }
مطالب
EF Code First #5

در قسمت قبل خاصیت AutomaticMigrationsEnabled را در کلاس Configuration به true تنظیم کردیم. به این ترتیب، عملیات ساده شده، اما یک سری از قابلیت‌های ردیابی تغییرات را از دست خواهیم داد و این عملیات،‌ صرفا یک عملیات رو به جلو خواهد بود.
اگر AutomaticMigrationsEnabled را مجددا به false تنظیم کنیم و هربار به کمک دستوارت Add-Migration و Update-Database تغییرات مدل‌ها را به بانک اطلاعاتی اعمال نمائیم، علاوه بر تشکیل تاریخچه این تغییرات در برنامه، امکان بازگشت به عقب و لغو تغییرات صورت گرفته نیز مهیا می‌گردد.

هدف قرار دادن مرحله‌ای خاص یا لغو آن

به همان پروژه قسمت قبل مراجعه نمائید. در کلاس Configuration آن، خاصیت AutomaticMigrationsEnabled را به false تنظیم کنید. سپس یک خاصیت جدید را به کلاس Project اضافه نموده و برنامه را اجرا نمائید. بلافاصله خطای زیر را دریافت خواهیم کرد:

Unable to update database to match the current model because there are pending changes and 
automatic migration is disabled. Either write the pending model changes to a code-based migration
or enable automatic migration. Set DbMigrationsConfiguration.AutomaticMigrationsEnabled to true
to enable automatic migration.

EF تشخیص داده است که کلاس مدل برنامه، با بانک اطلاعاتی تطابق ندارد و همچنین ویژگی مهاجرت خودکار نیز فعال نیست. بنابراین اعمال code-based migration را توصیه کرده است.
برای این منظور به کنسول پاورشل NuGet مراجعه نمائید (منوی Tools در ویژوال استودیو، گزینه‌ Library package manager آن و سپس انتخاب گزینه package manager console). در ادامه فرمان add-m را نوشته و دکمه tab را فشار دهید. یک منوی Auto Complete ظاهر خواهد شد که از آن‌ می‌توان فرمان add-migration را انتخاب نمود. در اینجا یک نام را هم نیاز است وارد کرد؛ برای مثال:

Add-Migration AddSomeProp2ToProject

به این ترتیب کلاس زیر را به صورت خودکار تولید خواهد کرد:

namespace EF_Sample02.Migrations
{
using System.Data.Entity.Migrations;

public partial class AddSomeProp2ToProject : DbMigration
{
public override void Up()
{
AddColumn("Projects", "SomeProp", c => c.String());
AddColumn("Projects", "SomeProp2", c => c.String());
}

public override void Down()
{
DropColumn("Projects", "SomeProp2");
DropColumn("Projects", "SomeProp");
}
}
}

مدل‌های برنامه را با بانک اطلاعاتی تطابق داده و دریافته است که هنوز دو خاصیت در اینجا به بانک اطلاعاتی اضافه نشده‌اند.
از متد Up برای اعمال تغییرات و از متد Down برای بازگشت به قبل استفاده می‌گردد. نام فایل این کلاس هم طبق معمول چیزی است شبیه به timeStamp_AddSomeProp2ToProject.cs .

در ادامه نیاز است این تغییرات به بانک اطلاعاتی اعمال شوند. به همین منظور دستور زیر را در کنسول پاورشل وارد نمائید:

Update-Database -Verbose

پارامتر Verbose آن سبب خواهد شد تا جزئیات عملیات به صورت مفصل گزارش داده شود که شامل دستورات ALTER TABLE نیز هست:

Using NuGet project 'EF_Sample02'.
Using StartUp project 'EF_Sample02'.
Target database is: 'testdb2012' (DataSource: (local), Provider: System.Data.SqlClient, Origin: Configuration).
Applying explicit migrations: [201205061835024_AddSomeProp2ToProject].
Applying explicit migration: 201205061835024_AddSomeProp2ToProject.
ALTER TABLE [Projects] ADD [SomeProp] [nvarchar](max)
ALTER TABLE [Projects] ADD [SomeProp2] [nvarchar](max)
[Inserting migration history record]

اکنون مجددا یک خاصیت دیگر را مثلا به نام public string SomeProp3، به کلاس Project اضافه نمائید.
سپس همین روال باید مجددا تکرار شود. دستورات زیر را در کنسول پاورشل NuGet اجرا نمائید:

Add-Migration AddSomeProp3ToProject
Update-Database -Verbose

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

در ادامه برای مثال به این نتیجه رسیده‌ایم که نیازی به خاصیت public string SomeProp3 اضافه شده، نبوده است. روش متداول، باز هم مانند سابق است. ابتدا خاصیت را از کلاس Project حذف خواهیم کرد و سپس دو دستور Add-Migration و Update-Database را اجرا خواهیم نمود.
اما با توجه به اینکه مهاجرت خودکار را غیرفعال کرده‌ایم و هربار با فراخوانی دستور Add-Migration یک کلاس جدید، با متدهای Up و Down به پروژه، جهت نگهداری سوابق عملیات اضافه می‌شوند، می‌توان دستور Update-Database را جهت فراخوانی متد Down صرفا یک مرحله موجود نیز فراخوانی نمود.

نکته:
اگر علاقمند باشید که راهنمای مفصل پارامترهای دستور Update-Database را مشاهده کنید، تنها کافی است دستور زیر را در کنسول پاورشل اجرا نمائید:

get-help update-database -detailed

به عنوان نمونه اگر در حین فراخوانی دستور Update-Database احتمال از دست رفتن اطلاعات باشد، عملیات متوقف می‌شود. برای وادار کردن پروسه به انجام تغییرات بر روی بانک اطلاعاتی می‌توان از پارامتر Force در اینجا استفاده کرد.

در ادامه برای اینکه دستور Update-Database تنها یک مرحله مشخص را که سابقه آن در برنامه موجود است، هدف قرار دهد، باید از پارامتر TargetMigration به همراه نام کلاس مرتبط استفاده کرد:

Update-Database -TargetMigration:"AddSomeProp2ToProject" -Verbose

اگر دقت کرده باشید در اینجا AddSomeProp2ToProject بجای AddSomeProp3ToProject بکارگرفته شده است. اگر یک مرحله قبل را هدف قرار دهیم، متد Down را اجرا خواهد کرد:

Using NuGet project 'EF_Sample02'.
Using StartUp project 'EF_Sample02'.
Target database is: 'testdb2012' (DataSource: (local), Provider: System.Data.SqlClient, Origin: Configuration).
Reverting migrations: [201205061845485_AddSomeProp3ToProject].
Reverting explicit migration: 201205061845485_AddSomeProp3ToProject.
DECLARE @var0 nvarchar(128)
SELECT @var0 = name
FROM sys.default_constraints
WHERE parent_object_id = object_id(N'Projects')
AND col_name(parent_object_id, parent_column_id) = 'SomeProp3';
IF @var0 IS NOT NULL
EXECUTE('ALTER TABLE [Projects] DROP CONSTRAINT ' + @var0)
ALTER TABLE [Projects] DROP COLUMN [SomeProp3]
[Deleting migration history record]

همانطور که ملاحظه می‌کنید در اینجا عملیات حذف ستون SomeProp3 انجام شده است. البته این خاصیت به صورت خودکار از کدهای برنامه (کلاس Project در این مثال) حذف نمی‌شود و فرض بر این است که پیشتر اینکار را انجام داده‌اید.


سفارشی سازی کلاس‌های مهاجرت

تمام کلاس‌های خودکار مهاجرت تولید شده توسط پاورشل، از کلاس DbMigration ارث بری می‌کنند. در این کلاس امکانات قابل توجهی مانند AddColumn، AddForeignKey، AddPrimaryKey، AlterColumn، CreateIndex و امثال آن وجود دارند که در تمام کلاس‌های مشتق شده از آن، قابل استفاده هستند. حتی متد Sql نیز در آن پیش بینی شده است که در صورت نیاز به اجرای دستوارت خام SQL، می‌توان از آن استفاده کرد.
برای مثال فرض کنید مجددا همان خاصیت public string SomeProp3 را به کلاس Project اضافه کرد‌ه‌ایم. اما اینبار نیاز است حین تشکیل این فیلد در بانک اطلاعاتی، یک مقدار پیش فرض نیز برای آن درنظر گرفته شود که در صورت نال بودن مقدار خاصیت آن در برنامه، به صورت خودکار توسط بانک اطلاعاتی مقدار دهی گردد:

namespace EF_Sample02.Migrations
{
using System.Data.Entity.Migrations;

public partial class AddSomeProp3ToProject : DbMigration
{
public override void Up()
{
AddColumn("Projects", "SomeProp3", c => c.String(defaultValue: "some data"));
Sql("Update Projects set SomeProp3=N'some data'");
}

public override void Down()
{
DropColumn("Projects", "SomeProp3");
}
}
}

متد String در اینجا چنین امضایی دارد:

public ColumnModel String(bool? nullable = null, int? maxLength = null, bool? fixedLength = null, 
bool? isMaxLength = null, bool? unicode = null, string defaultValue = null, string defaultValueSql = null,
string name = null, string storeType = null)

که برای نمونه در اینجا پارامتر defaultValue آن‌را در کلاس AddSomeProp3ToProject مقدار دهی کرده‌ایم.
برای اعمال این تغییرات تنها کافی است دستور Update-Database -Verbose اجرا گردد. اینبار خروجی SQL اجرا شده آن به نحو زیر است که شامل مقدار پیش فرض نیز شده است:

ALTER TABLE [Projects] ADD [SomeProp3] [nvarchar](max) DEFAULT 'some data'

تعیین مقدار پیش فرض، زمانیکه یک فیلد not null تعریف شده‌است نیز می‌تواند مفید باشد. همچنین در اینجا امکان اجرای دستورات مستقیم SQL نیز وجود دارد که نمونه‌ای از آن‌را در متد Up فوق مشاهده می‌کنید.


افزودن رکوردهای پیش فرض در حین به روز رسانی بانک اطلاعاتی

در قسمت‌های قبل با متد Seed که به همراه آغاز کننده‌های بانک اطلاعاتی EF ارائه شده‌اند، جهت افزودن رکوردهای اولیه و پیش فرض به بانک اطلاعاتی آشنا شدید. در اینجا نیز با تحریف متد Seed در کلاس Configuration،‌ چنین امری میسر است:

namespace EF_Sample02.Migrations
{
using System;
using System.Data.Entity.Migrations;

internal sealed class Configuration : DbMigrationsConfiguration<EF_Sample02.Sample2Context>
{
public Configuration()
{
this.AutomaticMigrationsEnabled = false;
this.AutomaticMigrationDataLossAllowed = true;
}

protected override void Seed(EF_Sample02.Sample2Context context)
{
context.Users.AddOrUpdate(
a => a.Name,
new Models.User { Name = "Vahid", AddDate = DateTime.Now },
new Models.User { Name = "Test", AddDate = DateTime.Now });
}
}
}

متد AddOrUpdate در EF 4.3 اضافه شده است. این متد ابتدا بررسی می‌کند که آیا رکورد مورد نظر در بانک اطلاعاتی وجود دارد یا خیر. اگر خیر، آن‌را اضافه خواهد کرد در غیراینصورت، نمونه موجود را به روز رسانی می‌کند. اولین پارامتر آن، identifierExpression نام دارد. توسط آن مشخص می‌شود که بر اساس چه خاصیتی باید در مورد update یا add تصمیم‌گیری شود. دراینجا اگر نیاز به ذکر بیش از یک خاصیت وجود داشت، از anonymously type object می‌توان کمک گرفت new { p.Name, p.LastName } .


تولید اسکریپت به روز رسانی بانک اطلاعاتی

بهترین کار و امن‌ترین روش حین انجام این نوع به روز رسانی‌ها، تهیه اسکریپت SQL فرامینی است که باید بر روی بانک اطلاعاتی اجرا شوند. سپس می‌توان این دستورات و اسکریپت نهایی را دستی هم اجرا کرد (که روش متداول‌تری است در محیط کاری).
برای اینکار تنها کافی است دستور زیر را در کنسول پاورشل اجرا نمائیم:
Update-Database -Verbose -Script

پس از اجرای این دستور، یک فایل اسکریپت با پسوند sql تولید شده و بلافاصله در ویژوال استودیو جهت مرور نیز گشوده خواهد شد. برای نمونه محتوای آن برای افزودن خاصیت جدید SomeProp5 به صورت زیر است:

ALTER TABLE [Projects] ADD [SomeProp5] [nvarchar](max)
INSERT INTO [__MigrationHistory] ([MigrationId], [CreatedOn], [Model], [ProductVersion]) VALUES
('201205060852004_AutomaticMigration', '2012-05-06T08:52:00.937Z', 0x1F8B0800000............ '4.3.1')

همانطور که ملاحظه می‌کنید، در یک مرحله، جدول پروژه‌ها را به روز خواهد کرد و در مرحله بعد، سابقه آن‌را در جدول __MigrationHistory ثبت می‌کند.

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

Update-Database -Verbose -Script -SourceMigration:"stepName"




استفاده از DB Migrations در عمل

البته این یک روش پیشنهادی و امن است:
الف) در ابتدای اجرا برنامه، پارامتر ورودی متد System.Data.Entity.Database.SetInitializer را به نال تنظیم کنید تا برنامه تغییری را بر روی بانک اطلاعاتی اعمال نکند.
ب) توسط دستور enable-migrations،‌ فایل‌های اولیه DB Migration را ایجاد کنید. پیش فرض‌های آن را نیز تغییر ندهید.
ج) هر بار که کلاس‌های مدل‌ برنامه تغییر کردند و پس از آن نیاز به به روز رسانی ساختار بانک اطلاعاتی وجود داشت دو دستور زیر را اجرا کنید:
Add-Migration AddSomePropToProject
Update-Database -Verbose -Script

به این ترتیب سابقه تغییرات در برنامه نگهداری شده و همچنین بدون اجرای دستورات بر روی بانک اطلاعاتی، اسکریپت نهایی اعمال تغییرات تولید می‌گردد.
د) اسکریپت تولید شده را بررسی کرده و پس از تائید و افزودن به سورس کنترل، به صورت دستی بر روی بانک اطلاعاتی اجرا کنید (مثلا توسط management studio).


مطالب
آموزش ایجاد برنامه های چند زبانه در WPF
با گسترش استفاده از کامپیوتر در بسیاری از امور روزمره انسان‌ها سازگار بودن برنامه‌ها با سلیقه کاربران به یکی از نیاز‌های اصلی برنامه‌های کامپیوتری تبدیل شده است. بدون شک زبان و فرهنگ یکی از مهم‌ترین عوامل در ایجاد ارتباط نزدیک بین برنامه و کاربر به شمار می‌رود و نقشی غیر قابل انکار در میزان موفقیت یک برنامه به عهده دارد. از این رو در این نوشته تلاش بر آن است تا یکی از ساده‌ترین و در عین حال کارا‌ترین راه‌های ممکن برای ایجاد برنامه‌های چند زبانه با استفاده از تکنولوژی WPF آموزش داده شود.

مروری بر روش‌های موجود
همواره روش‌های مختلفی برای پیاده سازی یک ایده در دنیای نرم افزار وجود دارد که هر روش را می‌توان بر حسب نیاز مورد استفاده قرار داد. در برنامه‌های مبتنی بر WPF معمولا از دو روش عمده برای این منظور استفاده می‌شود:

1-استفاده از فایل‌های resx
در این روش که برای Win App نیز استفاده می‌شود، اطلاعات مورد نیاز برای هر زبان به شکل جدول هایی دارای کلید و مقدار در داخل یک فایل .resx نگهداری می‌شود و در زمان اجرای برنامه بر اساس انتخاب کاربر اطلاعات زبان مورد نظر از داخل فایل  resx خوانده شده و نمایش داده می‌شود. یکی از ضعف هایی که این روش در عین ساده بودن دارد این است که همه اطلاعات مورد نیاز داخل assembly اصلی برنامه قرار می‌گیرد و امکان افزودن زبان‌های جدید بدون تغییر دادن برنامه اصلی ممکن نخواهد بود.

2-استفاده از فایل‌های csv که به فایل‌های dll تبدیل می‌شوند
در این روش با استفاده از ابزار‌های موجود در کامپایلر WPF برای هر کنترل یک property به نام Uid ایجاد شده و مقدار دهی می‌شود. سپس با ابزار دیگری ( که جزو ابزار‌های کامپایلر محسوب نمی‌شود ) از فایل csproj پروژه یک خروجی اکسل با فرمت csv ایجاد می‌شود که شامل Uid‌های کنترل‌ها و مقادیر آن‌ها است. پس از ترجمه متون مورد نظر به زبان مقصد با کمک ابزار دیگری فایل اکسل مورد نظر به یک net assembly تبدیل می‌شود و داخل پوشه ای با نام culture استاندارد ذخیره می‌شود. ( مثلا برای زبان فارسی نام پوشه fa-IR خواهد بود ). زمانی که برنامه اجرا می‌شود بر اساس culture ای که در سیستم عامل انتخاب شده است و در صورتی که برای آن culture فایل dll ای موجود باشد، زبان مربوط به آن culture را load خواهد کرد. با وجود این که این روش مشکل روش قبلی را ندارد و بیشتر با ویژگی‌های WPF سازگار است اما پروسه ای طولانی برای انجام کار‌ها دارد و به ازای هر تغییری باید کل مراحل هر بار تکرار شوند. همچنین مشکلاتی در نمایش برخی زبان‌ها ( از جمله فارسی ) در این روش مشاهده شده است.

روش سوم!
روش سوم اما کاملا بر پایه WPF و در اصطلاح WPF-Native می‌باشد. ایده از آنجا ناشی شده است که برای ایجاد skin در برنامه‌های WPF استفاده می‌شود. در ایجاد برنامه‌های Skin-Based به این شیوه عمل می‌شود که skin‌های مورد نظر به صورت style هایی در داخل ResourceDictionary ‌ها قرار می‌گیرند. سپس آن ResourceDictionary به شکل dll کامپایل می‌شود. در برنامه اصلی نیز همه کنترل‌ها style هایشان را به شکل dynamic resource از داخل یک ResourceDictionary مشخص شده load می‌کنند. حال کافی است برای تغییر skin فعلی، ResourceDictionary  مورد نظر از dll مشخص load شود و ResourceDictionary ای که در حال حاضر در برنامه از آن استفاده می‌شود با ResourceDictionary ای که load شده جایگزین شود. کنترل‌ها مقادیر جدید را از ResourceDictionary جدید به شکل کاملا خودکار دریافت خواهند کرد.
به سادگی می‌توان از این روش برای تغییر زبان برنامه نیز استفاده کرد با این تفاوت که این بار، به جای Style ها، String‌های زبان‌های مختلف را درون resource‌ها نگهداری خواهیم کرد.

یک مثال ساده
در این قسمت نحوه پیاده سازی این روش با ایجاد یک نمونه برنامه ساده که دارای دو زبان انگلیسی و فارسی خواهد بود آموزش داده می‌شود.
ابتدا یک پروژه WPF Application در Visual Studio 2010 ایجاد کنید. در MainWindow سه کنترل Button قرار دهید و یک ComboBox که قرار است زبان‌های موجود را نمایش دهد و با انتخاب یک زبان، نوشته‌های درون Button‌ها متناسب با آن تغییر خواهند کرد.

توجه داشته باشید که برای Button‌ها نباید به صورت مستقیم مقداری به Content شان داده شود. زیرا مقدار مورد نظر از داخل ResourceDictionary که خواهیم ساخت به شکل dynamic گرفته خواهد شد. پس در این مرحله یک ResourceDictionary به پروژه اضافه کرده و در آن resource هایی به شکل string ایجاد می‌کنیم. هر resource دارای یک Key می‌باشد که بر اساس آن، Button مورد نظر، مقدار آن Resource را load خواهد کرد. فایل ResourceDictionary را
Culture_en-US.xaml نامگذاری کنید و مقادیر مورد نظر را به آن اضافه نمایید.  

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:system="clr-namespace:System;assembly=mscorlib">
    <system:String x:Key="button1">Hello!</system:String>
    <system:String x:Key="button2">How Are You?</system:String>
    <system:String x:Key="button3">Are You OK?</system:String>
 
</ResourceDictionary>

دقت کنید که namespace ای که کلاس string در آن قرار دارد به فایل xaml اضافه شده است و پیشوند system به آن نسبت داده شده است.

با افزودن یک ResourceDictionary به پروژه، آن ResourceDictionary به MergedDictionary کلاس App اضافه می‌شود. بنابراین فایل App.xaml به شکل زیر خواهد بود:

<Application x:Class="BeRMOoDA.WPF.LocalizationSample.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
 
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Culture_en-US.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
 
    </Application.Resources>
</Application>

برای اینکه بتوانیم محتوای Button‌های موجود را به صورت داینامیک و در زمان اجرای برنامه، از داخل Resource‌ها بگیریم، از DynamicResource استفاده می‌کنیم.

<Button Content="{DynamicResource ResourceKey=button1}" />
<Button Content="{DynamicResource ResourceKey=button2}" />
<Button Content="{DynamicResource ResourceKey=button3}" />

بسیار خوب! اکنون باید شروع به ایجاد یک ResourceDictionary برای زبان فارسی کنیم و آن را به صورت یک فایل dll کامپایل نماییم.
برای این کار یک پروژه جدید در قسمت WPF از نوع User control ایجاد می‌کنیم و نام آن را Culture_fa-IR_Farsi قرار می‌دهیم. لطفا شیوه نامگذاری را رعایت کنید چرا که در ادامه به آن نیاز خواهیم داشت.
پس از ایجاد پروژه فایل UserControl1.xaml را از پروژه حذف کنید و یک ResourceDictionary با نام Culture_fa-IR.xaml اضافه کنید. محتوای آن را پاک کنید و محتوای فایل Culture_en-US.xaml را از پروژه قبلی به صورت کامل در فایل جدید کپی کنید. دو فایل باید ساختار کاملا یکسانی از نظر key برای Resource‌های موجود داشته باشند. حالا زمان ترجمه فرا رسیده است! رشته‌های دلخواه را ترجمه کنید و پروژه را build نمایید. 
پس از ترجمه فایل Culture_fa-IR.xaml به شکل زیر خواهد بود:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:system="clr-namespace:System;assembly=mscorlib">
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Culture_fa-IR_Farsi.xaml"/>
    </ResourceDictionary.MergedDictionaries>
    <system:String x:Key="button1">سلام!</system:String>
    <system:String x:Key="button2">حالت چطوره؟</system:String>
    <system:String x:Key="button3">خوبی؟</system:String>
</ResourceDictionary>
خروجی این پروژه یک فایل با نام Culture_fa-IR_Farsi.dll خواهد بود که حاوی یک ResourceDictionary برای زبان فارسی می‌باشد.

در ادامه میخواهیم راهکاری ارئه دهیم تا بتوان فایل‌های dll مربوط به زبان‌ها را در زمان اجرای برنامه اصلی، load کرده و نام زبان‌ها را در داخل ComboBox ای که داریم نشان دهیم. سپس با انتخاب هر زبان در ComboBox، محتوای Button‌ها بر اساس زبان انتخاب شده تغییر کند.
برای سهولت کار، نام فایل‌ها را به گونه ای انتخاب کردیم که بتوانیم ساده‌تر به این هدف برسیم. نام هر فایل از سه بخش تشکیل شده است:
Culture_[standard culture notation]_[display name for this culture].dll
یعنی اگر فایل Culture_fa-IR_Farsi.dll را در نظر بگیریم، Culture نشان دهنده این است که این فایل مربوط به یک culture می‌باشد. fa-IR نمایش استاندارد culture برای کشور ایران و زبان فارسی است و Farsi هم مقداری است که می‌خواهیم در ComboBox برای این زبان نمایش داده شود.
پوشه ای با نام Languages در کنار فایل اجرایی برنامه اصلی ایجاد کنید و فایل Culture_fa-IR_Farsi.dll را درون آن کپی کنید. تصمیم داریم همه dll‌های مربوط به زبان‌ها را داخل این پوشه قرار دهیم تا مدیریت آن‌ها ساده‌تر شود. 
برای مدیریت بهتر فایل‌های مربوط به زبان‌ها یک کلاس با نام CultureAssemblyModel خواهیم ساخت که هر instance از آن نشانگر یک فایل زبان خواهد بود. یک کلاس با این نام به پروژه اضافه کنید و property‌های زیر را در آن تعریف نمایید:

public class CultureAssemblyModel
    {
        //the text will be displayed to user as language name (like Farsi)
        public string DisplayText { get; set; }
        //name of .dll file (like Culture_fa-IR_Farsi.dll)
        public string Name { get; set; }
        //standar notation of this culture (like fa-IR)
        public string Culture { get; set; }
        //name of resource dictionary file inside the loaded .dll (like Culture_fa-IR.xaml)
        public string XamlFileName { get; set; }
    }
اکنون باید لیست culture‌های موجود را از داخل پوشه languages خوانده و نام آنها را در ComboBox نمایش دهیم.
برای خواندن لیست culture‌های موجود، لیستی از CultureAssmeblyModel‌ها ایجاد کرده و با استفاده از متد LoadCultureAssmeblies، آن را پر می‌کنیم.

//will keep information about loaded assemblies
public List<CultureAssemblyModel> CultureAssemblies { get; set; }
 
//loads assmeblies in languages folder and adds their info to list
 void LoadCultureAssemblies()
 {
      //we should be sure that list is empty before adding info (do u want to add some cultures more than one? of course u dont!)
      CultureAssemblies.Clear();
      //creating a directory represents applications directory\languages
      DirectoryInfo dir = new DirectoryInfo(System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\languages");
      //getting all .dll files in the language folder and its sub dirs. (who knows? maybe someone keeps each culture file in a seperate folder!)
      var assemblies = dir.GetFiles("*.dll", SearchOption.AllDirectories);
      //for each found .dll we will create a model and set its properties and then add to list  for (int i = 0; i < assemblies.Count(); i++)
      {
string name = assemblies[i].Name;
  CultureAssemblyModel model = new CultureAssemblyModel() { DisplayText = name.Split('.', '_')[2], Culture = name.Split('.', '_')[1], Name = name  , XamlFileName =name.Substring(0, name.LastIndexOf(".")) + ".xaml" }; CultureAssemblies.Add(model); } }
پس از دریافت اطلاعات culture‌های موجود، زمان نمایش آن‌ها در ComboBox است. این کار بسیار ساده است، تنها کافی است ItemsSource آن را با لیستی از CultureAssmeblyModel‌ها که ساختیم، مقدار دهی کنیم.

comboboxLanguages.ItemsSource = CultureAssemblies;
البته لازم به ذکر است که برای نمایش فقط نام هر CultureAssemblyModel در ComboBox، باید ItemTemplate مناسبی برای ComboBox ایجاد کنیم. در مثال ما ItemTemplate به شکل زیر خواهد بود:

<ComboBox HorizontalAlignment="Left" Margin="10" VerticalAlignment="Top" MinWidth="100" Name="comboboxLanguages">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <Label Content="{Binding DisplayText}"/>
                </DataTemplate>
            </ComboBox.ItemTemplate>
</ComboBox>
توجه داشته باشید که با وجود اینکه فقط نام را در ComboBox نشان می‌دهیم، اما باز هم هر آیتم از ComboBox یک instance از نوع CultureAssemblyModel می‌باشد.

در مرحله بعد، قرار است متدی بنویسیم که اطلاعات زبان انتخاب شده را گرفته و با جابجایی ResourceDictionary ها، زبان برنامه را تغییر دهیم.
متدی با نام LoadCulture در کلاس App ایجاد می‌کنیم که یک CultureAssemblyModel به عنوان ورودی دریافت کرده و ResourceDictionary داخل آن را load می‌کند و آن را با ResourceDictionary فعلی موجود در App.xaml جابجا می‌نماید.
با این کار، Button هایی که قبلا مقدار Content خود را از Resource‌های موجود دریافت می‌کردند، اکنون از Resource‌های جابجا شده خواهند گرفت و به این ترتیب زبان انتخاب شده بر روی برنامه اعمال می‌شود.

//loads selected culture
 public void LoadCulture(CultureAssemblyModel culture)
 {
     //creating a FileInfo object represents .dll file of selected cultur
     FileInfo assemblyFile = new FileInfo("languages\\" + culture.Name);
     //loading .dll into memory as a .net assembly
     var assembly = Assembly.LoadFile(assemblyFile.FullName);
     //getting .dll file name
     var assemblyName = assemblyFile.Name.Substring(0, assemblyFile.Name.LastIndexOf("."));
     //creating string represents structure of a pack uri (something like this: /{myassemblyname;component/myresourcefile.xaml}
     string packUri = string.Format(@"/{0};component/{1}", assemblyName, culture.XamlFileName);
     //creating a pack uri
     Uri uri = new Uri(packUri, UriKind.Relative);
     //now we have created a pack uri that represents a resource object in loaded assembly
     //and its time to load that as a resource dictionary (do u remember that we had resource dictionary in culture assemblies? don't u?)
     var dic = Application.LoadComponent(uri) as ResourceDictionary;
     dic.Source = uri;
     //here we will remove current merged dictionaries in our resource dictionary and add recently-loaded resource dictionary as e merged dictionary
     var mergedDics = this.Resources.MergedDictionaries;
     if (mergedDics.Count > 0)
          mergedDics.Clear();
     mergedDics.Add(dic);
 }
برای ارسال زبان انتخاب شده به این متد، باید رویداد SelectionChanged را برای ComboBox مدیریت کنیم:

void comboboxLanguages_SelectionChanged(object sender, SelectionChangedEventArgs e)
 {
     var selectedCulture = (CultureAssemblyModel)comboboxLanguages.SelectedItem;
     App app = Application.Current as App;
     app.LoadCulture(selectedCulture);
 }

کار انجام شد!
از مزیت‌های این روش می‌توان به WPF-Native بودن، سادگی در پیاده سازی، قابلیت load کردن هر زبان جدیدی در زمان اجرا بدون نیاز به کوچک‌ترین تغییر در برنامه اصلی و همچنین پشتیبانی کامل از نمایش زبان‌های مختلف از جمله فارسی اشاره کرد. 





مطالب
آشنایی با Visual Studio 2012 Code Map
Code Map چیست؟
در نسخه Visual Studio 2012 Ultimate Update 1  قابلیتی به نام Code Map اضافه گردید که امکان تصویر سازی، روابط کد‌ها را فراهم می‌سازد.
در نسخه  Visual Studio 2012 Update 2 مایکروسافت Code Map را توسعه داد و با پشتیبانی از اشکال زدایی، با Code Map نیز می‌توانید قدم به قدم کد را اشکال زایی نمایید. به زبان ساده‌تر Code Map فلوچارت اجرای برنامه است که در آن ارتباط بین متود‌ها نمایش داده شده است.
چگونه  از Code Map Debugging استفاده نماییم؟

در خطی از برنامه Break Point گذاشته و برنامه را اجرا نمایید. وقتی برنامه به خط مورد نظر رسید، نوار ابزار Debug را فعال و گزینه Code Map را انتخاب کنید تا پنجره Code Map باز شده و فلوچارت کد مورد نظر را رسم نماید. نوار قرمز رنگ دور گره، قسمتی از کد که در حال حاضر در حال اشکال زدایی است را نشان می‌دهد. وقتی با کلید F11 به درون متودی می‌روید گره متناظر آن نیز رسم می‌شود.

اگر بر روی فیلد Summary راست کلیک و گزینه Find All References on Code Map را انتخاب کنید، همه ارجاع‌های که این فیلد در آنها صدا زده شده است را نمایش می‌دهد.

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

بررسی ویژگی‌های Code Map:
برای هر گره در صورت لزوم می‌توانید یادداشتی اضافه نماید برای این کار گره مورد نظر را انتخاب تا نوار ابزاری در کنار آن ظاهر شود و گزینه create new comment node را انتخاب و یادداشت خود را ثبت نمایید.

می توانید code map را با دیگران از طریق ایمیل به اشتراک گذارید یا آن را ذخیره نمایید. برای این کار در بالای پنجره code map گزینه share را انتخاب و یکی از آینم‌ها مورد نظر را کلیک نمایید.

علاوه بر این برای تعقیب کردن یک گره آن می‌توانید آن را با یک پرچم و تغییر رنگ آن در پنجره code map از دیگر گره‌ها مجزا و تعقیب نمایید. برای این کار بر روی گره مورد نظر راست کلیک و گزینه Flag for Follow Up را انتخاب نمایید. از گزینه Other Flag Colors رنگ پیش فرض آن را می‌توانید تغییر دهید.

بازبینی اشاره گر ها:

در کنار هر گره علامتی نمایان می‌شود که وضعیت code amp در آن لحظه برای آن گره را نمایش می‌دهد.

تغییر نمای دیاگرام:

برای تغییر نمای گراف code map و نمایش بهتر آن از گزینه layout یکی از حالات موجود را می‌توانید انتخاب نمایید. هر وقت گره ای  اضافه شود که قبلا اضافه شده باشد رنگ آن سبر می‌شود برای پاک کردن این چنین گره‌های گزینه clear Result Highlighting را انتخاب نمایید.

نظرات مطالب
خواندنی‌های 16 اردیبهشت
Forms authentication که در ASP.Net 1.0 معرفی شد پایه افزونه‌ای به نام membership است که در ASP.Net 2.0 ارائه شده. بنابراین شما به صورت مستقل و بدون استفاده از membership دات نت 2 هم می‌تونید از form authentication استفاده کنید. فقط باید مباحث آن‌را کد نویسی کنید. از لاگین گرفته تا هش کردن پسوردها و غیره.
مثالی از خود مایکروسافت:
http://support.microsoft.com/kb/301240

در این حالت سیستم شما هم افزونه دیگری خواهد شد برای پایه‌ای به نام forms authentication و مسلما نه به پختگی سیستم طراحی شده توسط مایکروسافت. زیاد به هجمه‌های سیاسی که پشت این شرکت هست توجه نکنید. سیستم membership آن‌را که ملاحظه و تحلیل کنید متوجه خواهید شد این مسایل سرسری و سطحی طراحی نشده.
اگر هم بخواهید از سیستم membership استفاده کنید، می‌شود دیتابیس آن‌را در محل دیتابیس خودتون ایجاد کنید. جداول شما در کنار جداول آن قرار خواهد گرفت. یعنی الزاما نیازی به دو دیتابیس مجزا نیست.
این مباحث رو در کتاب امنیت در ASP.Net 2.0 توضیح داده‌ام (قدم به قدم) و نیاز به ذکر چندین فصل در این مورد هست اگر بخواهم توضیح کامل و جامع بدهم:
http://naghoos-andisheh.ir/product_info.php?products_id=197

به صورت خلاصه:
از پایه‌ای به نام Forms authentication استفاده کنید بدون نیاز به مباحث ASP.Net 2.0 که اساسا فقط یک افزونه هستند و نه بیشتر. سپس سیستم اعتبارسنجی خاص خودتون را بر اساس جداول موجود طراحی کنید.
یا اگر به دنبال سیستم پخته‌ای هستید که توسط یک سری متخصص امنیتی طراحی شده، جدول خودتان را کنار بگذارید و به سیستم membership مایکروسافت آ‌ن‌را ارتقاء دهید و باز هم تکرار می‌کنم این مورد اختیاری است.
نظرات مطالب
معرفی DNTProfiler
- لطفا برای طرح سؤالات و ارائه‌ی پیشنهادات خود در زمینه‌ی این پروژه، به قسمت اختصاصی آن در سایت مراجعه نمائید:
https://www.dntips.ir/projects/details/21 
- نیاز است stack trace کامل را ارسال کنید. این استثناء دقیقا از کجا صادر شده‌است؟ دقیقا کدام متد این پروژه این استثناء را صادر کرده‌است؟
+
این پروژه چون از interceptors خود EF استفاده می‌کند، به هیچ عنوان دخالتی در نحوه‌ی اجرای متدهای آن ندارد. خطایی را که دریافت کردید مربوط است به خود EF و نه این پروژه. برای آزمایش، آن‌را غیرفعال کنید (مداخل وب کانفیگ آن‌را کامنت کنید) و بعد برنامه را اجرا کنید.
Supported and Unsupported LINQ Methods (LINQ to Entities)  
نظرات مطالب
معرفی ELMAH
خلاصه بحث ارسال ایمیل:
- امکان ندارد هاست شما برای ارسال ایمیل نیاز به smtp authentication نداشته باشد (من ندیدم). بنابراین یا این اطلاعات را باید زنگ بزنید و از هاست بگیرید یا در کنترل پنل ایمیل‌های سایت یک یوزر مخصوص را درست کنید تا بشود در برنامه از آن استفاده کرد.
- سپس تگ errorMail باید دقیقا مقدار دهی شود. آدرس و نام کاربری و غیره. (این موارد مرتبط به ارسال ایمیل است و با نام کاربری مثلا ftp سایت متفاوت می‌باشد)
- در IIS6 : باید در قسمت system.web -- httpModules ، مطابق مثال web.config پوشه sample کتابخانه، قسمت Elmah.ErrorMailModule را از کامنت خارج کنید.
- در IIS7 : باید در قسمت system.webServer فایل web.config شما Elmah.ErrorMailModule نیز مطابق مثال یاد شده ، ذکر شده باشد.