DCSIMG
May 2010 - Posts - שלמה גולדברג (הרב דוטנט)

שלמה גולדברג (הרב דוטנט)

מרצה בסלע ויועץ בעולם ה - net.

May 2010 - Posts

Cross-document Messaging (CDM) in IE8

איך להשתשמש במנגון שליחת הודעות בין דפים שונים ואפילו מדומיינים שונים ב - IE8

 
 
בהמשך לפוסטים על IE8 נראה הפעם כיצד לשלוח הודעות בין דפים שונים, בתנאי שהם יושבים באותו עמוד מארח (כלומר בתוך IFrame).
 
 
קוד של דף A:
 

<input type="button" value="Send" onclick="Send()" />

<iframe src="CDR2.aspx"></iframe>

 

function Send() {

    var o = document.getElementsByTagName('iframe')[0];

    o.contentWindow.postMessage("Hello World", "*");

}

 
קוד של דף B:
 

window.attachEvent('onmessage', function(e) {

    document.writeln(e.data);

});

 
 
מה בעצם עשינו כאן.
דף A מכיל בתוכו את דף B ולכן אפשר להפעיל את מתודות postMessage על דף B שהוא מקבל שני פרמטרים.
 
דף A:
1. תוכן ההודעה (לפי ההגדרות זה אמור להיות הודעה טקסטואלית)
2. למי אנחנו שולחים את ההודעה. (לפי ההגדרות זה פרמטר אופציונאלי ולא לכתוב כלום זה כמו לכתוב *)
 
דף B:
נרשם ל - onmessage ומדפיס את התוכן של ההודעה.
 
 
נקודות מעניינות.
  • זה עובד רק על iframe בתוך העמוד ואי אפשר לשלוח הודעות לחלונות שיש לנו מצביע אליהם (לדוגמא, אם פתחנו popup) במדה וננסה בכל זאת לשלוח הודעה, נקבל את השגיאה No such interface supported
  • לפי ההגדרה הפרמטר השני הינו אופציונאלי אבל בפועל אם לא נשלח ערך נעוף עם השגיאה "Invalid Arguments"
  • אפשר להרשם ל - onmessage בעזרת attachEvent ולא ברישום רגיל - כלומר הצורה הזאת
 

window.onmessage = function(e) {

}

תעבוד ונגיע לאירוע - אבל e יהיה מוגדר כ - undefine

Native JSON Support in IE8

 

עבודה עם פורמט JSON ב - IE8

 
 
בהמשך לפוסטים שלי על IE8 נראה הפעם אילו חידושים קבלנו ב - IE8.
 
 
 
כדי לעבוד עם JSON ב - javascript אנחנו צריכים להכיר את שלושת המתודות הבאות
 
  • JSON.stringify
  • JSON.parse
  • toJSON
 
 
בעזרת stringify נוכל לקחת אובייקט ולהמיר אותו למחרוזת בפורמט JSON.
 
לדוגמא:
 
הדוגמא הבאה מדגימה קריאה ל - WebService ושליחת אובייקט שטוח בפורמט JSON
נניח שיש לנו WebService עם מתודה שנראת כך:
 

[WebMethod]

public void HelloWorld(string person)

{

    JavaScriptSerializer serializer = new JavaScriptSerializer();

    Person x = serializer.Deserialize<Person>(person);

}

 
נוכל לקרוא לה מ - javascript בצורה הבאה:
 

function stringifyDemo() {

    var Person = new Object();

    Person.Name = 'Shlomo';

    Person.Age = 25;

 

    var xhr = new XMLHttpRequest();

    var url = "WebService1.asmx/HelloWorld?person=" + JSON.stringify(Person);

    xhr.open("GET", url, true);

    xhr.send('');

}

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

function stringifyDemoReplaceToUpper() {

    var data = new Array();

    data[0] = "a";

    data[1] = "ab";

    data[2] = "edwqe";

    data[3] = "dfvgd vf";

 

    var xhr = new XMLHttpRequest();

    var url = "WebService1.asmx/GetArray?data=" + JSON.stringify(data,

        function replaceToUpper(key, value) {

            for (var i = 0; i < value.length; i++) {

                value[i] = value[i].toString().toUpperCase();

            }

            return value;

        });

 

    xhr.open("GET", url, true);

    xhr.send('');

}

 
 
במדה והאובייקט שממירים אותו בעזרת stringify מכיל מתודה בשם toJSON המתודה תופעל בצורה אוטומטית.
בדוגמא רואים כיצד קריאה ל - stringify על אובייקט מסוג Person מחזיר למעשה מחרוזת שמייצג אובייקט מסוג PersonJ (שלא מכיל מאפיין בשם Name)
 
 

