‏הצגת רשומות עם תוויות ASPNET. הצג את כל הרשומות
‏הצגת רשומות עם תוויות ASPNET. הצג את כל הרשומות

יום רביעי, 24 באוקטובר 2012

REST Web Service Asp.Net



עד עכשיו כתבתי על SOAP והגיע הזמן להכיר את השיטה המתחרה REST - representational state transfer , ההבדל העיקרי הוא ש SOAP הוא פרוטוקול, יש בו חוקים ברורים שבעזרתם עוטפים את המידע שברצוננו לשלוח, ב REST העסק שונה, REST היא ארכיטקטורה שמתבססת על HTTP Protocol וכל אחד יכול לממש אותה אחרת.

ב SOAP אנחנו עובדים מול קובץ WSDL שמכיל בתוכו את המעטפת (אלמנטים וקריאות לפונקציות) שמאוד קשה לתחזק  וכשמדובר על Service מורכב העסק עלול להפוך למסורבל, REST נותן פתרון פשוט שמתבסס על HTTP ,בעזרת פונקציות שקיימות בפרוטוקול (Get,Put,Post,Delete) ננתב את הבקשות.

שימו לב! המאמר מציג שיטה למימוש Rest ע"ג IIS 7.

שלב א - צד השרת:

תחילה נבנה פרויקט חדש של Web Site ב Visual Studio.

ניצור Class חדש שיורש את ה Interface של IHttpHandler , עלינו לממש את המאפיין IsReusable ופונקציית ProcessRequest כפי שניתן לראות בדוגמה הבאה:


public class Service: IHttpHandler
    {
        bool IHttpHandler.IsReusable
        {
            get { return false; }
        }

        void IHttpHandler.ProcessRequest(HttpContext context)
        {
            //implementation of request by method...
        }

}

CURD (create , update, read, delete) Method

פרוטוקל HTTP מכיל בתוכו פונקציות מובנות, מי שבונה אתרי אינטרנט מכיר בעיקר את ה GET ו POST המפורסמים שמאפשרים לנו להעביר מידע בין טפסים, אבל קיימות פונקציות נוספות כמו PUT ו DELETE שבעזרתם ניתן לנתב את הבקשות ל Service שלנו.

GET
בקשות למידע, לדוגמה קריאות מה Database.

POST
הוספת אובייקט ל Database בעזרת המידע שנשלח ב Body.

PUT
דומה ל POST , עדכון אובייקט קיים בעזרת המידע שנשלח ב Body.

DELETE
מחיקת אובייקט

כשנשלחת בקשת GET אנחנו פונים ל Database ומחזירים את הנתונים ללקוח על בסיס פרמטרים שעוברים ב Url, כאשר הלקוח שולח בקשת Post יוצרים אובייקט חדש ב Database שאת המידע אנחנו אוספים מה Body של החבילה.

כאשר מתבצעת קריאה ל Service הפונקציה Process Request היא בעצם ה Entry Point וכל בקשה תפעיל את הפונקציה הזאת ודרכה ננתב את הבקשות של המשתמש למשאבים המתאימים כפי שניתן לראות בדוגמה הבאה:

  void IHttpHandler.ProcessRequest(HttpContext _context)
        {
            try
            {
                string url = Convert.ToString(_context.Request.Url);
                //handling CURD (CREATE UPDATE READ DELETE)
                switch (_context.Request.HttpMethod)
                {
                    case "GET":
                        //return data from database             
                        READ(_context);
                        break;
                    case "POST":
                        //create new element in database
                        CREATE(_context);
                        break;
                    case "PUT":
                        //update element in database
                        UPDATE(_context);
                        break;
                    case "DELETE":
                        //delete element from the database
                        DELETE(_context);
                        break;
                    default:
                        break;
                }
            }
            catch (Exception ex)
            { _context.Response.Write(ex.Message);}
        }

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


