Thursday, July 28, 2005

CSS Tip: Using media=print for printer-friendly pages

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/css_tip_using_mediaprint_for_printerfriendly_pages.htm]

When you print a page, you want just the workspace of the page in normal portrait view - not banner ads, left navigation bars or text that extends off the printed page . This is a printer-friendly view. There are at least two categories of solutions:

  1. Have a "click here for printer-friendly version" link that posts back to the server, does manipulation such as hiding menus, and creates a new instance of the page in printer-friendly mode
  2. Use Cascading Style Sheets (CSS).

The former has several problems that the latter solves:

  • It posts back to the server, which hurts performance
  • It becomes a nightmare if you want to open a new instance of the page for printing, such that closing this print-page won't accidentally close the main app page.
  • It is a pain for editable pages because it requires the developer to manually persist all values to the new print page. Say the user enters a value in a text field, how do you persist that to a new page instance, perhaps via querystring or session? But what if the values are large?
  • It requires additional effort for each page.

CSS provides a "media" attribute that can apply different style sheets to different media. The two media we're looking at here are screen (default) and print.

A stylesheet can set the color, visibility, or any other style that's relevant to a print-version. Here's a practical example that hides buttons (you can click a button in printview) and formats all text in greycolor (you many not want to waste color printing on text):

Html page:

<HTML>
    <HEAD>
       
        <LINK href="Print.css" type="text/css" rel="stylesheet" media="print">
        <LINK href="StyleSheet1.css" type="text/css" rel="stylesheet" media="screen">
    HEAD>
    <body MS_POSITIONING="FlowLayout">
        <form id="Form1" method="post" runat="server">
            <P>This tests styles.P>
            <P>
                <asp:Label id="Label1" runat="server" CssClass="MainFont">
                Labelasp:Label>P>
            <P>
                <asp:Button id="Button1" runat="server" CssClass="PrintButton"
                Text="Button">asp:Button>P>
        form>
    body>
HTML
>

Stylesheet (Normal):

body
{
}
.MainFont
{
    font-weight: bold;
    color: red;
}

Stylesheet (Print):

body
{
}
.PrintButton
{
    display: none;
}
.Template
{
    display: none;
}

Eric Myer has a great article that explains how to use CSS for printing.

Monday, July 25, 2005

Tips to Efficiently create database unit tests

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/tips_to_efficiently_create_database_unit_tests.htm]

A while ago I published an article and blogged on how to Unit Test the Data Layer. Recall that the basic approach is:

  1. Create a test-only instance of the database
  2. Initialize the table data to a specific state
  3. Run your object
  4. Check either the return value of that object (for selects) or the new state of the database (for insert/update/delete).

A common problem I keep facing is that these tests can take long to create, and longer to modify. Below are a few tips that I've been learning.

Creating the initialization script is usually tedious and time-consuming. One approach is to create or find a tool that takes a select statement and generates inserts from its result set (I built such a tool, but I can't release it because it's proprietary to my company, Ameripay). This lets you easily copy existing data for testing purposes.

I modified this tool to put tabs after each column, and place the insert and values sections on separate lines.

insert into myTable ( myId,    col1,     col2)
values ( '1',     'abc',     'def')

This lets me easily copy the text into Excel, which then automatically formats it in a tabular way that lines up column headers with contents, like so:

insert into myTable(myId,col1,col2)
values('1','abc','def')

It's much easier to edit this way!

Therefore to maintain the data, I only need the raw SQL script itself - not some fancy generator/mapping tool or spreadsheet. I can now take the raw text and swap it between:

  • Query Analyzer -  to easily test it
  • Visual Studio - in a source file as the contents of an ExecuteNonQuery(@"...") method that runs it to initialize the test
  • Excel - to put it in tabular form and maintain it.

Two applications of this:

  1. I created a MasterInserts Excel sheet that contains standard inserts for each table. Therefore if I have 5 objects all requiring test data from the same table, I go to this master sheet as the definitive source, copy the lines I need, and modify them appropriately. This prevents me from wasting time re-creating SQL inserts for tables.
  2. Say I have multiple tests for a single object. 90% of the base data for each test is the same - usually it's just tweaking a value like making sure a SP handles a null column. Therefore I refactor the common base script to a single method that runs it in ExecuteNonQuery. Then each test can call this method and merely do the simple update or additional insert that it needs.

