Blogger Widgets
  • Sharing Photos using SignalR
  • TFS Extenstion - allows copy work items between projects
  • Displaying jquery progressbar with ajax call on a modal dialog
  • Managing windows services of a server via a website
  • Exploring technologies available to date. TechCipher is one place that any professional would like to visit, either to get an overview or to have better understanding.

Search This Blog

Tuesday, 25 September 2012

Measuring performance using Fiddler API

Having used Fiddler as one of the most useful tool as a developer, would it not be easy to actually use Fiddler to measure up website performance, throughput etc. Well!! FiddlerCore API can be used to achieve this. Refer to FiddlerCode API for some samples.

Pretty cool. I have been using DevExpress ASP.NET controls for quite sometime now and I wanted to measure the performance and throughput for some of very interesting controls such as aspxcallbackpanel & aspxcallback.

All I want is a small windows app with a single form having a grid that show all of the interactions to and from the website I wanted to test. So here is how it looks when comparing performance against 30 secs max.

Steps 1. Initialize and associate all relevant events and flags for Fiddler API.
public Form1()
        {
            InitializeComponent();

            oAllSessions = new List();
            Fiddler.FiddlerApplication.OnNotification += delegate(object sender, NotificationEventArgs oNEA) { Console.WriteLine("** NotifyUser: " + oNEA.NotifyString); };
            Fiddler.FiddlerApplication.Log.OnLogString += delegate(object sender, LogEventArgs oLEA) { Console.WriteLine("** LogString: " + oLEA.LogString); };
            Fiddler.FiddlerApplication.BeforeRequest += delegate(Fiddler.Session oS)
            {
                oS.bBufferResponse = false;
                Monitor.Enter(oAllSessions);
                if (oS.fullUrl.StartsWith(sSecureEndpointHostname))
                {
                    oAllSessions.Add(oS);
                }
                Monitor.Exit(oAllSessions);
            };
            Fiddler.FiddlerApplication.AfterSessionComplete += delegate(Fiddler.Session oS)
            {
                if (bUpdateTitle)
                {
                    this.Text = ("Session list contains: " + oAllSessions.Count.ToString() + " sessions");
                }
            };
            Fiddler.CONFIG.IgnoreServerCertErrors = false;
            oFCSF = FiddlerCoreStartupFlags.Default;
        }
2. Now write code to handle start/stop monitoring of fiddler sessions
 private void btnStartStop_Click(object sender, EventArgs e)
        {
            test = new Random(120);
            if (btnStartStop.Text == "Start")
            {                
                Uri uri = new Uri(txtWebSite.Text);
                iSecureEndpointPort = uri.Port;                
                btnStartStop.Text = "Stop";
                tmrAnalyse.Enabled = true;
                tmrAnalyse.Interval = 5000;
                sSecureEndpointHostname = uri.AbsoluteUri;

                lstAnalysisData.Items.Clear();
                dgSessions.Rows.Clear();


                Fiddler.FiddlerApplication.Startup(8877, oFCSF);                
            }
            else
            {                
                Fiddler.FiddlerApplication.Shutdown();
                btnStartStop.Text = "Start";
                tmrAnalyse.Enabled = false;
            }
        }
