Showing posts with label .NET. Show all posts
Showing posts with label .NET. Show all posts

Aug 9, 2011

A book is born!!!

As most of you know, I was involved in writing a book about C# programming (we were 30 authors, each had to write a chapter and edit a chapter).You can click on its cover in order to be taken to download the PDF version:

Hope you will enjoy it.

Oh, almost forgot – it is in BULGARIAN Winking smile. There were some plans to have it translated but as I am not a part of telerik anymore, I don’t have any information from the kitchen how far this project went.

Please be sure to say a great thanks to telerik for sponsoring this book!

Jun 10, 2011

Convert string to a known type (using its default converter)

I was in a need to get a type, instantiate it and then fill its properties (I'm currently doing an engine that will give me an instant CRUD UI).

So what I basically needed was to be able to fill a new object instance out of a Hashtable (the key is the name of the property and the value is its string representation).

I wanted to be able to convert that string value into the type it needs to be.
Here is some code to help you get it:

foreach(string strPropertyName in htValues.Keys)
{
PropertyInfo pi = entity.GetType()
.GetProperties()
.ToList()
.FirstOrDefault(property => property.Name == strPropertyName);
}
(this is kind of pretotype so don't blame me if you don't like the code :).

In the above code I am iterating in the keys of the hashtable, so if I have an user object it will strPropertyName will hold "FirstName", then "LastName".
So far so good, I am able to fill the object and send it to the EntityFramework for DB Persistance.

The problem was when the strPropertyName was holding "BirthDate" as it is a DateTime and the EntityFramework or the Reflection (not quite sure which one) was crying it can't Convert the string to the respective type for me.

Here is how I solved the problem:
// Create a new Instance of the given type.
object entity = Activator.CreateInstance(this.EntityType);
// Iterate through all the properties.
foreach(string strPropertyName in htValues.Keys)
{
// Get the property with that name:
PropertyInfo pi = entity.GetType()
.GetProperties()
.ToList()
.FirstOrDefault(property => property.Name == strPropertyName);
// Get the default type converter for the given property type:
TypeConverter converter = TypeDescriptor.GetConverter(pi.PropertyType);
// Set the value by converting non-values to the given type
// and setting null where it is a null value.
pi.SetValue(entity, htValues[pi.Name] == null ? null : converter.ConvertFromString(htValues[pi.Name].ToString()), new object[] { });
}

Basically the thing you (and I!) need to remember is that the TypeDescriptor class has a GetConverter() method that takes a type and returns a TypeConvertor for that type.

Now in order to be able to convert from string to that type you just need to call .ConvertFromString(string value) of the TypeConverter returned by the TypeDescriptor.

Hope this helps someone out there. To me it seems it can give you a great deal of abstraction and I (for some reason) believe this is heavilly used in nowadays OR/M's.

Jun 9, 2011

Get the underlying type out of a Nullable

It appeared to be really simple actually, this post title suggest the solution:

Type nonNullableType = null;
if (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
nonNullableType = new NullableConverter(property.PropertyType).UnderlyingType;
else
nonNullableType = property.PropertyType;

What we actually do is to check if the type is nullable or not, if so - we are getting its Underlying type, and if not - we are getting the type itself.

Check if a type is Nullable or not

I was in a need to determine if the type of PropertyInfo is a nullable or not.
Here is what I've found on MSDN about this:

property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)

So you basically need to determine if the type is generic (makes sense as nullable is a type that takes T (Nullable)) and then to check if the type is a Nullable then.

Now, I really wondered do I really need both checks?
As it was coded that way at MSDN I first didn't look at that, but I wanted to tackle it a bit more.

First I thought that the first one is needed to protect you from the null value returned by the GetGenericTypeDefinition() method.
But what's the problem even if it does?
Well, you get InvalidOperationException saying "This operation is only valid on generic types.".

So you definetelly need both checks ;).
It is kind of ugly for me, maybe it will be better to create an extender to the Type type. Something like "IsGeneric()", but the Is prefix always suggests property while this is a method.

Anyway, I'll go with that.
In the next post I'll show you how to get the type out of a Nullable<>.

May 26, 2011

Serializing object to JSON returns empty string?