The sky is always the limit, but it's getting there.

Thursday, July 21, 2005

Internet Explorer tool to see partial source

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/internet_explorer_tool_to_see_partial_source.htm]

A coworker of mine recently showed me this great and free tool:
http://www.microsoft.com/windows/ie/previous/webaccess/default.mspx

It's an IE add-in that lets you select a portion of the rendered text and view its source.

  1. Select the text
  2. release both mouse buttons
  3. Right click the mouse over the selected text for the context menu
  4. You'll see a new option "View Partial Source".

Very helpful for development!

Tuesday, July 19, 2005

Overlapping Server and embedded &lt;% %&gt; tags.

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/overlapping_server_and_embedded_lt_gt_tags.htm]

In ASP.Net, you can run into unexpected problems when combining embedded script and runat=server controls on the same object. Two resulting problems are:

  1. Your Html simply won't render (and you'll wonder why)
  2. You'll get an Html parse error, without it ever even hitting your code behind.

Let's look at a couple such snippets:

Okay: Embedded script doesn't overlap runat=server control.

<table border="1">
  <tr
>
    <td><%="Hello World" %>td
>
    <td><asp:Label id="Label1" runat="server">This is okayasp:Label>td>
  tr
>
table>

Problem: This embedded script won't render because it is within the innerHtml of a WebControl (which is obviously runat=server).:

<tr>
  <td
>
    <asp:Label id="Label1" runat
="server">
      <%="Hello World"
%>
    asp:Label
>
  td
>
tr>

Okay: This does render (within the innerHtml of a runat=server Html control):

<tr>
  <td runat="server" id
="Td1">
    By<%="Hello World"
%>
  td
>
tr>

Problem: This won't render, because it is within the attributes of a runat=server control:

<tr>
  <td runat="server" id="Td1" height='<%="60" %>'
>
    By
  td
>
tr>

Big Problem: And this doesn't just render, it gives an Html parse error:

<tr>
  <td
>
    <asp:Label id="Label1" runat="server" Height='<%="30px"%>'>Labelasp:Label
>
  td
>
tr>

The principles we see here are:

  1. Try to avoid combining embedded script and runat=server controls for the same object.
  2. While you may be able to get away with embedded script within the innerHtml of a runat=server HtmlControl, you:
    1. May run into difficulty putting it in the innerHtml of a WebControl (such as the Text of a Label).
    2. Should never put it in the attribute of the control itself. If you do need to put it in the attribute, then don't make the control runat=server.

 

Sunday, July 17, 2005

Tips to avoid breaking the build

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/tips_to_avoid_breaking_the_build.htm]

As automated builds become more popular, one of the main principles is to avoid breaking that build. The basic idea is that your team has an official server that regularly gets all the source code from source control and recompiles the entire project. If you check in source code that causes the build to not compile on this server, then you broke the build. We assume that the relevant environment (programs, external DLLs, version of .Net) on your machine is the same as the build server, as these change infrequently. Of course this dedicated server can do more than just compile the code, such as run automated unit tests. Check out NAnt for links on this.