function toJSONDemo() {

    var Person = new Object();

    Person.FirstName = 'Shlomo';

    Person.Age = 25;

    Person.LastName = 'Goldberg';

    Person.Name = Person.FirstName + " " + Person.LastName;

 

    Person.toJSON = function(key) {

        var PersonJ = new Object();

        PersonJ.FirstName = this["FirstName"];

        PersonJ.Age = this["Age"]; ;

        PersonJ.LastName = this["LastName"];

 

        return PersonJ;

    }

 

    var xhr = new XMLHttpRequest();

    xhr.open("GET", "WebService1.asmx/Person2?data=" + JSON.stringify(Person), true);

    xhr.send('');

}

 
 
בעזרת JSON.parse נוכל להמיר מחרוזת לאובייקטים.
לדוגמא, ה - WebService הבא מחזיר אובייקט שטוח
 

[WebMethod]

public string GetPerson()

{

    JavaScriptSerializer serializer = new JavaScriptSerializer();

    return serializer.Serialize(new Person() { Age = 25, Name = "Shlomo" });

}

 
כשבצד הלוקח נוכל לקרוא לה כך

function JSONParseDemo() {

 

    var xhr = new XMLHttpRequest();

    xhr.open("GET", "WebService1.asmx/GetPerson", true);

    xhr.onreadystatechange = function() {

        if (xhr.readyState == 4 && xhr.status == 200) {

            var person = JSON.parse(xhr.responseXML.text);

        }

    }

    xhr.send('');

}

איש סיסטם מוכשר ביותר (והרבה שנות ניסיון) התפנה לעבודה

 

איש סיסטם התפנה לעבודה.

אם אתם צריכים איש סיסטם לעבודה קבועה עם הרבה ניסיון וידע שכיף לעבוד איתו (בן אדם מקסים) מוזמן ליצור איתי קשר דרך דף צור קשר.
 
קורות חיים ישלחו למבקשים.
 
שלמה
Posted: May 25 2010, 12:47 AM by Shlomo | with no comments
תגים:,

למה אני לא אקנה יותר מחשב נייד של HP

למה לא כדאי לקנות HP.

 
 
 יש לי מחשב נייד של HP דגם pavilion dv7 אני רוצה להיות הוגן כלפי HP ולכן אני אקדים ואומר שאני מאוד מרוצה מהמחשב עצמו הוא מחשב טוב ואני נהנה בעבודה היומית שלי איתו.
 
למה בכל זאת המחשב הבא לא יהיה HP ?
 
שתי סיבות:
הראשונה - (שהיא הסיבה המשנית) כשהתקשרתי למוקד שלהם כדי לבדוק האם יש לי אחריות (זה פג שלושה ימים לפני הטלפון) התברר לי שאני צריך להתקשר למוקד אחר מכיוון שהמוקד מחולק לשניים "עסקי" ו"ביתי", הייתי מקבל את העובדה שהיו מעבירים אותי למוקד השני אבל זה מעצבן לנתק ולחייג למספר אחר.
 
השנייה (העיקרית) המטען של המחשב הלך לישון שנת עולמים, ניסתי לחבר מטענים אונברסליים אבל לצערי אף אחד מהם לא עבד, כשהלכתי למעבדה התברר לי ש - HP דואגים להעביר דרך המטען גם Data כדי שאני אהיה חייב להשתמש במטען מקורי משלהם ולא במטען אונברסלי. ולכן בפעם הבאה שאני אקנה מחשב נייד זה לא יהיה מתוצרת HP.
Posted: May 25 2010, 12:23 AM by Shlomo | with 4 comment(s) |
תגים:

toStaticHTML

הסרת סקריפטים ואירועים מתוך קטע HTML

 
 
בהמשך לפוסטים שלי על IE8 נראה הפעם מתודה מעניינית שבעזרתה נוכל לקחת html שקבלנו ולהסיר ממנה את הסקריפטים והאירועים.
 
 
(לקריאה נוספת כאן.)
 
 
נניח שיש לכם את קוד ה - html הבא:

<div id="myDiv">

 

    <script>

        function test() {

            alert("Testing, Testing, 123...");

        }

    </script>

 

    <span onclick="test()">Click Me</span>

</div>

 
כשהמשתמש ילחץ על ה - span הוא יקבל את ההודעה.
 
 
כעת אם נפעיל את הסקריפט הבא:

<script type="text/javascript">

    function sanitize() {

        var szInput = myDiv.innerHTML;

        var szStaticHTML = toStaticHTML(szInput);

        ResultComment = "\ntoStaticHTML sanitized the HTML fragment as follows:\n"

            + "Original Content:\n" + szInput + "\n"

            + "Static Content:\n" + szStaticHTML + "\n";

        alert(ResultComment);

    }

