.NET development, Information Worker, Sharepoint and Team System Jean-Pierre under the Guru Meditation Tree
Downloading/Streaming Documents whilst Setting Control Values using an ASP.NET 'Download' button
Tuesday, August 19, 2008 5:42 PM

Ok, have you ever tried downloading a document using a server-side Click event on a button?  You probably did something like sending the content in the response as a stream, like this?:

private void DownloadDocument(int documentId)
    {
        string filePath = Server.MapPath(String.Concat("Document_", documentId, ".pdf"));
        System.IO.FileInfo file = new System.IO.FileInfo(filePath);
        if(file.Exists)
        {
            Response.Clear();
            Response.AddHeader("Content-Disposition", "attachment; filename=" + file.Name);
            Response.AddHeader("Content-Length", file.Length.ToString());
            Response.ContentType = "application/octet-stream";
            Response.WriteFile(file.FullName);
            Response.End();
        }
        else
        {
            Response.Write("This file does not exist.");
            this.DocumentFiledCheckBox.Enabled = false;
            Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "AsyncCallbacks", "");
        }
    }

Now what if you wanted to set the values of certain controls on the form, in addition to sending the  pdf stream? (e.g. you wanted to enable a check box, so the user can indicate whether she has filed the document, but this check box should only be available if she has downloaded it)

Maybe you had something like this:


   protected void DownloadButton_Click(object sender, EventArgs e)
    {
        //Enable the check box, as per requirement
        this.DocumentFiledCheckBox.Enabled = true;
        DownloadDocument(101);

    }

 

Problem is that you won't be able to set the control values in this way, probably because you are streaming an entirely different response. 

 

Scratch your head for a day and a half on this, and then try the following solution:

MY SOLUTION

In the aspx file

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="Default" ValidateRequest="false"  EnableEventValidation="false" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Download a Document</title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:TextBox ID="DocumentIdTextBox" Text = "101" runat="server" />
            <asp:Button ID="DownloadButton" runat="server" OnClick="DownloadButton_Click" Text="Download Document" />&nbsp;
            <br />
            <br />
            <asp:CheckBox ID="DocumentFiledCheckBox" Text="Document Filed" Enabled="false" runat="server" />
            <asp:Button ID="CallbackButton" runat="server" OnClick="CallbackButton_Click" Text="DownloadDocumentCallbackPlaceholderButton" UseSubmitBehavior="False" Visible="True" /></div>
    </form>
</body>
</html>

 

We have a simple form containing:

- a DocumentIdTextBox Text Box control for the document ID you want to download.

-a hidden CallbackButton Text Box controls which you are going to use to do an automated post back when the response has been downloaded from the server.

- a DocumentFiledCheckBox which will be enabled when you click the download button, otherwise its initial state is disabled.

- Notice that the UseSubmitBehavior property for each of the buttons above is set to false.  This will enable ASP.NET to render the __doPostBack functions.  If you do not set this property, you may not get a __doPostBack function in your browser.  This is presumably because a submit button will post to the server as part of the behaviour provided by HTML.  See point 5 of the .cs file notes below, for more on this...

In the .cs file:

1. Handle the initial click event:

    //1. Download button is clicked
    protected void DownloadButton_Click(object sender, EventArgs e)
    {
        //Enable the check box, as per requirement
        this.DocumentFiledCheckBox.Enabled = true;
        //Cause the browser to download the document
       SetUpClientSideScriptToDownloadDocument(int.Parse(this.DocumentIdTextBox.Text));
    }

Notice that the key bit here is to send a client-side callback which fires as soon as the response is received

2.  Fire a client-side callback:

Notice that we need to set a timeout, and attach to the onload event of the window.  Otherwise, you may find that your code breaks every so often, in search of your mystery client-side control, which has not loaded yet.

 

You are welcome to try raising the click event of our hidden control by using __doPostBack... This didn't work for me.  I could not get the server to fire the Click event.  Instead, it just went wizzing by my Click event handler.   It did do a postback, though.

