نظرات مطالب
تغییرات بوجود آمده در Bundling and Minification -MVC4
- با توجه به محتوای فایل هست و این محاسبات فقط بر اساس درخواست مرورگر انجام می‌شود. یعنی هربار به ازای نمایش صفحات این کارها و محاسبات صورت نمی‌گیرد و اگر کش شده باشد (که شده برای یکسال)، اصلا فشاری به سرور وارد نمی‌شود چون مرورگر برای موارد کش شده درخواست جدیدی را به سرور ارسال نمی‌کند.
- نگارش تولیدی بر اساس هش محتوای فایل محاسبه می‌شود به صورت خودکار.
- در وب فرم‌ها هم این قابلیت مدتی هست که وجود دارد: (^)
نظرات مطالب
ASP.NET MVC #12
- برای نمایش خودکار تاریخ فارسی می‌تونید از این فایل استفاده کنید (تست شده) : (^)
- برای حالت nullable هم همین فایل کافی است. یعنی در اصل بهتر است DisplayTemplate برای حالت nullable نوشته شود که برای هر دو حالت مورد استفاده قرار خواهد گرفت.

- در مورد validator هم می‌تونید یک attribute سفارشی تهیه کنید. در قسمت 13 راه کلی انجام کار رو توضیح دادم. برای تاریخ شمسی بحث مفصلی است. یک کلاس قبلا در این مورد تهیه کردم : (^) البته این فقط یک ایده برای شروع است که چه فرمت‌هایی می‌تونه وارد بشه و قابل قبول باشه.
مطالب
BloggerToCHM 1.3

نگارش جدید برنامه BloggerToCHM را از اینجا می‌توانید دریافت کنید.
تغییرات حاصل شده:
  • پشتیبانی بهتر از تغییرات open search API که هر از چندگاهی توسط گوگل اعمال می‌شود.
  • رفع مشکل تخریب اعداد فارسی در فایل تولیدی نهایی
  • اضافه شدن چند گزینه جهت کنترل بر روی نمایش قسمت about در فایل نهایی حاصل و همچنین درج نظرات
  • و ...

مطالب
آموزش LINQ بخش پنجم
در ادامه سری آموزشی LINQ، موارد دیگری از عبارت‌های پرس و جو را بررسی می‌کنیم:
 • عبارت group
 • عبارت orderby
 • کلمات کلیدی ascending و descending
 • کلمه کلیدی by


بررسی عبارت group و کلمه‌ی کلیدی by

عبارت group یک توالی یک بعدی (flat sequence) یا ساده را از ورودی دریافت و یک توالی گروه بندی شده را تولید می‌کند.
مثال: در بخش دوم این سری آموزشی، کلاسی به نام Ingredient تعریف کردیم که مواد غذایی و کالری آنها را نگهداری می‌کرد. در این مثال قصد داریم مواد غذایی دریافت شده از توالی ورودی را بر اساس کالری آنها، به گروه‌هایی تقسیم کنیم، بطوریکه مواد غذایی با کالری‌های یکسان در یک گروه قرار بگیرند:
Ingredient[] ingredients =
{
   new Ingredient{Name = "Sugar", Calories=500},
   new Ingredient{Name = "Lard", Calories=500},
   new Ingredient{Name = "Butter", Calories=500},
   new Ingredient{Name = "Egg", Calories=100},
   new Ingredient{Name = "Milk", Calories=100},
   new Ingredient{Name = "Flour", Calories=50},
   new Ingredient{Name = "Oats", Calories=50}
};

IEnumerable<IGrouping<int, Ingredient>> query =
from i in ingredients
group i by i.Calories;

