Telerik CSS issues with Windows Azure

There appears to be an issue with the Windows Azure system where the AssemblyResourceLocator does not work correctly when the compiled assemblies of a site is uploaded to Azure from a timezone ahead of the Azure servers timezones. You can read about this issue at http://social.msdn.microsoft.com/Forums/en/windowsazure/thread/751e27a9-4108-4446-9870-411f409d2c08?prof=required&lc=1033

This issue presented itself in my application by failing to load any CSS for any of the Telerik controls I was using. Telerik loads it’s CSS using WebResource.axd. As I’m in Australia and the servers I uploading to are behind the Australian timezones, the call to the WebResource.axd would return a 404 error. Once the time on the server caught up to the compile time of my site assembly files, the CSS would start displaying.

I found 2 workarounds before finding a permanent solution.

Workaround 1: Change my PC’s timezone to Samoa (this first timezone in the list) and deploying my application. Obviously not ideal.

Workaround 2: Deploy the site to Staging and wait until several hours past and the site started working, then Swap VIP to Production. Also no ideal.

The Solution

The solution I found to resolve the issue involved using the touch.exe app found at http://www.touchdotexe.com/ to touch the assembly dll file to update it to the current time on the server after the app had been deployed.

To do this I added the touch.exe file and a setup.cmd file to the root of my app, set the build action on the 2 files to Content and the Copy to Output Directory to Copy always.

image

image

I then added a startup task to the Azure Project’s ServiceDefinition.csdef file to execute the setup.cmd file at role startup.

<Startup priority="1">
      <Task commandLine="setup.cmd" executionContext="elevated" taskType="simple" />
    </Startup>

The setup.cmd file just has one line of code

touch.exe mywebapp.dll

As both of these files are copied to the bin folder, there’s no need to specify a full path the assembly file.

Textboxes Timers and Updatepanels

In a project I’m working on, I had to create a Facebook style notification system. I wanted the user to be able to enter a status and click the add button and have the list of notifications below it update with their most recent post. That is simple enough to do, all I had to do was to add the notification, clear the textbox then call the updateNotifications function in my button_click code behind method. This all had to be very smooth to the eye so i added the usual updatepanel around the textbox, button and div that listed the notifications.

As well as that, I also wanted the notifications system to automatically update with other users notifications within the same group. So I added a Time control to the mix and set it to refresh the notifications list every 10 seconds.

This seemed to work well until I was half way through typing a new notification when the timer triggered and refreshed the notification list. As the textbox was inside the updatepanel it stopped letting me type any text while it refreshed.

So then I thought that I’d move the textbox outside the updatepanel so it wasn’t impacted when the timer refreshed the list.

The only problem now is that because the submit button to add a new notification was inside the updatepanel and the textbox was outside the updatepanel the textbox could no longer be cleared on the partial postback. My txtNotification.Text = String.Empty; was being ignored.

I can’t quite remember the next thing I tried but it obviously didn’t work because now the whole page was refreshing everytime the timer triggered.

In the end I remembered about the UpdateMode property on the update panel. I set the updatemode to conditional around my textbox/button updatepanel and always on the notification list/timer updatepanel. That way the timer triggers updated the notification list without upsetting the textbox and submitting the add button updated the list and cleared the textbox. Perfect result.

ASPX code:

<asp:UpdatePanel ID="updStatusUpdate" runat="server" UpdateMode="Conditional">
    <ContentTemplate>        
        <asp:TextBox ID="txtStatusUpdate" runat="server" TextMode="MultiLine" Rows="2" Width="570"></asp:TextBox> <br />        

        <asp:Button ID="btnAddStatusUpdate" runat="server" Text="Update Status" 
            onclick="btnAddStatusUpdate_Click" class="ui-state-default ui-corner-all"/>

    </ContentTemplate>
</asp:UpdatePanel> 

<asp:UpdatePanel ID="updNotifications" runat="server" UpdateMode="Always">
    <ContentTemplate>        
        <div class="NotificationList">
            <asp:Literal ID="litNotifications" runat="server"></asp:Literal>
        </div>
        <asp:Timer ID="Timer1" runat="server" ontick="Timer1_Tick" Interval="10000"></asp:Timer>
    </ContentTemplate>
</asp:UpdatePanel>    

A function to convert a TimeSpan to an x minutes ago string

An application I’m working on requires a facebook style status system and I thought it would be good to include the “posted x minutes ago” text after the status.

I’m sure my code is not the most elegant solution but it works so I thought I’d share.

public static String LastUpdatedText(DateTime DateNow, DateTime LastUpdated)
        {
            TimeSpan timeDiff = DateNow.Subtract(LastUpdated);

            if (timeDiff.TotalHours < 1)
            {
                return Math.Round(timeDiff.TotalMinutes,0) + " minutes ago";
            }

            if (timeDiff.TotalHours < 24)
            {
                return Math.Round(timeDiff.TotalHours, 0) + " hours ago";
            }

            if (timeDiff.TotalHours < 48)
            {
                return "yesterday";
            }

            if (timeDiff.TotalHours < 168)
            {
                return Math.Round(timeDiff.TotalDays,0) + " days ago";
            }

            if (timeDiff.TotalDays < 42)
            {
                return Math.Round((timeDiff.TotalDays / 7),0) + " weeks ago";
            }

            if (timeDiff.TotalDays < 365)
            {
                return Math.Round((timeDiff.TotalDays / 30),0) + " months ago";
            }

            return Math.Round((timeDiff.TotalDays / 365),0) + " years ago";
        }