Archives

Archives / 2008 / July
  • Dynamically create ASP.NET user control using JQuery and JSON enabled Ajax Web Service

    Please read my previous post Dynamically create ASP.NET user control using ASP.NET Ajax and Web Service to understand this approach. In this article I am doing the same thing using JQuery. Other code I already explain in previous post, so I will explain only JQuery related code in this article. To subscribe my blog through mail, Please click here subscribe blog by email.

    You can download the VB.NET solution code here and the C# solution code here

    Dynamic control creation using JQuery is more fun and easy. Here is sample request to access JSON enabled web service using JQuery.

    function getJsonAjaxObject(webServiceURL, jsonData) {

     $.ajax({

      type: "POST",

      contentType: "application/json; charset=utf-8",

      url: serviceURL,

      data: jsonData,

      success:

       function(msg){

       //execute code related to success of web service

       },

      error:

       function(XMLHttpRequest, textStatus, errorThrown){

          //execute code related to failier of web service

       }

     });

    }


    Few thing you need to consider when you are accesing ASP.NET webservice through JQuery.
    • Request verb Type
    • Content- length with IIS6+
    • Default contentType
    • JSON object formatting
    • Maximum length exceed exception

    I am explaining these issues and workaround to make JQuery work fine with ASP.NET Ajax enabled web service.

    Request action Type

    ASP.NET Ajax enabled web service by default only allows the HTTP POST verb to be used when invoking web service methods using JSON, which means you can't inadvertently allow browsers to invoke methods via HTTP GET. Workaround for this issue is to use "POST" verb for request.

    Content- length with IIS6+

    Most installations of IIS6+ require a content-length be provided with all POST requests, even if there is no content (POST data). The content-length for a request with no data should be 0, but jQuery doesn’t set that header automatically unless there is a data parameter. The workaround for this issue to use an empty JSON object as a parameter on read-only requests.

    for example data: "{}"

    This will cause jQuery to correctly set a content-length, while your web service will ignore the empty parameter and treat the request as read-only. 

    Default contentType 

    ASP.NET AJAX enabled webservice requires a Content-Type header to be set to "application/json" for invocations to AJAX web services.  JSON requests that do not contain this header will be rejected by an ASP.NET server. For JQuery Ajax request you need to mention content type as application/json.

    for example contentType: "application/json;charset=utf-8"

    JSON object formatting

    If you directly provide a JSON object as the data parameter for an JQuery Ajax call, jQuery will attempt to serialize the object instead of passing it on to your web service and you will get invalid JSON primitive exception.

    Work around to this issue is to pass JSON data parameter as string, like this

    data: "{'controlLocation':'~/Controls/GridView.ascx'}"

    Maximum length exceed exception

    When you are accessing large JSON object via script service you need to update maxJsonLength in web.config otherwise you will get "maximum length exceed" exception.

    <system.web.extensions>

                  <scripting>

                         <webServices>

            <jsonSerialization maxJsonLength="5000000" />

                         </webServices>

                  </scripting>

           </system.web.extensions>

     


    The C#/VB.NET code is same as my last post. The XHTML code is slightly changed to call JQuery function instead of ASP.NET AJAX. 

    <%@ Page Language="C#" EnableViewState="false"  %>

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <html xmlns="http://www.w3.org/1999/xhtml">

    <head id="head" runat="server">

        <title>With JQuery</title>

        <link type="text/css" href="StyleSheets/iGridView-classic.css" rel="stylesheet" />

        <link type="text/css" href="StyleSheets/iGridView-common.css" rel="stylesheet" />

        <script language="javascript" type="text/javascript"   src="Scripts/jquery-1.2.6.pack.js"></script>

        <style type="text/css">

            body

            {

                width:95%;

                padding-left:20px;

                font-family:Arial;

                font-size:10pt;

                padding-right:20px;

            }

        </style>

    </head>

    <body>

        <form id="form" runat="server">

            <input type="button" value="Load Customer Order" onclick="getData('ScriptService.asmx/GetControlHtml','~/Controls/GridView.ascx');" />

            <input type="button" value="Load Login" onclick="getData('ScriptService.asmx/GetControlHtml','~/Controls/LoginControl.ascx');" />

            <input type="button" value="Register New User" onclick="getData('ScriptService.asmx/GetControlHtml','~/Controls/NewUserControl.ascx');" />

     <div id="testDiv"></div>

        </form>

    </body>

     

    </html>

    The JavaScript to call JSON enabled WebService is mentioned below

    <script type="text/javascript">

    function getData(serviceURL, controlLocation) {

     $.ajax({

      type: "POST",

      contentType: "application/json; charset=utf-8",

      url: serviceURL,

      data: "{'controlLocation':'" + controlLocation + "'}",

      success:

       function(msg){

         $('#testDiv').html(eval(msg));

         formatTable();

       },

      error:

       function(XMLHttpRequest, textStatus, errorThrown){

           alert( "Error Occured!" );

       }

     });

    }

    function formatTable(){

        //get all row in gridview table and set style/event/attribute on them

        $("div#testDiv tr")

        .addClass("data-row")

        .mouseover(function(){

        if(! isClickedStyleSet(this.className)){

        this.className = "row-over";}

        if(! jQuery.browser.mozilla){

        this.style.cursor ="hand";

        }})

        .mouseout(function(){

         if(! isClickedStyleSet(this.className)){

         this.className = "data-row" ;}

        })

        .click(

        function(){

          if(! isClickedStyleSet(this.className)){

        this.className = "row-select" ;}

        else{this.className = "data-row" ;}

        });

        //get all cell in gridview table and set style/event/attribute on them

        $("div#testDiv td")

        .addClass("data-row")

        .css("white-space", "nowrap")

        .css("vertical-align", "middle")

        .mouseover(function(){

        setTitle(this);

        });

    }

           

    function setTitle(object){

        //check browser type 

        if(jQuery.browser.mozilla){

            object.title = object.textContent;

        }

        else{

            object.title = object.innerText;

        }

    }

    function isClickedStyleSet(className){

        //if row is already clicked return true

        if(className == "row-select"){

        return true;

        }

        return false;

    }       

     

    </script>

    Below is the screenshot of the initial page.

    Gridview Effect 

    When user clicks on "Load Customer Order", It will call the ScriptService.asmx/GetControlHtml Web Service method get the usercontrol html data, load in the 'testDIV' and format the table inside div to implement mouseover/mouseout, click and title functionality using JQuery.

    Gridview Effect 

    Same way user can clicks on "load login" button to load "User Login" form dynamically.

    Gridview Effect 


    To load any usercontrol you need to call "getdata" function with webservice url and control location.

    for example getData('ScriptService.asmx/GetControlHtml', '~/Controls/GridView.ascx');.

    Please post your valuable feedback for this article.

    You can download the VB.NET solution code here and the C# solution code here

    kick it on DotNetKicks.com

  • Dynamically create ASP.NET user control using ASP.NET Ajax and Web Service

    Thanks for your tremendous response for my first post on asp.net blog Reduce ASP.NET Page size and complexity using JQuery-Part 1. Within last 10 days it's got more then 1500 views. To subscribe my blog through mail, Please click here subscribe blog by email.

    In this post I will explain how to load ASP.NET user control dynamically using ASP.NET AJAX and Web Service. In next post I will explain the samething using JQuery. Lot of user asked me to mentioned examples in VB.NET, so in this article, I will explain code in both language C#/VB.NET.      

    You can download the VB.NET solution code here and the C# solution code here

    To make web UI dynamic and more responsive to the various situations and modes, several techniques are used by the developers like making irrelevant controls invisible, disabling unused controls. This technique makes you page complex and heavy in size. Dynamic user control is another story. With dynamic control creation you will get the unmatched flexibility and innovation with robustness. Using this technique you can add any usercontrol to any page as per demand without postback or update panel.

    I am using the last post example and extending it to use this feature. In last post I created the gridview control and placed on the page, In this example I will create this control on page dynamically using web service and ASP.NET Ajax and enhance it to support tooltip, mouseover, mouseout and click effect using ASP.NET Ajax client side framework. 

    Below is the screenshot of the initial page.

    Gridview Effect 

    When user clicks on "Load Customer Order", It will call the webservice get the usercontrol html data and load in the 'testDIV'.

    Gridview Effect 

    Same way user can clicks on "load login" button to load "User Login" form.

    Gridview Effect 

    the XHTML code of the page in mentioned below.  

    <%@ Page Language="C#" EnableViewState="false" %>

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <html xmlns="http://www.w3.org/1999/xhtml">

    <head id="head" runat="server">

        <title>With MS Ajax</title>

        <link type="text/css" href="StyleSheets/iGridView-classic.css" rel="stylesheet" />

        <link type="text/css" href="StyleSheets/iGridView-common.css" rel="stylesheet" />

        <style type="text/css">

            body

            {

                width:95%;

                padding-left:20px;

                font-family:Arial;

                font-size:10pt;

                padding-right:20px;

            }

        </style>

    </head>

    <body>

        <form id="form" runat="server">

            <asp:ScriptManager runat="server">

            <Services>

            <asp:ServiceReference Path="~/ScriptService.asmx" />

            </Services>

            </asp:ScriptManager>

            <input type="button" value="Load Customer Order" onclick="getData('~/Controls/GridView.ascx');" />

            <input type="button" value="Load Login" onclick="getData('~/Controls/LoginControl.ascx');" />

            <input type="button" value="Register New User" onclick="getData('~/Controls/NewUserControl.ascx');" />

            <div id="testDiv"></div>

        </form>

    </body>

    </html>


    To use web service on page you need to mention it in ScriptManager.

    <asp:ScriptManager runat="server">

    <Services>

    <asp:ServiceReference Path="~/ScriptService.asmx" />

    </Services>

    </asp:ScriptManager>


    Also update maxJsonLength in web.config otherwise you will get "maximum length exceed" exception for large json data.

    <system.web.extensions>

                  <scripting>

                         <webServices>

            <jsonSerialization maxJsonLength="5000000" />

                         </webServices>

                  </scripting>

           </system.web.extensions>

     


    Below is the code of webservice file in C# with comment, don't forget to add

    System.Web.Script.Services.ScriptService() attribute to mark this web service as script service. 

    using System;

    using System.Collections;

    using System.IO;

    using System.Text.RegularExpressions;

    using System.Web;

    using System.Web.UI;

    using System.Web.UI.HtmlControls;

    using System.Web.Services;

    using System.Web.Services.Protocols;

     

    /// <summary>

    /// Summary description for ScriptService

    /// To access from ASP.NET AJAX remember to mentioned

    /// System.Web.Script.Services.ScriptService() attribute

    /// </summary>

    [WebService(Namespace = "http://tempuri.org/")]

    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

    [System.Web.Script.Services.ScriptService()]

    public class ScriptService : System.Web.Services.WebService

    {

     

        public ScriptService()

        {

            //Uncomment the following line if using designed components

            //InitializeComponent();

        }

     

        /// <summary>

        /// Get User Control Html

        /// use EnableSession=true if you are using session variables

        /// </summary>

        /// <returns>Html Table</returns>

        [WebMethod(EnableSession = true)]

        public string GetControlHtml(string controlLocation)

        {

            // Create instance of the page control

            Page page = new Page();

     

            // Create instance of the user control

            UserControl userControl = (UserControl)page.LoadControl(controlLocation);

     

            //Disabled ViewState- If required

            userControl.EnableViewState = false;

           

            //Form control is mandatory on page control to process User Controls

            HtmlForm form = new HtmlForm();

     

            //Add user control to the form

            form.Controls.Add(userControl);

           

            //Add form to the page

            page.Controls.Add(form);

     

            //Write the control Html to text writer

            StringWriter textWriter = new StringWriter();

     

            //execute page on server

            HttpContext.Current.Server.Execute(page, textWriter, false);

           

            // Clean up code and return html

            return CleanHtml(textWriter.ToString());

        }

     

        /// <summary>

        /// Removes Form tags

        /// </summary>

        private string CleanHtml(string html)

        {

            return Regex.Replace(html, @"<[/]?(form)[^>]*?>", "", RegexOptions.IgnoreCase);

        }

     

    }


    Same code of script service in VB.net is mentioned below

     

    Imports System

    Imports System.Collections

    Imports System.IO

    Imports System.Text.RegularExpressions

    Imports System.Web

    Imports System.Web.UI

    Imports System.Web.UI.HtmlControls

    Imports System.Web.Services

    Imports System.Web.Services.Protocols

    ''' <summary>

    ''' Summary description for ScriptService

    ''' To access from ASP.NET AJAXremember to mentioned

    ''' System.Web.Script.Services.ScriptService() attribute

    ''' </summary>

    <WebService([Namespace]:="http://tempuri.org/")> _

    <WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _

    <System.Web.Script.Services.ScriptService()> _

    Public Class ScriptService

        Inherits System.Web.Services.WebService

        'Uncomment the following line if using designed components

        'InitializeComponent();

        Public Sub New()

        End Sub

        ''' <summary>

        ''' Get User Control Html

        ''' use EnableSession=true if you are using session variables

        ''' </summary>

        ''' <returns>Html Table</returns>

        <WebMethod(EnableSession:=True)> _

        Public Function GetControlHtml(ByVal controlLocation As String) As String

            ' Create instance of the page control

            Dim page As New Page()

            ' Create instance of the user control

            Dim userControl As UserControl = DirectCast(page.LoadControl(controlLocation), UserControl)

            'Disabled ViewState- If required

            userControl.EnableViewState = False

            'Form control is mandatory on page control to process User Controls

            Dim form As New HtmlForm()

            'Add user control to the form

            form.Controls.Add(userControl)

            'Add form to the page

            page.Controls.Add(form)

            'Write the control Html to text writer

            Dim textWriter As New StringWriter()

            'execute page on server

            HttpContext.Current.Server.Execute(page, textWriter, False)

            ' Clean up code and return html

            Return CleanHtml(textWriter.ToString())

        End Function

        ''' <summary>

        ''' Removes Form tags

        ''' </summary>

        Private Function CleanHtml(ByVal html As String) As String

            Return Regex.Replace(html, "<[/]?(form)[^>]*?>", "", RegexOptions.IgnoreCase)

        End Function

     

    End Class

    The javascript code to access web service with comment is mentioned below.

    <script type="text/javascript">

            ///<summary>Method for Web Service Failed Event</summary>

            ///<param name="error">Error Object</param>

            ///<returns>false</returns>

            function onFailedWS(error)

            {

             alert(error.get_message());

            }

       

            ///<summary>This is the callback function that processes the Web Service return value.</summary>

            ///<param name="result">result Object from Web Service</param>

            function SucceededCallback(result)

            {

                //get the div element

                var RsltElem = $get("testDiv");

                //update div inner Html

                RsltElem.innerHTML =result;

                //format table inside the div

                //if you have multiple table call format table in loop

                formatTable(RsltElem.getElementsByTagName('table')[0].id)

            }

       

            ///<summary>This function calls the GetControlHtml Web Service method.</summary>

            ///<param name="error">Succeed Object</param>

            ///<param name="error">Error Object</param>

            function getData(controlLocation)

            {

                    ScriptService.GetControlHtml(controlLocation, SucceededCallback, onFailedWS);

            }

           

            function formatTable(gvID){

                //get the gridview

                var gv = $get(gvID);

                //get numbers of column in grid view

                cols = gv.rows[0].cells.length - 1;

                //get numbers of rows in grid view

                rows = gv.rows.length -1;

                //intialized looping variables

                var i=0;

                var j=0;

                //loop for each row in gridview

                for(i=1;i<rows;i++){

                    //attach mouseover event for row

                    $addHandler(gv.rows[i], "mouseover", mouseOver);

                    //attach mouseout event for row

                    $addHandler(gv.rows[i], "mouseout", mouseOut);

                    //attach click event for row

                    $addHandler(gv.rows[i], "click", onClick);

                     //loop for each cell in row

                    for(j=0;j<cols;j++){

                            //set tooltip for cells in row

                        setTitle(gv.rows[i].cells[j]);                        

                    }

                }   

            }

            function setTitle(object){

                //check browser type

                if(Sys.Browser.name =="Firefox"){

                object.title = object.textContent;

                }

                else{

                object.title = object.innerText;

                }

            }

           

            function mouseOver(objectEvent){

                //is row already clicked

                if(! isClickedStyleSet(objectEvent.target.parentNode.className))

                {

                //set class name

                objectEvent.target.parentNode.className = "row-over" ;

                //check browser type

                 if(Sys.Browser.name !="Firefox"){

                    objectEvent.target.parentNode.style.cursor ="hand";

                }}

            }

            function mouseOut(objectEvent){

                //is row already clicked

                if(! isClickedStyleSet(objectEvent.target.parentNode.className)){

                //set class name

                objectEvent.target.parentNode.className = "data-row" ;

            }}

            function onClick(objectEvent){

                //set class name

                if(! isClickedStyleSet(objectEvent.target.parentNode.className))

                {

                    objectEvent.target.parentNode.className = "row-select" ;

                }

                else

                {

                    objectEvent.target.parentNode.className = "data-row" ;

                }

            }

            function isClickedStyleSet(className){

                //if row is already clicked return true

                if(className == "row-select"){

                return true;

                }

                return false;

            }

        </script>


    To load any usercontrol you need to call "getdata" function with control location and name for example
    getData("~/Controls/GridView.ascx");.

    The benefit of the above approach are following

    • No need to the add usercontrol on the page at design time
    • Post back not required to load new User control
    • Update panel not required
    • Developer/ User can add usercontrol to any web page
    • Developer can load control on demand 
    • It will reduce intial page size
    • Easy to create custom User interface
    • More Responsive as less data is loaded on page

    In next post I will explain above approach with JQuery. Please post your valuable feedback for this article.

    You can download the VB.NET solution code here and the C# solution code here

    kick it on DotNetKicks.com

  • Reduce ASP.NET Page size and complexity using JQuery-Part 1

    This is my first post on asp.net blog. ASP.NET Ajax and JQuery are two different ajax framework. In this post I will show, how we can enhance gridview using ASP.NET Ajax and JQuery. I also compare the implementation of these frameworks. In next posts i will explain more about JQuery and ASP.NET Ajax and also tell you "How to combine the power of both framework". My Future post will related to ASP.NET and related frameworks.   

    You can download the solution code here

    In web based application for displaying data developers generally used grid view. We can enchance gridview to support tooltip, mouseover, mouseout and click effect using ASP.NET Ajax/JQuery.

    Below image will show this effect on page

    Gridview Effect 


    the XHTML code for creating and populating GridView is shown in the grid.

    <%@ Page Language="C#" EnableViewState="false" %>

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head id="head" runat="server">    <title>With MS Ajax</title>    <link type="text/css" href="StyleSheets/iGridView-classic.css" rel="stylesheet" />    <link type="text/css" href="StyleSheets/iGridView-common.css" rel="stylesheet" />    <style type="text/css">        body         {            width:95%;             padding-left:20px;            font-family:Arial;            font-size:10pt;            padding-right:20px;        }    </style></head><body onload="formatTable('<%= this.gv.ClientID %>');">    <form id="form" runat="server">        <asp:ScriptManager runat="server" />        <asp:ObjectDataSource ID="odsCustomers" runat="server"         SelectMethod="Select" TypeName="CustomerOrdersDataObject" />        <div>            <asp:GridView ID="gv" runat="server" CssClass="iGridViewi iGridView-classic"             AutoGenerateColumns="false" DataSourceID="odsCustomers">                <RowStyle CssClass="data-row" Wrap="false" VerticalAlign="middle" />                <HeaderStyle CssClass="header-row" />                <Columns>                    <asp:BoundField HeaderText="OrderID" DataField="OrderID" />                    <asp:BoundField HeaderText="ProductName" DataField="ProductName" />                    <asp:BoundField HeaderText="UnitPrice" DataField="UnitPrice" />                    <asp:BoundField HeaderText="Discount" DataField="Discount" />                    <asp:BoundField HeaderText="Quantity" DataField="Quantity" />                    <asp:BoundField HeaderText="ContactTitle" DataField="ContactTitle" />                    <asp:BoundField HeaderText="ContactName" DataField="ContactName" />                    <asp:BoundField HeaderText="CompanyName" DataField="CompanyName" />                </Columns>            </asp:GridView>        </div>    </form></body></html>                           

    Microsoft ASP.NET Ajax provided client side library to work with JavaScript. You can easily use it in your web page.

    The following script I used to implement the mouseover, mouseout, click event and tooltip for each cell in GridView using ASP.NET Ajax

    <script type="text/javascript">        function formatTable(gvID){            //get the gridview            var gv = $get(gvID);            //get numbers of column in grid view            cols = gv.rows[0].cells.length - 1;            //get numbers of rows in grid view            rows = gv.rows.length -1;            //intialized looping variables            var i=0;             var j=0;            //loop for each row in gridview            for(i=0;i<rows;i++){                //attach mouseover event for row                 $addHandler(gv.rows[i], "mouseover", mouseOver);                //attach mouseout event for row                $addHandler(gv.rows[i], "mouseout", mouseOut);                //attach click event for row                $addHandler(gv.rows[i], "click", onClick);                 //loop for each cell in row                for(j=0;j<cols;j++){                        //set tooltip for cells in row                    setTitle(gv.rows[i].cells[j]);                                         }            }            }        function setTitle(object){            //check browser type            if(Sys.Browser.name =="Firefox"){            object.title = object.textContent;            }            else{            object.title = object.innerText;            }        }                function mouseOver(objectEvent){            //is row already clicked            if(! isClickedStyleSet(objectEvent.target.parentNode.className))            {            //set class name            objectEvent.target.parentNode.className = "row-over" ;            //check browser type             if(Sys.Browser.name !="Firefox"){                objectEvent.target.parentNode.style.cursor ="hand";            }}        }        function mouseOut(objectEvent){            //is row already clicked            if(! isClickedStyleSet(objectEvent.target.parentNode.className)){            //set class name            objectEvent.target.parentNode.className = "data-row" ;        }}        function onClick(objectEvent){            //set class name            objectEvent.target.parentNode.className = "row-select" ;        }        function isClickedStyleSet(className){            //if row is already clicked return true            if(className == "row-select"){            return true;            }            return false;        }

    </script>


    For JQuery implementation, I removed the following line from xhtml

    <asp:ScriptManager runat="server" />

    <RowStyle CssClass="data-row" Wrap="false" VerticalAlign="middle" />
    The following script I used to implement the mouseover, mouseout, click event and tooltip for each cell in GridView using JQuery

    <script type="text/javascript">        function formatTable(){            //get all row in gridview table and set style/event/attribute on them            $("table#<%= this.gv.ClientID %> tr")            .addClass("data-row")            .mouseover(function(){            this.className = "row-over";            if(! jQuery.browser.mozilla){            this.style.cursor ="hand";            }})            .mouseout(function(){            this.className = "data-row" ;            })            .click(            function(){            this.className = "row-select" ;            });            //get all cell in gridview table and set style/event/attribute on them            $("table#<%= this.gv.ClientID %> td")            .addClass("data-row")            .css("white-space", "nowrap")            .css("vertical-align", "middle")            .mouseover(function(){            setTitle(this);            });        }                function setTitle(object){            //check browser type              if(jQuery.browser.mozilla){                object.title = object.textContent;            }            else{                object.title = object.innerText;            }        }

    </script>


    Getting all object using id/tag/class is very easy in JQuery, In one line you can implement all the attribute, event,class using “.”

    The following line give all row in gridview table
    $("table#<%= this.gv.ClientID %> tr") The following line give all cell in gridview table
    $("table#<%= this.gv.ClientID %> td")
    For network monitoring, I used Firebug for FireFox 3
    You can download FireBug from here

    Below image for ASP.NET Ajax implementation related files 

    With MS Ajax 


    Below image show JQuery related implementation files

    With JQuery 


    It clear from the figure that after JQuery implementation
    • The aspx file size is reduce
    • ASP.NET Ajax files are not required
    • You can search/get DOM elements easily
    • Loop is not required for setting attribute/event/css on array of element
    • In one line you can set all attribute/event/css of elements using "."

     

    I will discuss more JQuery feature in next post, If you also want the video cast of this article please reply/post your comment for this article.  

    Soultion files you can download here

    kick it on DotNetKicks.com