//getting object from request using GET method
        private void READ(HttpContext _context)
        {
            string serialized = "";
         
            //getting guides parameters from request
            if (_context.Request["type"].ToString() == "person")
            {
                //properly the point to call database
                //get data and parse to xml back to client
                person _person = new person();
                _person.FirstName = "HELLO";
                _person.LastName = "WORLD";
                serialized = Serialize(_person);
            }

            //depend what language you want to use
            _context.Response.ContentType = "text/xml";
            HttpContext.Current.Response.Write(serialized);
        }

        //insert new object using the POST method
        private void CREATE(HttpContext _context)
        {
            //reading the body of the message
            byte[] bodybytes = _context.Request.BinaryRead(_context.Request.ContentLength);
            //convert the bytes array to string as utf8
            string str = Encoding.UTF8.GetString(bodybytes);
            // deserialize xml into person
            person _person = person.deSerialize(bodybytes);
            //insert database...
        }

        //update object using the POST method
        private void UPDATE(HttpContext _context)
        {
            //reading the body of the message
            byte[] bodybytes = _context.Request.BinaryRead(_context.Request.ContentLength);
            //convert the bytes array to string as utf8
            string str = Encoding.UTF8.GetString(bodybytes);
            // deserialize xml into person
            person _person = person.deSerialize(bodybytes);
            //update database...
        }

        //delete element using the DELETE method
        private void DELETE(HttpContext _context)
        {

            if (_context.Request["type"].ToString() == "person")
            {
                if (_context.Request["id"] != null)
                {
                    int i = 0;
                    if (int.TryParse(_context.Request["id"].ToString(), out i))
                    {
                        //continue to database...
                    }
                }
            }
        }

אחד היתרונות ב REST שניתן לעבוד עם סוגי מבנים שונים, בניגוד ל SOAP שמבוסס על XML ב REST אפשר לבחור מה שבא לנו XML , JSON או להמציא בעצמנו את המבנה, במאמר זה נעבוד עם XML , לכן חשוב לייצר 2 פונקציות נוספות שימירו לנו את המידע מ XML לאובייקט .Net ומ .Net ל XML.

קוד מלא:

using System;
using System.Collections.Generic;
using System.Web;
using System.Xml.Serialization;
using System.IO;
using System.Text;
using System.Xml;

namespace restLand
{
    public class rest : IHttpHandler
    {
        bool IHttpHandler.IsReusable
        {
            get { return false; }
        }

        void IHttpHandler.ProcessRequest(HttpContext _context)
        {
            try
            {
                string url = Convert.ToString(_context.Request.Url);

                //handling CURD (CREATE UPDATE READ DELETE)
                switch (_context.Request.HttpMethod)
                {
                    case "GET":
                        //return data from database          
                        READ(_context);
                        break;
                    case "POST":
                        //create new element in database
                        CREATE(_context);
                        break;
                    case "PUT":
                        //update element in database
                        UPDATE(_context);
                        break;
                    case "DELETE":
                        //delete element from the database
                        DELETE(_context);
                        break;
                    default:
                        break;
                }
            }
            catch (Exception ex)
            { _context.Response.Write(ex.Message);}
        }

        //getting object from request using GET method
        private void READ(HttpContext _context)
        {
            string serialized = "";
         
            //getting guides parameters from request
            if (_context.Request["type"].ToString() == "person")
            {
                //properly the point to call database
                //get data and parse to xml back to client
                person _person = new person();
                _person.FirstName = "HELLO";
                _person.LastName = "WORLD";
                serialized = Serialize(_person);
            }

            //depend what language you want to use
            _context.Response.ContentType = "text/xml";
            HttpContext.Current.Response.Write(serialized );
        }

        //insert new object using the POST method
        private void CREATE(HttpContext _context)
        {
            //reading the body of the message
            byte[] bodybytes = _context.Request.BinaryRead(_context.Request.ContentLength);
            //convert the bytes array to string as utf8
            string str = Encoding.UTF8.GetString(bodybytes);
            // deserialize xml into person
            person _person = person.deSerialize(bodybytes);
            //insert database...
        }

