Two issues I had to fight with today which took longer to solve than I originally thought.

First I looked into a problem I had since the last new version of my travelog website. When I add a new entry for the day, the date and time is send along with the other data to the server with an http post. But every time I save a entry the time is reduced by 7 hours. So after a few edits even the day itself is wrong.
I can explain the 7 hours, that the time difference between where I am (Peru) and the server (Germany), but where does it come from?

I looked at the database server and it has the time as specified in the web form. So the issue is getting the data back from the server. I checked my JavaScript which pulls the data via AJAX from the server and puts it onto the form, that looked fine too. Then I used Firebug to look at the JSON data that comes from the web server. The time there is seven hours less than whats in the database! I use ASP.NET web methods to return an object serialized as JSON.

The JSON serializer figures out, the client is 7 hours behind the server and takes those seven hours off each DateTime value. How does the server even know about those seven hours. I first thought about the http request headers but there is no time zone information in there. Well I still don´t know how it knows.

To fix the problem I send the timezoneOffset in the browser available through the JavaScript getTimezoneOffset() method when making a request. On the server I find out the time zone offset of the server and then fix all DateTime fields before sending them down. Not nice but it works.

  // get a local time zone info
  TimeZoneInfo tz = TimeZoneInfo.Local;

  // get it in hours
  int offset = tz.BaseUtcOffset.Hours;

  // add one hour if we are in daylight savings
  if (tz.IsDaylightSavingTime(DateTime.Now))
  {
      offset++;
  }

The second problem I had was with a very simple site, I added an aspx page to download zip files from the site and log the downloads. It worked fine locally but on the live server the line:

if (System.IO.File.Exists(fileName)
which makes sure the file exists before it is trying to send it returned false. I triple checked that the file was there and it was. I checked NTFS permissions and IIS settings, all fine. I could download the file directly via http from the same location. I ran ProcessMonitor on the server and the web process didn't even try to open the file. What is going on here?

I finally removed the line above and let the Response.TransmitFile method throw the error, now it told me what was going on. I had set the site to Medium Trust because it only performed very basic operations. In Medium Trust your application is not allowed to access the file system.

So in this case System.IO.File.Exists returns a false, but shouldn´t it really throw an exception? I am not sure, but it made it harder to debug.
 
Categories: ASP.Net

October 9, 2009
@ 02:52 AM

When travelling around the world I plug in my USB devices in countless public computers.

Many viruses use the autorun.inf file to spread themselves around. When plugging in a USB device into an infected computer the virus copies itself into a hidden location, often the Recycler directory and adds a autorun.inf file in the root of the device to automatically start itself on the next computer.

An easy way to notice whether you may have a virus on your device is to create your own autorun.inf and assign an icon to the device.

Create a text file with the name autorun.inf and place it into the root of your device. The content should look like this:

[autorun]
icon=panama.ico

Now place the icon file "panama.ico" into the root of the device as well. The next time you plug in your device the Windows dialog will look like this:

Windows New Device dialog

Notice the icon in the top left corner. If you do not see your icon, you know something has overwritten your autorun.inf, most likely a virus.

What to do in this case? Check my post Manually finding and removing malware

I prepared some icon files in case you do not have any:

icons

icons.zip (27.17 KB)
 
Categories: Work on the road

On TweeNet to access a band page, the old url is


www.twee.net/bands/band.asp?key=smiths

You have to know the internal name of the band as well.

Now you can get to the same page using

www.twee.net/band/The Smiths

The site runs under ASP.Net 3.5 SP1 on IIS6, so I have all the routing goodness of that ASP.Net version.
To get this working, I first had to add the routing assemblies and modules to my web.config

<assemblies>
        <add assembly="System.Web.Abstractions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</assemblies>
      
<httpmodules>
      <add type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, 
             Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" name="UrlRoutingModule" />
</httpmodules>


These are additions to the already existing assemblies and modules which are not listed here.

Next I implemented a routing handler:

using System;
using System.Web;
using System.Web.Compilation;
using System.Web.Routing;
using System.Web.UI;

namespace TweeNet.PublicSite.RouteHandlers
{
    public class BandRouteHandler : IRouteHandler
    {
        public BandRouteHandler(string virtualPath)
        {
            this.VirtualPath = virtualPath;
        }

        public string VirtualPath { get; private set; }

        public IHttpHandler GetHttpHandler(RequestContext
              requestContext)
        {

            foreach (var urlParm in requestContext.RouteData.Values)
            {
                requestContext.HttpContext.Items[urlParm.Key] = urlParm.Value;
            }

            var page = BuildManager.CreateInstanceFromVirtualPath
                 (VirtualPath, typeof(Page)) as IHttpHandler;
            return page;
        }
    }
}

then in Global.asax I added the route:
    protected void Application_Start(Object sender, EventArgs e)
    {
            RegisterRoutes(RouteTable.Routes);
    }
    
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.Add(new System.Web.Routing.Route
        (
             "band/{bandname}"
             , new TweeNet.PublicSite.RouteHandlers.BandRouteHandler("~/bands/band.aspx")
        ));
    }

In the code behind of the band.aspx page I added some code:
    if (HttpContext.Current.Items["bandname"] != null)
    {
        string userTerm = HttpContext.Current.Items["bandname"].ToString();

        // now use that term to find the band data in the database and display the page content
    }


The last problem was that IIS6 doesn't pass something like "The Smiths" to the ASP.net pipeline. Steve Sanderson's blog post describes some options how to deal with this 

But in my situation the best option was the following:
As a /band directory did not existed yet, I created that empty folder in the filesystem.

Then in IIS I selected it and created an application for it. I now added a wildcard application mapping to the asp.net runtime. So all requests under /band/ will go to asp.net.

All the other static files on the site are not affected. I then removed the application from '/band/'. IIS still keeps the wildcard mapping even if the folder is no longer an application and you can not see that mapping in the IIS Manager GUI.


 
Categories: ASP.Net