</script>

 
נקבל את ההודעה הבאה:
toStaticHTML
כמו שאפשר לראות ה - Ststic Content מכיל אך ורק את ה - HTML הססטי.

Connectivity Enhancements in IE8

 

שיפורים ותוסופות במידע על מצב החיבור של הלקוח ב - AJAX
 

בהמשך לפוסטים על IE8 הפעם נראה איזה מידע אנחנו יכולים לקושש על מצב החיבור לרשת של הלקוח.
 
 
 
 
מספר בקשות בו זמנית.
עד ל - IE8 מספר ה - connections שיכולנו לפתוח בו זמנית הוגבל ל - 2 כל שאר הבקשות המתינו בתור. ב - IE8 המספר הוגדל ל - 6 (אם מפתחים מערכת סגורה - כלומר אינטרא-נט ואתם צריכים להגדיל את מספר ה - connection בו זמנית, זה אפשרי וצריך לשנות ערכים ב - registry - אפשר לקרוא על הנושא בלינק למעלה)
 
כדי לדעת את מקסימום מספר ה - connection שניתן להשתמש בו תוכלו להשתמש בקוד הבא:
 

window.maxConnectionsPerServer;

 
מצב החיבור לרשת.
כדי לדעת מה המצב של המשתמש כרגע ניתן להשתשמש במאפיין onLine בצורה הבאה

window.navigator.onLine

ניתן גם להרשם לאירועים כדי לדעת מתי הגולש התחבר/התנתק מהרשת (הדוגמא הועתקה מכאן)
 

function reportConnectionEvent(e) {

    if (!e) e = window.event;

 

    if ('online' == e.type) {

        alert('The browser is ONLINE.');

    }

    else if ('offline' == e.type) {

        alert('The browser is OFFLINE.');

    }

    else {

        alert('Unexpected event: ' + e.type);

    }

}

window.onload = function() {

    document.body.ononline = reportConnectionEvent;

    document.body.onoffline = reportConnectionEvent;

}

Max() => Sequence contains no elements

 

קריאה לפונקציית Max או פונקציית Min כשהמערך ריק תתרסק עם השגיאה "Sequence contains no elements"

 
 
אף פעם לא הבנתי למה אין MaxOrDefault עד שלבסוף מצאתי את הפוסט הבא (שמביא את הקוד הבא)
 
 

public static int MaxOrDefault<TSource>(this IEnumerable<TSource> source,

                                        Func<TSource, int> selector,

                                        int defaultValue)

{

    if (source.Any<TSource>())

        return source.Max<TSource>(selector);

 

    return defaultValue;

}

Local query in Entity Framework

 

איך להריץ שאילתות ב - Entity Framework על ה - context ולא לרוץ לבסיס הנתונים.

 
(הקרדיט של הפוסט הזה שייך לאחי יוסי גולדברג)
 
בעייה:
כלל ידוע ב - Entity Framework שכל הפעלה של פונקצייה מתבצעת בבסיס הנתונים.
יכול להיות שזה טוב ויכול להיות שלא, אבל זה מביא אותנו לבעייה הבאה.
 
נניח שאנחנו נותנים למשתמש את היכולת להוסיף מידע באמצעות Entity Framework אבל אנחנו לא עושים SaveChanges בכל פעם שהמשתמש מוסיף שורה וכתוצאה מכך בפעם הבאה שננסה להביא את הנתונים (נניח לקשר אותו לגריד) המשתמש לא יראה את השורה שהוא הוסיף ברגע זה.
 
פיתרון:
כשיש שאלות ב - Entity Framework פונים כמובן או לגיל או לעידו, התמזל מזלנו ומצאנו את עידו במסדרונות סלע, הפיתרון הוא להשתמש ב - Local Query כלומר להריץ שאילתות על ה - ObjectStateManager.
 
לדוגמא:
 

var localList = from stateEntry in NewsEntities.ObjectStateManager

                                .GetObjectStateEntries(EntityState.Added |

                                                       EntityState.Modified |

                                                       EntityState.Unchanged)

                where stateEntry.Entity != null && stateEntry.EntitySet.Name == "NewsSet"

                select stateEntry.Entity as News;

 

return localList.ToList();

History with AJAX in IE8

 

כיצד לתמוך בלחצני Back ו - Forward כשעובדים עם AJAX בעזרת IE8.

 
הבעייה ידועה:
אין תמיכה בלחצני ההיסטוריה של הדפדפן כשעושים פעולות ב - AJAX.
 
 
לדוגמא:
לפניכם מערכת פשוטה שמביאה שמות של ערים ב - AJAX לפי בחירת שם המדינה.
 