foreach (IGrouping<int, Ingredient> group in query)
{
   Console.WriteLine($"Ingredients with {group.Key} calories");
   foreach (Ingredient ingredient in group)
   {
      Console.WriteLine($"- { ingredient.Name}");
   }
}
در این مثال، از نوع جنریکی به نام IGrouping استفاده شده‌است که اولین پارامتر آن کلید گروه است (در این مثال کالری مواد غذایی) و دومین پارامتر آن، نوع لیست را مشخص می‌کند که در اینجا کلاس Ingredient است. اعضای لیست تولید شده، کالری یکسانی دارند. دلیل استفاده‌ی از نوع‌ها بصورت صریح و آشکار (Explicit) خوانایی بیشتر برای تشخیص خروجی‌های تولید شده‌ی در کد‌ها می‌باشد. ولی راه بهتر، جایگزین کردن کد <<IEnumerable<IGrouping<int, Ingredient با کلمه‌ی کلیدی var  می‌باشد.
خروجی مثال بالا:
 Ingredients with 500 calories
- Sugar
- Lard
- Butter
Ingredients with 100 calories
- Egg
- Milk
Ingredients with 50 calories
- Flour
- Oats

برای آشنایی بیشتر با اینترفیس IGrouping اینجا را مطالعه کنید.


عبارت orderby و کلمات کلیدی ascending  و descending 

عبارت orderby برای تولید یک توالی مرتب شده‌ی بصورت صعودی (ascending)  و یا نزولی (descending) مورد استفاده قرار می‌گیرد.
مثال: توالی مثال قبل را در نظر بگیرد:
IOrderedEnumerable<Ingredient> sortedByNameQuery =
from i in ingredients
orderby i.Name
select i;

foreach (var ingredient in sortedByNameQuery)
{
   Console.WriteLine(ingredient.Name);
}
خروجی مثال بالا:
Butter
Egg
Flour
Lard
Milk
Oats
Sugar
علملیات مرتب سازی بصورت پیش فرض بصورت صعودی می‌باشد (Ascending). برای تغییر این حالت می‌توانید از کلمه‌ی کلیدی descending استفاده کنید:
IOrderedEnumerable<Ingredient> sortedByNameQuery =
from i in ingredients
orderby i.Name descending
select i;
با اجرای مجدد برنامه، خروجی زیر را مشاهده خواهید کرد:
 Sugar
Oats
Milk
Lard
Flour
Egg
Butter
عبارت orderby  را می‌توان با عبارت groupby ترکیب کرد و نتیجه‌ی حاصل از مثال اول این مطلب را بصورت مرتب شده بر اساس کالری مواد غذایی مشاهده کرد.
مثال:
 Ingredient[] ingredients =
{
   new Ingredient{Name = "Sugar", Calories=500},
   new Ingredient{Name = "Lard", Calories=500},
   new Ingredient{Name = "Butter", Calories=500},
   new Ingredient{Name = "Egg", Calories=100},
   new Ingredient{Name = "Milk", Calories=100},
   new Ingredient{Name = "Flour", Calories=50},
   new Ingredient{Name = "Oats", Calories=50}
};

IEnumerable<IGrouping<int, Ingredient>> query =
from i in ingredients
group i by i.Calories
into calorieGroup
orderby calorieGroup.Key
select calorieGroup;

foreach (IGrouping<int, Ingredient> group in query)
{
   Console.WriteLine($"Ingredients with {group.Key} calories");
   foreach (Ingredient ingredient in group)
   {
     Console.WriteLine($"- { ingredient.Name}");
   }
}
خروجی مثال بالا :
 Ingredients with 50 calories
- Flour
- Oats
Ingredients with 100 calories
- Egg
- Milk
Ingredients with 500 calories
- Sugar
- Lard
- Butter
همانطور که مشاهده می‌کنید بر عکس حالت قبلی که خروجی گروه‌ها بصورت نزولی بود، اینجا خروجی بر اساس کالری غذا و بصورت صعودی، نمایش داده شده است.


