Monthly Archives: March 2010

Removing the Trainling Slash of a URL

Sometimes I forget those really obvious methods in various common classes. For example, I recently had to write a method to remove the trailing slash for a url (if any). I did not have time to mess about, so I quickly churned out:

private static string parseUrl(string newUrl)
{
    if (newUrl[newUrl.Length - 1] == '/')
        newUrl = newUrl.Remove(newUrl.Length - 1);
    return newUrl;
}

When I got time, I revisited this. The first thing I did was to hunt around to see if there was already a method in the framework for removing trailing slashes of URLs. I thought there might be something specifically, purpose-built for that in either the globalisation or web namespaces. I came up with nada; the big bagel.

So, I thought I’d write something a little more readable (maintainable). And of course – the EndsWith(…) method of the string class. A much more elegant approach than mine. Practically the same, but much more readable:

private static string parseUrl(string url)
{
    if (url.EndsWith("/"))
        url = url.Remove(url.LastIndexOf('/'));
    return url;
}

Recycling an App Pool in Sharepoint

OK. So you may have read somewhere about the little vbs script that lives in c:\windows\system32 called iisapp.vbs, and the fact that this script can be used to recycle app pools

When I first read about this, the first thing I had to work out was exactly which app pool I wanted to recycle. Turns out, for Sharepoint, this is very easily done. Simply open Central Administration, click on the Application Management tab and select Web Application List under the SharePoint Web Application Management heading. This will take you to the following screen, which basically outlines which app pools marry up to your Sharepoint urls. The following figure depicts the Web Application List, with IIS superimposed on top of it.

Now, recycling the app pool for my default Sharepoint web application is as simple as creating a batch file with the following statement:
cscript c:\windows\system32\iisapp.vbs /a “SharePoint – 80” /r

Debugging Inline Code in a Sharepoint Application Page

Steps to take when debugging inline code in a Sharepoint “application page”.

  1. Go to the web.config of your Sharepoint app – usually found here – C:\Inetpub\wwwroot\wss\VirtualDirectories\80
  2. Find the SafeMode element and change the callStack attribute to “true”
    <SafeMode MaxControls="200" CallStack="true" DirectFileDependencies="10" TotalFileDependencies="50" AllowPageLevelTrace="false">
  3. Find the compilation element and change the debug attribute to true
    <compilation batch="false" debug="true">
  4. Open, in Visual Studio, the aspx file to be debugged. Make sure it is the one in your 12 hive, as opposed to one you may have been developing and deploying to your 12 hive. Believe me, this is an easy mistake to make. I once sat for an hour trying to figure out why the debugger would not attach. My dev version was open in VS already and it took that long for the penny to drop, that the page being processed was the deployed version in the 12 hive. Not the one I already had opened in VS, which was the one in my source tree. For good measure, in the Page directive of that aspx page, set the debug attribute to true.
  5. Then, attach the debugger in the normal way. For those unaware, follow these steps:
    • Click the Debug menu and the Attach to Process menu item.
    • Find the process you want to attach to, and click the Attach button. For web development, the process is w3wp.exe. That process is the one that is running under IIS for the application pool under which your site is running. If there is more than one w3wp.exe process running, you can attach to both. This is often the case when you have a workflow running under Sharepoint.

I hope this post saves someone the frustrations of not knowing how to proceed in this scenario.

Developer Tools

I keep forgetting how to dock the Developer Tools in IE.
So, I’m posting this screenshot to always remind me.
No doubt, now that I have posted it, I won’t ever forget.

devTools

While I’m here, a couple of cool things about the Developer Tools.

  • If you click on the CSS tab, the dropbox gives you a list of every CSS file which is applying to the loaded page.
  • The save button lets you save the stylesheet to your hard-drive. This is a bit easier than manually doing so.
  • Each tab has a clear cache button. Saves a trip to the options menu item.

HTML Email from XML via XSLT

download code for post

During the last week, I had to do a really cool task involving the creation of automated e-mail templates dynamically, using various technologies, including XSLT. I am going to set out a simplified version of that task in this post, as the actual work involved workflows within sharepoint – which is very convoluted.

The first step is to come up with an XML file, from which we can infer an XML schema. The XML file will contain elements that provide the dynamic variables which will be read by the XLST stylesheet during the transform.

<email>
    <firstName>dave</firstName>
    <lastName>rogers</lastName>
    <dateOfBirth>12/12/1900</dateOfBirth>
    <address>
        <number>3</number>
        <street>Smith</street>
        <suburb>Darwin</suburb>
        <state>NT</state> 
        <postcode>0800</postcode>
    </address>
</email>