<select id="country" onchange="FillData(this.value)">

    <option value="-1">Select</option>

    <option value="Israel">Israel</option>

    <option value="USA">USA</option>

</select>

 

 

<select id="City">

</select>

 
שני פקדים מסוג select - בזמן שישנו את הראשון ה -select השני אמור לקבל את הערכים שלו ב - AJAX.
 
הנה ה - JS
 

function FillData(country) {

 

    if (country.value != "-1") {

 

        var xhr = new XMLHttpRequest();

        xhr.onreadystatechange = function() {

            if (xhr.readyState == 4 && xhr.status == 200) {

                ClearCity();

                FillCity(xhr.responseText);

            }

        }

 

        xhr.open("GET", "Handler1.ashx?country=" + country, true);

        xhr.send();

    }

}

 
  • במידה והמשתמש לא בחר באופציית ה - Select.
  • נייצר אובייקט מסוג XMLHttpRequest.
  • בזמן שהסטטוס ישתנה ונוודא שהכל חזר כשורה.
  • נמחוק מתוך ה - select של הערים את מה שקיים כרגע
  • נמלא את התוצאות מחדש.
  • נגלוש ל - handler1.ashx ונשלח כפרמטר את המדינה.
  • נביא את הנתונים.
 
 
מייד נראה את המתודות Fill ו - Clear. אבל לפני כן נראה את ה - handler
 

public void ProcessRequest(HttpContext context)

{

    context.Response.ContentType = "text/plain";

 

    if (context.Request["country"] == "USA")

    {

        context.Response.Write("NY;Washington");

    }

    else

    {

        context.Response.Write("tel aviv;beni brak;ramt gan");

    }

}

 
לפניכם המשך מתודות הסקריפט
 

function FillCity(responseText) {

    var city = document.getElementById('City');

 

    var array = responseText.split(';');

    for (var i = 0; i < array.length; i++) {

        var item = document.createElement("option");

        item.text = array[i];

        city.add(item);

    }

}

 

function ClearCity() {

    var city = document.getElementById('City');

 

    for (var i = city.children.length; i >= 0; i--) {

        city.remove(i);

    }

}

 
 
הקוד שתואר למעלה יעבוד כמו שצריך, הבעייה הגדולה היא שכשאשר המשתמש ישנה את הערך בקומבו של המדינות הוא לא יוכל ללחוץ על הקודם כדי לחזור לבחירה הקודמת שלו.
 
פיתרון:
שימוש בשינוי ה - hash ב - url.
 
נוסיף למתודה FillData את השורה הבאה
 

window.location.hash = country;

מה שישנה את ה - url ועל כן לחצן "הקודם" יתעורר לתחייה.
 
נוסיף ל - body את הקוד הבא
 

 onhashchange="HashChangeHandler();

בזמן שהמשתמש ילחץ על "אחורה" או "קדימה" נגיע למתודה הזאת
 

function HashChangeHandler() {

    var country = document.getElementById('country');

    var hash = window.location.hash;

    if (hash == '#' || hash == '') {

        country.value = "-1";

        ClearCity();

        return;

    }

 

    if (hash.substr(1) != country.value) {

        country.value = hash.substr(1);

        FillData(country.value);

    }

}

Asp.net Movies

 

כל הסרטונים שלי בנושאי Asp.net

 
יצרתי דף ובו כל הסרטונים שלי בנושאי Asp.net.
 
תוכלו גם להגיע אליו מהתפריט מהימני בבלוג בלחיצה על "סרטונים בנושאי Asp.net"
 
אני אעדכן את הדף ההוא בכל פעם שאני אוציא סרטון חדש
Posted: May 14 2010, 07:45 AM by Shlomo | with 4 comment(s)
תגים:

Enable or Disable Asp.net validators

 

איך ניתן להגדיר האם להפעיל או לכבות את הולידציות בעמוד

 
 בתפוז נשאלה השאלה הבאה: "איך עושים ששדה מסוים יהיה חובה בתנאי ש CHECKBOX מסוים לחוץ?"
 
 
תשובה:
בעזרת שינוי של ה - Validation Group.
 
והנה דוגמא:
 
 

<input type="checkbox" name="myCheckBox" onclick="valid(this)" checked="checked" />

 

<asp:TextBox ID="txt" runat="server"></asp:TextBox>

 

<asp:RequiredFieldValidator ID="rfv1" runat="server" ValidationGroup="check"

     ControlToValidate="txt" Text="*"></asp:RequiredFieldValidator>

 