در این سری آموزشی با دو روش نوشتن پرس و جو، در LINQ آشنا شدیم:
 1- Fluent Style (استفاده از متدهای الحاقی برای انجام عملیات‌های مختلف بر روی توالی)
 2- Expression Style (استفاده از کلمات کلیدی (key word) برای انجام عملیات‌های مختلف بر روی توالی)

 هر یک از روش‌های فوق مزایایی دارند که با توجه به شرایطی که با آن روبرو هستیم از آنها استفاده می‌کنیم:
 • تعداد عملگر‌ها : در صورتی که پرس و جو نیاز به یک عملگر بر روی توالی داشته باشد می‌توان از روش اول استفاده کرد. به این خاطر که نسبت به روش دوم تعداد دستورات کمتری مورد استفاده قرار خواهد گرفت.
مثال :
 var q1 = ingredients.Where(x => x.Calories > 100);
var q2 = from i in ingredients
 where i.Calories >
100 select i;
در مثال فوق نتیجه‌ی اجرای دو پرس و جو، موادی است که کالری آنها بیشتر از 100 می‌باشد. همانطور که مشاهده می‌کنید روش اول مختصرتر از روش دوم است. این مورد در زمانی است که تنها یک عملیات بر روی توالی اجرا شود.
 • پرس و جویی که قرار است نوشته شود، از نظر عملیات بر روی توالی ساده باشد: در این حالت روش استفاده شده تفاوتی نمی‌کند و بستگی به روش برگزیده و مورد علاقه‌ی برنامه نویس و یا تیم برنامه نویسی دارد. مثلا زمانیکه تنها عملگر‌های Where  و orderby بخواهند اجرا شود.
 • پرس و جوهایی که با متغیر‌های range مختلفی رو برو هستند: در این حالت استفاده از عبارت‌های پرس و جو راحت از روش عملگر‌های پرس و جو می‌باشد.

لیستی از عملگرهای جستجو که در روش عبارت‌های جستجو معادل آنها مهیا شده است :
 • GroupBy
 • GroupJoin
 • Join
 • OrderBy
 • OrderByDescending
 • Select
 • SelectMany
 • ThenBy
 • ThenByDescending
 • Where

در بسیاری از پرس و جو‌ها می‌توانیم هر دو روش را با هم ترکیب کنیم که نمونه‌ای از آن، در جلسه‌ی چهارم در زمان استفاده‌ی از متد DefaultIfEmpty استفاده شد. درمثال زیر استفاده از عملگر count، با استفاده از روش اول، به همراه عبارت پرس و جوی تولید شده‌ی با روش دوم، نمایش داده شده است:
 int mixedQuery =
(from i in ingredients
where i.Calories > 100
select i).Count();
اشتراک‌ها
چگونه بفهمیم فایل انتخابی واقعا عکسه یا نه ؟

موقعی که از کاربر یک عکس رو دریافت میکنیم نیازه که بررسی شه که آیا این فایل واقعا عکسه یا نه.

برای کنترل این موضوع Attribute‌های اعتبارسنجی بهترین انتخاب هستن و با یکبار افزودن میتوان از آنها در هر جایی استفاده کرد.

سمت سرور اینکار به این صورت هست ^

اما سمت کلاینت حتی اگه بیایم فرمت فایل رو هم بررسی کنیم بازهم جوابگو نیست و میشه به راحتی فرمت یک فایل ZIP رو به PNG تغییر داد و ارسالش کرد و عملا اعتبارسنجی سمت کلاینت کار خاصی رو انجام نمیده.

در این پروژه Attribute اعتبارسنجی برای بررسی فایل که آیا واقعا عکس هست یا نه نوشته شده، هم سمت کلاینت و هم سمت سرور.

نحوه انجام کار: برای سمت کلاینت عکسی که کاربر وارد میکنه رو در داخل تگ IMG نمایش میده و اگه عکس به درستی لود بشه رخداد OnLoad تگ IMG فراخوانی میشه و اعتبارسنجی پاس میشه.