Consider the following code:

string JSONObject = string.Empty;
DataContractJsonSerializer serializer = new DataContractJsonSerializer(this.GetType());
using (MemoryStream ms = new MemoryStream())
{
    serializer.WriteObject(ms, this);
    // Donchev - we need to reset because the write has gone to the end of the stream
    // and the StreamReader.ReadToEnd() won't seek to the beginning of the stream again.
    using (StreamReader sr = new StreamReader(ms))
    {
        JSONObject = sr.ReadToEnd();
        sr.Close();
        sr.Dispose();
    }
    ms.Close();
    ms.Dispose();
}
return JSONObject;

It seems perfectly correct but have a few problems.

And the first one is very important – it is based on wrong assumption and it is returning empty string because of that.

I will let you tackle it for a while to see if you can find where the problem is.

Ready?

If not – I’ll tell you – the problem is that when I wrote this code, I was expecting the ReadToEnd() method of the StreamReader class to auto reset the stream to its beginning, it sounds for some reason to me that this method it is saying - “Read the whole thing.”.

Unfortunately this assumption evaluated to false.

The method actually says - “Read from where you are to the end of the thing.”.

So before calling JSONObject = sr.ReadToEnd();

I needed to simply call:

ms.Seek(0, SeekOrigin.Begin);

In order to reset the pointer to the beginning of the stream.

Voilla!

The other question I asked myself is why the pointer is at the end of the stream (after the string is empty and not some portion of the stream, it should be at the end).

The answer – the serializer.WriteObject() method is probably not resetting it to be at the beginning after it completes its job.

Not quite sure who is responsible for resetting the stream – the caller or the callee, we can have a long discussion about this.

Anyway – just wanted to share this with you. I know it is very old thing but I am trying to write for much of the things that made an impression on me.

May 9, 2011

Very old stuff – convert System.Drawing.Color to HTML.

When I was with Delphi, I wrote utility to do this myself (I mean Delphi in its early days) as I wasn’t aware for built-in mechanism to achieve that.

Now with .NET there is utility to do this for you but I often forgot which class has static method to convert System.Drawing.Color to Html string.

Here it is:

System.Drawing.ColorTranslator.ToHtml(color)

I think wouldn’t it be smarter to have an extender attached to System.Drawing.Color to do this for me from now on … :).

May 6, 2011

Having column display name in RadGrid Column chooser but not in the header of the grid

A little bit of background for this one.

I had a Telerik RadGrid that was having few columns ...

It had the column chooser enabled. Few of the columns were icons (for example “Answered”, “Rating”).

I wanted to have them without header text so I added the Template column and everything was just fine.

Until I right clicked on the header in order to show the column chooser. It was displaying the columns with auto generated names like “GridTemplateColumn7”, “GridTemplateColumn10”.

My goal was to keep the header of the grid clean (e.g. no label) because the icons were 16x16 and that’s all the space I needed to occupy with those columns, having a header “Answered” would extend the entire column. So to solve this case here is what I did:

Solution:

1. Added header text to the column and saw that the header text is appearing in the column chooser.

2. To hide it from the header of the column I added an empty <HeaderTemplae>.

The column should look like this:

<telerik:GridTemplateColumn HeaderText="Bookmark">
    <HeaderTemplate>
    </HeaderTemplate>
    <ItemTemplate>
    </ItemTemplate>
</telerik:GridTemplateColumn>

 

This would solve the problem for Template columns (and all column types that allow you to define HeaderTemplate). This will not work for GridBoundColumn for example as this type doesn’t have HeaderTemplate.

 

Hope this helps someone out there …

Jul 19, 2010

Site is recycled + ThreadPool.QueueUserWorkItem


Just to let you know that you may experience this issue.

If you have an unhandled exception it may be because of a job queued using ThreadPool.QueueUserWorkItem method.

Actually it appears that although the exception is not affecting the main thread (it was in another one) - the .NET will kill the running process (w3wp in our case).