Now that we have our XML file, we can use the command line tool that comes with visual studio “xsd”, which will create an XML schema based on the structure of the XML file that are created above. (I just kept the xml file and xsd file in the root directory of the C: drive, for simplicity sake).
Xsd.exe
A bit of manual tweaking is required. As you can see, one of the elements is a date type (dateOfBirth). So, we need to change the type of that element in the schema file from an xs:string to an xs:dateTime. Also, through a bit of trial and error, I discovered that I needed to make this element mandatory. To make it mandatory, all that is required is to set both minOccurs and maxOccurs attributes of that relevant element in the schema file to 1. This means that the dateOfBirth element must have at least 1 value, and at most 1 value. I have also made the address element mandatory.

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
  <xs:element name="Email">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="firstName" type="xs:string" minOccurs="0" />
        <xs:element name="lastName" type="xs:string" minOccurs="0" />
        <xs:element name="dateOfBirth" type="xs:dateTime" minOccurs="1" maxOccurs="1" />
        <xs:element name="address" minOccurs="1" maxOccurs="1">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="number" type="xs:string" minOccurs="0" />
              <xs:element name="street" type="xs:string" minOccurs="0" />
              <xs:element name="suburb" type="xs:string" minOccurs="0" />
              <xs:element name="state" type="xs:string" minOccurs="0" />
              <xs:element name="postcode" type="xs:string" minOccurs="0" />
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element ref="email" />
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>	

OK. Now is where it starts getting really cool. Download and install Xsd2Code. This is a way cool Visual Studio plugin which creates C# (or VB.NET) classes, that are based on the schema we just created. I’ll walk you through it.

First, create an empty Visual Studio project. Add the schema file email.xsd to the project. As a default behavior, VS creates a DataSet based on the new file. Delete the three files email.Ddesigner.cs, email.xsc and email.xss. They are not required.
Also, go to the Properties window and remove the value MSDataSetGenerator from the Custom Tool property. Again, that would just get in the way.

Now, right-click on the schema file and select “Run Xsd2Code generation”.

Xsd2Code
That will pop up the following properties window:

Xsd2CodeProperties

Have a think about each property. I’d start with the TargetFramework property, as that one can impact the available properties that will be displayed. For my purposes, I was targeting the 2.0 framework, as my client’s SOE was based on .NET 2.0.

When you run the generator, you’ll find a new cs file called email.Designer.cs. For any classes that I found in there, I changed the first letter of the name to upper-case, as per C# convention. I also renamed the file accordingly (Email.Designer.cs).
Now the really, really cool stuff -> lets use it!

I need to create an API which uses this stuff. So, I am adding a class called EmailCreate to the project. This will have the following 2 methods:

  1. CreateEmail ; and
  2. Transform (2 overloads).

I have added a second project in the solution. Just a simple WinForms app. It’s only function, for the purposes of this “tutorial”, will be to display on a form the HTML that will be created using our new EmailCreate API. That’s all we want to see here. The HTML. It will use the API that I have created in the EmailSchema project.
(Note that this is not how one would use the API in the real world. Obviously, you’d use the HTML email in some kind of automated emailing component that takes care of that aspect of things e.g. Sharepoint’s email notification features.)

The key function here is Transform. Basically, this takes 3 inputs and an output. The inputs are:

  1. The email – as created by the CreateEmail method of the EmailCreate class
  2. The xsd schema, which validates the structure of the xml email fragment that gets deserialised from the Email object.
  3. The XSLT stylesheet, which transforms the xml email fragment to the final HTML document.

The output is simply an object which will write the new HTML document to the label on the WinForm.

So where do we get the inputs from?

As mentioned above, the email comes from the CreateEmail method of the EmailCreate class. This is just hard-coded for the purposes of this demonstration.
As can be seen from the following figure, the xsd schema file is embedded in the EmailCreate assembly.

xsd Schema

Embedded Resource in the Assembly

I embedded that file, because it is not meant to change or be tampered with in any way.

I used the following code snippet to retrieve that file as a stream, using reflection:

			//  Get the xsd from the embedded resources of the assembly as a stream.
            Stream xsdStream =
                typeof(EmailSchema.EmailCreate).Assembly.GetManifestResourceStream(
                        typeof(EmailSchema.EmailCreate),
                        "email.xsd"
                        );	

The XSLT stylesheet, on the other hand, is meant to be changeable. Users should be able to choose from more than one stylesheet, depending on their needs, to create the particular email template they require. Templates are able to be added or removed from the XSLT template repository. Here, I have simply retrieved it using an open file dialog. In a real world situation, you would store it in some kind of repository, whether it be a Sharepoint document library or just a directory on a server.

The Transform overload which I chose to use takes Xmlreaders and an XmlWriter as its arguments. The method call looks like this:

            EmailSchema.EmailCreate.Transform(
                XmlReader.Create(emailStream),
                XmlReader.Create(xsdStream),
                XmlReader.Create(xsltFileStream),
                XmlWriter.Create(outputString, new XmlWriterSettings() { Indent = true }));

And voila, one HTML document which you can use as the body of an email message. (It takes a while to perform the transform the 1st time around. So wait a few moments before deciding it has crashed.)

You can download the code for this post here.