        //update object using the POST method
        private void UPDATE(HttpContext _context)
        {
            //reading the body of the message
            byte[] bodybytes = _context.Request.BinaryRead(_context.Request.ContentLength);
            //convert the bytes array to string as utf8
            string str = Encoding.UTF8.GetString(bodybytes);
            //deserialize xml into person
            person _person = person.deSerialize(bodybytes);
            //update database...
        }

        //delete element using the DELETE method
        private void DELETE(HttpContext _context)
        {

            if (_context.Request["type"].ToString() == "person")
            {
                if (_context.Request["id"] != null)
                {
                    int i = 0;
                    if (int.TryParse(_context.Request["id"].ToString(), out i))
                    {
                        //continue to database...
                    }
                }
            }
        }

        private String Serialize(object _class)
        {
            try
            {
                //output string
                String xmlstring = null;

                //parser to xml from object using polymorphism
                XmlSerializer seriailizor = null;
                if (_class.GetType().ToString() == "restLand.person")
                    seriailizor = new XmlSerializer(typeof(person));
             
                //memory buffer
                MemoryStream stream = new MemoryStream();
             
                //xml writer be sure using utf8 encoding
                XmlTextWriter textwriter = new XmlTextWriter(stream, Encoding.UTF8);

                //the moment of true, parsing object
                seriailizor.Serialize(textwriter, _class);
             
                //fill the buffer
                stream = (MemoryStream)textwriter.BaseStream;
             
                //Convert to array to string 
                xmlstring = UTFbytesToString(stream.ToArray());
                return xmlstring;
            }
            catch (Exception ex)
            {
                return "";
            }

        }

        //convert utf8 bytes array to string
        private string UTFbytesToString(Byte[] array)
        {
            UTF8Encoding utf8encoder = new UTF8Encoding();
            string convertedString = utf8encoder.GetString(array);
            return convertedString;
        }

    }


    public class person
    {
        private string _firstName;
        public string FirstName
        {
            get { return _firstName; }
            set { _firstName = value; }
        }

        private string _lastName;
        public string LastName
        {
            get { return _lastName; }
            set { _lastName = value; }
        }

        //create deserialize function for each class
        public static person deSerialize(byte[] xmlbyte)
        {
           try
           {
               XmlSerializer seriailizor = new XmlSerializer(typeof(person));
               MemoryStream stream = new MemoryStream(xmlbyte);
               person _person = new person();
               //parsing the bytes to person
               _person = (person)seriailizor.Deserialize(stream);
               return _person;
           }
           catch (Exception ex)
           {throw;}
        }
    }
}

חשוב מאוד! להגדיר את ה Handler ב Web.config:

</system.web>
 <httpHandlers>
        <add type="restLand.rest" verb="*" path="service" />
  </httpHandlers>
 </system.web>


  <system.webServer>
     <handlers accessPolicy="Read, Script">
            <add name="service" path="service" verb="*" modules="IsapiModule" scriptProcessor="C:\Windows\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" resourceType="Unspecified" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
     </handlers>
   </system.webServer>




שלב ב - צד הלקוח

החלק הזה מאוד פשוט, ניצור פרוייקט חדש מסוג Console Application, ונבצע בקשות ל Url של ה Service בעזרת אובייקט HttpRequest, ונקבל את התשובה בעזרת HttpResponse.

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Xml;

namespace resttest
{
    class Program
    {
        //service url
        static string url = "http://192.168.1.8:443/service?type=person";
        
        static void Main(string[] args)
        {
            GET();
            POST();
        }

        //GET method
        private static void GET()
        {
           
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            
            //selected method
            request.Method = "GET";

            Console.WriteLine("send GET request");
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Stream stream = response.GetResponseStream();
            StreamReader reader = new StreamReader(stream);
            Console.WriteLine("get response");
            Console.WriteLine(reader.ReadToEnd());
            Console.WriteLine("end GET request");
        }