// 2.   Browser receives this code --> we use __doPostBack as an alternative to window.open()
    //to avoid Popup blockers, used by most browsers these days.
    private void SetUpClientSideScriptToDownloadDocument(int documentId)
    {

        //Defer tag should make this fire only after the full response has been received
        //This didn't work for me
        //        string javaScript = @"<script language='JavaScript' defer='defer'>
        //                __doPostBack('CallbackButton','onclick');
        //           </script>";

        //Set a timeout so that this fires timeously i.e. AFTER entire response has been received
        string javaScript = @"<script language='javascript' type='text/javascript'>
                          window.attachEvent('onload',function(){setTimeout('DownloadKeyFactsDocument()',50);});

                                    function DownloadKeyFactsDocument()
                                    {
                                        //__doPostBack('CallbackButton','onclick');
                                        document.getElementById('" + this.CallbackButton.ClientID + @"').click();
                                    }
                                  </script>";

        if (!Page.ClientScript.IsClientScriptBlockRegistered("AsyncCallbacks"))
            Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "AsyncCallbacks", javaScript);

    }

3.   Handle the Callback on the server:

Our server-side function handles the click event of our invisible button.

    //3.  Browser calls this function(browser calls __doPostBack('CallbackButton', 'onclick');
    protected void CallbackButton_Click(object sender, EventArgs e)
    {
        this.DownloadDocument(int.Parse(this.DocumentIdTextBox.Text));
    }

 

4.  Download the document

The rest is history...

    //4.    Stream the document to the browser from the server
    private void DownloadDocument(int documentId)
    {
        string filePath = Server.MapPath(String.Concat("Document_", documentId, ".pdf"));
        System.IO.FileInfo file = new System.IO.FileInfo(filePath);
        if(file.Exists)
        {
            Response.Clear();
            Response.AddHeader("Content-Disposition", "attachment; filename=" + file.Name);
            Response.AddHeader("Content-Length", file.Length.ToString());
            Response.ContentType = "application/octet-stream";
            Response.WriteFile(file.FullName);
            Response.End();
        }
        else
        {
            Response.Write("This file does not exist.");
            this.DocumentFiledCheckBox.Enabled = false;
            Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "AsyncCallbacks", "");
        }
    }
}

5. Make sure you get a __doPostBack function as part of the response

The following code in Page_Load ensures that the browser gets a __doPostBack function:

protected void Page_Load(object sender, EventArgs e)
    {
        //Must always render __doPostBack
       // (even when callback button is invisible, and/or when 'UseSubmitBehavior' is true)
       //Notice that these two conditions (invisible and UseSubmitBehavior=true) will cause    
     
//ASP.Net not to render the __doPostBack function
        Page.ClientScript.GetPostBackClientHyperlink(this, "");
        this.CallbackButton.Attributes.Add("style", "display:none");
    }

 

6.  Make sure you hide your control correctly

Just in case you don't want to see the dummy control, you will also use this code in Page Load:

this.CallbackButton.Attributes.Add("style", "display:none");

Why don't we just use server side code, and set the Visible property of the button to false?  The answer is that if you do this, ASP>NET won't render the control.  So trying this will make our infrastructure will fall over!

 

Here is a complete code listing for you:

 

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="Default" ValidateRequest="false"  EnableEventValidation="false" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Download a Document</title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:TextBox ID="DocumentIdTextBox" Text = "101" runat="server" />
            <asp:Button ID="DownloadButton" runat="server" OnClick="DownloadButton_Click" Text="Download Document" />&nbsp;
            <br />
            <br />
            <asp:CheckBox ID="DocumentFiledCheckBox" Text="Document Filed" Enabled="false" runat="server" />
            <asp:Button ID="CallbackButton" runat="server" OnClick="CallbackButton_Click" Text="DownloadDocumentCallbackPlaceholderButton" UseSubmitBehavior="False" Visible="True" /></div>
    </form>
</body>
</html>

 