<asp:Button ID="btn" Text="Post" runat="server" ValidationGroup="check" />

 
יש לנו:
checkbox שאמור לבטל את הוילדצייה.
 
תיבת טקסט.
 
RequiredFieldValidator שמקושר לתיבת הטקסט (כשחייבים להגדיר את ה - ValidationGroup)
 
ולחצן כדי לנסות לעשות PostBack.
 
 
הנה פונקציית ביטול הוילדיצייה בזמן לחיצה על ה - checkbox
 
 

function valid(chk) {

    var validator = document.getElementById('rfv1');

    validator.validationGroup = chk.checked ? 'check' : 'dont';

}

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

public override void Validate(string validationGroup)

{

    if (validationGroup == "check")

    {

        rfv1.ValidationGroup = Request["myCheckBox"] == null ? "dont" : "check";

    }

 

    base.Validate(validationGroup);

}

 
במידה ובודקים כרגע Validation Group שנקרא check והמשתמש לא בחר ב - checkbox אזי נשנה את ה - validation group כך שהקריאה ל - base.Validate לא תבדוק האם יש ערך בתיבת הטקסט.

XMLHttpRequest Enhancements in Internet Explorer 8

שינויים שנכנסו ל - AJAX ב - IE8

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

var xhr = new XMLHttpRequest();

xhr.open("GET", "url", true);

xhr.timeout = 10000;

 
הגדרנו שבמדה ולא נקבל תשובה במשך 10 שניות הבקשה תתבטל.
 
חשוב מאוד: אי אפשר להגדיר את המאפיין לפני שקוראים למתודת open.
 
 
בנוסף אפשר להרשם לאירוע של ontimeout כמו שאפשר לראות בדוגמת הקוד הבאה.
 

xhr.ontimeout = function() {

    alert("timout");

};

Adding a Web reference dynamically at Runtime And Invoke the methods

כיצד ניתן להפעיל מתודות של WebService שה - Proxy שלו נוצר בזמן ריצה.

 
 
בפוסט הקודם הראיתי שני דרכים לעבוד עם WebService שיש לנו את הכתובת שלו רק בזמן ריצה.
 
קבלתי שאלה במייל כיצד ניתן לקבל את רשימת המתודות שלו ולהפעיל אותם.
 
התשובה היא כמובן בעזרת reflection. ואני אדגים כאן איך עושים את זה.
 
 
את דוגמת הקוד ניתן להוריד כאן. הפתרון של בניית ה - WebService בצורה דינמית מתבסס על התשובה כאן
 
 
נתחיל:
נגדיר מחלקה בשם WsProxy. ויהיו בו המתודות הבאות:
 
  • GetWebService
  • Methods
  • GetPartameters
  • Inovke
 
נעבור על המתודות.
GetWebService תפקידה לקבל את הכתובת של ה - WevService וליצור proxy בזמן ריצה
 

[SecurityPermissionAttribute(SecurityAction.Demand, Unrestricted = true)]

internal static object GetWebService(string webServiceAsmxUrl, string serviceName)

{

    WebClient client = new WebClient();

 

    // Connect To the web service

    Stream stream = client.OpenRead(webServiceAsmxUrl + "?wsdl");

 

    // Now read the WSDL file describing a service.

    ServiceDescription description = ServiceDescription.Read(stream);

 

    ///// LOAD THE DOM /////////

 

    // Initialize a service description importer.

    ServiceDescriptionImporter importer = new ServiceDescriptionImporter();

    importer.ProtocolName = "Soap12"; // Use SOAP 1.2.

    importer.AddServiceDescription(description, null, null);

 

    // Generate a proxy client.

    importer.Style = ServiceDescriptionImportStyle.Client;

 

    // Generate properties to represent primitive values.

    importer.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateProperties;

 

    // Initialize a Code-DOM tree into which we will import the service.

 

    CodeNamespace nmspace = new CodeNamespace();

    CodeCompileUnit unit1 = new CodeCompileUnit();

 

    unit1.Namespaces.Add(nmspace);

 

    // Import the service into the Code-DOM tree. This creates proxy code that uses the service.

    ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit1);

 

    if (warning == 0) // If zero then we are good to go

    {

        // Generate the proxy code

 

        CodeDomProvider provider1 = CodeDomProvider.CreateProvider("CSharp");

 

        // Compile the assembly proxy with the appropriate references

        string[] assemblyReferences = new string[5]

                                                {

                                                    "System.dll",

                                                    "System.Web.Services.dll",

                                                    "System.Web.dll",

                                                    "System.Xml.dll",

                                                    "System.Data.dll"

                                                };

 

        CompilerParameters parms = new CompilerParameters(assemblyReferences);

        CompilerResults results = provider1.CompileAssemblyFromDom(parms, unit1);

 

        // Check For Errors

        if (results.Errors.Count > 0)

        {

            throw new System.Exception("Compile Error Occured calling webservice. Check Debug ouput window.");

        }

 

        // Finally, Invoke the web service method

        object wsvcClass = results.CompiledAssembly.CreateInstance(serviceName);

 

        return wsvcClass;

    }

    else

    {

        return null;

    }

}

 
 
