<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>Tim Mackey's Weblog</title>
    <link>http://tim.mackey.ie/</link>
    <description>mostly.Net</description>
    <language>en-ie</language>
    <copyright>Tim Mackey</copyright>
    <lastBuildDate>Sat, 19 Sep 2009 14:49:34 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.3.9074.18820</generator>
    <managingEditor>tim@mackey.ie</managingEditor>
    <webMaster>tim@mackey.ie</webMaster>
    <item>
      <trackback:ping>http://tim.mackey.ie/Trackback.aspx?guid=0c4c5e87-645a-4f02-a4f2-a24598ac8728</trackback:ping>
      <pingback:server>http://tim.mackey.ie/pingback.aspx</pingback:server>
      <pingback:target>http://tim.mackey.ie/PermaLink,guid,0c4c5e87-645a-4f02-a4f2-a24598ac8728.aspx</pingback:target>
      <dc:creator>Tim Mackey</dc:creator>
      <wfw:comment>http://tim.mackey.ie/CommentView,guid,0c4c5e87-645a-4f02-a4f2-a24598ac8728.aspx</wfw:comment>
      <wfw:commentRss>http://tim.mackey.ie/SyndicationService.asmx/GetEntryCommentsRss?guid=0c4c5e87-645a-4f02-a4f2-a24598ac8728</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <img src="http://tim.mackey.ie/dev/grasmere_camp.jpg" />
        <br />
Just back from a two week trip in the Lake District in England, what a discovery. 
this photo was taken at sunrise at 500m on the last day.  unfortunately the first
10 days were mostly torrential rain, but it was worth it in the end. i want to go
back next year.  i posted some photos and comments on the <a href="http://wainwright.proboards.com/index.cgi?board=general&amp;action=display&amp;thread=5081">wainwright
society forum</a> where i got some good advice before going.<br /><p></p><img width="0" height="0" src="http://tim.mackey.ie/aggbug.ashx?id=0c4c5e87-645a-4f02-a4f2-a24598ac8728" /></body>
      <title>Hillwalking in the Lakeland Fells</title>
      <guid isPermaLink="false">http://tim.mackey.ie/PermaLink,guid,0c4c5e87-645a-4f02-a4f2-a24598ac8728.aspx</guid>
      <link>http://tim.mackey.ie/HillwalkingInTheLakelandFells.aspx</link>
      <pubDate>Sat, 19 Sep 2009 14:49:34 GMT</pubDate>
      <description>&lt;img src="http://tim.mackey.ie/dev/grasmere_camp.jpg"&gt;
&lt;br&gt;
Just back from a two week trip in the Lake District in England, what a discovery.&amp;nbsp;
this photo was taken at sunrise at 500m on the last day.&amp;nbsp; unfortunately the first
10 days were mostly torrential rain, but it was worth it in the end. i want to go
back next year.&amp;nbsp; i posted some photos and comments on the &lt;a href="http://wainwright.proboards.com/index.cgi?board=general&amp;amp;action=display&amp;amp;thread=5081"&gt;wainwright
society forum&lt;/a&gt; where i got some good advice before going.&lt;br&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://tim.mackey.ie/aggbug.ashx?id=0c4c5e87-645a-4f02-a4f2-a24598ac8728" /&gt;</description>
      <comments>http://tim.mackey.ie/CommentView,guid,0c4c5e87-645a-4f02-a4f2-a24598ac8728.aspx</comments>
      <category>Outdoors</category>
    </item>
    <item>
      <trackback:ping>http://tim.mackey.ie/Trackback.aspx?guid=c947af7f-9cb4-4018-a856-c92855b04738</trackback:ping>
      <pingback:server>http://tim.mackey.ie/pingback.aspx</pingback:server>
      <pingback:target>http://tim.mackey.ie/PermaLink,guid,c947af7f-9cb4-4018-a856-c92855b04738.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://tim.mackey.ie/CommentView,guid,c947af7f-9cb4-4018-a856-c92855b04738.aspx</wfw:comment>
      <wfw:commentRss>http://tim.mackey.ie/SyndicationService.asmx/GetEntryCommentsRss?guid=c947af7f-9cb4-4018-a856-c92855b04738</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">I got a request from a client for a 'mini'
navigation menu to appear on a page to allow the user to 'jump' to the various sections
of the page.  Maintaining a set of named anchor hyperlinks in a document (with
a javascript-based select menu) is not really an option for someone who doesn't know
HTML, which is most people who use content management.  In the wrong hands this
creates more trouble than it's worth.  
<br />
so i started thinking. the documents in question are well structured, using paragraphs
and headings, as enforced by the content management system.  i worked out this
solution which is exactly what i need, a maintenance free javascript jump menu, that
doesn't add clutter to the document with named anchors.  it assumes that the
all H2 tags should be displayed as links in the menu.  the javascript iterates
through the H2 tags and loads up the menu, with a ScrollTo function used when an item
is selected.<br /><br />
here's a <a href="/content/binary/jumpmenu.png">screenshot<br /><img style="border: 1px solid rgb(0, 0, 0);" src="http://tim.mackey.ie/content/binary/jumpmenu.png" border="1" width="420" height="257" /></a><br /><br />
The code for the HTML page:<br /><pre>&lt;script src="/JumpMenu.js" type="text/javascript"&gt;&lt;/script&gt;<br />
&lt;select id="jumpNavSelect" name="jumpNavSelect" onchange="JumpToHeading(this.selectedIndex)"&gt;<br />
&lt;option value=""&gt;On this page...&lt;/option&gt;<br />
&lt;/select&gt;<br /></pre>and the JumpMenu.js file<br /><pre>var array;<br /><br />
function CreateAnchorMenu() {<br />
array = document.getElementsByTagName("h2"); 
<br />
var src = document.getElementById('jumpNavSelect');<br />
// iterate through all H2 headings, add dropdown items for each. 
<br />
for (var i = 0; i &lt; array.length; i++) {<br />
var heading = array[i];<br />
var text = heading.firstChild.nodeValue;<br />
if (!text)<br />
continue;<br />
src[i+1] = new Option(text, i);<br />
}<br />
}<br /><br />
function JumpToHeading(HeadingIndex) {<br />
if (HeadingIndex == 0)<br />
return;<br />
var heading = array[HeadingIndex-1];<br />
ScrollToElement(heading);<br />
}<br /><br />
function ScrollToElement(theElement) {<br />
var selectedPosX = 0;<br />
var selectedPosY = 0;<br />
while (theElement != null) {<br />
selectedPosX += theElement.offsetLeft;<br />
selectedPosY += theElement.offsetTop;<br />
theElement = theElement.offsetParent;<br />
}<br />
window.scrollTo(selectedPosX, selectedPosY);<br />
}<br /><br />
window.onload = CreateAnchorMenu;<br /></pre><img width="0" height="0" src="http://tim.mackey.ie/aggbug.ashx?id=c947af7f-9cb4-4018-a856-c92855b04738" /></body>
      <title>Javascript dynamic anchor select menu</title>
      <guid isPermaLink="false">http://tim.mackey.ie/PermaLink,guid,c947af7f-9cb4-4018-a856-c92855b04738.aspx</guid>
      <link>http://tim.mackey.ie/JavascriptDynamicAnchorSelectMenu.aspx</link>
      <pubDate>Tue, 21 Apr 2009 12:30:58 GMT</pubDate>
      <description>I got a request from a client for a 'mini' navigation menu to appear on