using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class Default : System.Web.UI.Page
{

    protected void Page_Load(object sender, EventArgs e)
    {
        //Must always render __doPostBack
       // (even when callback button is invisible, and/or when 'UseSubmitBehavior' is true)
       //Notice that these two conditions (invisible and UseSubmitBehavior=true) will cause    
     
//ASP.Net not to render the __doPostBack function
        Page.ClientScript.GetPostBackClientHyperlink(this, "");
        this.CallbackButton.Attributes.Add("style", "display:none");
    }

    //1. Download button is clicked
    protected void DownloadButton_Click(object sender, EventArgs e)
    {
        //Enable the check box, as per requirement
        this.DocumentFiledCheckBox.Enabled = true;
        //Cause the browser to download the document
        SetUpClientSideScriptToDownloadDocument(int.Parse(this.DocumentIdTextBox.Text));
    }

    //2.  Browser receives this code --> we use __doPostBack as an alternative to window.open()
    //to avoid Popup blockers, used by most browsers these days.
    private void SetUpClientSideScriptToDownloadDocument(int documentId)
    {

        //Defer tag should make this fire only after the full response has been received
        //This didn't work for me
        //        string javaScript = @"<script language='JavaScript' defer='defer'>
        //                __doPostBack('CallbackButton','onclick');
        //           </script>";

        //Set a timeout so that this fires timeously i.e. AFTER entire response has been received
        string javaScript = @"<script language='javascript' type='text/javascript'>
                          window.attachEvent('onload',function(){setTimeout('DownloadKeyFactsDocument()',50);});

                                    function DownloadKeyFactsDocument()
                                    {
                                        //__doPostBack('CallbackButton','onclick');
                                        document.getElementById('" + this.CallbackButton.ClientID + @"').click();
                                    }
                                  </script>";

        if (!Page.ClientScript.IsClientScriptBlockRegistered("AsyncCallbacks"))
            Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "AsyncCallbacks", javaScript);

    }

    //3.  Browser calls this function(browser calls __doPostBack('CallbackButton', 'onclick');
    protected void CallbackButton_Click(object sender, EventArgs e)
    {
        this.DownloadDocument(int.Parse(this.DocumentIdTextBox.Text));
    }

    //4.    Stream the document to the browser from the server
    private void DownloadDocument(int documentId)
    {
        string filePath = Server.MapPath(String.Concat("Document_", documentId, ".pdf"));
        System.IO.FileInfo file = new System.IO.FileInfo(filePath);
        if(file.Exists)
        {
            Response.Clear();
            Response.AddHeader("Content-Disposition", "attachment; filename=" + file.Name);
            Response.AddHeader("Content-Length", file.Length.ToString());
            Response.ContentType = "application/octet-stream";
            Response.WriteFile(file.FullName);
            Response.End();
        }
        else
        {
            Response.Write("This file does not exist.");
            this.DocumentFiledCheckBox.Enabled = false;
            Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "AsyncCallbacks", "");
        }
    }
}

by virasana
Filed under:
VSTS Source Control Problem - No "Add to Source Control" menu item
Friday, August 08, 2008 12:34 PM

Problem Description:

“Add to source control” item is missing in Solution Explorer, for a particular project.

We did the following:

1. Ensure that workspace folders are the same structure as on the server.  The folder on the workspace did not exist on the server. 

2. Add the folder on the server using source control explorer (Team Explorer). 

3. Adjust local workspace to reflect server structure.  We needed to remove the project from the solution in order to do this.

4. File|Source Control | Change Source Control -->  the binding for our naughty project  was marked “invalid” --> unbind and then rebind this project  --> project now “Valid”