تگ IMG به کاربر نمایش داده نمیشه و به صورت display: none هستش.

از این Attribute اعتبارسنجی در کنار Attribute‌های کنترل حجم فایل هم میشه استفاده کرد که قبل از اینکه بخوایم بررسی کنیم که آیا فایل واقعا عکسه یا نه ابتدا حجم فایل مورد بررسی قرار بگیره.

چگونه بفهمیم فایل انتخابی واقعا عکسه یا نه ؟
نظرات اشتراک‌ها
نقدی بر سامانۀ اتوماسیون اداری همکاران سیستم و نامۀ جوابیۀ شرکت
هرچند که هیچوقت نظر مثبتی در مورد سیستمهای همکاران سیستم نداشته ام اما با نظر شما در مورد این نقد موافقم. جمله "انگار سیستم بر اساس بی اعتمادی بین مدیران و کارشناسان طراحی شده است." در مورد مکانیزم دقیق جلوگیری از خطای کاربران و سطوح‌های مختلف کاربران نشان از یک نقد غیر کارشناسانه داشته باشد. در مورد وابستگی به برنامه‌های دیگر هم تقریبا همه سیستمهای اتوماسیون به برنامه هایی مانند Word و Acrobat و ... وابستگی دارند
در مورد باقی ماندن سرورهای قدیمی بعد از عملیات Convert هم باید عرض کنم که این یک اصله و یک باید. اگر سازمانی خلاف این عمل کند اشتباه کرده است. همیشه برای اطمینان از عملکرد صحیح و بررسی داده‌های انتقال داده شده مدتی سیستمهای قدیمی سرپا نگهداشته میشن.
و اما در جواب جمله "و نهایتا اینکه سیستم با اعتراض‌های مختلف کاربران در حال پیاده سازی می‌باشد." متاسفانه این واکنش طبیعی کارمندان ایرانی به تغییرات همیشگی است و باید اینو خدمت شما عرض کنم که بر خلاف دلیل اصلی نوشتن این مقاله که تنبلی شرکتهای قدیمی و بزرگ است در ایران مشکل اصلی تنبلی کاربران (بخوانید کارمندان) شرکتهاست که به خاطر این تنبلی در برابر تغییرات مقاومت می‌کنن. نمونه همین مقاومتها را در بسیاری از شرکتهای ایرانی دیده ام و گاها حتی باعث کندی فرایند مهاجرت به سیستم جدید و یا حتی ممانعت از سیستم جدید شده اند.
اشتراک‌ها
انتشار EF6.1.3 RTM
EF6.1.3 just contain fixes to high priority issues that have been reported on the 6.1.2 release. The fixes include
Query: Regression in EF 6.1.2: OUTER APPLY introduced and more compex queries for 1:1 relationships and "let" clause
TPT problem with hiding base class property in inherited class
DbMigration.Sql fails when the word 'go' is contained in the text
Create compatibility flag for UnionAll and Intersect flattening support
Query with multiple Includes does not work in 6.1.2 (working in 6.1.1)
"You have an error in your SQL syntax" after upgrading from EF 6.1.1 to 6.1.2
انتشار EF6.1.3 RTM
نظرات مطالب
نحوه تنظیم زمانبندی (Scheduling) برای Crawler در شیرپوینت
در وهله اول باید عرض کنم که این مقادیر صرفا جهت یه مثال و آموزش بیان شده اند و دلیل بر پیاده سازی مانند آنها وجود ندارد . ضمنا در تنظیمات ، نوع Indexing به صورت   incremental    است که در نتیجه به طور کامل جستجو انجام نمی‌شود . اما در مورد اینکه اصلا چرا باید ایندکس انجام شود باید عرض کنم که ساختار ایندکسر در شیرپوینت ، که بر مبنای Full-Text Index در SQL Server بنا شده است تمام محتویات سایت هایی که برای ایندکسر تعریف شده است (با توجه به سطح دسترسی تعریف شده) می‌خواند و به یک Stream از کاراکتر‌های unicode تبدیل میکند ، (به کمک IFilter مربوطه) سپس برنامه ای به نام word breaker واژه‌های رایج مانند And و OR و ... (noise words) را حذف کرده و اطلاعات آن واژه‌ها به همراه آدرسی که واژه‌ها وجود دارند بعلاوه سطح دسترسی آنها و تنظیمات امنیتی و ... را به کمک برنامه ای به نام Gatherer Program  در پایگاه داده sql نگه داری میکند (اگر واژه وجود داست فقط اطلاعات منبع ذخیره می‌شود) این پروسه به استخراج اطلاعات در سامانه جستجو کمک می‌کند . امــا در مورد  full-fledge   اطلاعات  کافی ندارم که بتونم راهنماییتون کنم . در صورتی که اطلاعاتی بدست آوردم ، حتما در اختیارتون قرار می‌دهم. موفق باشید
مطالب
AOP با استفاده از Microsoft Unity
چند روز پیش فرصتی پیش آمد تا بتوانم مروری بر مطلب منتشر شده درباره AOP داشته باشم. به حق مطلب مورد نظر، بسیار خوب و مناسب شرح داده شده بود و همانند سایر مقالات جناب نصیری چیزی کم نداشت. اما امروز قصد پیاده سازی یک مثال AOP، با استفاده از Microsoft Unity Application Block را به عنوان IOC Container دارم. اگر شما هم، مانند من از UnityContainer به عنوان IOC Container در پروژه‌های خود استفاده می‌کنید نگران نباشید. این کتابخانه به خوبی از مباحث Interception پشتیبانی می‌کند. در ادامه طی یک مقاله این مورد را با هم بررسی می‌کنیم.
برای دوستانی که با AOP آشنایی ندارند پیشنهاد می‌شود ابتدا مطلب مورد نظر را یک بار مطالعه نمایند.
برای شروع یک پروژه در VS.Net بسازید و ارجاع به اسمبلی‌های زیر را در پروژه فراموش نکنید:
»Microsoft.Practices.EnterpriseLibrary.Common
»Microsoft.Practices.Unity
»Microsoft.Practices.Unity.Configuration
»Microsoft.Practices.Unity.Interception
»Microsoft.Practices.Unity.Interception.Configuration