As far as I read this behavior is implemented since .NET Framework 2.0.
It is because you may miss unhandled exceptions in a child thread (if it's in the main thread the process will be terminated in a windows application).

I imagine each request to a web server as a separate thread so I am kind of worried why unhandled exceptions aren't killing the W3WP process as well.
It only seems to be killed if you create another thread in the request thread and this another child thread exits with unhandled exception.

Will need to investigate a bit more about that.

Jul 14, 2010

Thread was being aborted. Exception on Response.Redirect()

This is actually an old issue but I try to make sure I have most of the things that stopped me at some point so I can easilly search.

So if you experience the "Thread was being aborted." exception on Response.Redirect(string Url), it is because this method internally calls Response.End().

In order to prevent it to do so, you will need to use the overloaded version that requires another boolean parameter (something like "bool endResponse", don't remember it exactly).

So the thing that should solve it is:

Response.Redirect("http://donchevp.blogspot.com", false);
This way you should avoid "Thread was being aborted.".

Hope I helped a bit ...

Jun 18, 2010

How does your manager make a coffee?


I had an architectural problem yesterday.
I was working on a methods and managers I won't disclose but will analogy instead.



Imagine you have a coffee manager. Let's name it CoffeeManager.
In my case not only I had coffee manager but also I had a SugarManager, a CupManager etc.

In order to take a coffee without sugar in a plastic cup I should do something like:

Sugar sugarObject = SugarManager.GetSugar(Sugar.None);
Cup plasticCup = CupManager.GetCup(Cups.PlasticCup);
Coffee shortCoffee = CoffeeManager.GetCoffee(sugarObject, plasticCup);

And this happens at the very frontend of the project (in ascx for example).
And not only it happens that way but the managers are spread in few different projects.

So in the frontend I need to call few different managers, get some results from them and pass those results to the manager that should be doing my job.

I also need to handle all the problems that may rise in the managers so I get a lot of code in the frontend just to get something that in my opinion for that particular case should be returned calling a single method and auto handled in the manager.

I think the front end shouldn't care about business operations that much, also as I said the managers were in different assemblies so I ended up adding few references to the frontend project.

I refactored the code so the CoffeeManager can do this job internally (drawback is that the matrix of all combinations of sugar and cup should be added as a methods in the CofeeManager, but I can live with that).

Dec 3, 2009

Introduction to programming with C#

As Vesko Kolev stated in his blog - a new bulgarian book about C# programming is in progress.
I decided to take part because it seems very interesting. I haven't much experience in publishing so it will be very beneficial for me to work on this.
Actually I was author in a software magazine few years ago (as far as I remember I was about 17 years old so it must have been about 6 years ago). It should help me as I took the first chapter - introduction to programming where I will show the readers how to install Visual Studio 2010, how to start their first project and how to write their first program, some diagrams of the .NET framework 4.0 will also be included in this chapter.

We decided not to include any advanced features in this book, just core programming language, no extensions, no lambda expressions, no var, no automatic properties, no nothing.
This is because this book targets potential software developers and not software developers. It should show the developer how to code, how to think etc. We decided that if a man / lady without any software experience may think that auto property won't take memory after it doesn't involve variables (at least visualy :).
That is why we do only core things.

Wish us luck. We would really love to expand bulgarian software development community with few more people :). After all if even one guy / gal of all the people that will potentiall read the book becomes an expert - our mission would be completed (we are dreaming for more impact ofcourse :).

As Svetlin Nakov and Vesko Kolev said - telerik is sponsor for this book so it should be published easilly than their prеvious book - "Introduction to programming with Java" and would probably joy some more marketing efforts.

That was it about the book.
Now about my motivation to join the project no matter my personal engagements and all the work I have at telerik and at the university.
The first reason is that I am a self - taught (almost) developer.
I never had degree that will help me find my work, join some society of developers that will help me when I hit a difficult problem.
There wasn't even internet in my hometown. A friend of mine gave me a book on programming with Delphi (that Sams 21 days brick :).
The Delphi help also helped me and I also downloaded html files to read later when I was at school.

Then I applied for a job in the city where I was studying (Veliko Tyrnovo).
It was all my collegues that helped me improve my skills.
I don't feel as a worldwide recognised expert or something but getting to the intermediate level from nowhere is achievement to me.
So reason #1 to join this book is to give something back.

Another reason is that I would like to see how a book is written, are there different proccesses than in the software development. It has something to do with the blog posts I guess :)
So reason #2 is to steal some knowledge :)