3. code snippets for add/update session data onto grid
private void AddSession(Session oS, Dictionary whoData, int timeTaken)
        {
            DataGridViewRow row = new DataGridViewRow();
            dgSessions.Rows.Add(row);

            DataGridViewCell cell1 = new DataGridViewTextBoxCell();
            cell1.Value = oS.id;
            row.Cells["SessionID"] = cell1;

            DataGridViewCell cell2 = new DataGridViewTextBoxCell();
            cell2.Value = Ellipsize(oS.fullUrl, 60);
            row.Cells["URL"] = cell2;

            DataGridViewCell cell3 = new DataGridViewTextBoxCell();
            cell3.Value = oS.oRequest.headers.HTTPMethod;
            row.Cells["HttpMethod"] = cell3;

            DataGridViewCell cell4 = new DataGridViewTextBoxCell();
            cell4.Value = oS.responseCode;
            row.Cells["RresponseCode"] = cell4;

            DataGridViewCell cell5 = new DataGridViewTextBoxCell();
            cell5.Value = oS.oResponse.MIMEType;
            row.Cells["MIMEType"] = cell5;

            DataGridViewCell cell6 = new DataGridViewTextBoxCell();
            DataGridViewCell cell7 = new DataGridViewTextBoxCell();
            

            if (whoData.ContainsKey(NotFound))
            {
                cell6.Value = "Not found";
                cell7.Value = "Not found";                
            }
            else
            {
                cell6.Value = whoData[DataColumn1];
                cell7.Value = whoData[DataColumn2];
            }

            row.Cells["Data1"] = cell6;
            row.Cells["Data2"] = cell7;

            DataGridViewCell cell8 = new DataGridViewTextBoxCell();
            cell8.Value = timeTaken;
            row.Cells["Data3"] = cell8;

        }

        private int FindRow(Session oS)
        {
            int rowId = -1;
            for (int i = 0; i < dgSessions.Rows.Count; i++)
            {
                DataGridViewRow row = dgSessions.Rows[i];
                if (row.Cells[0].Value != null)
                {
                    if (row.Cells[0].Value.ToString() == oS.id.ToString())
                    {
                        rowId = i;
                        break;
                    }
                }
                else
                {
                    rowId = i;
                    break;
                }
            }
            return rowId;
        }

        private void UpdateSession(int rowId, Session oS, Dictionary whoData, int timeTaken)
        {
            DataGridViewRow row = dgSessions.Rows[rowId];
            row.Cells["SessionID"].Value = oS.id;
            row.Cells["URL"].Value = Ellipsize(oS.fullUrl, 60);
            row.Cells["HttpMethod"].Value = oS.oRequest.headers.HTTPMethod;
            row.Cells["RresponseCode"].Value = oS.responseCode;
            row.Cells["MIMEType"].Value = oS.oResponse.MIMEType;
            row.Cells["Data1"].Value = whoData[DataColumn1];
            row.Cells["Data2"].Value = whoData[DataColumn2];
            row.Cells["Data3"].Value = timeTaken;
        }
4. code snippet for updating grid every 5 secs
private void WriteSessionList()
        {
            try
            {
                Monitor.Enter(oAllSessions);
                foreach (Session oS in oAllSessions)
                {
                    WriteSession(oS);
                }
            }
            catch (Exception ex)
            {
                lstAnalysisData.Items.Add("Exception " + ex.Message);
            }
            finally
            {
                Monitor.Exit(oAllSessions);
            }
        }

        private void tmrAnalyse_Tick(object sender, EventArgs e)
        {           
            WriteSessionList();
        }
That's it all in place now. Some of the tiny bits were missed out in the intention highlight more important bits. Download FidderAPI.rar for more details. This is common code and can be used for any website or web applications. Mostly useful to verify throughput/speed for websites that utilises any of the following controls or JavaScript plugins :-
- asp:UpdatePanel (ASP.NET ajax control)
- $.ajax (JQuery ajax call to webservice/webpage)
- ActionResult (ASP.NET MVC action) etc.

Some people worry that artificial intelligence will make us feel inferior, but then, anybody in his right mind should have an inferiority complex every time he looks at a flower. ~Alan C. Kay

Wednesday, 19 September 2012

DevExpress Input string was not in a correct format

I have started using ASP.NET DevExpress controls quite some time now. In last couple of days I have seen a strange error on pages with the following error message :

"Input string was not in a correct format"

Here is what my page consisted of a list of controls
- ASPxTextBox
- ASPxComboBox
- ASPxButton
- ASPxCallback

I want to pass the input data of ASPxTextBox & ASPxComboBox on button click to server via ASPxCallback and store this information in a database. Not so complicated as it sounds.

I have got some Nlog tracing enabled, got try-catch for ASPxCallback and all wired up. Started testing the page and I got this error ""Input string was not in a correct format"

Started debugging. No server side exceptions and nothing wrong, do not know where the error is coming from after googling and search in DevExpress support tickets I have found how to enable callback errors.

So I have enabled tracing callback errors as mentioned by DevExpress in the article Handling Callback Exceptions on Client.

Now I have got the tracing as:-

at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
at System.Int32.Parse(String s)
at DevExpress.Web.ASPxEditors.ListEditItemsSerializingHelper.ParseItemIndex(String serializedItem, Int32& startPos)
at DevExpress.Web.ASPxEditors.ListBoxItemsSerializingHelper.DeserializeItems(String serializedItems, Boolean sortRequired)
at DevExpress.Web.ASPxEditors.ListBoxProperties.SynchronizeItems(String serializedItems, Boolean isInsertingSyncType)
at DevExpress.Web.ASPxEditors.ASPxComboBox.SynchronizeItems(NameValueCollection postCollection)
at DevExpress.Web.ASPxEditors.ASPxComboBox.LoadPostData(NameValueCollection postCollection)
at DevExpress.Web.ASPxClasses.ASPxWebControl.LoadPostDataInternal(NameValueCollection postCollection, Boolean raisePostDataEvent)