        //create xml stream of person
        private static byte[] create_person(string firstname, string lastname)
        {
            //create person xml 
            MemoryStream stream = new MemoryStream();
            XmlTextWriter writer = new XmlTextWriter(stream, Encoding.UTF8);
            writer.Formatting = Formatting.Indented;
            writer.WriteStartDocument();
            writer.WriteStartElement("person");
            writer.WriteStartElement("FirstName");
            writer.WriteString(firstname);
            writer.WriteEndElement();
            writer.WriteStartElement("LastName");
            writer.WriteString(lastname);
            writer.WriteEndElement();
            writer.WriteEndElement();
            writer.WriteEndDocument();
            writer.Flush();
            writer.Close();

            return stream.ToArray();
        }

        //POST method, PUT and DELETE like this method
        private static void POST()
        {

            byte[] _arr = create_person("WORLD", "HELLO");

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            Console.WriteLine("send POST request");
            
            //selected method
            request.Method = "POST";
            request.ContentType = "text/xml";
            request.KeepAlive = false;
            request.Timeout = 5000;
            request.ContentLength = _arr.Length;

            Stream stream = request.GetRequestStream();
            // write xml to stream
            stream.Write(_arr, 0, _arr.Length);

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
            //write the response from server
            Console.WriteLine(reader.ReadToEnd().ToString());
            Console.WriteLine("end POST request");
        }
       
    }
}

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

כולל שירות...

יום שבת, 29 בספטמבר 2012

Web Service Authentication ASP.NET




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

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

נבנה פרויקט חדש ב Visual Studio.



מבנה הפרוייקט


נערוך את קובץ Service1.asmx ונוסיף לתוכו 3 פונקציות:

  public class Service1 : System.Web.Services.WebService
    {
        [WebMethod]
        public string restricted_functionA()
        {
            return "restricted_functionA";
        }

        [WebMethod]
        public string restricted_functionB()
        {
            return "restricted_functionA";
        }

        [WebMethod]
        public string restricted_functionC()
        {
            return "restricted_functionA";
        }
    }


נריץ את ה Web Service בדפדפן ונגיע לדף Webservice1.asmx  שחושף לנו את הפונקציות של ה Web Service , כאן בעצם יש בעייה , אנחנו ממש לא מעוניינים לחשוף את הפונקציות של ה Service שלנו לכל אחד ובמיוחד לא לחשוף אותו בחיפושים ב Google כבר היום ניתן למצוא מליונים Web Services חשופים.


רק כדי להמחיש את הסכנה אני אשתמש ב Google ככלי פריצה וסריקה ( Google Hack) בעזרת החיפוש המתקדם במנוע ניתן לחפש חשיפות לדוגמה, אם נרשום בחיפוש filetype:asmx נקבל את כל הדפים ש Google מצא בסיומת asmx.


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

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

קודם כל העלמת השירות מגוגל, נכתוב קובץ robots.txt ונשמור אותו בתיקייה של הפרויקט, נרשום את השורות הבאות:

User-agent: *
Disallow: /

ונמנע מ Google לסרוק את ה Service שלנו, עד כאן היה החלק הפשוט בכל הסיפור ועכשיו נתחיל את תהליך Authentication.

 Forms Authentication

הדרך הפשוטה ביותר לאבטח את ה Web Service שלנו, על מנת לגשת ל Web Service יש להפעיל את פונקצית Login בשביל להתחבר ל Service, מה שקורה בפועל שהשם משתמש והסיסמא נבדקים מול ה DB ובמקרה שהם נכונים ה Web Service רושם Cookie עם Ticket אצל ה Client.

Webservice

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Services;
using System.Web.Security;

