Thursday, August 21, 2008
Sometimes, when working on your application, an exception is raised, and you don't necessary have a try ... catch block to handle this exception, or even to see it!
When you are in the debug mode, just launch a "quick watch" and type "$exception".
Could be useful!
Wednesday, June 11, 2008
When sending or receiving data with a HttpWebRequest or a HttpWebResponse, you probably need to provide an explicit Encoding for the data you send or the data you receive. If you don't do that, you might have a conversion problem, because of an invalid encoding. For instance, if the stream returned by your request is ib Unicode and if you read it in the Latin encoding, you will have invalid characters.
To avoid this problem, when receiving data, you need to use the encoding from your HttpWebResponse:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Encoding responseEncoding = Encoding.GetEncoding(response.CharacterSet);
StreamReader myStream = new StreamReader(response.GetResponseStream(), responseEncoding);
In the same way, when sending data, you need to first encode your data in the expected encoding:
String dataToSend = "......";
byte[] bContent = requestEncoding.GetBytes(dataToSend);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
Stream reqStream = request.GetRequestStream();
try
{
reqStream.Write(bContent, 0, bContent.Length);
reqStream.Flush();
}
finally
{
reqStream.Close();
}
Here is a full sample of posting data and reading the response in the expecting encoding:
String dataToSend = "......";
byte[] bContent = requestEncoding.GetBytes(dataToSend);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
Stream reqStream = request.GetRequestStream();
try
{
reqStream.Write(bContent, 0, bContent.Length);
reqStream.Flush();
}
finally
{
reqStream.Close();
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Encoding responseEncoding = Encoding.GetEncoding(response.CharacterSet);
StreamReader myStream = new StreamReader(response.GetResponseStream(), responseEncoding);
If you want to know more about GETing and POSTing data, while using a specific encoding, I advice you to read this detailed
article from
West Wind Technologies.
Thursday, May 29, 2008
When using a HttpWebRequest or a HttpWebResponse, you might need to send or receive cookies. If you try to access directly the Cookie property of your HttpWebRequest, no cookie will be returned.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost/MyApp/MyPage");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
// response.Cookies is always empty
It's a bit tricky, but to be able to access the cookies, you need to first assign the CookieContainer of your request.
A CookieContainer contains cookies for many requests. In fact, while the CookieCollection just store a list of Cookie, the CookieContainer store many CookieCollection, each for a specified URI. It allows storing cookies for different URI in a single place.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost/MyApp/MyPage");
CookieContainer cookieContainer = new CookieContainer();
request.CookieContainer = cookieContainer;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.Cookies != null && response.Cookies.Count != 0)
{
foreach(Cookie cookie in response.Cookies)
{
// Access to each cookie here
}
}
else
{
// No cookie
}
In some cases, you might need to perform several requests, GET or POST, toward several URLs, and pass each time the cookie information gathered from the previous requests. The easiest way to do that is to reuse your CookieContainer object. For instance:
CookieContainer cookieContainer = new CookieContainer();
HttpWebRequest request1 = (HttpWebRequest)WebRequest.Create("http://localhost/MyApp/MyPage1");
request1.CookieContainer = cookieContainer;
HttpWebResponse response1 = (HttpWebResponse)request1.GetResponse();
// Do something here
HttpWebRequest request2 = (HttpWebRequest)WebRequest.Create("http://localhost/MyApp/MyPage2");
request2.CookieContainer = cookieContainer;
HttpWebResponse response2 = (HttpWebResponse)request2.GetResponse();
By doing this way, you share your cookies between the two requests. The cookies retrieve in response1 are store in your cookieContainer, and then sent within request2. Cookies retrieved in response2 are added or updated inside your cookieContainer, and so on.
Sunday, May 11, 2008
I had to take over a project last week, an ASP.NET application. I found a lot of mistakes regarding resources protection and the use of try/catch/finally block. For instance, I found that:
SqlConnection con = new SqlConnection()
try
{
con.Open();
// Some code here
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (con != null)
con.close();
}
During a normal processing, if the code inside the
try block works, everything is fine. No problem.
Now, imagine:
1-
// Some code here raises an exception.
First, the execution goes to the
catch block. This one does nothing than re-throwing the same exception (by the way, I advice you to read this post about
rethrowing exceptions and preserving the full call stack trace, explaining how you will loose some important information like the stack trace of the exception). In this case, the block is useless.
Then, the execution goes to the
finally block. The connection exists (
con != null) and is closed. But the test is wrong… we should check if the connection is not null, and not if the connection is opened! The test is quite different, even if it works in this case.
2-
con.Open() fails and raises an exception
The execution goes in the
catch block (still useless) and then in the
finally block. In this case, the connection exists (
con != null) and is closed. But the
con.Close() call will throw an exception, because the previous
con.Open() didn’t work. The current exception will be lost (ie. “
con.Open() failed”) and will be replaced by another one (ie. “
con.Close() failed”). You loose some information about the problem you had.
This is now a better way to write your code:
SqlConnection con = new SqlConnection()
con.Open();
try
{
// Some code here
}
finally
{
con.Close();
}
In this situation:
1- If
con.Open() raises an exception
The execution goes out immediately, with the “
con.Open() failed” exception.
2- If
// Some code here raises an exception
The execution goes directly to the
finally block, closes the connection (that was previously opened) and then goes out of the function with the appropriate exception.
This method works fine, and is also much more readable!
Talking about connections, you can also use in a better way the
using statement! For instance:
using (SqlConnection con = new SqlConnection())
{
// Some code here
}
The generated MSIL code will be translated as a
try/finally block (as shown in this post about the
using statement), just like our previous sample. This one is just easier to read and to write, and you will not forget to close the connection.
Friday, May 09, 2008
If you open your project's properties and go to the "Web" tab in the "Servers" section, the first checkbox you see should be "Apply server settings to all users (store in project file)".
If this checkbox is checked, then the server settings (IIS, Cassini, etc.) will be stored in the csproj file. If it is unchecked, then the settings will be stored in the .csproj.user file instead.
Visual Studio crashes or is unable to open your project if the settings stored in the project file don’t match the settings of your computer.
Anyway, if several developers are working on a Web project, you should uncheck this option, to let each of them use their own settings or environment.
Tuesday, April 22, 2008
After
testing my websites with different browsers, I realized they don't work with IE8! Amazing, because most of them use a standard HTML code!
I found an interesting post from the
Windows Internet Explorer Blog talking about
Compatibility and IE8. The solution they ended up with is a meta tag. For them, the web developer needs to test his website against one version of Internet Explorer (IE5, IE7 or IE8), and use a meta tag to specify which version of IE is working with his website. Then, IE8 will automatically use the appropriate compatibility depending on the meta tag of the website.
The different meta tags available for this compatibility issue are:
<meta http-equiv="X-UA-Compatible" content="IE=5" />
<meta http-equiv="X-UA-Compatible" content="IE=7" />
<meta http-equiv="X-UA-Compatible" content="IE=8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
The "edge" value means the website supports the last version of IE8 and even further versions.
Remark: I'm talking about website all the time, but this meta tag can be different from one page to another one. I just consider that all your website should have the same compatibility and that you shouldn't have one page working only with IE5, the other one with IE8 and so on.
When developing a website using ASP.NET, you can directly specify the compatibility tag inside your web.config file, as follow:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<clear />
<add name="X-UA-Compatible" value="IE=7">
</customHeaders>
</httpProtocol>
<system.webServer>
</configuration>
Monday, April 14, 2008
You can now easily do it with
http://browsershots.org. This website uses distributed computers to open your URL on different browsers. Here is a description of the service created by Johann C. Rocholl:
"Browsershots makes screenshots of your web design in different browsers. It is a free open-source online service created by Johann C. Rocholl. When you submit your web address, it will be added to the job queue. A number of distributed computers will open your website in their browser. Then they will make screenshots and upload them to the central server here."
If you select all the default browsers, it is quite ... really slow. But you can just let it work and come back later. Really a useful website!
PS: thank you to
Erebuss for the link!
Thursday, April 10, 2008
I had to create a Windows Service with a Timer inside, to perform some actions regularly (in my case, sending emails). I just created a new project, add a Timer on the main form and add my code in the Tick event.
Nothing worked. My code was never called. I spent some time debugging, changing parameters, trying to understand...
Then, I realized I didn't use the right component... I was using a System.Windows.Forms.Timer instead of a System.Timers.Timer!! I just changed by hand the designer file and it worked from the first time.
Be careful, these two components don't have exactly the same properties and events. For instance, the elapse event is called Tick for the first one and Elapsed for the second one. But the behavior is the same.
Thursday, December 13, 2007
When uploading files in an ASP.NET application, you always face the "Maximum request length exceeded." when the user upload a file too big.
Of course, you can change the size of the HTTP request in the machine.config file (for all the web sites of your server) or rather in the Web.config file (only for your application):
<configuration>
<system.web>
<httpRuntime maxRequestLength="51200"/> <!-- 50 Mo HTTP request -->
My problem was not to increase the file size, but to handle this exception in a nice way. The easiest way I found was to handle this exception in the Application_Error event, in the Global.asax file. I just retrieve the last error, check the HTTP code and also compare the inner exception message. Here is my code:
HttpException serverException;
Exception innerException = null; // Get server exception
serverException = (HttpException)Server.GetLastError();
// Get inner exception
if (serverException.InnerException != null)
innerException = serverException.InnerException;
// Handle "Maximum request length exceeded." exception
if (serverException.GetHttpCode() == 500 && innerException != null && innerException.Message == "Maximum request length exceeded.")
{
Server.ClearError();
Server.Transfer("FileTooBig.aspx");
return;
}
This code is quite simple but is working fine! Any other way to do it?
Thursday, October 25, 2007
Ever wanted to debug GET or POST HTTP request? In this case, you have to use
Fiddler, the "Web debugging proxy".
Fiddler acts as a proxy between your computer and Internet. It logs all the HTTP/HTTPs (yes, HTTPs as well!) data, offers a lot of different views for your data (text, raw, xml...), provide some charts about data usage and much more!
You can also set breakpoints on a request, change the data of the request and then continue the process! You can also replay requests. Something else that looks interesting (unfortunately I didn't try yet): you can add your own script (it includes a event-based scripting system) and then add your own actions.
A must have if you need to debug/trace your requests!
Friday, October 19, 2007
I had to generate barcodes for one of my application. Unfortunately, I know nothing about barcodes!
I found this
interesting page, listing a lot of existing barcodes. For each, you have a sample picture, and a lot of information on each barcode (the kind of characters you can put inside, the size of the data and so on).
I had a low budget on this project (let's say no budget at all), so I tried to find something cheap :)
I found an article about writing a
C# Barcode Generator Webservice. The main idea is nice: you use a Windows font, and when you write using this font, it'll write the barcode. Easy to use. I tried it, it works fine. But the only free font I found is the one generating the Code 39 barcode. This code doesn't allow much data to be written. Not enough for me.
And all the one dimensional barcodes are all more or less the same. So I tried to use another kind of barcode, 2 dimensional ones. And I focused on the more popular one, the
QR Code. For this one, I found a open source barcode library, written in C#, to encode and decode barcodes. You can find an article
here and the library
here (you need to create an account first).
Really easy to use, the download comes with the full source code and a Windows application to use it. You change the parameters and make a lot of tests. I found one bug in this program: when the input data is too big (depending on the parameters you put), you will have an exception. Easy to fix, and not really important in my case because the entry data will always have the same size.
So if you are like me, looking for an open source library to encode your data into a QR Code, try this library as soon as you can!
Wednesday, October 03, 2007
In one of my Web application, I wanted to display a blink text, to inform users about something really important. Unfortunately, the <blink> tag doesn't work on IE, only on Firefox.
I found a nice way to avoid this limitation
here, using a javascript.
I copy the sample below:
<body onload="setInterval('blinkIt()',500)">
<script type="text/javascript">
function blinkIt() {
if (!document.all) return;
else {
for(i=0;i<document.all.tags('blink').length;i++){
s=document.all.tags('blink')[i];
s.style.visibility=(s.style.visibility=='visible')?'hidden':'visible';
}
}
}
</script>
<blink>Am i blinking ?</blink>
So easy to integrate in your application!
Tuesday, October 02, 2007
When dealing with SQL Server and auto identity fields, we always need to get the newly generated identity value. To do that, I've always used the @@IDENTITY function. Something simple like this:
insert into TABLE values ('My value'); select @@IDENTITY
This has been working fine ... till now! What if you have an insert trigger on the table, and what if this trigger inserts some records as well? In this case, the @@IDENTITY function will return the newly identity values generated inside the trigger, and not the one generated by the "insert into TABLE" statement.
To avoid that, you can just use the @@SCOPE_IDENTITY function. For instance:
insert into TABLE values ('My value'); select SCOPE_IDENTITY()
In this case, the newly generated identity returned will be the one from the "insert into TABLE" statement, and not the one from the last record inserted in our trigger.
You can visit the post
SCOPE_IDENTITY() and @@IDENTITY Desmystified from John Papa for more details.
Friday, July 27, 2007
I've just seen the post on
ScottGu's blog: VS 2008 and .NET 3.5 Beta 2 are just released!
Among the new features, you will find:
- multi-targeting support (multiple version of .NET framework)
- improvement of the HTML/CSS support inside VS
- support for Ajax and Javascript directly in VS
- many improvements regarding LINQ and LINQ to SQL
And much more!
Download the Visual Studio 2008 product
here.
Download the smaller VS 2008 Express Editions
here.
Wednesday, July 25, 2007
For a few hours now, I've been having this error when compiling my solution. Really annoying!
When launching VS 2005 and compiling the solution, everything works fine. But the second compilation leads to this exception. Using
Process Explorer showed the files were locked by VS itself! The easy solution is to exit/restart VS, but it's not a reasonable solution.
I started to try something on my own: clean the solution, clean .NET temporary files (in Windows\Microsoft.net directories), add a pre-build event to clean directories, add a pre-build event to kill the webserver, etc. Nothing really worked.
I looked around, trying to figure it out, and I found this interesting post on the
MSDN Forums talking about it and also a feedback related to this issue
here.
The solution working for me was to remove this line from my web.config file:
<hostingEnvironment shadowCopyBinAssemblies="false"/>
I tried to add this option once during the development in order to develop my own plugin system, and I forgot to remove it.
Everything working fine now!
Saturday, June 23, 2007
I'm working on a WinForms application, using TabControl, and I need to handle the middle button on the TabPage. I want to have the same behavior as when using my FireFox: when I click with the middle button on the TabPage, the TabPage closes.
By default, you can handle the middle button event, using the OnClick event on the TabControl. But I want to handle this event when the user clicks on the TabPage, and from that, close the selected TabPage. To do that, I use the OnClick event and check if the coordinates of the mouse match with the TabPage area.
Here is the source code below, with the appropriate comments:
private void TabControl1_Click(object sender, EventArgs e)
{
MouseEventArgs mea = (MouseEventArgs)e;
if (mea.Button == MouseButtons.Middle)
{
// Get the point from the current mouse click
Point ptClick = new Point(mea.X, mea.Y);
// Loop on TabPages
for(int index = 0; index < TabControl1.TabPages.Count; index++)
{
// Get the TabPage that contains the click coordinates
if (TabControl1.GetTabRect(index).Contains(ptClick))
{
// Remove the selected TabPage
TabControl1.TabPages.RemoveAt(index);
}
}
}
}
One might do a more appropriate treatment when closing the TabPage, maybe not just close it.
Friday, June 22, 2007
Hi, my name is Christophe, and this is my first post on my weblog.
Two words about me: I studied for five years in a computer science school, and also started to work at the same time on various software projects. I started to work with Microsoft .NET from the beta one, in 2001. I have now more than 6 years of experience with the .NET technology, both ASP.NET and WinForms applications, and more than 10 years in software development.
What about this blog? I want to share technology points with you, as well as ideas and thoughts on .NET, engineering, software management and much more!
Want to know more about me? View my complete profile on
voir mon profil
Hope to see you soon around here!
Regards,
Christophe