And some kind of nostalgy would be the last reason to join :).As I said, I was an editor in a software magazine, it was very nice thing to do. The article, then the readers asking for some more information. I miss this a bit :)
Reason #3 - to feel the old days when I was an editor :)

Aug 2, 2009

Work in a cooperation with your compiler. Always tell the truth about your datatypes!

When you have a cast you should avoid asking the compiler to figure out what kind of data should be returned. This is more about objects and the string data type.
For example I've seen (and to be honest I myself did the following mistake when getting data from DataSet. Don't laugh in .NET 1.1 and 2.0 there was no Linq :)

foreach (DataRow row in dsReportSource.Tables[0].Rows)
{
string strName = row["name"].ToString();
}

The compiler will let you think that it knows how to do the fastest transformation from object (in the dataset all the columns in a row are objects) to the destination type (in our case - string). But it will only let you think so. What will actually happen is that the compiler will slow down the data acquisition due to some internal checks and conversions ...

Instead do the following (as you are more than sure that this column is string):

foreach (DataRow row in dsReportSource.Tables[0].Rows)
{
string strName = (string)row["name"];
}

This way you tell the compiler - "Look, don't even bother to try to infer the type for me. I am telling you this is a string, so please just treat it as string). And it makes sense - after you have a column of type NVARCHAR in the database it will always come to you as a string (masked as object :).

Now there are even worse cases like:

foreach (DataRow row in dsReportSource.Tables[0].Rows)
{
int iId = int.Parse(row["id"].ToString());
}

As you can see you are parsing the id column. You know it's int. But int.Parse can only work on strings, so you are required to turn this object to string, calling its .ToString() method. This will slow down your code insignifficantly on few rows and signifficantly on more rows (few thousands for example).

The following is also wrong:

foreach (DataRow row in dsReportSource.Tables[0].Rows)
{
int iId = Convert.ToInt32(row["id"]);
}

Here you are telling your compiller that you are sure the parameter (row[
"id"]) will cast to Int32 without problems.
But here you are telling your compiller only 50% of the truth. After you KNOW it is int, just be honest and say:

foreach (DataRow row in dsReportSource.Tables[0].Rows)
{
int iId = (int)row["id"];
}

This applies not only to DataSets but everywhere you have a fixed datatype and you know what the type is.


Don't let your compiler do the work.
Just look at your project and try to find places where you are uncertain about fixed datatype.
Change it to be a direct cast and I am pretty sure you will experience speed improvements.

Aug 1, 2009

Why your HttpHandler has the Session set to NULL?

I was in a need to create HttpHandler. I also needed to use the session.
Here is my first attempt:

  
public class ChbHandler : IHttpHandler
   {
     #region IHttpHandler Members

    
public bool IsReusable
     {
        
get { return true; }
     }

    
public void ProcessRequest(HttpContext context)
     {
        
HttpRequest req = context.Request;
        
HttpResponse resp = context.Response;
        resp.Write(
"HttpHandler: Hello World!");
     }
     #endregion
   }

In Here if you try to use the Session object you will not it is null. Why is that?
I googled a bit and found that in order to support session, your HttpHandler should inherit the

IRequiresSessionState or IReadOnlySessionState in order to have the session state in the context parameter (the one that is passed to the ProcessRequest() routine.
Luckilly both interfaces are just marker interfaces, meaning you are not required to implement any additional methods.
So something like this:

  
public class ChbHandler : IHttpHandler, IRequiresSessionState
   {
     #region IHttpHandler Members

    
public bool IsReusable
     {
        
get { return true; }
     }

    
public void ProcessRequest(HttpContext context)
     {
        
HttpRequest req = context.Request;
        
HttpResponse resp = context.Response;
        resp.Write(
"HttpHandler: Hello World!");
     }
     #endregion
   }

Should work just fine for you.
The only change is :
IRequiresSessionState in the list of Interfaces that the class will inherit.

Nov 14, 2008

Two new automated blogs

I've been very busy this month. All the exams (for microsoft certification, in the faculty and so on), my extended work day (from 9 to 20 as I was absent
from work for about a month and need to do some extra work to catch my collegues), some ongoing projects I was stupid enough to take and so on...