یک اینترفیس به نام IMyOperation بسازید:
    public interface IMyOperation
    {      
        void DoIt();
    }

کلاسی می‌سازیم که اینترفیس بالا را پیاده سازی نماید:
 public void DoIt()
  {
     Console.WriteLine( "this is main block of code" );
  }
قصد داریم با استفاده از AOP یک سری کد مورد نظر خود(در این مثال کد لاگ کردن عملیات در یک فایل مد نظر است) را به کد‌های متد‌های مورد نظر تزریق کنیم. یعنی با فراخوانی این متد کد‌های لاگ عملیات در یک فایل ذخیره شود بدون تکرار یا فراخوانی دستی متد لاگ.
ابتدا یک کلاس برای لاگ عملیات می‌سازیم:
public class Logger
    {
        const string path = @"D:\Log.txt";

        public static void WriteToFile( string methodName )
        {
            object lockObject = new object();
            if ( !File.Exists( path ) )
            {
                File.Create( path );
            }
            lock ( lockObject )
            {
                using ( TextWriter writer = new StreamWriter( path , true ) )
                {
                    writer.WriteLine( string.Format( "{0} at {1}" , methodName , DateTime.Now ) );                
                }
            }
        }
    }
حال نیاز به یک Handler برای مدیریت فراخوانی کد‌های تزریق شده داریم. برای این کار یک کلاس می‌سازیم که اینترفیس ICallHandler را پیاده سازی نماید.
public class LogHandler : ICallHandler
    {
        public IMethodReturn Invoke( IMethodInvocation input , GetNextHandlerDelegate getNext )
        {
            Logger.WriteToFile( input.MethodBase.Name );

            var methodReturn = getNext()( input , getNext );         

            return methodReturn;
        }

        public int Order { get; set; }
    }