a page to allow the user to 'jump' to the various sections of the
page.&amp;nbsp; Maintaining a set of named anchor hyperlinks in a document (with
a javascript-based select menu) is not really an option for someone who
doesn't know HTML, which is most people who use content management.&amp;nbsp; In
the wrong hands this creates more trouble than it's worth.&amp;nbsp; &lt;br&gt;
so i started thinking. the documents in question are well structured, using paragraphs
and headings, as enforced by the content management system.&amp;nbsp; i worked out this
solution which is exactly what i need, a maintenance free javascript jump menu, that
doesn't add clutter to the document with named anchors.&amp;nbsp; it assumes that the
all H2 tags should be displayed as links in the menu.&amp;nbsp; the javascript iterates
through the H2 tags and loads up the menu, with a ScrollTo function used when an item
is selected.&lt;br&gt;
&lt;br&gt;
here's a &lt;a href="/content/binary/jumpmenu.png"&gt;screenshot&lt;br&gt;
&lt;img style="border: 1px solid rgb(0, 0, 0);" src="http://tim.mackey.ie/content/binary/jumpmenu.png" border="1" width="420" height="257"&gt;&lt;/a&gt;
&lt;br&gt;
&lt;br&gt;
The code for the HTML page:&lt;br&gt;
&lt;pre&gt;&amp;lt;script src="/JumpMenu.js" type="text/javascript"&amp;gt;&amp;lt;/script&amp;gt;&lt;br&gt;
&amp;lt;select id="jumpNavSelect" name="jumpNavSelect" onchange="JumpToHeading(this.selectedIndex)"&amp;gt;&lt;br&gt;
&amp;lt;option value=""&amp;gt;On this page...&amp;lt;/option&amp;gt;&lt;br&gt;
&amp;lt;/select&amp;gt;&lt;br&gt;
&lt;/pre&gt;and the JumpMenu.js file&lt;br&gt;
&lt;pre&gt;var array;&lt;br&gt;
&lt;br&gt;
function CreateAnchorMenu() {&lt;br&gt;
array = document.getElementsByTagName("h2"); 
&lt;br&gt;
var src = document.getElementById('jumpNavSelect');&lt;br&gt;
// iterate through all H2 headings, add dropdown items for each. 
&lt;br&gt;
for (var i = 0; i &amp;lt; array.length; i++) {&lt;br&gt;
var heading = array[i];&lt;br&gt;
var text = heading.firstChild.nodeValue;&lt;br&gt;
if (!text)&lt;br&gt;
continue;&lt;br&gt;
src[i+1] = new Option(text, i);&lt;br&gt;
}&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
function JumpToHeading(HeadingIndex) {&lt;br&gt;
if (HeadingIndex == 0)&lt;br&gt;
return;&lt;br&gt;
var heading = array[HeadingIndex-1];&lt;br&gt;
ScrollToElement(heading);&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
function ScrollToElement(theElement) {&lt;br&gt;
var selectedPosX = 0;&lt;br&gt;
var selectedPosY = 0;&lt;br&gt;
while (theElement != null) {&lt;br&gt;
selectedPosX += theElement.offsetLeft;&lt;br&gt;
selectedPosY += theElement.offsetTop;&lt;br&gt;
theElement = theElement.offsetParent;&lt;br&gt;
}&lt;br&gt;
window.scrollTo(selectedPosX, selectedPosY);&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
window.onload = CreateAnchorMenu;&lt;br&gt;
&lt;/pre&gt;&lt;img width="0" height="0" src="http://tim.mackey.ie/aggbug.ashx?id=c947af7f-9cb4-4018-a856-c92855b04738" /&gt;</description>
      <comments>http://tim.mackey.ie/CommentView,guid,c947af7f-9cb4-4018-a856-c92855b04738.aspx</comments>
      <category>.Net General</category>
      <category>Asp.Net</category>
    </item>
    <item>
      <trackback:ping>http://tim.mackey.ie/Trackback.aspx?guid=943b3c7e-bf3e-4047-a672-e0d2eac43c31</trackback:ping>
      <pingback:server>http://tim.mackey.ie/pingback.aspx</pingback:server>
      <pingback:target>http://tim.mackey.ie/PermaLink,guid,943b3c7e-bf3e-4047-a672-e0d2eac43c31.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://tim.mackey.ie/CommentView,guid,943b3c7e-bf3e-4047-a672-e0d2eac43c31.aspx</wfw:comment>
      <wfw:commentRss>http://tim.mackey.ie/SyndicationService.asmx/GetEntryCommentsRss?guid=943b3c7e-bf3e-4047-a672-e0d2eac43c31</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">if your application has users who like
to log in as "JOE BLOGGS" or "joe bloggs" when their username is actually "Joe Bloggs",
you might want to ensure that they login with the correct "case" of their username. 
It can cause discrepancies if you refer to the current Identity.User in your web application,
for example if you use the username anywhere in your database and run reports grouped
on the username, you will get multiple records for each variation on the case of the
username.  It is surprisingly unintuitive to solve this problem.  Firstly
you would think that Asp.Net membership would take care of this itself.  Then
you would think that you could determine the correct case of the username as follows:<br /><pre>protected void Login1_LoggedIn(object sender, EventArgs e)<br />
{<br />
string correctUsername = Membership.GetUser(this.Login1.Username).Username;<br />
FormsAuthentication.SetAuthCookie(correctUsername , true);<br />
}<br /></pre><p>
but this doesn't work because the "Username" property of the MembershipUser object
does not collect its value from the AspNetDB SQL database like you would expect, instead
it is filled with whatever you pass it when loading the user, this must be a bug but
i'm not bothered trying to convince MS.  instead, i came up with this solution
below, to directly load the AspNetUser object from a Linq DataSource of the AspNetDb
database (created using SqlMetal).<br /></p><pre>protected void Login1_LoggedIn(object sender, EventArgs e)<br />
{<br />
// correct the case of the username<br />
string Username = this.Login1.UserName;<br />
AspNetDb db = new AspNetDb();<br />
MembershipUser memUser = Membership.GetUser(Username); // load the MembershipUser
object to get the UserID<br />
Aspnet_User aspnetUser = db.Aspnet_Users.SingleOrDefault(z =&gt; z.UserId == new Guid(memUser.ProviderUserKey.ToString()));<br />
if(aspnetUser != null)<br />
Username = aspnetUser.UserName;<br />
FormsAuthentication.SetAuthCookie(Username, true);<br />
}<br /></pre><p></p><img width="0" height="0" src="http://tim.mackey.ie/aggbug.ashx?id=943b3c7e-bf3e-4047-a672-e0d2eac43c31" /></body>
      <title>Asp.Net membership, correcting username case at login</title>
      <guid isPermaLink="false">http://tim.mackey.ie/PermaLink,guid,943b3c7e-bf3e-4047-a672-e0d2eac43c31.aspx</guid>
      <link>http://tim.mackey.ie/AspNetMembershipCorrectingUsernameCaseAtLogin.aspx</link>
      <pubDate>Tue, 24 Mar 2009 16:38:48 GMT</pubDate>
      <description>if your application has users who like to log in as "JOE BLOGGS" or "joe bloggs" when their username is actually "Joe Bloggs", you might want to ensure that they login with the correct "case" of their username.&amp;nbsp; It can cause discrepancies if you refer to the current Identity.User in your web application, for example if you use the username anywhere in your database and run reports grouped on the username, you will get multiple records for each variation on the case of the username.&amp;nbsp; It is surprisingly unintuitive to solve this problem.&amp;nbsp; Firstly you would think that Asp.Net membership would take care of this itself.&amp;nbsp; Then you would think that you could determine the correct case of the username as follows:&lt;br&gt;
&lt;pre&gt;protected void Login1_LoggedIn(object sender, EventArgs e)&lt;br&gt;
{&lt;br&gt;
string correctUsername = Membership.GetUser(this.Login1.Username).Username;&lt;br&gt;
FormsAuthentication.SetAuthCookie(correctUsername , true);&lt;br&gt;
}&lt;br&gt;
&lt;/pre&gt;
&lt;p&gt;
but this doesn't work because the "Username" property of the MembershipUser object
does not collect its value from the AspNetDB SQL database like you would expect, instead
it is filled with whatever you pass it when loading the user, this must be a bug but
i'm not bothered trying to convince MS.&amp;nbsp; instead, i came up with this solution
below, to directly load the AspNetUser object from a Linq DataSource of the AspNetDb
database (created using SqlMetal).&lt;br&gt;
&lt;/p&gt;
&lt;pre&gt;protected void Login1_LoggedIn(object sender, EventArgs e)&lt;br&gt;
{&lt;br&gt;
// correct the case of the username&lt;br&gt;
string Username = this.Login1.UserName;&lt;br&gt;
AspNetDb db = new AspNetDb();&lt;br&gt;
MembershipUser memUser = Membership.GetUser(Username); // load the MembershipUser
object to get the UserID&lt;br&gt;
Aspnet_User aspnetUser = db.Aspnet_Users.SingleOrDefault(z =&amp;gt; z.UserId == new Guid(memUser.ProviderUserKey.ToString()));&lt;br&gt;
if(aspnetUser != null)&lt;br&gt;
Username = aspnetUser.UserName;&lt;br&gt;
FormsAuthentication.SetAuthCookie(Username, true);&lt;br&gt;
}&lt;br&gt;
&lt;/pre&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://tim.mackey.ie/aggbug.ashx?id=943b3c7e-bf3e-4047-a672-e0d2eac43c31" /&gt;</description>
      <comments>http://tim.mackey.ie/CommentView,guid,943b3c7e-bf3e-4047-a672-e0d2eac43c31.aspx</comments>
      <category>Asp.Net</category>
    </item>
    <item>
      <trackback:ping>http://tim.mackey.ie/Trackback.aspx?guid=1f65c32e-7a99-4fe1-b58c-92c8241bcc13</trackback:ping>
      <pingback:server>http://tim.mackey.ie/pingback.aspx</pingback:server>
      <pingback:target>http://tim.mackey.ie/PermaLink,guid,1f65c32e-7a99-4fe1-b58c-92c8241bcc13.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://tim.mackey.ie/CommentView,guid,1f65c32e-7a99-4fe1-b58c-92c8241bcc13.aspx</wfw:comment>
      <wfw:commentRss>http://tim.mackey.ie/SyndicationService.asmx/GetEntryCommentsRss?guid=1f65c32e-7a99-4fe1-b58c-92c8241bcc13</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <pre>Cstr(CDate({Table.Column}), "dd/MM/yyyy")</pre>
        <p>
        </p>
        <img width="0" height="0" src="http://tim.mackey.ie/aggbug.ashx?id=1f65c32e-7a99-4fe1-b58c-92c8241bcc13" />
      </body>
      <title>Crystal Reports date format (in code)</title>
      <guid isPermaLink="false">http://tim.mackey.ie/PermaLink,guid,1f65c32e-7a99-4fe1-b58c-92c8241bcc13.aspx</guid>
      <link>http://tim.mackey.ie/CrystalReportsDateFormatInCode.aspx</link>
      <pubDate>Fri, 27 Feb 2009 17:47:52 GMT</pubDate>
      <description>&lt;pre&gt;Cstr(CDate({Table.Column}), "dd/MM/yyyy")&lt;/pre&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://tim.mackey.ie/aggbug.ashx?id=1f65c32e-7a99-4fe1-b58c-92c8241bcc13" /&gt;</description>
      <comments>http://tim.mackey.ie/CommentView,guid,1f65c32e-7a99-4fe1-b58c-92c8241bcc13.aspx</comments>
      <category>.Net General</category>
      <category>Asp.Net</category>
    </item>
    <item>
      <trackback:ping>http://tim.mackey.ie/Trackback.aspx?guid=779ba072-7636-496e-a71c-0f09ea71f16e</trackback:ping>
      <pingback:server>http://tim.mackey.ie/pingback.aspx</pingback:server>
      <pingback:target>http://tim.mackey.ie/PermaLink,guid,779ba072-7636-496e-a71c-0f09ea71f16e.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://tim.mackey.ie/CommentView,guid,779ba072-7636-496e-a71c-0f09ea71f16e.aspx</wfw:comment>
      <wfw:commentRss>http://tim.mackey.ie/SyndicationService.asmx/GetEntryCommentsRss?guid=779ba072-7636-496e-a71c-0f09ea71f16e</wfw:commentRss>
      <slash:comments>5</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">today i came across a situation where a
user was spending a long time filling out a form.  they went past the session
timeout and when they hit save they got booted back to the login screen, having lost
the previous 30 minutes of work.  i looked around the net and found a few options
with AJAX and what not but it doesn't make sense to keep renewing the session automatically
otherwise you might as well not have a timeout, which is there for security reasons
anyway.  in my case i don't actually want to save the information to the database
(it's a transaction) until the user hits the Save button, i just want to keep the
session alive.  
<br /><br />
so i came up with this idea to ask the user if they want to keep their session alive
with a javascript prompt every 15 minutes. if they leave their computer and don't
answer the prompt, the session will time out since they won't have interacted with
the web site (regardless of how they answer the prompt after the timeout).  if
they answer OK to the prompt it invokes a Ping() type web service to keep the session
alive.  this is the most lightweight way i could think of doing it.  i don't
want to post back to the page because that will interrupt the user and make them wait
for the page to reload. 
<br /><br />
there are 3 parts:<br /><h3>"KeepAlive" function<br /></h3><p>
I put this function in a 'Util' class so pages can easily turn on the 'Keep Alive'
functionality, simply call <font face="Courier New">Util.KeepAlive(this);</font></p><pre>public static void KeepAlive(Page p)<br />
{<br />
p.ClientScript.RegisterClientScriptInclude("KeepAlive", "/KeepAlive.js");<br />
}</pre><h3>Ping.asmx (add the web service to your root folder)<br /></h3><pre>[WebMethod]<br />
public void Ping()<br />
{<br />
HttpContext.Current.Response.Write("OK"); 
<br />
HttpContext.Current.Response.End(); // this makes the result easier to parse than
an XML web service message<br />
}</pre><h3>KeepAlive.js (put this file in your root folder)<br /></h3><pre>var timerID = 0;	     // used to track the timer function<br />
var interval = 1000*60*15; // 15 mins<br />
var KeepAliveUrl = '/Ping.asmx/Ping'; // replace your web service address here<br />
var xmlhttpKeepAlive;<br /><br />
function AutoSaveSubmit()<br />
{<br />
if(confirm('15 minutes of idle time has passed, do you want to keep your session active?'))<br />
InvokeWebService();<br />
}<br /><br />
function InvokeWebService() 
<br />
{ 
<br />
if (window.XMLHttpRequest)<br />
{<br />
xmlhttpKeepAlive=new XMLHttpRequest();<br />
xmlhttpKeepAlive.onreadystatechange = xmlhttpChangeKeepAlive;<br />
xmlhttpKeepAlive.open('GET',KeepAliveUrl + '?T=' + timerID,true);<br />
xmlhttpKeepAlive.send(null);<br />
}<br />
// code for IE<br />
else if (window.ActiveXObject)<br />
{<br />
xmlhttpKeepAlive=new ActiveXObject('Microsoft.XMLHTTP')<br />
if (xmlhttp)<br />
{<br />
xmlhttpKeepAlive.onreadystatechange = xmlhttpChangeKeepAlive;<br />
xmlhttpKeepAlive.open('GET', KeepAliveUrl + '?T=' + timerID, true);<br />
xmlhttpKeepAlive.send();<br />
}<br />
}<br />
return false;<br />
}<br /><br />
function xmlhttpChangeKeepAlive()<br />
{<br />
var text;<br />
if (xmlhttpKeepAlive.readyState == 4) 
<br />
{<br />
text = xmlhttpKeepAlive.responseText;<br />
if (xmlhttpKeepAlive.status==200) // OK<br />
{<br />
if(text == 'OK') // reset the timer 
<br />
timerID = setTimeout('AutoSaveSubmit()', interval); 
<br />
else<br />
alert('Your session has already expired.\nIf you have any information on this page
you will lose it if you try to save this page now. You have 2 options to avoid losing
the information on this screen.\n\nOption 1: open a new internet window and log in
again to the web site, then close that window and go back to this window, at which
point you will have a new session and you will be able to save the information.\n\nOption
2: Copy all the text you have typed on this page and paste it into another program
(such as Word or Notepad), then log in to the web site again (click the home page)
and come back to this page, and paste in the text again.\n\nTo prevent this happening
in the future, click OK on the 15 minute reminder box each time it appears, this will
keep your session active. If you do not answer the reminder within 10 minutes the
session may expire.');<br />
}<br />
else<br />
alert('Error: ' + xmlhttpKeepAlive.status + '. The session may have already expired,
please try to save the page now');<br />
}<br />
}<br />
window.setTimeout('AutoSaveSubmit()',interval); 
<br /></pre><p>
You might be wondering why i append the timer code/number to the url of the web service. 
The reason is because IE has a caching bug and will not actually send the XmlHttp
request unless the URL is different to what it has in its history, it will just return
the previous result. 
<br /></p><p></p><img width="0" height="0" src="http://tim.mackey.ie/aggbug.ashx?id=779ba072-7636-496e-a71c-0f09ea71f16e" /></body>
      <title>A simple Auto-Save / Keep Alive feature for Asp.Net</title>
      <guid isPermaLink="false">http://tim.mackey.ie/PermaLink,guid,779ba072-7636-496e-a71c-0f09ea71f16e.aspx</guid>
      <link>http://tim.mackey.ie/ASimpleAutoSaveKeepAliveFeatureForAspNet.aspx</link>
      <pubDate>Thu, 19 Feb 2009 16:18:50 GMT</pubDate>
      <description>today i came across a situation where a user was spending a long time filling out a form.&amp;nbsp; they went past the session timeout and when they hit save they got booted back to the login screen, having lost the previous 30 minutes of work.&amp;nbsp; i looked around the net and found a few options with AJAX and what not but it doesn't make sense to keep renewing the session automatically otherwise you might as well not have a timeout, which is there for security reasons anyway.&amp;nbsp; in my case i don't actually want to save the information to the database (it's a transaction) until the user hits the Save button, i just want to keep the session alive.&amp;nbsp; &lt;br&gt;
&lt;br&gt;
so i came up with this idea to ask the user if they want to keep their session alive
with a javascript prompt every 15 minutes. if they leave their computer and don't
answer the prompt, the session will time out since they won't have interacted with
the web site (regardless of how they answer the prompt after the timeout).&amp;nbsp; if
they answer OK to the prompt it invokes a Ping() type web service to keep the session
alive.&amp;nbsp; this is the most lightweight way i could think of doing it.&amp;nbsp; i don't
want to post back to the page because that will interrupt the user and make them wait
for the page to reload. 
&lt;br&gt;
&lt;br&gt;
there are 3 parts:&lt;br&gt;
&lt;h3&gt;"KeepAlive" function&lt;br&gt;
&lt;/h3&gt;
&lt;p&gt;
I put this function in a 'Util' class so pages can easily turn on the 'Keep Alive'
functionality, simply call &lt;font face="Courier New"&gt;Util.KeepAlive(this);&lt;/font&gt;
&lt;/p&gt;
&lt;pre&gt;public static void KeepAlive(Page p)&lt;br&gt;
{&lt;br&gt;
p.ClientScript.RegisterClientScriptInclude("KeepAlive", "/KeepAlive.js");&lt;br&gt;
}&lt;/pre&gt;
&lt;h3&gt;Ping.asmx (add the web service to your root folder)&lt;br&gt;
&lt;/h3&gt;
&lt;pre&gt;[WebMethod]&lt;br&gt;
public void Ping()&lt;br&gt;
{&lt;br&gt;
HttpContext.Current.Response.Write("OK"); 
&lt;br&gt;
HttpContext.Current.Response.End(); // this makes the result easier to parse than
an XML web service message&lt;br&gt;
}&lt;/pre&gt;
&lt;h3&gt;KeepAlive.js (put this file in your root folder)&lt;br&gt;
&lt;/h3&gt;
&lt;pre&gt;var timerID = 0;	     // used to track the timer function&lt;br&gt;
var interval = 1000*60*15; // 15 mins&lt;br&gt;
var KeepAliveUrl = '/Ping.asmx/Ping'; // replace your web service address here&lt;br&gt;
var xmlhttpKeepAlive;&lt;br&gt;
&lt;br&gt;
function AutoSaveSubmit()&lt;br&gt;
{&lt;br&gt;
if(confirm('15 minutes of idle time has passed, do you want to keep your session active?'))&lt;br&gt;
InvokeWebService();&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
function InvokeWebService() 
&lt;br&gt;
{ 
&lt;br&gt;
if (window.XMLHttpRequest)&lt;br&gt;
{&lt;br&gt;
xmlhttpKeepAlive=new XMLHttpRequest();&lt;br&gt;
xmlhttpKeepAlive.onreadystatechange = xmlhttpChangeKeepAlive;&lt;br&gt;
xmlhttpKeepAlive.open('GET',KeepAliveUrl + '?T=' + timerID,true);&lt;br&gt;
xmlhttpKeepAlive.send(null);&lt;br&gt;
}&lt;br&gt;
// code for IE&lt;br&gt;
else if (window.ActiveXObject)&lt;br&gt;
{&lt;br&gt;
xmlhttpKeepAlive=new ActiveXObject('Microsoft.XMLHTTP')&lt;br&gt;
if (xmlhttp)&lt;br&gt;
{&lt;br&gt;
xmlhttpKeepAlive.onreadystatechange = xmlhttpChangeKeepAlive;&lt;br&gt;
xmlhttpKeepAlive.open('GET', KeepAliveUrl + '?T=' + timerID, true);&lt;br&gt;
xmlhttpKeepAlive.send();&lt;br&gt;
}&lt;br&gt;
}&lt;br&gt;
return false;&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
function xmlhttpChangeKeepAlive()&lt;br&gt;
{&lt;br&gt;
var text;&lt;br&gt;
if (xmlhttpKeepAlive.readyState == 4) 
&lt;br&gt;
{&lt;br&gt;
text = xmlhttpKeepAlive.responseText;&lt;br&gt;
if (xmlhttpKeepAlive.status==200) // OK&lt;br&gt;
{&lt;br&gt;
if(text == 'OK') // reset the timer 
&lt;br&gt;
timerID = setTimeout('AutoSaveSubmit()', interval); 
&lt;br&gt;
else&lt;br&gt;
alert('Your session has already expired.\nIf you have any information on this page
you will lose it if you try to save this page now. You have 2 options to avoid losing
the information on this screen.\n\nOption 1: open a new internet window and log in
again to the web site, then close that window and go back to this window, at which
point you will have a new session and you will be able to save the information.\n\nOption
2: Copy all the text you have typed on this page and paste it into another program
(such as Word or Notepad), then log in to the web site again (click the home page)
and come back to this page, and paste in the text again.\n\nTo prevent this happening
in the future, click OK on the 15 minute reminder box each time it appears, this will
keep your session active. If you do not answer the reminder within 10 minutes the
session may expire.');&lt;br&gt;
}&lt;br&gt;
else&lt;br&gt;
alert('Error: ' + xmlhttpKeepAlive.status + '. The session may have already expired,
please try to save the page now');&lt;br&gt;
}&lt;br&gt;
}&lt;br&gt;
window.setTimeout('AutoSaveSubmit()',interval); 
&lt;br&gt;
&lt;/pre&gt;
&lt;p&gt;
You might be wondering why i append the timer code/number to the url of the web service.&amp;nbsp;
The reason is because IE has a caching bug and will not actually send the XmlHttp
request unless the URL is different to what it has in its history, it will just return
the previous result. 
&lt;br&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://tim.mackey.ie/aggbug.ashx?id=779ba072-7636-496e-a71c-0f09ea71f16e" /&gt;</description>
      <comments>http://tim.mackey.ie/CommentView,guid,779ba072-7636-496e-a71c-0f09ea71f16e.aspx</comments>
      <category>Asp.Net</category>
    </item>
    <item>
      <trackback:ping>http://tim.mackey.ie/Trackback.aspx?guid=65639461-f6c9-4e62-90ba-f2bbf556c7b4</trackback:ping>
      <pingback:server>http://tim.mackey.ie/pingback.aspx</pingback:server>
      <pingback:target>http://tim.mackey.ie/PermaLink,guid,65639461-f6c9-4e62-90ba-f2bbf556c7b4.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://tim.mackey.ie/CommentView,guid,65639461-f6c9-4e62-90ba-f2bbf556c7b4.aspx</wfw:comment>
      <wfw:commentRss>http://tim.mackey.ie/SyndicationService.asmx/GetEntryCommentsRss?guid=65639461-f6c9-4e62-90ba-f2bbf556c7b4</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">i notice when i backup a database and restore
it to another server, the user IDs are different and i have to delete the users and
add them back in to the database.  however last time i tried this the drop failed
because the user owned a schema.  i right-clicked on the user's properties and
the tick box for 'db_owner' was shaded in a read only state.  so i couldn't delete
the user and couldn't remove their schema ownership.  took a while to figure
out that the way to do this is via the Database &gt; Security &gt; Schemas menu, then
change the schema owner back to itself, e.g. db_owner.  then the user is free
to be deleted.<br /><p></p><img width="0" height="0" src="http://tim.mackey.ie/aggbug.ashx?id=65639461-f6c9-4e62-90ba-f2bbf556c7b4" /></body>
      <title>SQL 2005 cannot drop user with owned schema</title>
      <guid isPermaLink="false">http://tim.mackey.ie/PermaLink,guid,65639461-f6c9-4e62-90ba-f2bbf556c7b4.aspx</guid>
      <link>http://tim.mackey.ie/SQL2005CannotDropUserWithOwnedSchema.aspx</link>
      <pubDate>Sun, 11 Jan 2009 15:28:04 GMT</pubDate>
      <description>i notice when i backup a database and restore it to another server, the user IDs are different and i have to delete the users and add them back in to the database.&amp;nbsp; however last time i tried this the drop failed because the user owned a schema.&amp;nbsp; i right-clicked on the user's properties and the tick box for 'db_owner' was shaded in a read only state.&amp;nbsp; so i couldn't delete the user and couldn't remove their schema ownership.&amp;nbsp; took a while to figure out that the way to do this is via the Database &amp;gt; Security &amp;gt; Schemas menu, then change the schema owner back to itself, e.g. db_owner.&amp;nbsp; then the user is free to be deleted.&lt;br&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://tim.mackey.ie/aggbug.ashx?id=65639461-f6c9-4e62-90ba-f2bbf556c7b4" /&gt;</description>
      <comments>http://tim.mackey.ie/CommentView,guid,65639461-f6c9-4e62-90ba-f2bbf556c7b4.aspx</comments>
      <category>Database</category>
    </item>
    <item>
      <trackback:ping>http://tim.mackey.ie/Trackback.aspx?guid=5de9f2ca-d589-4a84-9386-602f0b2a4dde</trackback:ping>
      <pingback:server>http://tim.mackey.ie/pingback.aspx</pingback:server>
      <pingback:target>http://tim.mackey.ie/PermaLink,guid,5de9f2ca-d589-4a84-9386-602f0b2a4dde.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://tim.mackey.ie/CommentView,guid,5de9f2ca-d589-4a84-9386-602f0b2a4dde.aspx</wfw:comment>
      <wfw:commentRss>http://tim.mackey.ie/SyndicationService.asmx/GetEntryCommentsRss?guid=5de9f2ca-d589-4a84-9386-602f0b2a4dde</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">many web sites export tabular information
from grids/tables into 'Excel' format. the file is not a true Excel format and actually
contains X/HTML.  if the file is opened in Excel 2007 you may get a prompt that
the file is in a different format than specified by the file extension.  if you
regularly work with files like this, there is a way to disable this prompt, add a
DWORD key called ExtensionHardening with value 0 to HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Excel\Security<br />
it works straight away, no need for a reboot.<br /><p></p><img width="0" height="0" src="http://tim.mackey.ie/aggbug.ashx?id=5de9f2ca-d589-4a84-9386-602f0b2a4dde" /></body>
      <title>HowTo: disable the Excel prompt for opening formats different than the extension</title>
      <guid isPermaLink="false">http://tim.mackey.ie/PermaLink,guid,5de9f2ca-d589-4a84-9386-602f0b2a4dde.aspx</guid>
      <link>http://tim.mackey.ie/HowToDisableTheExcelPromptForOpeningFormatsDifferentThanTheExtension.aspx</link>
      <pubDate>Tue, 23 Dec 2008 12:08:07 GMT</pubDate>
      <description>many web sites export tabular information from grids/tables into 'Excel' format. the file is not a true Excel format and actually contains X/HTML.&amp;nbsp; if the file is opened in Excel 2007 you may get a prompt that the file is in a different format than specified by the file extension.&amp;nbsp; if you regularly work with files like this, there is a way to disable this prompt, add a DWORD key called ExtensionHardening with value 0 to HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Excel\Security&lt;br&gt;
it works straight away, no need for a reboot.&lt;br&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://tim.mackey.ie/aggbug.ashx?id=5de9f2ca-d589-4a84-9386-602f0b2a4dde" /&gt;</description>
      <comments>http://tim.mackey.ie/CommentView,guid,5de9f2ca-d589-4a84-9386-602f0b2a4dde.aspx</comments>
      <category>Asp.Net</category>
    </item>
    <item>
      <trackback:ping>http://tim.mackey.ie/Trackback.aspx?guid=aeaf79d2-578e-47d3-bab8-75ab2b599967</trackback:ping>
      <pingback:server>http://tim.mackey.ie/pingback.aspx</pingback:server>
      <pingback:target>http://tim.mackey.ie/PermaLink,guid,aeaf79d2-578e-47d3-bab8-75ab2b599967.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://tim.mackey.ie/CommentView,guid,aeaf79d2-578e-47d3-bab8-75ab2b599967.aspx</wfw:comment>
      <wfw:commentRss>http://tim.mackey.ie/SyndicationService.asmx/GetEntryCommentsRss?guid=aeaf79d2-578e-47d3-bab8-75ab2b599967</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">great outlook macro to strip attachments
from selected emails, <a href="http://www.darinarcher.com/blog/technology/remove_attachments_from_microsoft_outlook.htm">darin
archer's blog</a><br /><br /><br /><img width="0" height="0" src="http://tim.mackey.ie/aggbug.ashx?id=aeaf79d2-578e-47d3-bab8-75ab2b599967" /></body>
      <title>Outlook Macro to Remove Attachments</title>
      <guid isPermaLink="false">http://tim.mackey.ie/PermaLink,guid,aeaf79d2-578e-47d3-bab8-75ab2b599967.aspx</guid>
      <link>http://tim.mackey.ie/OutlookMacroToRemoveAttachments.aspx</link>
      <pubDate>Wed, 10 Dec 2008 13:04:44 GMT</pubDate>
      <description>great outlook macro to strip attachments from selected emails, &lt;a href="http://www.darinarcher.com/blog/technology/remove_attachments_from_microsoft_outlook.htm"&gt;darin
archer's blog&lt;/a&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;img width="0" height="0" src="http://tim.mackey.ie/aggbug.ashx?id=aeaf79d2-578e-47d3-bab8-75ab2b599967" /&gt;</description>
      <comments>http://tim.mackey.ie/CommentView,guid,aeaf79d2-578e-47d3-bab8-75ab2b599967.aspx</comments>
      <category>General</category>
    </item>
    <item>
      <trackback:ping>http://tim.mackey.ie/Trackback.aspx?guid=b37a4584-9ca3-47e0-b6c1-6d7afe5a09d3</trackback:ping>
      <pingback:server>http://tim.mackey.ie/pingback.aspx</pingback:server>
      <pingback:target>http://tim.mackey.ie/PermaLink,guid,b37a4584-9ca3-47e0-b6c1-6d7afe5a09d3.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://tim.mackey.ie/CommentView,guid,b37a4584-9ca3-47e0-b6c1-6d7afe5a09d3.aspx</wfw:comment>
      <wfw:commentRss>http://tim.mackey.ie/SyndicationService.asmx/GetEntryCommentsRss?guid=b37a4584-9ca3-47e0-b6c1-6d7afe5a09d3</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">IIS went down this morning after KB 958644
was isntalled automatically last night. My sites were showing "Service Unavailable"<br />
there were several system event logs like so:<br /><ul><li>
A process serving application pool '.Net 2.0 App Pool' suffered a fatal communication
error with the World Wide Web Publishing Service. The process id was '2960'. The data
field contains the error number.</li><li>
Application pool '.Net 2.0 App Pool' is being automatically disabled due to a series
of failures in the process(es) serving that application pool.<br /></li></ul><p></p>
rebooting the server did not solve the problem.  so, on further research, <a href="http://support.microsoft.com/kb/885654">KB
article 885654</a> revealed the cause of the errors, lack of registry permissions
for NETWORK SERVICE.  i hadn't changed any configuration on the server so assumed
it was caused by a change in that windows update package.  i dug out <a href="http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx">ProcessMonitor</a> and
set up a registry filter for w3wp.exe where the Result was ACCESS DENIED.  there
were about 50 entries during the time i enabled event capture and loaded up one of
the sites that uses the affected application pool.  Most of them pointed to SystemCertificates
entries.  I went through each one in regedit and gave NETWORK SERVICE full control
where the process attempted to Create a key, and Read only access where the process
attemped to Open the key.  worked fine then. 
<br /><br />
hope this helps someone out. 
<br /><img width="0" height="0" src="http://tim.mackey.ie/aggbug.ashx?id=b37a4584-9ca3-47e0-b6c1-6d7afe5a09d3" /></body>
      <title>IIS6 Service Unavailable, after installing KB 958644</title>
      <guid isPermaLink="false">http://tim.mackey.ie/PermaLink,guid,b37a4584-9ca3-47e0-b6c1-6d7afe5a09d3.aspx</guid>
      <link>http://tim.mackey.ie/IIS6ServiceUnavailableAfterInstallingKB958644.aspx</link>
      <pubDate>Sun, 26 Oct 2008 13:41:10 GMT</pubDate>
      <description>IIS went down this morning after KB 958644 was isntalled automatically last night. My sites were showing "Service Unavailable"&lt;br&gt;
there were several system event logs like so:&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;
A process serving application pool '.Net 2.0 App Pool' suffered a fatal communication
error with the World Wide Web Publishing Service. The process id was '2960'. The data
field contains the error number.&lt;/li&gt;
&lt;li&gt;
Application pool '.Net 2.0 App Pool' is being automatically disabled due to a series
of failures in the process(es) serving that application pool.&lt;br&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;/p&gt;
rebooting the server did not solve the problem.&amp;nbsp; so, on further research, &lt;a href="http://support.microsoft.com/kb/885654"&gt;KB
article 885654&lt;/a&gt; revealed the cause of the errors, lack of registry permissions
for NETWORK SERVICE.&amp;nbsp; i hadn't changed any configuration on the server so assumed
it was caused by a change in that windows update package.&amp;nbsp; i dug out &lt;a href="http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx"&gt;ProcessMonitor&lt;/a&gt; and
set up a registry filter for w3wp.exe where the Result was ACCESS DENIED.&amp;nbsp; there
were about 50 entries during the time i enabled event capture and loaded up one of
the sites that uses the affected application pool.&amp;nbsp; Most of them pointed to SystemCertificates
entries.&amp;nbsp; I went through each one in regedit and gave NETWORK SERVICE full control
where the process attempted to Create a key, and Read only access where the process
attemped to Open the key.&amp;nbsp; worked fine then. 
&lt;br&gt;
&lt;br&gt;
hope this helps someone out. 
&lt;br&gt;
&lt;img width="0" height="0" src="http://tim.mackey.ie/aggbug.ashx?id=b37a4584-9ca3-47e0-b6c1-6d7afe5a09d3" /&gt;</description>
      <comments>http://tim.mackey.ie/CommentView,guid,b37a4584-9ca3-47e0-b6c1-6d7afe5a09d3.aspx</comments>
      <category>Asp.Net</category>
      <category>Windows Server 2003</category>
    </item>
    <item>
      <trackback:ping>http://tim.mackey.ie/Trackback.aspx?guid=7e32c01d-1f87-41c8-995a-11c74cd8ce42</trackback:ping>
      <pingback:server>http://tim.mackey.ie/pingback.aspx</pingback:server>
      <pingback:target>http://tim.mackey.ie/PermaLink,guid,7e32c01d-1f87-41c8-995a-11c74cd8ce42.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://tim.mackey.ie/CommentView,guid,7e32c01d-1f87-41c8-995a-11c74cd8ce42.aspx</wfw:comment>
      <wfw:commentRss>http://tim.mackey.ie/SyndicationService.asmx/GetEntryCommentsRss?guid=7e32c01d-1f87-41c8-995a-11c74cd8ce42</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">thanks to Kev for his <a href="http://blog.zygonia.net/2006/03/12/SystemXmlXmlNamespaceManagerXPathAndTheDefaultNamespace.aspx">brilliant
post</a> about solving this problem, where you know you have the correct XPath expression
but .Net is not giving you any nodes :(<br />
his solution is the correct one, an alternative approach is to remove the xmlns from
the root element before you load the XmlDocument so that you can use the default empty
namespace (or something like that).<br /><p></p><img width="0" height="0" src="http://tim.mackey.ie/aggbug.ashx?id=7e32c01d-1f87-41c8-995a-11c74cd8ce42" /></body>
      <title>XPath problems, SelectNodes returns no nodes</title>
      <guid isPermaLink="false">http://tim.mackey.ie/PermaLink,guid,7e32c01d-1f87-41c8-995a-11c74cd8ce42.aspx</guid>
      <link>http://tim.mackey.ie/XPathProblemsSelectNodesReturnsNoNodes.aspx</link>
      <pubDate>Thu, 16 Oct 2008 18:05:36 GMT</pubDate>
      <description>thanks to Kev for his &lt;a href="http://blog.zygonia.net/2006/03/12/SystemXmlXmlNamespaceManagerXPathAndTheDefaultNamespace.aspx"&gt;brilliant
post&lt;/a&gt; about solving this problem, where you know you have the correct XPath expression
but .Net is not giving you any nodes :(&lt;br&gt;
his solution is the correct one, an alternative approach is to remove the xmlns from
the root element before you load the XmlDocument so that you can use the default empty
namespace (or something like that).&lt;br&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://tim.mackey.ie/aggbug.ashx?id=7e32c01d-1f87-41c8-995a-11c74cd8ce42" /&gt;</description>
      <comments>http://tim.mackey.ie/CommentView,guid,7e32c01d-1f87-41c8-995a-11c74cd8ce42.aspx</comments>
      <category>.Net General</category>
    </item>
  </channel>
</rss>