But still do not know where the issue is. So started again looking into code step-by-step and I have found something. The items I am adding to ASPxComboBox is the issue.

aspx

 
        
javascript

var dataItems:
        [
          ["Item1","Available"],
["Item2","Available"],
["Item3","Available"],
["Item4","Available"],
["Item5","NotAvailable"],
["Item6","Available"]];
var itemid = 0;
for (var i = 0; i < dataItems.length; i++) {
 var dataItem = dataItems[i];
 if(dataItem[1] == "Available"){
   ClientCmbData.AddItem(dataItem, itemid++);
}
}


The issue occurs at ClientCmbData.AddItem(dataItem, itemid++), instead of ClientCmbData.AddItem(dataItem[0], itemid++);

So data passed in for ASPxComboBox items text value is invalid and hence parsing fails. That's it problem solved.



“The computer was born to solve problems that did not exist before.” – Bill Gates

Wednesday, 12 September 2012

State management in ASP.NET for high availability of data

ASP.NET session is the correct answer for state management. Yes that's it developers have to just use session to maintain state ie.. any data relavant to a user's session. Ways to store session state can mainly be categorized into InProc and OutProc.

InProc


Session state stored as in-memory on the web server.

Websites running in "Inproc" mode is completely dependent on the resources of the server. Limitation for number of users is dependent on the following factors
- Memory of server
- Amount of data stored per user session

As the memory used starts to exceed available memory application pool gets recycled and hence data stored is lost.

Single Web Server

Easy to configure and setup.
To enable session state as "Inproc" update web.config as follows:-


Advantages
- Easy access to data as stored in-memory

Disadvantages
- Data loss due exceeded memory utilization

Web Farm

Another method of increasing user capacity is by enabling sticky sessions on a web farm. This can achieved by using a Network Load Balancing (NLB). NLB has a feature known as "The Request Forwarder" and can be used to configure a cluster (web farm).

Sticky sessions use a HTTP cookie, which is returned for each client request that contains server instance GUID (ie.. first server that handled the request) and session ID allocated for the user. Subsequent requests will pass back server instance GUID and session ID that load balancer identifies and forwards to respective server. For mode detail explanation of this works look at technet article avalaible at http://technet.microsoft.com/en-us/library/bb734910.aspx.

Advantages
- Increased user capacity
- Easy access to data as stored in-memory

Dis-Advantages
- Partial load balance as user's are tied to specific server that served the request
- Still has possibility of data loss due exceeded memory utilization

OutProc


Session state is stored on a state server. Also this can be located on the same machine as web server or can point to another machine on your network. This mode is reliable as restarting web application does not affect state server and hence no data loss.

This mode can be configured either for a single server instance or for multiple servers on a web farm. In case of multiple web servers in a web farm,
- objects stored in session needs to be serializable
- should be installed on the same path in each of the web server in the Web farm.

1)StateServer

Session state is stored on an ASP.NET state service. Session data stored on a remote machine, no data loss due to application pool recycling. But still has the overhead of data loss if machine that has been configured as state management server is restarted.

Advantages
- No data loss due to application pool recycle

Dis-Advantages
- Is still limited based on the memory
- Reduces performance as data is read from a remote machine

2)SQLServer

session state is stored in an SQL Server database. Session data stored in a database because of which data is never lost. Machine restart will still not loose data as data is stored in a database.

Advantages
- No data loss due to application pool recycle - Data stored permanently in a database which has high reliability

Dis-Advantages
- Reduces performance as data read is from a database - Limited to memory allocated to database

3)Custom

Session state is stored on a custom provider. There are various options available for custom provider are AppFabric, Memcached etc.

AppFabric
- distributed in-memory application cache, refer to AppFabric for windows server for more details.
Memcached
- high-performance, distributed memory object caching system, refer to Memcached for more details.
SharedCache
- distributed and replicated memory object caching system, refer to SharedCache for more details.
“The most likely way for the world to be destroyed, most experts agree, is by accident. That’s where we come in; we’re computer professionals. We cause accidents.” – Nathaniel Borenstein
Copyright © 2013 Template Doctor . Designed by Malith Madushanka - Cool Blogger Tutorials | Code by CBT | Images by by HQ Wallpapers