5. Add solution to source control (you now see the menu item in solution explorer

Developer Express v 7.2 issue - Properties missing in property editor on VGrid Control
Tuesday, July 22, 2008 10:31 AM

If you are having problems with the VGrid control in DevExpress i.e. your properties do not display on the Row Editor, try removing the registry key below.  I am using Visual Studio 2005 on VIsta, Business edition.

 

Here is the response from Developer Express support: 

"We fixed a similar bug in one of recent updates. Please upgrade your components to the most recent version.

Currently, to fix the problem on your machine, please delete the following key from the system registry:

HKEY_CURRENT_USER\Software\Developer Express\Designer\XtraVertGrid"

 

You can check the state of your issue at: https://www.devexpress.com/issue=B32034"

 

WPAD.dat and Visual Sudio 2008 Web Tests - problem
Tuesday, June 03, 2008 9:23 AM

We are using Visual Studio 2008 Team Edition for Software Testers to run web tests against our test website.

We find that our tests are failing on a particular request for a wpad.dat file.  No http error is reported. 

 

After some searching on the internet, we discovered just what a wpad.dat file is:

 WPAD (Web Proxy Autodiscovery Protocol)

·         Check  out a full description of what it is on http://en.wikipedia.org/wiki/Web_Proxy_Autodiscovery_Protocol

·         This is simply a method used by browsers to auto-discover the location of a proxy auto-config (.pac) file. 

·         You can set this up in your network through one of two methods:

o   DHCP

o   DNS

·         If your network is not configured for WPAD, you may have problems if your browsers are configured to “autodetect”.

 Solution to our problem

·         Internet Explorer:

o   / Internet Options / Connections / LAN Settings

o   Turn OFF the option to automatically detect proxy settings.

·         Contact network admin to see whether wpad is correctly configured.

 

The problem occurs for us ONLY when using the web test interface.  Through the browser, everything is OK.  We have decided to configure IE and consider the test to have passed. 

 Requirements to get WPAD to work properly (from WIKIPEDIA)

In order for WPAD to work, a few requirements have to be met:

 

·         If you want to use DHCP, then the DHCP must be configured to serve up the "site-local" option 252 ("auto-proxy-config") with a string value of "http://xxx.yyy.zzz.qqq/wpad.dat" (without the quotes) where xxx.yyy.zzz.qqq is the address of a web server (either IP or DNS).

·         If you want to use DNS, then a DNS entry is needed for a host named WPAD.

·         The host WPAD must be able to serve a web page.

·         In both cases, the web server must be configured to set up dat files with a MIME type of "application/x-ns-proxy-autoconfig".

·         The file named wpad.dat must be located in the WPAD web site's root directory.

·         Examples for PAC files are shown in Proxy auto-config.

·         Use caution when configuring a WPAD server in a virtual hosting environment. When automatic proxy detection is used, Internet Explorer sends a "Host: <IP address>" header and Firefox sends a "Host: wpad" header. This is unexpected behavior, therefore, it is recommended that the wpad.dat file be hosted under the default Virtual Host rather than its own. 

Note the last point, which indicates potential problems when using virtual hosting.  What is “virtual hosting”?  It is the procedure of serving up the same website from multiple host header names or IP addresses – this has been employed in our project.  This indicates a potential source for our problem, which you might want to investigate if you experience the same problem.

 

Happy web testing!

 

Kind Regards

Jean-Pierre Fouche  

 

Migrating Sharepoint 2007 List to Calendar
Tuesday, March 25, 2008 4:47 PM

Whew... That was a long and arduous process.

If you have tried migrating lists in Sharepoint 2007, you have probably tried exporting the source list to Excel and then Exporting the Excel worksheet to the new list in Sharepoint.  The problem with this approach is that it doesn't work for Calendars.  When you export a list from Excel, it creates a new List, which is not a Calendar type.  THis means that you cannot "Connect to Outlook", resulting in a poor user experience.

I tried numerous ways of migrating the content, but here's my solution (using Access 2007 with linked tables).

1.Open a new access database from the source list, and link a new table to the destination (My Source list was Readiness Sessions; my target was Readiness Sessions Calendar).

2.In a Module, execute the following (rather horrible) algorithm:

'This code is posted 'as-is' and requires alteration...

Function DoIt()

    Dim strValue
    Dim conn As New ADODB.Connection
    Dim rs As New ADODB.Recordset
    Dim strSql As String
    Dim fld As ADODB.Field
    Dim strFieldList As String
    Dim strValueList As String
    Dim n As Integer
    Set conn = CodeProject.Connection
    conn.Execute "DELETE FROM [Readiness Sessions Calendar]"
    sql = "select * from [readiness sessions]"
    Set rs = conn.Execute(sql)
    strFieldList = ""
    strValueList = ""
    strSql = ""
    While Not rs.EOF
        n = n + 1
        For m = 1 To 17
            If m < 13 Or m > 15 Then
                Set fld = rs.Fields(m)
                If Not IsNull(fld.Value) Then
                    strValue = Replace(fld.Value, "'", "''")
                Else
                    strValue = fld.Value
                End If
                If strValue <> "''" Then
                    If m = 1 Then 'Event Name
                        strSql = "INSERT INTO [Readiness Sessions Calendar] "
                        strSql = strSql & "([" & fld.Name & "]) "
                        strSql = strSql & "VALUES ('" & strValue & "')"
                        Debug.Print strSql
                        conn.Execute strSql
                    Else
                    If m <> 8 Then
                        strSql = "UPDATE [Readiness Sessions Calendar] SET [" & fld.Name & "] = '" & Replace(rs.Fields(m).Value, "'", "") & "' WHERE [Event Name] = '" & Replace(rs("Event Name"), "'", "") & "'"
                        conn.Execute (strSql)
                        Debug.Print strSql
                    End If
                    End If
                End If
            End If
        Next
        rs.MoveNext
    Wend

Exit Function

by virasana
Filed under:
Tech Titbits
Tuesday, February 12, 2008 7:56 PM

Google Code Search
Looking for a particular snippet of code?  Use

http://www.google.com/codesearch (simple search) or
http://www.google.com/codesearch/advanced_code_search?hl=en (advanced search)

image

SQL Server 2005 Service Manager
If you are looking for a "retro" look on your desktop, how about this nice tool from SQLDBATips.com - a Service Manager for SQL 2005, similar to the one used in Enterprise Manager for SQL 2000.  On my Vista OS, it comes with a curiosity - the message "Service Stoppe" at the bottom of the screen!  Use this aplication to manage all the SQL Server instances on your machine.   Mine works only with local instances.

image

http://www.sqldbatips.com/showarticle.asp?ID=46

.iso Reader for Vista
If you are looking for an .iso reader for 64-bit Vista, use MagicISO. The screenshot below shows you what it can do:

image

Access Manage Network Connections in Vista
- Add a desktop/quick launch shortcut to C:\Windows\System32\ncpa.cpl
- Type ncpa.cpl plus enter from the start menu.  Whew! :(

by virasana
Filed under:
Renaming your SharePoint Virtual Machine
Tuesday, February 12, 2008 5:28 PM

In my previous post entitled SharePoint Development Environment Scenarios, I posted a diagram recommending deployment using virtual machines on each developer's desktop.  The practical upshot of this is that you will need to store a central "base" VM somewhere - perhaps on a file share - and copy this to each developer's desktop whenever a new developer arrives. 

A problem you will encounter when doing this is that you will get an IP / Name conflict when you first boot the server - you now have two machines trying to access the same network resource, and they have the same name!  Clinton Cherry outlines a procedure to solve this problem here

The simple procedure I followed was:

1.Run the command line indicated i.e. stsadm -o setconfigdb -databaseserver "nameofdatabaseserver\instance" -farmuser "networkserviceaccount" -farmpassword "networkserviceaccountpassword" where I found that you had to remove the computer name if using a local account for the farmuser.  This is because the computer name has changed, and somewhere along the line the config wizard tries to use the old computer name.

2.Grant access to the new farmuser account on the relevant databases in SQL Server. The wizard will fail if it cannot access the databases.

The method worked well for me.  Check it out on Clinton Cherry's blog.

 

An update to this post was presented to me by my colleague, Joseph Neimann, who recently tried the process again.  Here it is:

"The final verdict was that inorder to effectively change a name you need to remove the domain from the user name before you can rename.

So first run

stsadm -o setconfigdb -databaseserver "Old_databaseserver\instance" -farmuser "networkserviceaccount" -farmpassword "networkserviceaccountpassword"

Then Rename server

Then Run

stsadm -o setconfigdb -databaseserver "New_databaseserver\instance" -farmuser "networkserviceaccount" -farmpassword "networkserviceaccountpassword"

Then run the wizard.

Success."

Giving "Performant" Presentations
Tuesday, February 12, 2008 5:27 PM

Here are some links to help you to deliver better presentations...

http://www.beyondbullets.com/

http://headrush.typepad.com/creating_passionate_users/

I will be updating this page.

IIS Redirection [with Sharepoint 2007] - URL and Wildcard Redirection
Friday, February 08, 2008 9:45 PM

If you are thinking of using redirection on your sharepoint site - e.g. you want to redirect all http requests to https, or perhaps you want to retire an old URL, you have perhaps considered some of these options:

1.  USE A QUICK AND DIRTY SCRIPT
Redirect using a script such as this one in .asp (I am using .asp for ease of scripting):

<%

Response.Redirect(https://mysite.co.za & Request.ServerVariables("URL") )

%>

You might even consider using the HTTP_REFERER Server Variable, and try to transform this into your new site's URL.

You save this script as default.asp, and set it as the default document in IIS.

Problem with this approach? 

a.Works great on your site if you only want to access the root!  What about http://mysite/mypage01.aspx?
b.  HTTP_REFERER is dangerously unreliable - e.g. it does not work if you enter the address into the browser and hit enter - you have to click a link!  It will return an empty value.
c:  URL will return the current URL, when what you really want is the URL that the user typed into the browser (see point 2 for trouble with this)
 

2.  CUSTOM ERROR PAGES
You have failed on point 1, so what about using custom error pages to specify a handler on 404 errors - say you redirect to redirect.asp every time you have a 404.  You can configure this in IIS in the Custom Errors tab - and also in web.config (I could not get this to work).  Problems with this are as follows:

a.You find that your script cannot access the original URL that the user typed in - if you try HTTP_REFERER, you get an empty value, and if you use URL, you get the current URL i.e. redirect.asp!  Next option...

3.  IHttpHandler
Try writing an IHttpHandler to handle all requests to the sharepoint site, and do the transform in C# code.  This sounds like an excellent idea, and it ALMOST worked for me.  Then I read an article stating that the handler cannot work on ANY extension - you have to configure IIS and the handler for a specific extension.  I also found that I was having trouble when I deployed my "working" solution (file system based) to an IIS-deployed website.  The file system based one worked, whereas the IIS-based one did not.  I believe this might work, and this approach needs more investigation.  But this took a lot of coding!

4.  CONFIGURE IIS
Now, the approach that worked for me... Set it up in IIS there is a setting to get content from "a redirection to a URL".  Here, you can specify the following:

- the "target" URL is the domain of the new site you want to direct to e.g. https://mysite.co.za.
- specify an EXACT MATCH (it is a check box)
- specify wildcard patterns to force querystrings to be used.  My URL in the target textbox was : https://mysite.com$Q (the $Q means "include the querystring)!

The site you need to visit in order to understand redirection strings is here http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/6b855a7a-0884-4508-ba95-079f38c77017.mspx?mfr=true

5.  DISABLE SHAREPOINT ON YOUR OLD SITE
Note that if you want a Sharepoint site to stop being a Sharepoint site, and to start serving up your scripts, you need to do but one small change - rename global.asax to global.asax.backup. If you do this, Sharepoint no longer implements an ApplicationHandler (which is specfied in global.asax) as Sharepoint can no linger find the global.asax file!  IIS will then process scripts as usual.

I would not say that this was a "painless" exercise, but it is a few minutes of work when you know how to set it up!

by virasana
Filed under: ,
IIS Redirection [with Sharepoint 2007] - URL and Wildcard Redirection
Friday, February 08, 2008 9:43 PM

If you are thinking of using redirection on your sharepoint site - e.g. you want to redirect all http requests to https, or perhaps you want to retire an old URL, you have perhaps considered some of these options:

1.  USE A QUICK AND DIRTY SCRIPT
Redirect using a script such as this one in .asp (I am using .asp for ease of scripting):

<%

Response.Redirect(https://mysite.co.za & Request.ServerVariables("URL") )

%>

You might even consider using the HTTP_REFERER Server Variable, and try to transform this into your new site's URL.

You save this script as default.asp, and set it as the default document in IIS.

Problem with this approach? 

a.Works great on your site if you only want to access the root!  What about http://mysite/mypage01.aspx?
b.  HTTP_REFERER is dangerously unreliable - e.g. it does not work if you enter the address into the browser and hit enter - you have to click a link!  It will return an empty value.
c:  URL will return the current URL, when what you really want is the URL that the user typed into the browser (see point 2 for trouble with this)
 

2.  CUSTOM ERROR PAGES
You have failed on point 1, so what about using custom error pages to specify a handler on 404 errors - say you redirect to redirect.asp every time you have a 404.  You can configure this in IIS in the Custom Errors tab - and also in web.config (I could not get this to work).  Problems with this are as follows:

a.You find that your script cannot access the original URL that the user typed in - if you try HTTP_REFERER, you get an empty value, and if you use URL, you get the current URL i.e. redirect.asp!  Next option...

3.  IHttpHandler
Try writing an IHttpHandler to handle all requests to the sharepoint site, and do the transform in C# code.  This sounds like an excellent idea, and it ALMOST worked for me.  Then I read an article stating that the handler cannot work on ANY extension - you have to configure IIS and the handler for a specific extension.  I also found that I was having trouble when I deployed my "working" solution (file system based) to an IIS-deployed website.  The file system based one worked, whereas the IIS-based one did not.  I believe this might work, and this approach needs more investigation.  But this took a lot of coding!

4.  CONFIGURE IIS
Now, the approach that worked for me... Set it up in IIS there is a setting to get content from "a redirection to a URL".  Here, you can specify the following:

- the "target" URL is the domain of the new site you want to direct to e.g. https://mysite.co.za.
- specify an EXACT MATCH (it is a check box)
- specify wildcard patterns to force querystrings to be used.  My URL in the target textbox was : https://mysite.com$Q (the $Q means "include the querystring)!

The site you need to visit in order to understand redirection strings is here http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/6b855a7a-0884-4508-ba95-079f38c77017.mspx?mfr=true

5.  DISABLE SHAREPOINT ON YOUR OLD SITE
Note that if you want a Sharepoint site to stop being a Sharepoint site, and to start serving up your scripts, you need to do but one small change - rename global.asax to global.asax.backup. If you do this, Sharepoint no longer implements an ApplicationHandler (which is specfied in global.asax) as Sharepoint can no linger find the global.asax file!  IIS will then process scripts as usual.

I would not say that this was a "painless" exercise, but it is a few minutes of work when you know how to set it up!

Sharepoint Quibbles - Developer Readiness Training Adventures
Friday, February 08, 2008 9:19 PM

I am providing Sharepoint training ("Deep Dive") this week (28th January 2008).   Here, in note form,  are some of the questions and problems we have been experiencing:

1.     Features. 
We find that multiple instances of our feature are being deployed!  Why is this happening?

Learning:
The feature we are trying to deploy was already installed on the virtual machine.  We did not uninstall the original feature, but rather added a new one, with a different GUID, and the same title.  Hence, we have multiple "HelloWorld" features.

Remember that a feature is defined by the following:
-    A GUID which causes a unique feature installation in Sharepoint.
-    Feature.xml, elements.xml fand other resource files which are copied to the "12" hive during deployment.  These can be cross-referenced by multiple installed features.  We noticed that certain students were changing the title in feature.xml, whereas multiple features reflected the change in Sharepoint!  This is to do with cross-referencing.
-     An optional feature receiver assembly which is installed to the GAC . If you lose this assembly, and you still define a feature receiver in feature.xml, you will have problems activating and deactivating the feature, as Sharepoint will be looking for a missing assembly in order to fire feature-related events.

2.     Page Templates.
A badly formed .aspx page does not get deployed when using a Module element in elements.xml.  In this case, we had a <!-- Comment -> (notice the missing closing tag!) in our page template which caused much confusion.  Initially, our page templates were successfully copied when activating our feature.  Later, however, after we had inserted the comment, the changes were not propagated to the site.  This all happened without any error notifications.

Learning:
Check very carefully that your page templates are properly formed when you find that changes are not being propagated whenever a feature with a <Module> element in elements.xml is activated. 

Always close comments!  <!-- Close me -> (where's the missing dash?)

3.     Sharepoint or SharePoint?
Some of us write Sharepoint, and others write SharePoint.  Sharepoint gives us errors.

Learning:
Always refer to SharePoint, and not Sharepoint.  (notice the Captialisation!)

4.     Installing to GAC - authentication issue (have to build twice)
When working on the Virtual machine, we sometimes have to build twice in order for our build script to install to the GAC. 

Learning:  Currently, our only learning is that "you have to build twice" :(  Is Sharepoint locking access to the assembly?

 

5.     Working With Sharepoint Pages - Feedback
Development environment is not complete. It is very frustrating to work with xml files - it is like going back 20 years in code history.

Debugging is difficult - no errors thrown.  Log files are a mystery,

Sharepoint as a server is good.  We are concerned about the lack of development environment.

Errors are mostly due to syntax - very difficult!

Architecture is nevertheless sound.

We prefer the object model to CAML/XML.

 

6.     Lists
Use of Object Model
The team prefers using the object model to CAML! 
Team liked the query mechanism.  We need a Query Designer.
Writing a query designer will be easier because it is all defined in XML. 
XML is great, but we need tools on top of XML.  XML is NOT human readable!
We spent hours trying to debug XML!
Sometimes our GUIDs needed curly braces, and other times not.  This is inconsistent.
No debugging tools.
A lot of "fiddling" and manual work required to get things working.
Wizards and snippets are needed because "our fingers hurt!"

7.     Sharepoint Workflow
InfoPath is easy to use.
Saving source files is difficult.
Creating cs class - need to have in-depth knowledge of WF.
You have to have in-depth knowledge of WF, not just Sharepoint. 
You have to DESIGN your workflow properly, otherwise you will have problems if you just code it ad hoc.

Nice to have common deployment architecture - features, elements et.
Forgot to enable browser-compatible features
Forgot to clear the alternate path property in InfoPath when publishing.  Why did this cause the solution to bomb?
Code needs to be more intuitive... Need knowledge of WF!
Visual Studio extensions were very helpful - less bugs on your server!
Debugging was nitty-gritty (not logical). 
The whole process was "confusing" - nitty gritty, a lot of pieces all over the place.  Compared to WCF, this is difficult.
Debugging seems to indicate that we need to write a whole lot of Console.Writeline statements... where is the bug?

Migrating SharePoint 2007 Content with Security Management and Obtaining Document Statistics
Thursday, January 24, 2008 4:19 AM

Content Migration with Security Management
I was recently asked by a colleague if there were any tools available to migrate SharePoint content from one domain to another, whilst maintaining security settings.  A little scouting around led me to a product suite called Doc Ave Content Manager for SharePoint.  We are busy evaluating this product.  Check it out on http://www.avepoint.com/products/sharepoint-content-management

Obtaining Document Statistics
Another issue I researched was how to obtain statistics on documents within SharePoint - number of docs, number of settings etc.  I came up with the following answers:

1.   Use SharePoint Designer.  There are a host of reports available from the Site menu.  Check them out below:

clip_image001

2.     Check out Doc Ave 4.5 SharePoint Administrator (http://www.avepoint.com/products/sharepoint-administration/sharepoint-administrator)  We are also evaluating this tool. 

SharePoint Development Environment Scenarios
Friday, January 18, 2008 9:33 PM

The following poster details some of the SharePoint development environments I have come across.  Please notice recent ammendments to point 1.  Developing in a multi-developer environment does not work on a single machine!

1.     Single Virtual Machine with RDP (SMALL team).
THIS SCENARIO DOES NOT WORK.  The team is happy with this simple setup, until we start debugging.  Attaching to the w3wp.exe IIS worker process causes hairy moments when developer A starts to catch bugs raised by developer B.  This is because they are working on the same worker process.  The worker process is not user specific, but belongs to the application pool identity.

a.  Promise to minimise on complexity.  
b.  Promise of easy integration - your code is already deployed to dev.  No need for an extra "integration" step as you re-deploy from your box to the dev server.
c.  Expect to experience poor performance.  Our two-person team is nevertheless happy with this.

2.     Large Team, Many Workstations (Native Machines without SharePoint)  - Recommended Approach.
You don't want the hassle of deploying Virtual Machines to each developer's workstation, or you are concerned with licensing?  If you are developing Web Parts, you can write them in ASP.NET and deploy to SharePoint.

3.     Large Team (VM's with SharePoint) 
Each developer in this scenario has a VM with SharePoint installed:
a.  Everybody has a performant environment.
b.  Everybody must go through a deployment-to-dev phase in order to integrate code.
c.   Licensing implications...

This poster will soon be posted to http://www.drp.co.za (The Developer Readiness Programme).

DevelopmentScenarios

Microsoft Best Practice Analyzer for Sharepoint 2007
Wednesday, January 16, 2008 2:20 PM

I downloaded and tested the BPA tool for Sharepoint 2007 today.  The BPA framework has been designed by Microsoft to provide rapid analysis on a particular product so that administrators can troubleshoot.

Willy-Peter has been working on the BPA tool for Team Foundation Server, and we find that this implementation has a wealth of information to display.  By contrast, the Sharepoint implementation is a bit lacking. 

Below is the output.  I have highlighted interesting points. My general observation is that this tool is rather sparse on output. Where is the knowledge base, where is the depth?  Come on, Microsoft, we need an analysis tool for Sharepoint!

Possible enhancements to this tool?:

- Every deployment of Sharepoint I have looked at so far has had a very ugly looking log file and the event log is inevitably full of errors.  I am sure that the BPA tool can be enhanced to include more rules. 
- A nice UI would be nice.  See the TFS version.

The following points are of interest:

1."No trusted locations have been defined for Excel Services within SSP SharedServices1."
Jean-Pierre: We don't have Excel Services enabled, on purpose.  OK with this.

2."Customer Experience Improvement Program is not enabled"
Jean-Pierre:  We are quite happy not to have this enabled!

3."No trusted locations have been defined for Excel Services within SSP SharedServices1."
Jean-Pierre:  Well, we don't have Excel Services enabled, on purpose!  So this is to be expected.

4."Only one instance of the SharePoint 3.0 Central Administration Web site exists in your installation. To make sure that you can administer the farm in the case of a failure of a server hosting SharePoint 3.0 Central Administration, you should have SharePoint 3.0 Central Administration installed on at least two servers in the farm."
Jean-Pierre:  Good advice.  We will implement this if and when the deployment scales.

5."No trusted Data Connection Libraries have been defined for Excel Services within SSP SharedServices1."
Jean-Pierre:  Same as above - we have disabled Excel Services on purpose - we like it this way.

 

Output follows:

Microsoft Best Practices Analyzer for Microsoft Windows SharePoint Services 3.0 and the 2007 Microsoft Office System

Run Date: January 16, 2008 15:52:45

Errors (1)

Warnings (7)

Error Details

Title:
No Trusted Locations

Severity:
2

Description:

No trusted locations have been defined for Excel Services within SSP SharedServices1.

Warning Details

Title:
Customer Experience Improvement Program is not enabled

Severity:
1

Title:
No trusted DCLs Defined

Severity:
2

Description:

No trusted Data Connection Libraries have been defined for Excel Services within SSP SharedServices1.