However, I've found some time to start two new blogs which I consider more as experiment than real blogs:

Sql Exceptions

and :


.NET Exceptions



Both blogs currently contain about 40 posts with Sql and .NET Exceptions which you may find helpful after time. I am saying after time as I plan to automate those blogs so the information there is posted by software and not by myself.

Also users are welcome to post comments. Soon I will publish special format of posts which you can use in order to give your opinion on specific exception and this exception will be automatically published in the post.

Unfortunatelly there is a limitation - Blogger allow me to only publish about 40 posts daily so I wasn't able to create posts about all the exceptions in SQL and .NET Framework.

I will batch post each day (may miss some of the days like weekends for example ;) so in few weeks both blogs will be up to date.

Oct 21, 2008

C# AddIn - Start Debugging and get the running Internet Explorer instance.

I needed to do this (actually I wanted). I was curious if you can obtain an instance of a Internet Explorer which was started in debugging session. Here is a snipet to do this:

        _applicationObject.Debugger.Go(
false);
        SHDocVw.
ShellWindowsClass windows = new ShellWindowsClass();
        
foreach (SHDocVw.InternetExplorer explorer in windows)
        {
          
if (explorer.LocationURL == string.Empty)
           {
            
// this is our guy!
             ie = explorer;
           }
        }


Note : this snipet should be added somewhere where you have access to the _applicationObject.
This is the variable which is declared automatically when you create new instance. I suggest you to put it into the exec method of the AddIn:

     public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
     {
        _applicationObject.Debugger.Go(
false);
        SHDocVw.
ShellWindowsClass windows = new ShellWindowsClass();
        
foreach (SHDocVw.InternetExplorer explorer in windows)
        {
          
if (explorer.LocationURL == string.Empty)
           {
            
// this is our guy!
             ie = explorer;
           }
        }
     }

You also need to add reference to ShDocVw (Microsoft Shell And Automation Library).
Enjoy!

Oct 19, 2008

Touchless SDK : Very interesting and promising technology each of you guys should play with :)

I came on this yesterday, I was bored because all the projects I am working on are to some degree "standard". No dev chalenge. I wanted to create, to do something interesting.
So I started to browse CodePlex and found this SDK.

Overview :
Touchless SDK is a software development kit to help developers create applications which can be controlled without the standard peripheral devices (mouse, keyboard and so on). It enable you to create a applications which are controlled without the need to touch anything at all, just gestures in the air.
How is this done?
Well, I think there was a lot of research on this topic. We already have programs to detect motion from your video camera, why not try to extract information from those motions? This is
exactly what Touchless does. It captures an info from your camera and if it finds something that is known to be marker - it raises events, to which you can subscribe and do something.
The better news is that Touchless is Open Source project and can be obtained from CodePlex for free.
You can also whach a video on Touchless:





I downloaded this SDK and in less than a minute I made a small program which let's you move your cursor with fingers (I still can't find a good enough way to left and right click ;).
I hope I will have enough time this week to post this simple project so you can get deeper with Touchless as it seems promising technology to me.

Limitations:
Well every good thing has drawbacks. Don't get it wrong. Touchless isn't the standard in this area. It has problems (however I think after it is open source a lot of people can work on it and improve it).
So what are the limitations?
First of all - Touchless is very very very sensitive to light and to colors. It is because the way it works. In order to work, you need to specify a "marker". Marker is the thing the program looks for. So if you have a red tape on your finger and define it as marker, you will be able to command your computer with it. But if there is a object with the same color on the screen and this object is about the same size, it may be found as another marker.

