Tags: , | Categories: IOC Posted by talgiladi on 3/4/2009 9:46 PM | Comments (0)

ראיתי את הפרוייקט הזה ב code plex שמיקל על השימוש בService Locator בצורה יותר Loosley Coupled. לאחר מה שקרה לי

לפני כמה זמן, בדיוק בנושא הזה, החלטתי מעצמי לישם פיתרון כזה ואז ראיתי היום שיש כבר קוד מוכן… לא שזה כזה משנה, בסך הכל 3

מחלקות יצרתי שם עם כמה שורות קוד…

בכל מקרה, עדיין הפרוייקט שלהם טעון שיפור, שכן הוא לא מספק דרך לקנפג את השירות דרך הקוד. הם פשוט סומכים על כל מחלקה שמממשת את הממשק שתקנפג את עצמה, שזה די טוב לרוב האנשים שמשתמשים בקבצי XML חיצוניים לקינפוג, אבל אני טוען את המידע בעצמי ואז בזמן ריצה מקנפג את המיפוי, וזה אומר שאני אצטרך בכל מחלקה שמממשת את הממשק אני אצטרך להכניס מעל 100 שורות עם המיפויים, וכולנו יודעים מה זה אומר לשכפל קוד…

אז רק כדי להשלים את הפרוייקט שלהם נראה שצריך להוסיף 2 מתודות בממשק.  הראשונה:

 void RegisterType<TFrom, TTo>() where TTo : TFrom;

זאת שאמורה למפות ממשק למחלקה הדיפולטית שמיישמת אותו, והשניה:

void RegisterInstance<TType>(TType instance);

שתמפה אינסטס קיים של אובייקט שמממש את הממשק.

עכשיו אני יכול בנקודת הכניסה לאפליקציה (נניח ב global.asax) למפות את כל מה שאני רוצה בלי להיות תלוי במימוש מסוים.

Technorati Tags: ,

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags: , , | Categories: MVC Posted by talgiladi on 3/1/2009 1:23 AM | Comments (0)

הבעיה: אני מאפשר להוסיף תגובות בדף, אני רוצה לשלוח את הבקשה באג’קס לשרת, ואם היא מאושרת להוסיף את התגובה ישירות לדף, בלי לרפרש אותו. קוד ה HTML של תגובה נמצא ב user control . אני רוצה שהשרת ישלח לי בחזרה את קוד ה HTML של התגובה החדשה, לא סתם ישלח, אלא בפורמט JSON.

עם web forms  לא הייתה לי בעיה, יש מתודה שנקראת RenderControl עבור כל פקד, והיא מדפיסה את קוד ה HTML שלו, ואחר כך אני עושה עם הטקסט הזה מה שאני רוצה, במקרה שלי, שולח לדפדפן בפורמט JSON.

ב MVC זה לא קיים. אני מתכוון שכל פעולה בנפרד קיימת, אבל הכל ביחד כמו שאני צריך, לא.

יש אפשרות לשלוח JSON על ידי שימוש במתודה Json שנמצאת בקונטרולר, או על ידי יצירת JsonResult.

יש אפשרות לרנדר קונטרול פשוט כמו שמרנדרים כל view אחר- פשוט לקרוא למתודה View() עם שם הקונטרול. הבעיה היא שהתוצאה מודפסת ישירות ל response בתור טקסט, ואני רוצה לשלוח אותה בתור json. אז ניסיתי לעבוד עליו, ליצור response מדומה ואז למשוך ממנו את הטקסט ולשלוח על ידי המתודה Json(), לא עבד. ניסיתי עוד כמה דברים שהיו בגוגל, לא עבד.

טוב, אז זה מה שיצא לי… לא שאני הכי שמח עם זה, אבל זה עובד..

  1. מחלקה שמרנדרת את הקונטרול לטקסט:

    public class BlockRenderer

        {

            private readonly HttpContextBase _httpContext;

     

            public BlockRenderer(HttpContextBase httpContext)

            {

                _httpContext = httpContext;

            }

     

            public partial class HttpResponse

            {

                public bool UsingHttpWriter { get { return true; } }

            }

     

            public string Capture(Action viewRenderer)

            {

                HttpResponseBase resp = _httpContext.Response;

                Stream originalFilter = null;

                CapturingResponseFilter innerFilter;

                string capturedHtml = "";

     

                if (viewRenderer != null)

                {

                    try

                    {

                        resp.Flush();

                        originalFilter = resp.Filter;

                        innerFilter = new CapturingResponseFilter(resp.Filter);

                        resp.Filter = innerFilter;

                        viewRenderer();

     

                        resp.Flush();

                        capturedHtml = innerFilter.GetContents(resp.ContentEncoding);

                    }

                    finally

                    {

                        if (originalFilter != null)

                        {

                            resp.Filter = originalFilter;

                        }

                    }

                }

                return capturedHtml;

            }

        }

    עכשיו כדי לקרוא לה, צריך מתוך הקונטרולר להוסיף את המתודה הבאה:

     

            public string RenderPartialToString(string userControl, ViewDataDictionary viewData, ControllerContext controllerContext)

            {

                HtmlHelper h = new HtmlHelper(new ViewContext(controllerContext, new WebFormView("Index"), viewData, TempData), new ViewPage());

                var blockRenderer = new BlockRenderer(controllerContext.HttpContext);

     

                string s = blockRenderer.Capture(

                    () => RenderPartialExtensions.RenderPartial(h, userControl, viewData)

                );

     

                return s;

            }

    ופשוט לקרוא כל פעם שרוצים לרנדר משהו על ידי שליחת הפרמטרים המתאימים:

     ViewDataDictionary viewData = new ViewDataDictionary(new List<Reply>() { reply });

     string s = RenderPartialToString("~/Views/Shared/ReplyItem.ascx", viewData, this.ControllerContext);

       טוב, אז עכשיו קיבלתי את הקונטרול בתור טקסט, ואז אתם חושבים, יפה פשוט נחזיר אותו על ידי קריאה למתודה JSON בקונטרולר, אז ניסיתי וקיבלתי שגיאה- מתברר שבמהלך הקריאה למחלקה שמרנדרת את הקונטרול, מישהו באמצע החליט להוסיף http headers, והקונטרולר לא מסכים לקריאה למתודה JSON כשיש לו headers כבר... טוב אז אחרי כמה משחקים עם הקוד הגעתי לפיתרון פשוט:
  2. לא לקרוא ל JSON, אלא להפוך את המידע לג'ייסון בעצמי, ולשלוח אותו בתור טקסט, אז לא איכפת לקונטרולר אם יש headers או לא. והקוד הפשוט הוא

     JavaScriptSerializer js = new JavaScriptSerializer();

      return new TextResult(js.Serialize(new { approved = reply.IsApproved.ToString(), replyHtml = html }));

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

Technorati Tags: ,,

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5