מה שהמתודה הזאת עושה זה לקבל את הכתובת של ה - WebService לקבל אותה בפורמט Soap12 ולהחזיר מופע של המחלקה. (בעזרת קומפילצייה בזמן ריצה)
 
 
Methods מקבלת כפרמטר את האובייקט ומחזירה מערך של מחרוזות כשכל מחרוזת מייצגת שם של מתודה שיש עליה attribute שזה מתודה שהיא בעצם WebMethod
 

internal static string[] Methods(object webService)

{

    var list = webService.GetType().GetMethods().

            Where(x => x.GetCustomAttributes(typeof(SoapDocumentMethodAttribute), false).Length > 0).

            Select(y => y.Name).ToArray();

 

    return list;

}

 
 
 
GetParameters מקבלת שם של מתודה ומחזירה אוסף שמייצג את שמות הפרמטרים והטיפוס שלהם
 

internal static List<KeyValuePair<string, Type>> GetParameters(object service, string methodeName)

{

    var list = new List<KeyValuePair<string, Type>>();

 

    MethodInfo mi = service.GetType().GetMethod(methodeName);

    foreach (var parameter in mi.GetParameters())

    {

        list.Add(new KeyValuePair<string, Type>(parameter.Name, parameter.ParameterType));

    }

 

 

    return list;

}

 
 
Invoke מקבלת את הפרמטרים ומפעילה את המתודה
 

internal static object Invoke(object service, string methodName, object[] parameters)

{

    return service.GetType().GetMethod(methodName).Invoke(service, parameters);

}

 
 
 
עד כאן המחלקה שתוכלו להשתמש איתה בכל צורה.
 
הדוגמא שאני אציג כאן היא שימוש במחלקה הזאת ב - Web Application.
 
 
נניח שיש לנו שני Web Serives שנראים כך:
 

public class MyWebService : System.Web.Services.WebService

{

    [WebMethod]

    public string HelloWorld()

    {

        return "Hello World";

    }

 

    [WebMethod]

    public int Add(int a, int b)

    {

        return a + b;

    }

}

 

public class YourWebService : System.Web.Services.WebService

{

 

    [WebMethod]

    public string HelloWorld()

    {

        return "Hello World";

    }

 

    [WebMethod]

    public int Random()

    {

        return new Random().Next(0, 100);

    }

}

 
 
אנחנו רוצים להפעיל את המתודות של ה - Web Services האלו בצורה  דינמית.
 
 צד לקוח:
נכתוב דף aspx שבו יש את הקוד הבא

<asp:DropDownList ID="ddlService" runat="server" AutoPostBack="true"

                    OnSelectedIndexChanged="ddlService_SelectedIndexChanged">

    <asp:ListItem Text="Select Service"></asp:ListItem>

    <asp:ListItem Text="http://localhost:51119/MyWebService.asmx"

                    Value="MyWebService"></asp:ListItem>

    <asp:ListItem Text="http://localhost:51119/YourWebService.asmx"

                    Value="YourWebService"></asp:ListItem>

</asp:DropDownList>

 
יש לנו הגדרה של DropDownList ובו רשימה של כתובות של webServices (כמובן שזה יכול להתמלא בצורה דינמית מבסיס נתונים כלשהו)
 
בנוסף לנו עוד DropDownList עבור המתודות

<asp:DropDownList ID="ddlMethod" runat="server" AutoPostBack="true"

            OnSelectedIndexChanged="ddlMethod_SelectedIndexChanged">

    <asp:ListItem Text="Select Method"></asp:ListItem>

</asp:DropDownList>

 
 
בנוסף יש לנו table שיבנה בזמן ריצה לפי הפרמטרים
 

<table id="tblParam" runat="server">

</table>

 
ולחצן שיפעיל את המתודה

<asp:Button ID="btnInvoke" runat="server" Text="Invoke" OnClick="btnInvoke_Click" />

 
 
 
צד שרת
 
בזמן בחירה של Service ב - DropDownList נבצע את הקוד הבא
 

protected void ddlService_SelectedIndexChanged(object sender, EventArgs e)