namespace WebService1
{
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    public class Service1 : System.Web.Services.WebService
    {
        private string Authenticate(string user, string pass)
        {
            //check the credential from DB or hard coded.
            if (user == "proxytype" && pass == "password")
                return "Proxytype connect";
            else
                return null;
        }

        [WebMethod]
        public bool login(string user, string pass)
        {
            string isLog = Authenticate(user, pass);

            if (isLog != null)
            {
                //return authentication cookie
                FormsAuthentication.SetAuthCookie(user, false);
                return true;
            }
            else
                return false;
        }

        [WebMethod]
        public void logout()
        {
            FormsAuthentication.SignOut();
        }

        [WebMethod]
        public string restricted_functionA()
        {
            //check if user authentication before execute
            if (Context.User.Identity.IsAuthenticated)
               return "Access Granted Restricted FunctionA";
            return "Access Denied Restricted FunctionA";
        }

        [WebMethod]
        public string restricted_functionB()
        {
            //check if user authentication before execute
            if (Context.User.Identity.IsAuthenticated)
                return "Access Granted Restricted FunctionB";
            return "Access Denied Restricted FunctionB";
        }

        [WebMethod]
        public string restricted_functionC()
        {
            //check if user authentication before execute
            if (Context.User.Identity.IsAuthenticated)
                return "Access Granted Restricted FunctionC";
            return "Access Denied Restricted FunctionC";
        }
    }
}


Client

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using example1.localhost;
namespace example1
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            //create new instance for the webservice
            Service1 myservice = new Service1();
            //create a cookie container for the return 
            //cookie from the web service
            myservice.CookieContainer = new System.Net.CookieContainer();
            
            myservice.login("proxytype", "password");
            Response.Write(myservice.restricted_functionA());

        }
    }
}


למרות שהמשתמש לא יכול להשתמש בפונקציות הן עדיין חשופות והמשתמש עדיין יכול לראות אותם אם הוא יכניס את הכתובת של ה Web Service בדפדפן שלו וזה עדיין לא מספיק מאובטח, המטרה שכל גישה לא מורשה תקבל הודעת שגיאה 401.1 Unauthorized, תחילה יש לשנות הגדרה ב IIS עצמו, בתגית Authentication במצב Feature View יש לבטל את ה Anonymous Authentication , ולהפעיל את ה Basic Authentication:


כשהמשתמש ינסה להכניס את הכתובת של ה Service בדפדפן הוא יצטרך להכניס שם משתמש וסיסמא , במקרה שהם לא נכונים הוא יקבל שגיאה 401.1 Unauthorized.



בשביל להעביר את ה Credentials יש לבצע מספר שינויים ב Client:

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using example1.localhost;
using System.Net;
namespace example1
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            //create new instance for the webservice
            Service1 myservice = new Service1();
           
            //create net credentials
            CredentialCache myCredentials = new System.Net.CredentialCache();
            NetworkCredential netCred = new NetworkCredential("proxytype", "password");

            //sign the credentials as basic authentication 
            myCredentials.Add(new Uri(myservice.Url), "Basic", netCred);
            myservice.Credentials = myCredentials;

            //create a cookie container for the return 
            //cookie from the web service
            myservice.CookieContainer = new System.Net.CookieContainer();
            
            myservice.login("proxytype", "password");
            Response.Write(myservice.restricted_functionA());
           

        }
    }
}

חשוב מאוד!  

Basic Authentication מתבסס על שמות והסיסמאות של המשתמשים שרשומים במערכת ההפעלה של ה Service, מומלץ ליצור משתמש חדש עם הרשאות מוגבלות , במקרה שאין SSL השם משתמש והסיסמא עוברים כ Clear Text והם חשופים לכל מי שמאזין על הרשת.

סיכום:

משחקי הרשאות עלולות להפוך את העסק למאוד מסורבל וחשוב מאוד לפשט כמה שאפשר את פריסת האבטחה סביב התוכנית שלנו, ניתן להשתמש בצורות Authentication נוספות כמו Windows ו Digest , כמובן לא לשכוח להשתמש ב SSL.

לא לחשוף סתם...

יום שבת, 18 בדצמבר 2010