Nobody wants to be the person who breaks the build. Here are some tips that I've learned (the hard way). The main concept is that before you check in changes, you want to compile the code on your machine, and if your code matches the code on the server, then it should compile on the server too. Build problems often result with your dev machine being out of sync with the build server.

  1. Work in small increments because there is less that can go wrong. Someone once said "Integration is a pay me now or pay me later" (I think it was Fowler). It's easier to integrate 5 small things than 1 big thing. Therefore if you're given an extensive 2-week task, see if you can break it into daily increments, where each check-in is still functional. XP talks about this more.
    1. For new classes that are in progress, you can check in just the class to "shelf it". As long as you don't check in the project, the build server won't try to compile it. For example, say you're spending 1 week on a new WebForm. You could check in your progress at the end of each day without fear of breaking the build because that file isn't included in the build.
  2. Use a source control that allows multiple people to check out the same file. This is why I no longer want to use Microsoft's VSS for enterprise apps, which has such a file-lock model. CVS or Subverion do not. Certain common files, like the *.proj file are constantly being updated as new pages are added to the project, and it's just a constant thorn for a 10 person team to let only 1 person check this out at once.
    1. NOTE: If you do need to use a file-lock source control system, them minimize the time you have such global files checked out. For example, you may add all the new files you need, and then check back in the *.proj file before implementing those classes. This will (1) Not break the build because you haven't implemented anything, (2) Give you the files you need to finish your task, and (3) not have that global file checked out.
  3. Before checking into the repository, update your local source to the latest from source control. This helps prevent some other dependency that changed from breaking the build. Even if your code compiled before, this helps ensure that someone else didn't change something such that the official build gets broken when you check in.
  4. For complex changes, check in everything at once. Partial check-ins are a common cause of broken builds. For example, say you add a class to the project, but only check in the project file. The code on the build server now has the updated project file, but not the class it was expecting, and the build will break.

Another technique, one I've only heard of but never implemented myself, is to have a queue. I think some groups at Microsoft do this. The idea is that instead of checking your code directly into the official build, it is checked into a queue instead. Then a process on the build server takes each fileset, one at a time, and integrates it into a temp build. If and only if that passes, then it adds the fileset to the official build and removes it from the queue.

[Update]: If the build is broken, try to avoid checking in source code. This will (1) make it easier to fix the build because it's not changing, (2) limit your association with the broken build.

Wednesday, July 13, 2005

Visual Studio Design Mode Changing your Html

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/visual_studio_design_mode_changing_your_html.htm]

Occasionally Visual Studio (2003) changes the Html when you go to design mode. While it reformats it, it may also add certain closing tags. This can be counter-productive if you're doing certain techniques where you want the Html to be the way you initially made it. I've heard rumors that 2005 guarantees that your Html won't get altered.

I see this Html changing in two categories:

  1. Ways you can solve it by adding extra html, such as multiple nested tables
  2. Ways that Visual Studio is just wrong

The problem with the first is that any extra html you add must be transported over the wire and rendered on the client, so it slows performance. The only helpful technique I know to avoid needing that extra overhead is to make Visual Studio open in Html view by default.  Goto: Tools > Options > Html Designer > General, and set the options to open in Html instead of Design view. Ideally your UI is refactored enough (with user controls, base pages, custom controls, possibly #includes, etc...) that the Html can be managed in Html view. I can then save my page, "peek" in design view to check the overall layout, disregarding any potential changes from Visual Studio.

In the second category, one (seemingly) blatant bug I came across in Visual Studio was when I had a custom control with custom attributes, and the attribute didn't have a value (kind of like "nowrap" - it only needs the attribute, not any associated value). Something like:

...

kept getting maligned to something like below when I went to design view. The attribute values got disjointed from the attributes:

...

However if I put the value-less attribute at the end, then I could toggle back and forth between Html and Design view:

...

I'm not sure what causes this - it could be something with the custom control, value-less attribute, affect from other attributes, or something else, but it solved that particular problem.

Sunday, July 10, 2005

System.Web.HttpException: External component has thrown an exception

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/systemwebhttpexception_external_component_has_thrown_an_exce.htm]

As far as debugging difficulty goes, anything that you can reproduce and step through with the debugger is likely simple. Sometimes you'll get an error that occurs before the codebehind is even hit, and you therefore can't debug it like "normal". One such error is: "System.Web.HttpException: External component has thrown an exception."

Web pages integrate both the aspx and codebehind pages. What may be happening is that some control in the html of the aspx page has an onserver attribute that references a non-existent server event. For example, you may have copied from a similar page that had a LinkButton with attribute onserverclick="AddLink_Click". The WebForm expects an "AddLink_Click" method in the codebehind. The original page may have had this method, but perhaps the target page does not. Therefore when you try to load the page, it can't "merge" the aspx and codebehind correctly and therefore crashes before even going to a breakpoint in the CodeBehind's Page_Load.

The solution (in this case) is to ensure that any attributes set in the aspx page are consistent with the codebehind.