{

    ddlMethod.Items.Clear();

    ddlMethod.Items.Add("Select Method");

 

    if (Session[ddlService.SelectedValue] == null)

    {

        Session[ddlService.SelectedValue] =

                WsProxy.GetWebService(ddlService.SelectedItem.Text, ddlService.SelectedItem.Value);

    }

 

    ddlMethod.Items.AddRange(WsProxy.Methods(Session[ddlService.SelectedValue]).

                            Select(x => new ListItem(x)).ToArray());

}

 
אנחנו בודקים האם כבר יצרנו את האובייקט מה - Service (מכיון שאין טעם לייצר בזמן ריצה כל פעם את ה - Proxy מחדש - זה סיפור יקר מכיוון שאנחנו מקמפלים מחלקה בזמן ריצה)
 
לאחר שיש לנו את האובייקט (או שקמפלנו או שהוצאנו מה - Session)
 
אנחנו מפעילים את מתודת Methods ושולחים כפרמטר את האובייקט וממירים את מערך המחרוזות למערך של ListItem.
את מערך ה - ListItem אנחנו מוסיפים ל - DropDownList השני (של המתודות)
 
בזמן בחירה באחד מהמתודות נפעיל את הקוד הבא 
 
 
 

protected void ddlMethod_SelectedIndexChanged(object sender, EventArgs e)

{

    var parameters = WsProxy.GetParameters(Session[ddlService.SelectedValue], ddlMethod.Text);

    foreach (var item in parameters)

    {

        HtmlTableRow row = new HtmlTableRow();

        HtmlTableCell cell = new HtmlTableCell();

 

        cell.InnerHtml = string.Format("{0} ({1}): <input type='text' name='{2}'/>",

                                        item.Key, item.Value.Name, item.Key);

       

        // num1 (Int32) <input type='text' name ='num1'/>

 

        row.Cells.Add(cell);

        tblParam.Rows.Add(row);

    }

}

 
נקבל את הפרמטרים מהמחלקה WsProxy עבור כל אחד מהפרמטרים נוסיף לטבלה שורה ותיבת טקסט שהמאפיין name יהיה שם הפרמטר (כך שהערך יחזור ב - request)
 
 
נניח שהמשתמש בחר ב - WebService הראשון ובחר במתודה Name המסך שלו יראה כך
 
Adding a Web reference dynamically at Runtime And Invoke the methods
 
 
לחיצה על Invoke תפעיל את הקוד הבא:
 

protected void btnInvoke_Click(object sender, EventArgs e)

{

    object service = Session[ddlService.SelectedValue];

    var parameters = WsProxy.GetParameters(service, ddlMethod.Text);

    object[] @params = new object[parameters.Count];

 

    for (int i = 0; i < parameters.Count; i++)

    {

        var data = Request[parameters[i].Key];

        @params[i] = Convert.ChangeType(data, parameters[i].Value);

    }

 

    var res = WsProxy.Invoke(service, ddlMethod.Text, @params);

}

 
נקבל את האובייקט מה - Session
נקבל את כל הפרמטרים,
נמלא מערך של אובייקטים לפי ה - Type שלהם בעזרת Convert.ChangeType
ונפעיל את המתודה בעזרת מתודת Invoke שכתבנו.
 
 
 
כאמור זאת דוגמת Web ותוכלו להוריד את הקוד מכאן, אבל תוכלו להשתמש במחלקה גם בפלטפורמה אחרת.

Adding a Web reference dynamically at Runtime

 

כיצד ניתן לקבל מידע מרחוק בצורה דינמית - (כלומר בלי לעשות Add Web Reference בזמן הפיתוח.)

 
(אפשר להוריד את דוגמת הקוד מכאן)
 
נניח את המקרה הבא:
אתם מפתחים אתר שיודע להציג סרטונים עבור חברות ואותם חברות מעוניינות להגדיר בצורה דינמית אלו פרסומות יוצגו לפני ואחרי הסרטון.
 
פתרון ראשון:
נשמור בבסיס הנתונים כתובת של Web Service שתחזיר רשימה של מחרוזות (עם שמות הפרסומות)
 
בעייה:
איך נפנה ל - Web Service בלי שאנחנו מכירים אותו מראש בזמן הפיתוח ?
הרי בדרך כלל אנחנו מוסיפים Reference ומקבלים proxy שאנחנו עובדים איתו, מה נעשה במקרה שאנחנו לא יודעים מה הכתובת.
 
 
שני פתרונות.
אחד מה שמוצע כאן שזה יצירה של ה - Proxy בצורה דינמית בעזרת CodeDom והקוד יראה בערך כך:
 
 
צד השרת (Web Service)
 

public class Service1 : System.Web.Services.WebService