کلاس بالا یک متد به نام Invoke دارد که فراخوانی متد‌های مورد نظر برای تزریق کد را در دست خواهد گرفت. در این متد ابتدا عملیات لاگ در فایل مورد نظر ثبت می‌شود(با استفاده از Logger.WriteToFile). سپس با استفاده از getNext که از نوع GetNextHandlerDelegate است، اجرا را به کد‌های اصلی برنامه منتقل می‌کنیم.
 var methodReturn = getNext()( input , getNext );
برای مدیریت بهتر عملیات لاگ یک Attribute می‌سازیم که فقط متد هایی که نیاز به لاگ کردن دارند را مشخص کنیم. به صورت زیر:
 public class LogAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler( Microsoft.Practices.Unity.IUnityContainer container )
        {
            return new LogHandler();
        }
    }
فقط دقت داشته باشید که کلاس مورد نظر به جای ارث بری از کلاس Attribute باید از کلاس HandlerAttribute که در فضای نام Microsoft.Practices.Unity.InterceptionExtension  تعبیه شده است ارث ببرد(خود این کلاس از کلاس Attribute ارث برده است).  کافیست در متد CreateHandler آن که Override شده است یک نمونه از کلاس LogHandler را برگشت دهیم.
برای آماده سازی Ms Unity جهت عملیات Interception باید کد‌های زیر در ابتدا برنامه قرار داده شود:
var  unityContainer = new UnityContainer();

 unityContainer.AddNewExtension<Interception>();

  unityContainer.Configure<Interception>().SetDefaultInterceptorFor<IMyOperation>( new InterfaceInterceptor() );
            
  unityContainer.RegisterType<IMyOperation, MyOperation>();

توضیح چند مطلب:
بعد از نمونه سازی از کلاس UnityContainer باید Interception به عنوان یک Extension به این Container اضافه شود. سپس با استفاده از متد Configure برای اینترفیس IMyOperation یک Interceptor پیش فرض تعیین می‌کنیم. در پایان هم به وسیله متد RegisterType کلاس MyOperation  به اینترفیس IMyOperation رجیستر می‌شود. از این پس هر گاه درخواستی برای اینترفیس IMyOperation از unityContainer شود یک نمونه از کلاس MyOperation در اختیار خواهیم داشت.
به عنوان نکته آخر متد DoIt در اینترفیس بالا باید دارای LogAttribute باشد تا عملیات مزین سازی با کد‌های لاگ به درستی انجام شود.

یک نکته تکمیلی:
در هنگام مزین سازی متد  set خاصیت ها، به دلیل اینکه اینترفیسی برای این کار وجود ندارد باید مستقیما عملیات AOP به خود کلاس اعمال شود. برای این کار باید به صورت زیر عمل نمود:

var container = new UnityContainer();
container.RegisterType<Book , Book>();

container.AddNewExtension<Interception>();

 var policy = container.Configure<Interception>().SetDefaultInterceptorFor<Book>( new VirtualMethodInterceptor() ).AddPolicy( "MyPolicy" );

  policy.AddMatchingRule( new PropertyMatchingRule( "*" , PropertyMatchingOption.Set ) );
  policy.AddCallHandler<Handler.NotifyChangedHandler>();
همان طور که مشاهده می‌کنید عملیات Interception مستقیما برای کلاس پیکر بندی می‌شود و به جای InterfaceInterceptor از VirtualMethodInterceptor برای تزریق کد به بدنه متد‌ها استفاده شده است. در پایان نیز با تعریف یک Policy می‌توانیم به راحتی(با استفاده از "*") متد Set  تمام خواص کلاس را به NotifyChangedHandler مزین نماییم.

سورس کامل مثال بالا