IIF(A,B,C) -- Beware it is a function not a statement!!

Learning how to write neat and clean is something many people wish to achieve. I believe it's an art which can be mastered with practice. I myself have this habit of keeping things brief and to the point, and I always tend to apply the same theory to my coding as well. However, today while writing a small piece of code in the similar consise manner for a small module, I found something interesting that made me realize the importance of understanding the difference between different programming constructs. I am talking about IIF(A,B,C) function and IF ELSE statement in particular here.

I had a situation where I was getting some value from the database and there was a fair chance of that value being NULL. I preferred IIF over IF ELSE to save 3 lines of code.

Dim lCVCount As Integer = IIf(IsDBNull(DataBinder.Eval(e.Item.DataItem, "IsCV")), 0, CInt(DataBinder.Eval(e.Item.DataItem, "IsCV")))

Mucy to my surprise, it didn't work and threw me exception. I kept wondering for a few minutes what is wrong with this. You know it is generally said that not knowing something is acceptable but forgetting something which you know is completely unacceptable and I agree with this. How can I forget that a function behaves differently than a statement. It passes parameter values to calle which means it must execute those parameters first, if they are found to be compund in order to get their value. This explains it all that why the third parameter in above statement is throwing exception. I thought I am better off using IF ELSE here in order to keep .NET runtime happy.

Sometimes It is good to get these kinds of errors which reinforces the fact that we should always be careful in what we write and specially when it comes to writing code!!

HTH,

File "Save As" issue while downloading with Content-Disposition: inline

It has been a long a time since I wrote anything on the blog. I was on a long holiday and (honestly speaking) wanted to stay away from the technology. But now, since life is back on rails, let's start with the very first issue I faced after I joined my workplace a couple of days ago. It is about an issue with the file name not being considered when using "inline" as HTTP response Content-Disposition header.

Downloading a file using Content-Disposition: attachment as HTTP response header displays a "File Download" dialog box asking the user whether to "Open", "Save" or "Cancel" the document. In certain scenarios this dialog box can be really painful specially when user has to repeatedly do this exercise for multiple links available on our website. In order to avoid this we use Content-Disposition: inline which opens the document without asking by using appropriate software like MS Word, Adobe Acrobat Reader etc. installed on the user's machine. This document can be saved later on using "Save As" option.

Before I move on, let's have a look on the following statement that shows the way to add Content-Disposition header to Response stream:

context.Response.AddHeader("Content-Disposition", "inline; filename=resume.doc")

The problem with the Content-Disposition: inline is that it doesn't pick the file name from filename attribute we use in AddHeader function rather, it always takes the name of web page from the URL while saving the document. Content-Disposition: attachment seems to be working fine even with the "Save As" command, but this is something I didn't want to use. I spent some time researching on this issue and couldn't found a workable solution. In order to workaround I came up with the below solution that seems to be doing the job.

I actually decided to use a URL for the document link that reflects the name of the document being downloaded. For example for the document "MyResume.doc", the URL I have used looks something like this:

<a href="Default/FileName/882bd3e9-5035-4946-8c2a-98ef0eccc6e0/uploads/MyResume.doc.aspx">Download File</a>

Did you notice ".aspx" at the end of the URL? It is very important to append it in the end in order to send the request back to server whenever user clicks on the link. On the server, I have created an HTTPHandler to catch this sort of request that contains "*.doc.aspx". Without appending ".aspx", browser will server your document directly without changing the URL in the browser. But, we want to change the URL which means request has to go to the server.

The rest of the solution is very easy as I have written below code under the body of ProcessRequest function in my HTTPHanlder which helps dump file contents into response stream. It is also important to note that URL of the document must be relative and not absolute. The reason being, it's a dummy URL which doesn't exist at all. Relative URL guarantees that request will come to the same web site/application where we can catch it before it goes to ASP.NET engine. QueryString data can be made part of the URL as in my case GUID is the piece of information which is part of the URL and I receive it on the server.


Public Sub ProcessRequest(ByVal context As System.Web.HttpContext) Implements System.Web.IHttpHandler.ProcessRequest

'Context.RewritePath("Test-Page.aspx")
context.Response.ContentType = "application/msword"
context.Response.AddHeader("Content-Disposition", "inline; filename=adeel.doc")
context.Response.TransmitFile("C:\inetpub\wwwroot\Uploads\882bd3e9-5035-4946-8c2a-98ef0eccc6e0.doc")
context.Response.Flush()
context.Response.End()

End Sub


The last bit is to add the below statement in web.config to enable HTTPHandler to catch "*.*.aspx" so that it will serve for all kinds of file type extensions.

<add verb="*" path="/uploads/*.*.aspx" type="Test.HttpHandler, Test"/>

XML Literals - (VB.NET only)

After I learned about lambda statements that they are supported only in C# 3.5 and not in VB.NET 9.0, I got curious and thought why not to find something that is available only for VB.NET and not for C#, and found this interesting thing which is called XML Literals. Using this nice features which is a part of LINQ to XML API, we can embed XML directly within Visual Basic 9.0 code.

To illustrate its power let's have a look at the below XML that we will produce using XML Literal.


<books>
<book>
<title>LINQ IN ACTION</title>
<author>FABRICE MARGUERIE</author>
<author>STEVE EICHERT</author>
<author>JIM WOOLEY</author>
<publisher>Manning</publisher>
</book>
</books>

now take a look at Listing 1.1 below, which shows the code for creating the XML using the XML literal syntax offered by VB9.

Listing 1.1

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

Dim booksElement As XElement = <books>
<book>
<title>LINQ IN ACTION</title>
<author>FABRICE MARGUERIE</author>
<author>STEVE EICHERT</author>
<author>JIM WOOLEY</author>
<publisher>Manning</publisher>
</book>
</books>
End Sub

Note that in the above code we are using XElement which is a new class introduced in .NET 3.5 which represents an XML element. According to MSDN:
"XElement can be used to create elements; change the content of the element; add, change, or delete child elements; add attributes to an element; or serialize the contents of an element in text form"
The XML fragment in listing 1.1 above is static. When building real applications we might need to create XML using expressions stored in a set of local variables. XML Literal allows us to do so through expression holes which is expressed with the <%= statement %>.

Listing 1.2

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

Dim xml = LoadXML("LINQ IN ACTION", "Manning", "FABRICE MARGUERIE", "STEVE EICHERT", "JIM WOOLEY")

End Sub

Private Sub LoadXML(ByVal title As String, ByVal publisher As String, ByVal ParamArray authours() As String)

Dim booksElement As XElement = <books>
<book>
<title><%= title %></title>
<author><%= authours(0) %></author>
<author><%= authours(1) %></author>
<author><%= authours(2) %></author>
<publisher><%= publisher %></publisher>
</book>
</books>

End Sub

Rather than having to learn the details of XML API, XML Literals allows us to directly embed XML directly within the code. It's a great addition to VB9.0 and hope that it will get added to C# as well in future.



HTH,