Vikram Lakhotia

The Online Weblog of Vikram Lakhotia

  • Microsoft MVP for the year 2011

    It’s been three year in a row now. I am MVP for the year 2011 also. It feels so great to get the news that I have been MVP again.

    Very big thanks to the MVP Team, My MVP Lead and Microsoft for giving the MVP award to me for 3 year in a row.

    Also a great thanks to all the friends, Family, developers, community members that have worked with me. Without your support this would not have been possible. I will try and continue the work in 2011 also

    Vikram

  • Inserting 40,000 records in MYSQL from Asp.Net

    Recently I got a task of importing about 40,000 records for a fixed length delimited file to MY SQL database. Copying the data into a list of Business object was not a problem, but to insert about 40000 records in MYSQL in an asp.net application looked time consuming. More over this event would take place regularly and over 200 times a day and also user need to process the data after it has been uploaded.

    My earlier post on multiple insert with Stored procedure seems would not be that effective here as all the data was different in the records.

    I first started by using a simple Insert query and then pass the data as parameters. The first efforts completed the job in about 500+ seconds (measurement of the time was being done by the stopwatch class). And I knew for sure this is not going to work for me.  Then I realized that in MYSQL we can use one insert statement to insert multiple values by keep on passing the values in the insert statement. Below is an example.

    INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);

    Hence I went ahead and created the string to insert the values in a loop. I made sure that Insert data in a batch (size of batch was configurable). I started with 20 records per batch and then 50 and hundred.
    Till then it was good. The amount of time taken for these 40,000 plus records came down to about 50 seconds or so. But this was not good enough so I kept on increasing the numbers in batch  

    After the hundred records for the batch I start to see a decline in performance of the insertion and the time taken to complete the job always started to increase. I analyzed the code and quickly realized that the problem was not with MYSQL but my usage of start to concatenate the query in the loop. As soon as I converted the string to stringBuilder class (to create the query) I could see that the improvement in performance and with a batch size of 5,000 to 10,000 per batch I could easily insert 40,000 plus records in less than 3 seconds in MYSQL database from Asp.net.

    Vikram

  • Major Asp.Net security issue found - Temporary workaround provided

    A new vulnerability in asp.net application was found last friday. This vulnerability exists include in all the Asp.net sites, including Asp.Net (All versions), Asp.Net MVC, SharePoint, Any framework in Asp.Net Like Dot Net nuke etc.

    An attacker of this vulnerability can use it and download file like web.config which contains sensitive data about the application including connection string for database etc.

    Currently a (temporary) workaround (till a proper patch for this vulnerability is made available) has been provided by Microsoft.
    The workaround involves setting the customerror in such a way that it returns only one page on any kind of error.

    Below is detail on how the workaround should be applied.

    Enabling the Workaround on ASP.NET V1.0 to V3.5

    If you are using ASP.NET 1.0, ASP.NET 1.1, ASP.NET 2.0, or ASP.NET
    3.5 then you should follow the below steps to enable <customErrors> and
    map all errors to a single error page:

    1) Edit your ASP.NET Application’s root Web.Config
    file.  If the file doesn’t exist, then create one in the root directory of
    the application.

    2) Create or modify the <customErrors> section of the web.config file to
    have the below settings:

    <configuration>        
       <system.web>
          <customErrors mode="On" defaultRedirect="~/error.html" />
       </system.web>        
    </configuration>

    3) You can then add an error.html file to your application that contains an appropriate error page of your choosing (containing whatever content you like).  This file will be displayed anytime an error occurs within the web application.

    Notes: The important things to note above is that customErrors is set to “on”, and that all errors are handled by the defaultRedirect error page.  There are not any per-status code error pages defined – which means that there are no <error> sub-elements within the <customErrors> section.  This avoids an attacker being able to differentiate why an error occurred on the server, and prevents information disclosure.

    Enabling the Workaround on ASP.NET V3.5 SP1 and ASP.NET 4.0


    If you are using ASP.NET 3.5 SP1 or ASP.NET 4.0 then you should follow the below steps to enable <customErrors> and map all errors to a single error page:

    1) Edit your ASP.NET Application’s root Web.Config
    file.  If the file doesn’t exist, then create one in the root directory of
    the application.

    2) Create or modify the <customErrors> section of the web.config file to
    have the below settings.  Note the use of redirectMode=”ResponseRewrite” with .NET 3.5 SP1 and .NET 4.0:

    <configuration>
       <system.web>
         <customErrors mode="On" redirectMode="ResponseRewrite" defaultRedirect="~/error.aspx" />
       </system.web>
    </configuration>

    3) You can then add an Error.aspx to your application that contains an appropriate error page of your choosing (containing whatever content you like).  This file will be displayed anytime an error occurs within the web application.

    4) We recommend adding the below code to the Page_Load() server event handler within the Error.aspx file to add a random, small sleep delay. This will help to further obfuscate errors.

    VB Version

    Below is a VB version of an Error.aspx file that you can use, and which has a random, small sleep delay in it.  You do not need to compile this into an application – you can optionally just save this Error.aspx file into the
    application directory on your web-server:

    <%@ Page Language="VB" AutoEventWireup="true" %>
    <%@ Import Namespace="System.Security.Cryptography" %>
    <%@ Import Namespace="System.Threading" %>
    <script runat="server">
        Sub Page_Load()
            Dim delay As Byte() = New Byte(0) {}
            Dim prng As RandomNumberGenerator = New RNGCryptoServiceProvider()
            prng.GetBytes(delay)
            Thread.Sleep(CType(delay(0), Integer))
            Dim disposable As IDisposable = TryCast(prng, IDisposable)
            If Not disposable Is Nothing Then
                disposable.Dispose()
            End If
        End Sub
    </script>
    <html>
    <head runat="server">
        <title>Error</title>
    </head>
    <body>
        <div>
            Sorry - an error occured
        </div>
    </body>
    </html>

    C# Version

    Below is a C# version of an Error.aspx file that you can use, and which has a random, small sleep delay in it.  You do not need to compile this into an
    application – you can optionally just save it into the application directory on your web-server:

    <%@ Page Language="C#" AutoEventWireup="true" %>
    <%@ Import Namespace="System.Security.Cryptography" %>
    <%@ Import Namespace="System.Threading" %>
     
    <script runat="server">
       void Page_Load() {
          byte[] delay = new byte[1];
          RandomNumberGenerator prng = new RNGCryptoServiceProvider();
          prng.GetBytes(delay);
          Thread.Sleep((int)delay[0]);
          IDisposable disposable = prng as IDisposable;
          if (disposable != null) { disposable.Dispose(); }
        }
    </script>
     
    <html>
    <head runat="server">
        <title>Error</title>
    </head>
    <body>
        <div>
            An error occurred while processing your request.
        </div>
    </body>
    </html>

    How to Find More Information about this Vulnerability

    You can learn more about this vulnerability from:

    Vikram

  • LINQ to SQL and Case statement

    Working with LINQ I realized that I had to use the simple case statement in my SQL query. There is no special keyword for this. To create a case statement like structure you will have to do it in the select section of the query.

    Below is an example of the usage of the case statement in LINQ.

    var t = from n in idc.categories
                select new
                {
                            catName =
                            (n.id==1 ? “Cat1” :
                            n.id==2 ? “Cat2” :
                            n.id==3 ? “Cat3” : “Unknown Category”
                            )

                };

    Here in the above code we are using multiple cases for value 1, 2 and 3 and the default value is given at the last.

    Vikram

  • Converting double to integer using cast and convert statement

    Check out the code below.

    double d = 13.6;

    int i1 = Convert.ToInt32(d);
    int i2 = (int)d;

    if (i1 == i2)
    { Console.WriteLine("Equal"); }
    else
    { Console.WriteLine("Not Equal"); }


    The output of the above program would be “Not Equal”.  The reasons being different rounding policy for in convert and cast operator.

    In the above program the actual value of i1 is 14 and i2 is 13 convert.ToInt32 uses Math.Round and the direct cast uses Math.floor for rounding values to integer from double.

    It's always better to call Math.Ceiling() or Math.Floor() (or Math.Round with MidpointRounding that meets our requirements)

    int i1 = Convert.ToInt32( Math.Ceiling(d) );
    int i2 = (int) Math.Ceiling(d);

     

    Vikram

  • Bankers Rounding in Math.Round Method


    What would be the output of the following program?

     Console.Write(Math.Round(-0.5).ToString() + “~”);
     Console.Write(Math.Round(0.5).ToString()+ “~”);
     Console.Write(Math.Round(1.5).ToString()+ “~”);

     Console.Write(Math.Round(2.5).ToString()+ “~”);

    If you think the answer is 0~0~2~3~ then you are wrong. The actual answer is 0~0~2~2~.

    And this is no compiler or runtime bug. This is because Dot net framework’s Math class uses Banker’s rounding to round things. According to the banker’s rounding the 0.5 number are rounded to the nearest even number. If the fractional component of d is halfway between two integers, one of which is even and the other odd, the even number is returned.

    This can lead to some unexpected bugs in financial calculations based on the more well-known Round-Half-Up rounding. To control the type of rounding used by the Round(Decimal) method, call the Math.Round(Decimal, MidpointRounding) overload.

    Vikram

  • Using Enviroment.FastFail method to exit the corrupt application Process

    Have you ever had some point in code where you want to exit the application immediately? Normally for this purpose you would use the Application.Exit method.  But Microsoft has provided a better method for this purpose which not only just exits the application but also adds a message to the Windows Application event log.

    The Enviroment.FastFail method takes a string as a parameter writes that value to the Windows Application Event log, creates a dump of the application and exits the process. The string passed is also included in the error reporting to Microsoft.

    FastFail method should be used instead of the Application.Exit method in case the application is damaged / resource Lost etc. beyond damage and execution of the applications try/finally blocks and finalizer can corrupt the program resources.

    Vikram

  • Convert string to uppercase when comparing after normalizing instead of lowercase

    While doing string comparison after normalizing (converting both string to upper case or lower case) we should always use the upper case. Upper case is optimized for normalization.

    A small group of characters, when they are converted to lowercase, cannot make a round trip. To make a round trip means to convert the characters from one locale to another locale that represents the same character data differently, and then to accurately retrieve the original characters from the converted characters.

    Converting to uppercase rather than lowercase can also prevent incorrect behavior in certain cultures. For example, in Turkish, two lowercase i's map to the same uppercase I.

    Vikram

  • Finding Network statistics in Dot Net

    Last few days while working with my broadband network (downloading few stuff) I wanted to check the exact amount of download per minute. I tried to check the data from task manager and resource monitor. But these gave data in terms of percentage of network use. Hence I could never find the exact amount of download.

    So I wrote a small application to sniff the network and find out the exact amount of download. After fetching the data we can do lots of thing like creating speed chart etc…

    To fetch the network we use the System.Net.NetworkInformation namespace

    First we need to get the network Interface to track. A Machine might be connected to many network and we need to track each network differently. We can do that by the code below.

    foreach (NetworkInterface currentNetworkInterface in NetworkInterface.GetAllNetworkInterfaces())

                {

                    if (currentNetworkInterface.Name.ToLower() == "NameOf network")

                    {

                        networkInterface = currentNetworkInterface;

                        break;

                    }

                }

    We get the network usage of the current network with the help of GetIPv4Statistics function which returns object of the IPv4InterfaceStatistics class.

    IPv4InterfaceStatistics interfaceStatistic = networkInterface.GetIPv4Statistics();

    You can find the total bytes send and received with the help of the property.

    lngBytesSend = interfaceStatistic.BytesSent;

    lngBtyesReceived = interfaceStatistic.BytesReceived

    To find the speed of the download and upload you need to find the difference of the Bytes send and received between required time interval and you will have the speed.

    Remember bytes send and received are kept differently hence total download  = bytes send + bytes received.

    Vikram