The second problem (at least for the sample project I did) is that most web cameras are not sensitive enough. They are (most of them offcourse) with 640 x 480 pixels resolution. If you are about to move your cursor and your screen resolutions is 1280 x 1024 you will be only able to move the cursor 640 pixels horizontally and 480 pixels vertically (this can be software corrected by moving the cursor 3 or 4 pixels on each pixel that comes from the camera but for sensitive operations (resizing, drawing) it will not be good enough.


However I think the things above will be resolved and we will have another great way to use our computers for almost no extra charge.
I do really wish those guys luck and I will definatelly watch how this project goes and even if I can I will help a bit.
I really fell in love with this toy!

Oct 16, 2008

C# - Web Browser Control - Load String in Web Browser control.

I was thinking about this long time ago. I recently found this post:

http://www.xtremevbtalk.com/showthread.php?t=167531

So how to load a string in WebBrowser Control with C#?

First - navigate to "about:blank" (as the web browser needs a document to operate on)
Then use WebBrowser.Document.Write(string text) to write the string you want to load in the WebBrowser control. Kind of tricky but ...

Another way is to write something like:

about:your html here

And the last one is to write the document on the hard disk with StreamWriter for example, and then to navigate to it.

Here is a code to show you all methods discussed:


        
WebBrowser wb = new WebBrowser();
        
// First way to
write html in WebBrowserControl with C#:
        string strHtml = "you html here";
        wb.Navigate(
"about:" + strHtml);

        
// Second way to write html in WebBrowserControl with C#:
        wb.Navigate("about:blank");
        wb.Document.Write(strHtml);

        
// Third way to write html in WebBrowserControl with C#:
        const string strAddress = "test.html";
        
using (StreamWriter sw = new StreamWriter(strAddress))


{
        sw.Write(strHtml);
        

}      wb.Navigate("file://" + Application.StartupPath + "\\" + strAddress);

Oct 7, 2008

One more ASP.NET page optimization ...

I wrote two articles on this topic already. The first was that you can earn few bytes from renaming the "javascript:__doPostBack" to "__dp". Then I noticed that I have problems with this. The problem was that in some cases you need to have the "javascript:" prefix.

So my first attempt to do some optimization is considered more unsuccessful than successful.

Now I am going to propose another way.
It is again based on removing / renaming / moving existing things in the page so they can be a bit more optimized.


Let's suppose we have a GridView. We clicked on the "Auto Format" thing and we not only have a GridView, but we have a nice looking grid view. It's great, but it seems to be unefficient. It appears that the GridView will add a
style="" attribute for each row / cell (not quite sure about the exact rules). And it will generate repeating markup, increasing the size of the page and respectivelly - your bandwidth.

I did a small snipet to fix this (not the best solution again but should be kind of starting point).

Here is my code:

     protected override void Render(HtmlTextWriter writer)
     {
        System.IO.
StringWriter stringWriter = new System.IO.StringWriter();
        
HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);

        
this.EnsureChildControls();
        
base.Render(htmlWriter);
        
string html = stringWriter.ToString();

        AnalyzeStyles(html);
        html = RepairStyles(html);

        writer.Write(html);
     }

    
private void AnalyzeStyles(string html)
     {
        
MatchCollection CSSMatch = Regex.Matches(html, "style=[\"].+?[\"]", RegexOptions.IgnoreCase);
        
foreach (Match mCss in CSSMatch)
        {
          
if (htDuplicates.ContainsKey(mCss.Value))
           {
             htDuplicates[mCss.Value] =
Convert.ToInt32(htDuplicates[mCss.Value]) + 1;
           }
          
else
           {
             htDuplicates.Add(mCss.Value, 0);
           }
        }
     }

    
private string RepairStyles(string html)
     {
        
int classID = 0;
        
int pos;

        
IDictionaryEnumerator iOccurences = htDuplicates.GetEnumerator();
        
this.CSS += "";

        InformaticsWeb.Pages.
Optimized master = (InformaticsWeb.Pages.Optimized)this.Master;
        
        pos =
Regex.Match(html, "", RegexOptions.IgnoreCase | RegexOptions.Singleline).Index + "".Length;
        
        html = html.Insert(pos, CSS);
        
return html;
     }

Please note : AnalyzeStyles adds each of the style="" found on the page (each unique). If it finds secound and third and so on - it increases a counter. The counter is not currently used, but may be later used to decide which of the styles should be converted to CSS classes.

So this code basically takes the page and moves all the style="" attributes in the head section as a CSS classes. I tested and my grid view seems as beautiful as before this code was applied.