{

    [WebMethod]

    public AdvertisementWS HelloWorld()

    {

        return new AdvertisementWS();

    }

}

 

public class AdvertisementWS

{

    public List<string> Before { get; set; }

    public List<string> After { get; set; }

 

    public AdvertisementWS()

    {

        Before = new List<string>() { "abf" };

        After = new List<string>() { "123" };

    }

}

 

 

צד הלקוח: כלומר (אנחנו)

 

object ret = WsProxy.CallWebService("http://localhost:60905/Service1.asmx",

                                    "Service1",

                                    "HelloWorld",

                                    null);

 

Advertisement advertisement = Advertisement.ConvertFromObject(ret);

 
בהתחלה נפנה למתודה שמקבלת:
  • כתובת של Web Service
  • שם המחלקה
  • שם המתודה
  • ופרמטרים (מערך של אובייקטים) למתודה
 
נקבל בחזרה אובייקט ונמיר את למחלקה שלנו בעזרת מתודה מיוחדת שנכתוב
 
 

public class Advertisement

{

    public string[] Before { get;set; }

    public string[] After { get; set; }

 

    public static Advertisement ConvertFromObject(object obj)

    {

        Advertisement res = new Advertisement();

        Type type = obj.GetType();

        res.Before = (string[])type.GetProperty("Before").GetValue(obj, null);

        res.After = (string[])type.GetProperty("After").GetValue(obj, null);

 

        return res;

    }

}

 
כמו שאפשר להבין צריך כמובן שהמתודה של ה - WebService תחזיר אוביקט שיש לו שני מאפיינים אחד בשם After והשני בשם Before.
 
(את הקוד המלא של המתודה CallWebService אפשר לראות בלינק הקודם או (ועדיף) שתורידו את דוגמת הקוד)
 
 
אופצייה שנייה.
נראית לי הרבה יותר טובה. היא לייצר handler שיחזיר מחרוזת בפורמט JSON ופשוט להמיר אותו בצד שלנו.
 
צד השרת (handler)
 

public class Handler1 : IHttpHandler

{

    public void ProcessRequest(HttpContext context)

    {

        context.Response.ContentType = "text/plain";

 

        JavaScriptSerializer serializer = new JavaScriptSerializer();

        context.Response.Write(serializer.Serialize(new AdvertisementHandler()));

 

    }

}

 

public class AdvertisementHandler

{

    public List<string> Before { get; set; }

    public List<string> After { get; set; }

 

    public AdvertisementHandler()

    {

        Before = new List<string>() { "abf" };

        After = new List<string>() { "123" };

    }

}

 
 
צד הלקוח:
 

JavaScriptSerializer serializer = new JavaScriptSerializer();

WebClient client = new WebClient();

string str = client.DownloadString("http://localhost:60905/Handler1.ashx");

 

Advertisement abc = serializer.Deserialize<Advertisement>(str);

 
 
 

HTML and DHTML Improvements in IE8

 

שינויים שנכנסו ל - HTML ול - DHTML ב - IE8.

 
 
בהמשך לפוסטים שלי על IE8 אני רוצה להציג מספר שינויים שמשפיעים על איך שהדף נראה, לקריאה נוספת כאן וכאן.
 
 
בפוסט הנוכחי נעבור על השינויים הבאים:
 
  • q Element
  • Automatically Closing P Elements
  • object image
  • getElementById
  • get/set Attribute
 
 
למעשה קצת קשה להסביר את ההבדלים בלי הדגמה חיה ולכן כתבתי אתר קטנטן שתוכלו לראות את השינויים בפועל.
 
תוכלו לגלוש ללינק המתאים לראות את הקוד להתנסות וללחוץ על הלחצן בצד ימין של הדפדפן כדי לעבור ל - IE7 ולראות את ההבדלים
 
•HTML and DHTML Improvements
 
 
אז נתחיל:
 
נוסף אלמנט חדש בשם q שנותן לנו את היכולת לכתוב ציטוט כשנקבל את הסימן " בתחילת ובסוף הציטוט.
 
 
אלמנטים מסוג p יסגרו בצורה אוטומטית לפני אלמנטים מסוג table, form, noscript
 
 
התג object יודע לקבל במאפיין data כתובת של תמונה.
 
 
הוא case-sensitive ולא מחפש ב - name
 
 
הם case-insensitive ואפשר גם להוסיף בעזרתם אירועים בנוסף זה מחזיר את התוכן האמיתי של ה - attribute (כלומר אם נבדוק האם תיבת טקטס היא readonly ב - IE7 נקבל ערך בולייאני לעומת IE8 שנקבל את הערך readonly.
More Posts Next page »