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
Tags: , , | Categories: JavaScript Posted by talgiladi on 12/4/2007 3:40 PM | Comments (4)
Technorati Tags: ,,

.התחלנו כבר לדבר על דיפדוף יעיל בדטה בייס בעבר, עכשיו נמשיך את זה לצד הלקוח
נשתמש באג'קס ליישום הדיפדוף (אני משתמש ב framework לנוחות, אבל כל אג'קס יעשה את העבודה)
נתחיל בבניית הטבלה בדף, אנחנו כבר יודעים איך למשוך את הנתונים כך שנקבל רק את השורות המתאימות לדף שלנו, אז פשוט נזרוק את כל הנתונים לדף בצורת טבלה. את הטבלה נשים בתוך div עם id

נבנה בדף פונקציה שתמשוך לנו את הנתונים מה ADP

private string GetTable()
{
    int pagenum;
    if (!int.TryParse(Request.Params["pagenum"], out pagenum))
    {
        pagenum = 1;
    }
    int rowsPerPage = 10;
    string sortByColumn = Request.Params["sortName"];
    if (string.IsNullOrEmpty(sortByColumn)) sortByColumn = "id";
    string sortOrder = Request.Params["sortOrder"];
    if (string.IsNullOrEmpty(sortOrder)) sortOrder = "asc";
    DataTable table = ADP.GetUsers(pagenum, rowsPerPage, sortByColumn, sortOrder);
    StringBuilder sb = new StringBuilder();
    sb.Append("<table><tr><td>id</td><td>name</td></tr>");
    foreach (DataRow dr in table.Rows)
    {
        sb.Append("<tr>");
        sb.Append("<td>");
        sb.Append(dr["id"]);
        sb.Append("</td>");
        sb.Append("<td>");
        sb.Append(dr["name"]);
        sb.Append("</td>");
        sb.Append("</tr>");
    }
    sb.Append("</table>");
    return sb.ToString();
}

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

<div id="div_data"><%=myTable%>
</div>

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

int rowsCount =ADP.GetUsersCount();
int rowsPerPage = 10;
int totalPages=(int)Math.Ceiling((double)rowsCount / rowsPerPage);

הפייג'ר עצמו בדף html:

<%for (int i=0;i<totalPages;i++)
{ %>
<a href="javascript:doPaging(<%=(i+1)%>)"><%=(i+1)%></a>
%<}%>

ופונקציית ג'אווה קטנה

<script type="text/javascript">
    var curpage=1;
    var sortName='id';
    var sortDirection='asc';
  
    function doPaging(pagenum){
        curpage=pagenum;
            var url='mypage.aspx?action=paging&pagenum='+curpage+'&sortName='+ sortName+'&sortOrder'+sortDirection;
        new Ajax.Request(url,{onSuccess:function(t){
            if (t.responseText=='error'){
                alert('error!');
            }else{
               
                document.getElementById('div_data').innerHTML=t.responseText;
            }
        }});
}
</script>

זהו, בשביל הדפדוף זה מספיק... רק בשביל המיון צריך עוד 2 דברים קטנים לעשות. קודם כל כשאנו בונים את הטבלה, אז בכותרות להוסיף הפניה לפונקציה של ג'אווה סקריפט כדי שכשמקליקים על הכותרת יתבצע מיון
נשנה מעט את איך שבנינו את הטבלה מקודם במקום לכתוב id בכותרת נכתוב <a href=\"javascript:doSort('id');\">id</a>  ,וכך לגבי שאר הכותרות, ונבנה את הפונקציה המתאימה בג'אווה סקריפט

function doSort(columnName){
        if (sortName==columnName){
            if (sortDirection=='asc'){
                sortDirection='desc';
            }else{
                sortDirection='asc';
            }
        }else{
            sortName=columnName;
        sortDirection='asc';
    }
            var url='mypage.aspx?action=paging&pagenum='+curpage+'&sortName='+ sortName+'&sortOrder'+sortDirection;
        new Ajax.Request(url,{onSuccess:function(t){
            if (t.responseText=='error'){
                alert('error!');
            }else{
                document.getElementById('div_data').innerHTML=t.responseText;
            }
        }});
}
</script>

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

להורדת דוגמה (ללא דטה בייס כמובן)

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags: , , | Categories: JavaScript Posted by talgiladi on 11/1/2007 3:20 PM | Comments (7)
Technorati Tags: ,

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

<script type="text/javascript">
    var ajaxResponse;
    var hasError;
    function GetAjax(url,parameters){
        var myAjax;
        try { myAjax = new ActiveXObject('Msxml2.XMLHTTP'); }
        catch (e)
        {
            try { myAjax = new ActiveXObject('Microsoft.XMLHTTP'); }
            catch (e2)
                {
                    try { myAjax = new XMLHttpRequest(); }
                    catch (e3) { alert('could not create ajax object');return; }
                }
        }
        myAjax.onreadystatechange = function()
        {
            if(myAjax.readyState == 4)
            {
                if(myAjax.status == 200)
                {
                    hasError=false;
                    ajaxResponse=myAjax.responseText;
                }
                else
                {
                    hasError=true;
                    ajaxResponse='Error ' + myAjax.status;
                }
                document.getElementById('div_result').innerHTML=ajaxResponse;
            }
        };
        myAjax.open('POST', url, true);
        myAjax.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
        myAjax.setRequestHeader('Content-length', parameters.length);
        myAjax.setRequestHeader('Connection', 'close');
        myAjax.send(parameters);
    }
</script>

נדאג שיש לנו כזה div בדף

<div id "div_result"></div>

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

Be the first to rate this post

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