File Upload With Flex And IIS 7

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

הגדרות מערכת
תחילה יש להגדיר את גודל המידע שיכול לעבור ואח"כ את גודל כל דרישה בשביל אותו מידע , ב IIS7  גודל המידע ה Default הוא  30 מגה ,אבל ניתן לדרוס את הפרמטר הזה בקובץ ApplicationHost שהוא בעצם קובץ XML שמכיל את הפרמטרים של ה IIS, בזמן טעינת האתר ה IIS טוען את הקובץ ולאחר מכן הוא טוען את ה Web.Config שמכילים את הפרמטרים של האתר העצמו.

ApplicationHost.config
תחילה נערוך את קובץ
C:\Windows\System32\inetsrv\config\applicationHost.config

נחפש את הבלוק שמגדיר את האתר שלנו ב ApplicationHost  (חשוב מאוד לגבות את הקובץ!) :

<location path="Your Website Name">
        <system.webserver>
           <security>
                        <requestfiltering>
                        <requestlimits maxallowedcontentlength="104857600">
                        </requestfiltering>
          </security>
          </system.webserver>
</location>
 
ברוב המצבים תגית האתר כבר מוגדרת ויש לוודא שקיימת גם תגית ה Security ואם לא להוסיף אותה.
ניתן לעשות את התהליך גם ב AppCmd שהיא אפליקצית Console שמגיע עם ה IIS 7 וניתן בעזרת לערוך את קובץ ה ApplicationHost ללא צורך לפתוח אותו , ובעצם למנוע תקלות בעקבות כתיבה לא נכונה.
 
C:\Windows\System32\inetsrv>appcmd set config "Your Website Name" -section:requestFiltering -requestLimits.maxAllowedContentLength:104857600 -commitpath:apphost
 
maxAllowedContentLength:104857600 מגדיר גודל של המידע שניתן להעביר, במקרה שלנו הגדלנו אותו ל 100 MB.
 
Web.config
נוסיף את הבלוק הבא בתוך התגית <system.web>(חשוב מאוד לגבות את הקובץ!) :
<httpRuntime executionTimeout="90" maxRequestLength="4096" />

maxRequestLength=2097151 הגדרנו את גודל של בקשה, בעצם 2 מגה.

Asp.net

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

יש לנו 2 קבצי Asp.net באתר ,הראשון הוא ה Upload Handler שתוכנת ה Flex שלנו מתחברת על מנת לשלוח את הקובץ לשרת, ודף נוסף שמציג לנו את ה Uploader עצמו.

upload_handler.aspx.cs

פונקציה אחת שבעצם שומרת לנו את הקבצים שאנו שולחים לספריית האחסון.

 protected void Page_Load(object sender, EventArgs e)
{
       string fileName = System.IO.Path.GetFileName(Request.Files[i].FileName);
       Request.Files[i].SaveAs(Server.MapPath("~/UploadedFiles/") + fileName);
} 
upload_manager.aspx
דף שמכיל לנו את אובייקט ה Flesh  שמעלה קבצים.
חשוב מאוד להגדיר Cross Domain Policy , שנוכל להעלות מכל שרת, או מרשתות שמורשות לכך.

Flex

אפליקצית ה Flex מורכבת ממספר פונקציות:
פונקצית Start
זאת הפוקציה שמתחילה את התוכנה ומוסיפה מאיזינים (listeners) עבור אירועים בכפתורים.

פונקצית eventRespnse
פותחת לנו את ה File Dialog שנוכל לבחור קבצים.

פונקצית selectResponse
מחזירה לנו את כל הקבצים שנבחרו להעלאה.

פונקצית UploadFiles
הפונקציה ששולחת את הקובץ לשרת, תחילה היא קוראת לקובץ upload_handler ואח"כ מתחילה בשליחת הקובץ.

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

Gui
הממשק מורכב מ - Button,Labels,Progress Bar


סרטון הדגמה:


קוד להורדה:

בהצלחה...