יום רביעי, 26 ביוני 2013

טיפים לקינפוג IIS

כאשר אנחנו מפתחים אתר, אנחנו מנסים לעשות הכל כדי שיהיה בעל ביצועים מיטביים.
כאשר אנחנו מרימים אתר באמצעות IIS, בעזרת קינפוג נכון של ה IIS אנחנו יכולים לשפר את הביצועים בכ 40%.

הטיפים שאציג נאמרו ע"י מרטין שוורצמן, מומחה IIS במיקרוסופט.
  1. החל מ IIS7 כשבוחרים Managed pipeline ב Application pool יש לבחור ב Integrated. זה מאפשר עבודה יותר מהירה ב .net וביצועים יותר טובים. Classic נמצא לשם תאימות לאחור עם IIS6
  2. נשים אפליקציות באותו application pool רק כאשר האפליקציות קשורות אחת לשנייה ע״י כך שחולקות מידע משותף.
  3. נבודד אפליקציה ל application pool משלה כאשר הקוד לא מושלם והוא גורם לדליפת זכרון, במצב זה נגביל את כמות הזכרון שמוקצה לאפליקציה.
  4. לא עושים iisreset. אם כבר בחרנו לעשות, אז לעשות דרך הממשק.
  5. אם יש במערכת רכיב שמשתמש ב 32 ביט ורכיב אחר שמשתמש ב 64 אז צריך להפריד את הרכיבים לapplication pool שונים. אין סיבה שרכיב 64 ירוץ על 32 ביט.
  6. IIS Compresion- פוסט של מרטין המסביר בהרחבה איך לבצע
  7. בקובץ global.asax ב application_start יש להוסיף: System.Net.ServicePointManager.DefaultConnectionLimit=int.MaxValue
תקנפגו נכון!

יום שני, 17 ביוני 2013

Ajax call is not working when script is on .js file

בעת ביצוע refactoring לדף ה view שלנו בפרוייקט ה mvc, העברתי את פונקציות ה JavaScript לקובץ js נפרד, שיושב בתיקיית הסקריפטים בפרוייקט.
ברגע שביצעתי זאת, כל פונקציות ה js כמובן נקראו, אבל קריאות ה Ajax לשרת הפסיקו לפעול.
אחרי חיפוש קצר מאוד בgoogle מצאנו את הבעיה ואת הפתרון
הבעיה היתה בשימוש ה relative path שבקובץ הjs. אם מעבירים את הפונקציה לדף ה view עצמו, הקריאה תתבצע כמו שצריך.
שימו לב, בעיה כזאת יכולה גם לקרות כאשר מעבירים את הפרוייקט לסביבת production, כאשר האתר לא רץ על ה localhost..

בהתחלה פונקציית ה js שלי נראתה כך:
$Post('Url.Action("ActionName","Controller")',.........

הפתרון הוא ליצור משתנה js בדף ה view שלנו, ולהשתמש איתו בקובץ ה js:

var myUrl='Url.Action("ActionName","Controller")';

קובץ ה js:

$Post(myUrl,.........

וזה יעבוד.

תהנו!

יום ראשון, 2 ביוני 2013

אני לא מכיר מה זה Switch- פתרון בעזרת Reflection

בהמשך לפוסט הקודם שלי "אני לא מכיר מה זה Switch- Case", היום נלמד עוד דרך לכתוב קוד ללא switch-case, והפעם באמצעות Reflection ובעזרת יצירת Custom Attributes . גם כאן Evgeny Borisov  לימד אותי את הפתרון הנכון.

נניח שיש לנו הרבה סוגי מאכלים. לכל סוג מאכל יש קוד כלשהו. התוכנית מקבלת קוד של סוג מאכל, ומפעילה פונקציה לוגית כלשהי הקשורה לסוג מאכל הספציפי.

ניצור Custom Attribute שנקרא לו "FoodType":

   
    [System.AttributeUsage(System.AttributeTargets.Class
                      | System.AttributeTargets.Struct)]
    public class FoodType : System.Attribute
    {
        private int dbCode;

        public FoodType(int dbCode)
        {
            this.dbCode = dbCode;
        }

        public int GetDBCode()
        {
            return dbCode;
        }
    }

ניצור interface:
 
    public interface FoodHandler
    {
        void handleFood();
    }
עכשיו קטע מעניין: כל מחלקה שמבצעת לוגיקה עבור סוג מאכל מסוים, תממש את ה interface שיצרנו, ותקבל את ה Attribute שיצרנו, וכמובן שנחליט מה הקוד המתאים של המחלקה:
 
    [FoodType(1)]
    public class MeatHandler : FoodHandler
    {
        public void handleFood()
        {
            System.Console.WriteLine("40 lines of code handling meat");
        }
    }


    [FoodType(2)]
    public class FishHandler : FoodHandler
    {
        public void handleFood()
        {
            System.Console.WriteLine("60 lines of code handling fish");
        }
    }

עכשיו נממש פונקציה, שבעת "הרמת המערכת" היא נגשת ב Reflection לקבצי ה dll, מחפשת שם את כל ה class שקיבלו את ה attribute שיצרנו, ויוצרת dictionary  שבו יש מיפוי של קוד מאכל - וה instance המתאים של ה class:

 
   public class MainHandler
    {
        Dictionary<int, FoodHandler> dic = new Dictionary<int, FoodHandler>();

        public MainHandler()
        {
            //get the full path
            string currentDirectory = Directory.GetCurrentDirectory();
            
            //get all the dll
            var files = Directory.GetFiles(currentDirectory, "*.dll");
         
            foreach (string file in files)
            {  
                //load each assembly
                var assembly = Assembly.LoadFile(file);

                foreach (var type in assembly.GetTypes())
                {
                    if (!type.IsClass || type.IsNotPublic) continue;

                    //if the class has our custom attribute
                    var foodTypeClass = type.GetCustomAttributes(typeof(FoodType), true);

                    FoodType foodType = (FoodType)foodTypeClass.FirstOrDefault();

                    if (foodType!=null)
                 {
                        int dbCode=foodType.GetDBCode();

                        //create new instance
                        var instance = (FoodHandler)Activator.CreateInstance(type);

                        //add the instance and his dbCode to the dictionery
                        dic.Add(dbCode, instance);
                     
                 } 
                }
                
            }
        }

וזהו! יצרנו את התשתית!

עכשיו כל מתכנת שירצה להוסיף לוגיקה עבור מאכל נוסף (או handler), הוא רק צריך לממש את ה interface, ולתת למחלקה Attribute מתאים.

איך מתבצעת קריאה לדוגמא (ללא שימוש ב Switch):

 
  //init the main handler
  MainHandler handler = new MainHandler();

  //handle the food by his db code (it could be also by his name..)
  handler.handleFood(2);

תהנו!

את קובץ ה cs אפשר להוריד מכאן