Now, does it worth to add this logic?
Well I think you can achieve the same functionality by using Skin files. I am adding this more for reference.
I also did a small excel diagram to show you how much bytes are saved based on the count of the items in the GridView:




Please note that the htDupplicates is a Hashtable, declared as a global variable, so you will need to add it if you want to use this code.

Let me now explain the columns in the excel file shown above.
The “Columns” column displays how much columns does the GridView render. Typically the columns are rendered as a table cells and doesn’t contain any style=”” attributes (at least I couldn’t see any), so this is something you can’t affect. The thing that this optimization affects is the number of rows in your gridview. The more rows you have the more bytes you will get.
The second column displays the number of rows in the grid view.
The third column is the optimized size of the gridview (when the above technique is applied).
The “Size Original” column displays the size for unoptimized page (the same page!).
And the last column shows you the difference before and after.

You can see it in the diagram - for 20 items you have about 842 bytes difference. While for 80 you have about 3,512 (I don’t think there is a live site which displays 80 items at once in a grid view ;).

Oct 6, 2008

Very elegant way to cut few more bytes from your ASP.NET markup and optimize your bandwidth a bit (2) - Solving the puzzle

As I mentioned in my previous post, I ocassinally received errors when replacing the "javscript:__doPostBack" with "_dpb". It saved few bytes, yes, but for example the ASP Menu stopped working.

I finally found what was causing the problem. It is because of links (rendered as "a href"). The ASP Menu renders them as a href="javscript:__doPostBack()". If you remove the "javascript:" part you will have problems as the browser will not be able to understand that you are trying to call a JS function. A possible solution is to move the call to the OnClick of the "a" element, leaving "#" in the "href" attribute like this:

a href="#" onclick="_dpb()"

This will however cause a small side effect. When the user clicks on the first
of a series of links, all the links will change their css class to "visited:" css class (because the browser sees you already have visited the "#" address).

Conclusion : You can apply the above technique but it will not help you much and I think it involves to much efforts for a small effect (few bytes). If you really want to get this benefit you can replace the "javascript:__doPostBack" with "javascript:_dp" and you will get less bytes than if removing the "javascript:" part but the page will work as expected.

I am currently working on other techniques to cut more of the ASP page markup, but they are a bit more serious. I hope I will write another post soon to inform you how it is going.

Oct 3, 2008

Very elegant way to cut few more bytes from your ASP.NET markup and optimize your bandwidth a bit

I was thinking about how can I optimize the markup of a page a bit.
I found a great way (great but not very very very efficient) to do so.
It is based on a strategy that came in my mind recently.

Let's think a bit.
We already have very interesting methods to cut bandwith of an ASP.NET page like for example compressing the view state and so on and so on.
So provided we already have applied those techniques, if we still want to optimize what should we do?

I call my method : iterative profit, you will soon understand why ...

If we have something that repeats few times in the markup and is relatively long as name, if we make it shorter we should win some bytes right?
And if the page is big enough and "the thing" is repeated more times, we
will win more and more bytes.
So each time we cut the name of something, we win few bytes.

The next question is what can we cut in order to optimize our page?
What is the thing that repeats in each web control?

The answer is the "__doPostBack" function. I tried to replace it during the Rendering of the page and was able to cut a bit of the page size, while keeping the source relatively clean of errors (please note the word "relatively").

Here is a sample code:

     protected override void Render(HtmlTextWriter writer)
     {
        System.IO.
StringWriter stringWriter = new System.IO.StringWriter();
        
HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);
        
base.Render(htmlWriter);
        
string html = stringWriter.ToString();
        html = html.Replace(
"\"javascript:__doPostBack", "\"__dpb");
        writer.Write(html);
     }

I had some issues I haven't yet identified, as I was in a rush to post this as it seems to me a brand new way to optimize pages - to look for repeating elements and cut their names... (I will be happy if there are volunteers to help with this one ;)...


Other things : DoPostBackWithOptions should also be replaced by dpbw for example, this will be done in the future, after I clean the _doPostBack as it still have few problems.


And some more things - we may consider optimizing some of the ASP.NET controls which are known to be "markup unoptimized" like the treeview, gridview for example (At least I think there may be some things in them to optimize).

Any comments are welcome.