New Blog Theme

Jan 07 2008, 08:45 AM By jeffesp; 0 Comments

When I attended CSDC back in October, in the presentations was by Ben Tiedt and Wyatt Lyon Preul they said to make a new theme, start with an XHTML template and throw the CS controls into it to make your theme.  Since I'm not a designer, I googled "website template", went to the first result, and then picked one pretty much at random.  Then I did exactly what Ben and Wyatt said - I opened the default theme so I could copy and paste the CS controls out of it into my template.  It took only a few hours to get it done in the basic form.  I just had the time recently to get back to this theme, and another few hours later (tweaking small stuff), it is running on my blog.  The template is attached to this post if you want it.

Creating an ASP.NET Membership Database for Community Server

Jun 11 2007, 03:52 PM By jeffesp; 2 Comments

With the addition of Morpheus in Community Server 2007, the ability to integrate CS and another ASP.NET site using the ASP.NET membership provider got a lot easier.  A recent KB article details sharing the same login and password data for multiple installations of Community Server.  The steps outlined there are:

  • Install CS multiple times.  One install will be membership master, others are children.
  • Add a connection to the children's connectionStrings.config.
  • Modify the children's web.config.

This is super simple and works great for multiple communities.  To develop an ASP.NET web app and share the login with CS you need to take a few more steps.

The basic steps needed to share a membership database with CS and an ASP.NET application are:

  • Install/deploy your application.
  • Install CS 2007.
  • Take a few stored procedures from CS and add to your membership database.
  • Modify CS connectionStrings.config.
  • Modify CS web.config.
Install Your Application

The key is the application must be configured to use ASP.NET Membership with the System.Web.Security.SqlMembershipProvider (or a custom provider that follows the provider model).  Since I am just testing this out, I used "aspnet_regsql.exe -E -S localhost -A m" as documented to create my membership database.  This gave me a new database named aspnetdb on my local instance of SQL Server.  I then went on to create a web application with two pages - a default.aspx and a login.aspx.  Default tells you whether you are logged in, and Login lets you login.  The zipped project can be downloaded here.

Once that application is configured properly, take note of the connection string and the name attribute of the <authentication> <forms> element in web.config.
Install CS 2007

Nothing special here.  A default installation will work just fine.  You need to remember the application name (the default seems to be 'dev'), admin username, admin email, and admin password you use when installing the application.

Take Stored Procedures from CS 2007

This is where you do most of the work.  We need to execute some CREATE scripts as well as hack together a new one (or copy some data).

Creating the Default Users

Before you can use Community Server with another application, you need to provide the default users that CS assumes are available.  This can be done by modifying an existing stored procedure or by copying data.  I modified an existing procedure - cs_system_CreateCommunity.  I included something like lines 57-66, and 529-580 excluding 544-556 and 570-579.  Anything that dealt with the aspnet_Applications, Membership, or Users tables was included, and everything else was left out.  I then executed this procedure with application name and admin user information that was used when installing CS.

It might be much easier copy the data from another database or use the aspnet_* stored procedures on the membership database.

Copying the cs_Membership_* procedures

Five stored procedures must be copied from the CS database to the membership database - they are the cs_Membership_* procedures that are created during the CS install.  I did this in SQL Management Studio by scripting the SPs as CREATE scripts and then executing them against my membership database.

Modify CS Install

Add a connection string to connectionStrings.config.  Change the name attribute in the <authentication> <forms> element.  Also change the connectionStringName in the <membership> <provider> attribute to match the values of the same elements from your application.

Conclusion

You can now create a user in your 'other' web application and when the visit the community pages of your site, they will automatically be logged in and able to interact just like they created their account on the CS install itself.

Note: I have not yet used this method on a production site, nor have I fully tested it. I cannot guarantee that it will work in all situations. I am relatively confident that it will work fine for any site as CS is using the membership database only for the username and password, and stores everything else in other tables. 

Community Server *_override.config

May 02 2007, 04:56 PM By jeffesp; 0 Comments

Although there have been a couple examples of how to use the *_override.config files in Community Server floating around, I haven't found a good reference on what is available.  Fortunately, Telligent makes the source available for much of the CS platform.  Looking at how these files work resulted in the following longer than expected information.

The first thing that must be recognized is the format of the override file.  The following schema is a rough approximation of what will work. 

<?xml version="1.0"?> 
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    <xs:element name="Overrides"> 
        <xs:sequence> 
            <xs:element name="Override"> 
                <xs:complexType mixed="true">
                <xs:attribute name="xpath" type="xs:string" use="required"/>
                <xs:attribute name="mode" type="xs:string" use="required"/>
                <xs:attribute name="name" type="xs:string"/>
                <xs:attribute name="value" type="xs:string"/>
                <xs:attribute name="where" type="xs:string"/>
            </xs:element>
        </xs:sequence>
    </xs:element>
</xs:schema>

 

The following operations (values for mode) are available to alter attributes within the configuration files.

  1. new

    Creates a new attribute on the node selected with the xpath expression.  The name,value pair of the attribute are specified as name and value in the <Override> element.  If the attribute already exists an exception is thrown.

  2. change

    Replaces the value of the attribute with the one specified in the <Override> element.  The attribute must exist or an exception is thrown.

  3. remove

    Deletes the attribute from the element.  The attribute must exist or an exception is thrown.

The following operations (values for mode) are available to change elements within the configuration files.  They all ignore the name and value attributes in the

  1. add

    The content inserted is the InnerXML of the Override element.  This is the only place that the where attribute can be used, and only one value is valid.  If you specify where="start" then it will be added as the first child of the node selected by the xpath attribute, otherwise it will be added as the last child of the selected node.  It would be nice if the where attribute could also be a xpath expression that would allow the element to be inserted as a sibling at the point selected by the where expression.

  2. update

    Simply replaces the content of the node selected by the xpath with InnerXML of the Override element.

  3. remove

    Deletes all descendent nodes of the selected element.  Be careful with this one as you can remove a bunch of elements without realizing it.

Examples to follow in another post.

ASP.NET Ajax and Community Server

Apr 05 2007, 07:29 PM By jeffesp; 1 Comments

I decided I wanted to use some features from ASP.NET Ajax and the AjaxControlToolkit in my Community Server install.  It was actually relatively simple.  Here's what I did:

  1. Download and install ASP.NET Ajax
  2. Download and build the AjaxControlToolkit.  Install AjaxControlToolkit.dll to GAC (copy to c:\WINDOWS\assembly, or use gacutil /i).
  3. Create a new ASP.NET Ajax WebSite in Visual Studio.
  4. Grab everything from the web.config in the new WebSite.
  5. Merge into web.config in Community Server.
  6. Add the following to the web.config:
<pages>
    <controls>
        <add tagPrefix="AJAX" namespace="System.Web.UI" 
            assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
        <add tagPrefix="AJAXKIT" namespace="AjaxControlToolkit" 
            assembly="AjaxControlToolkit, Version=1.0.10201.0, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e"/>
    </controls>
</pages> 

It really was that simple.  I was able to add a ScriptManager to my master page as required by ASP.NET Ajax and then I was able to add AjaxControlToolkit controls to my page and they just worked.  If you notice the 'Blog Actions' area on the right - you can click it and it will expand.  This is the CollapsiblePanelExtender from the AjaxControlToolkit at work.

(Although this site doesn't quite work with Firefox yet...)

SiteUrls.config for blog only site

Apr 05 2007, 04:17 PM By jeffesp; 0 Comments

There's a lot of info about how to host CS so you have only a single blog and gallery at the top level.  In fact, CS 2007 has a great feature where you can override the default settings in siteurls.config without the file itself. Scott Watermasysk has provided the siteurls_override.config and communityserver_override.config needed to host one blog at the top level. For this current site I wanted to host multiple blogs at the top level.  So I took the default that Scott provided and removed two lines.  The important thing is to know which two lines to remove.  Here's what creates a single blog at top level site:

<?xml version="1.0" encoding="utf-8" ?>
<Overrides>
   <Override xpath = "/SiteUrls/locations/location[@name='weblogs']" mode = "change" name = "path" value = "/" />
    <Override xpath = "/SiteUrls/locations/location[@name='weblogs']" mode = "new" name = "physicalPath" value = "/blogs/" />
</Overrides> 

This is the first line removed:

<Override xpath="/SiteUrls/transformers/add[@key='##blogdirectory##']" mode = "change" name = "value" value = "" />

It changes the transformer named ##blogdirectory## so it doesn't do anything.  The default for this is to add the blog path to the value being transformed.  For a single blog at the root, this is what you want.  Without this line the path to the blog would contain things like 'jeffesp'.  Obviously this is behavior that I needed, so I removed it.

The second line removed:

<Override xpath = "/SiteUrls/locations/location[@name='weblogs']" mode = "change" 
   name = "type" value = "CommunityServer.Blogs.Components.SingleBlogLocation, CommunityServer.Blogs" />

This changes the url rewriter for the blog location.  Instead of doing looking up the blog and figuring out the url from there, all the SingleBlogLocation url rewriter does is grab the ApplicationKey for the blog and insert it in the path between the site base path and whatever blog page is being requested.  An example will make this clearer:

If I were to request http://blogs.atgi.com/default.aspx and my blog application key is jeffesp, with this override in place, the request would come across (to the rest of the CS system) as http://blogs.atgi.com/jeffesp/default.aspx because jeffesp would be added to it.

Client Side Syntax Highlighting

Apr 03 2007, 01:54 PM By jeffesp; 1 Comments

A little while ago, I found a client side syntax highlighting library because I was using blogger.  Since I am now using a community server install, I wrote a CS Module that allows you to enter code in a post and the dp.SyntaxHighlighter library will be used when the post is rendered.  The previous post here gives an example of all languages supported (Not anymore, since I quit using the js to highlight code, and started using Windows Live Writer).

I know that if you use FreeTextBox in CS then this functionality is already available, but I wanted to continue to use TinyMCE.

Download the module.

CS: Date Chooser TinyMCE Plugin

Mar 30 2007, 08:15 PM By jeffesp; 0 Comments

The calendar component for Community Server is great.  It allows the integration of the forum posts and calendar events.  You can create an event about about the "Party at Joe's" and then the discussion of who brings the party supplies can occur on the forum.  Dan even provided an extension to FreeTextBox that enables a date chooser dialog.  The only issue is that CS now uses TinyMCE as the editor and the latest version of FTB so that Dan's extension no longer works.  So I created a Date Chooser plugin for TinyMCE to solve this problem.

Download it here - see Readme.txt for install instructions.  Read on for some implementation details.

Since I needed a modal dialog just like the content selector in CS I started by copying and renaming the directory for that plugin.  I also copied the image for the date picker out of Dan's FTB extension.  Once armed with these two pieces of the puzzle I did the following.

Edit editor_plugin.js to refer to DatePicker instead of ContentSelector where relevant and change the implementation of the open and addContent methods in the date picker class.  The code looks like this:

execCommand : function(editor_id, element, command, user_interface, value) 
{ 
    switch (command) { 
        case "csDatePicker": TinyMCE_DatePickerPlugin._openDatePicker(editor_id);
        return true; 
    } // Pass to next handler in chain 
    return false; 
}, 
_openDatePicker : function(editor_id) { 
    TinyMCE_DatePickerPlugin._currentEditor = tinyMCE.getInstanceById(editor_id);
    TinyMCE_DatePickerPlugin._currentBookmark = this._currentEditor.selection.getBookmark();
    Telligent_Modal.Open('/calendar/MCEDatePicker.aspx', 400, 250, this._addContent);
}, 
_addContent : function(content) 
{ 
    if (content != null) 
    { 
        TinyMCE_DatePickerPlugin._currentEditor.selection.moveToBookmark(this._currentBookmark);
        TinyMCE_DatePickerPlugin._currentEditor.execCommand("mceInsertRawHTML",false, content); 
    } 
}
The main things to note are line third line of _openDatePicker and last line of code in _addContent.  The modal dialog is loaded in the _openDatePicker method with a size and a callback of the _addContent function.  In the _addContent method we actually take the content from the dialog and insert it in the editor pane of the current post.

MCEDatePicker.aspx is not very interesting.  It contains a Generic control that loads the MCEDatePickerModal.ascx skin.  This file is much more interesting. The first thing to examine is the markup:

<div align="center" style="padding: 10px">
    <CA:Calendar runat="server" ID="Calendar1" SelectedDate='<%# DateTime.Today %>'
        CalendarCssClass="calendar" DayCssClass="day" DayHoverCssClass="dayhover"
        SelectedDayCssClass="selectedday" ShowNextPrev="true" 
        NextImageUrl='<%#CommunityServer.Components.Globals.GetSkinPath() + "/images/calendar/next_wht.gif" %>' 
        PrevImageUrl='<%# CommunityServer.Components.Globals.GetSkinPath() + "/images/calendar/prev_wht.gif" %>'> 
    </CA:Calendar> 
</div> 
<div align="right"> 
    <asp:Button ID="bSelect" runat="server" Text="Select Date" OnClientClick="ReturnDate()" /> 
    <asp:Button ID="bCancel" runat="server" Text="Cancel" OnClientClick="window.parent.Telligent_Modal.Close(null);" /> 
</div>

This code displays a ComponentArt Calendar control and a couple buttons that act on the control.  We end up with this modal dialog that allows you to pick a date from the calendar view.

The _addContent callback implemented above will run when the modal dialog is closed. It is closed with the following code which is renedered to the client as the page is loaded:

function ReturnDate() 
{ 
    var newDate = Calendar1.ClientID.FormatDate(Calendar1.ClientID.GetSelectedDate(), '[cal]MM-dd-yyyy[/cal]'); 
    if(newDate.length > 0) 
        window.parent.Telligent_Modal.Close(newDate); 
    else 
        window.parent.Telligent_Modal.Close(null); 
} 

As you might guess when looking at this code Calendar1.ClientID doesn't exist in the client code. This bit of javascript is dynamically created on the server and registered as a script block using the ClientID property.  The key thing to note in this code is the call to the Telligent_Modal.Close() function.  When called, this will in turn run the callback specified for the modal when it was opened - inserting the date into the editor.

The last piece of the puzzle requires adding the calendar button to the interface.  Part of this is setup in editor_plugin.js and part of it is done by changing the skin used for the editor.  In the Editor-Standard and Editor-Enhanced skin files, the 'datepicker' plugin was added to the plugins and theme_advanced_buttons1_add options on the editor control.

Many thanks to my employer (ATGi) since I developed this on work time.

Community Server 2007 Themes - Part 3

Mar 22 2007, 05:37 PM By jeffesp; 0 Comments
The first thing you encounter when you load the default community server site is the home page.  This is mainly controlled by the "main" master page with a couple small changes in the "home" master page.  I want to pick apart one portion of the header in the "main" master page and make a small change to it in my process of learning about themes in CS 2007.
Master.Master

The header and footer have all kinds of content specified that will show based on various configuration values and conditions.These serve as a great introduction to the new capabilities in CS 2007. Look at the CommonTitleBarSearchArea <td> in the header. This section is a great introduction to the new controls implemented in CS 2007.First we have a user control:

<div class="CommonUserArea">
    <div id="welcome">
       <CSUserControl:UserWelcome runat="server" />
    </div>
</div>

Nothing special is going on here.Continuing in the code, we have the beginning of the search form control.The properties of the control are mapped to the other controls on the page.

<div class="CommonSearch">
    <CSControl:SearchForm runat="server"
       QueryFilterDropDownListId="TitleBarSearchDropDownList"
       QueryTextBoxId="TitleBarSearchText" 
       SubmitButtonId="TitleBarSearchButton"> 
 

The SearchForm is not limited to a static layout - the FormTemplate portion begins by laying out a table:

<FormTemplate>
    <table cellpadding="0" cellspacing="0" border="0" align="right">
       <tr valign="middle"> 
 

And then it continues by defining two controls in the first <td>.Those controls are the text box for the search, and an ASP drop down list.The things to note here are the following:     The ids match the declaration in the SearchForm control.  There is a PlaceHolder control wrapping the drop-down list.  Its purpose is to control the visibility of the drop-down. The ResourceControl control is going to pull the text that it displays from the specified resource name in the current resource culture.The TitleBar_SearchIn element in resources.xml for the current culture provides the values for the drop-down list. I am not sure how exactly the resource values are tied to the drop-down list.

<td nowrap="nowrap">
    <CSControl:DefaultButtonTextBox ID="TitleBarSearchText" runat="server" 
        Columns="15" MaxLength="64" ButtonId="TitleBarSearchButton" />
       <CSControl:PlaceHolder runat="server">
          <DisplayConditions>
             <CSControl:ControlVisibilityCondition 
                 ControlId="TitleBarSearchDropDownList"
                 ControlVisiblilityEquals="true" runat="server" />
          </DisplayConditions>
          <ContentTemplate>
             <CSControl:ResourceControl runat="server" 
                 ResourceName="TitleBar_SearchIn" />
             <asp:DropDownList runat="server" ID="TitleBarSearchDropDownList" />
          </ContentTemplate>       
    </CSControl:PlaceHolder>
</td> 

The next table cell is a little simpler it only has the search button in it.Again, note the matching id, and that the link button is using the culture to provide internationalization of the Search text through the resources file.

<td>
    <span class="CommonSearchButtonOuter">
       <CSControl:ResourceLinkButton ID="TitleBarSearchButton" runat="server"
         CssClass="CommonSearchButton" ResourceName="Search" />
    </span>
</td>

In these few lines of code there have been a number of new things that have a great deal of power behind them. Some of them are:

  1. The ability to control visibility through DisplayConditions,
  2. The ability to provide your own templates for standard controls like the template for the search in the SearchForm.
  3. And the ability to declare controls that pull the text presented to the user from the Resources file which will provide for an internationalized interface.
Making a Change to the Search Box

If you wanted to display the search box only for registered users when they are logged in, you could do something like what I would do in ASP.NET - add some code that executes on databinding for the Visible property of the control.  It would need to get an instance of the user object and check its roles attribute. But CS provides a better way - we alreadly looked at it - the <DisplayConditions> element of a CSControl.  Adding this snippet of code:

<DisplayConditions>
    <CSControl:UserInRoleCondition Role="Registered Users"
      UseAccessingUser="true" runat="server" />
</DisplayConditions>
 

will make it so the search is only available to member. This is so easy.

Moving Forward

This is the end of my initial investigation into CS 2007 themes.  I am planning on continuing this work by creating a theme (even though I am no designer) and moving away from Blogger to a new site running CS with that theme.

Community Server 2007 Themes - Part 2

Mar 22 2007, 02:19 PM By jeffesp; 0 Comments
Master Pages

The initial intent of this post was to show diagrams of the Main, Blogs, Files, Forums, and Photos master pages in Community Server 2007 (in the style of this post).  I find a visual representation of the page is very helpful to me so I took some time to investigate the layout of the pages and create diagrams. As I dug into the new master pages I found the main pages for the Blogs, etc. are not very interesting.  Each page basically added the main content (such as the forum list) and a few items in the sidebar.  These are all obvious looking at the rendered page.  So I want to spend most of this post dedicated to the Main master page.

Main

Changing my diagram from CS 2.1 to match CS 2007 results in the following:

The first thing to note is this is an ASP 2.0 Master page.  Community Server is .Net 2.0 only, instead of allowing .Net 1.1 or 2.0 deployment like CS 2.1.  Differences between the new and old seem to be minimal once you are past the use of ASP master pages instead of the custom master pages.  The following image is a comparison of the two pages.

The change that sticks out in this comparison is the addition of a placeholder around the left and right content regions. Since CS 2007 allows for three different site layouts (3 column, 2 column with left for main content, 2 column with for main content), the other main changes to the main master page support this using the placeholders. Looking at this diagram it seems like there really isnt much change the body table is really only missing two <td> elements one for the right column and one for the left.But the real change is actually at the top of the file in the Page_Init method. It adds the missing <td> elements based on the configuration. One thing to note is that the left content renders above the right content when configured for either 2 column mode.

Blogs

Since the Blog main page wasn't very interesting, I went to look for an individual blog master page.  What I found here wasn't entirely surprising.  Each blog theme has a master page, and a whole set of styling information.  The dynamic style aspx that I talked abut in my last post is used here as well. 

The main difference in 2007 is in the number of files that need to be changed to create a theme - it looks like you can create a theme in 10-12 files including a preview image for the control panel and a print CSS.  Ben Claims 8 files are all you need - I got my number from inspecting the distributed themes.  My guess is this is a difference in number of files required to make a theme, and the number that make a theme with extra images, etc.  Either way, it is still a huge decrease from the 55 that were a part of the theme in CS 2.1.

Community Server 2007 Themes Part 1

Mar 20 2007, 09:06 PM By jeffesp; 0 Comments
I am currently learning about the new theme system (Chameleon) in Community Server 2007. There are a number of good resources on this around the web. I hope that this will be one more. I am going to start with the basic theme capabilities and the layout of the site, and then move to the more complex portions of Chameleon as I encounter them.

Theme Creation


Themes have changed quite a bit in CS 2007. The first thing that you run into with the themes is the new interface in the Control Panel to change the theme. To have a style to work from, I picked my corporate site (ATGi). I was able to change the CS site from the default theme to something decently close to our corporate site with only a few minutes work. The steps I followed were outlined on Ben Tiedts Blog. All that I had to do was enter the color codes I pulled from the source site in the right place, save, and preview my changes. As the last step, Ben tells us we need to update theme.config but doesnt tell us why. I am going to guess one reason is the default values are used for the "reset to defaults" function in the theme configuration section of the control panel.


It looks like the CS developers took the path of making the easy things easy and the difficult things possible with this update to the theme system. I dont know if they will come through in the screenshot, but the bullets in the right content area are still the default themes dark green.
In order to change them I needed to:
  1. Find the CSS class for the bullets,
  2. Find that class in Common.css,
  3. And then add the right content to the CSS Overrides configuration area of the theme.

Heres what I added to the theme to change the bullets:

UL.CommonSidebarList LI{color: #c54545;}

Since the CS developers couldnt predict what users want to change, they provided a method to change pretty much any part of the site without violating the idea of managing the theme through the Control Panel. Just by the addition of that one text area, they have made it so I should never touch the base CSS files again.

Theme Application

So far we have a good start, but there are some things going on behind the scene to get the changes made to the theme applied to the site. What follows is a summary of some of that information. I am not sure any of this information is necessary when creating a theme but it is useful to know how changes in one area propagate through the system.
Theme changes made in the Control Panel interface are saved to the Community Server database in the cs_ThemeConfigurationData table. It looks to be stored as a list of property names and a list of property values. I assume there is deserialization code and/or a data provider for this information. (Side note: There is also a cs_ThemeConfigurationData_TEMP table that I can only assume is used for the "Live Preview" function). To see where this data is used we need to look for is the stylesheets that are applied to the site. If we look in the main master page for the theme (master.Master), we see the following:

<CSControl:Style runat="server" visible = "true" />

<CSControl:Style runat="server" visible = "true" href="../style/Common.css" mce_href="../style/Common.css" />

<CSControl:Style runat="server" href="../style/common_print.css" mce_href="../style/common_print.css" media="print" />

<CSControl:Style runat="server" href="../style/DynamicStyle.aspx" mce_href="../style/DynamicStyle.aspx" EnsureNotCachedOnPreview="true" />


The first three lines look pretty standard to any web developer they are the inclusion of some styling information for the screen and for print. The last one is the interesting one. An aspx page is specified as the file containing the styling information. Looking at this file, we see the clever thing done to apply the information saved in the theme. Each CSS class is defined with some server side code. When it executes, it will pull information from the theme data (with an optional default). Heres the body/html class:

body, html

{


background-color: <%= ColorTranslator.ToHtml(ThemeData.GetColorValue("siteBackgroundColor", ColorTranslator.FromHtml("#606060"))) %>;

background-image: <%= UrlOrNone(ThemeData.GetUrlValue("siteBackgroundImage", null))%>;


}


The background color and image are loaded with the ThemeData.Get*Value() methods. Without access to the code I cant say for sure, but my guess is the provider for the theme data first tries the database, and failing that uses any defaults specified. I also cant say where or if the defaults provided in theme.config are used in this process. The ThemeData is an instance of the Telligent ConfigurationDataBase class, which has Get/Set methods for some of the basic types (int, bool, string, object), some more complex types (DateTime, Guid), as well as some interesting web specific ones (Url, Color).

Next Time

I am going to go through the master pages and see what is going on with them. I hope to create a set of diagrams like in my last post on Community Server, but one for each section of the application (home, blogs, forums, etc).

Windows Explorer FTP

Mar 20 2007, 08:10 PM By jeffesp; 0 Comments

Uploading a new site to an FTP server is fun.  Here's what we do:

  1. Login to the site through Windows Explorer,
  2. Select all files on local staging server,
  3. Copy files to server.
  4. Wait (copy dialog is telling me estimated 2 minutes),
  5. Wait (copy dialog is telling me estimated 5 more minutes),
  6. Wait (copy dialog is telling me estimated 6 more minutes),
  7. Cancel Transfer.

I must have waited at least 30 minutes for the transfer to complete.  The estimated times are total lies.  Here's the solution to the problem:

  1. Google "FTP Client",
  2. Download FileZilla,
  3. Install,
  4. Login to FTP server,
  5. In the Transfer menu, select Overwrite > Overwrite If Newer
  6. Select latest files,
  7. Copy files to server,
  8. Wait ~5 minutes for transfer to complete.

The right tools make all the difference.

Master Pages in Community Server

Mar 09 2007, 08:18 PM By jeffesp; 0 Comments

I have been working on small Community Server project and learning a bit about the way they do things.  The problem I needed to solve a couple days ago dealt with the requirement that some content show up on all pages in the system.  This seems like a no brainer - just add some content to Master.ascx in the current theme and be done with it.  The issue is the definition of all.  If I add content to the main master page, it will show up on every single page including pages like login and logout.  This was not the intent of the requirement even though it was the wording of the requirement.  So I needed to add this content to the all* pages.  Where the * implies the content doesn't show up on pages where it does not make sense.  Faced with the option of adding the content to individual pages or individual master pages, which would be a maintenance pain, I came up with the following solution.

  1. Add a new CS:MPSection to Master.ascx; give it the id "rcrcommon".
  2. Create a new master page - call it RightContentMaster.ascx.  RightContentMaster has the shared content on it and uses Master.ascx as its master page.  The shared content is in a CS:MPContent control with the id "rcrcommon".  I changed HomeMaster, BlogMaster, ForumMaster, etc. to use RightContentMaster as their ThemeMasterFile.

This allowed pages that rely solely on Master.ascx for layout to continue to function and display as they always have, but added my new content to the rest of the pages in the system.  The reason this works is the inheritance of the master pages that CS has provided and the way I was able to insert my new master page into that rendering pipeline so only the pages I need get the content, but it is on 90% of the pages in the site.

I decided I needed to know more about how the master pages in CS work and how I can work with them.  I started by reading Jeff's overview post on this topic to get a baseline for what is going on with the system:

The most common base implementation of a master page is of 3 sections called 'lcr' (left side content), 'bcr' (body content, and 'rcr' (right side content). You can either define controls for every descendent page in these sections in the master page, or override master page content by declaring CS:MPContent controls with these ids on your aspx page. Skins should not implement these content controls. For example, if you wanted to understand how each thing is showing up on default.aspx, you would open default.aspx and find the 'ThemeMasterFile' attribute on the page level CS:MPContainer control. If you navigate to the HomeMaster.ascx file you'll see that the only thing being added here are some style includes in a "HeaderRegion", and the 3 content sections.

Jeff tells us that a page using a master file has two important things it can do.

  1. "define controls for every descendent page in these sections in the master page"
  2. "override master page content by declaring CS:MPContent controls with [the same] ids on your aspx page"


Looking at Master.ascx in CS, we find a page with the following layout:

The regions highlighted in blue are the ones most often changed, but there are a bunch of things that can be done with this layout including changing headers and footers and even adding content outside of the page form.

Armed with this knowledge, I made the changes outlined above.  An updated diagram of Master.ascx looks like this:

My RightContentMaster page overrides the rcrcommon content area to add my content to most of the pages.  Here are the advantages of this method as I see them:

  1. I can control the pages where this content is shown by switching between RightContentMaster.ascx and Master.ascx as the base ThemeMasterFile.
  2. I only have one place to edit this content (RightContentMaster.ascx).
  3. If I ever need to change the content on a page I should be able to override the rcrcommon section with a new one.

The main disadvantage that I see is the need to change other master pages to use RightContentMaster.  If anyone has any thoughts on this way of doing things, I would love to hear them.

Symbolic Links (Junctions) for NTFS

Mar 06 2007, 05:20 PM By jeffesp; 0 Comments

This isn't anything new, but Sysinternals (now owned by Microsoft) released a tool called junction that allows creation of symbolic links in NTFS.  If you aren't familiar with symbolic links, they are a Unix concept that makes a file or directory look like it resides in one place on the file system, when it really is someplace else.  This in itself isn't worth a blog post, but I think one thing that I recently did with it was pretty neat and wanted to write it up. 

I regularly use about 3 different computers.  Because of differences in hardware configuration the drive letter for my flash is different at each location.  So I created a new directory - C:\flash\ - and then created a junction (symbolic link) pointing that directory to drive letter of my flash.  I see two benefits here.  One is that I don't have to remember what system I am on, and can just hit C:\flash whenever I need something from my drive.  The second advantage is that any programs I run from my flash can have a absolute path to C:\flash for any data they need.

I have also added C:\flash\bin to my profile PATH so any utilities I have saved to my flash are only a <windows key>+r away.

Next up is moving C:\Documents and Settings\ to another drive and creating a junction to point to it so I can blow away my install drive whenever I want and not worry about loosing any data.

Errors when Running VS 2005 Unit Tests

Nov 30 2005, 07:57 PM By jeffesp; 0 Comments
[To keep things on the up and up: I am using beta software and it looks like this is fixed in the release. I am still going to complain because I am still using the beta so I can integrate with Team System.]

Here's a fun one. When you go to run tests in VS 2k5 occasionally an error dialog pops up. The text of the dialog says "Operation is not valid due to the current state of the object." Here's a screenshot:

error dialog box

As if there is only ever one object that has state. And I know which object that is, and how to fix things.

So, how to fix this problem - delete your ProjectName.suo file. First close VS, then delete it, then open your project again. The .suo is regenerated, and you can then run the test. Here is where I found the solution (with thanks to Jeff G. for help on this one.)

Swap Control and Caps Lock

Nov 30 2005, 02:31 PM By jeffesp; 0 Comments
I come from a Unix background. Therefore, I like my control to be where caps lock normally is. And just so it's still available, I like caps lock where control is. This is commonly referred to as swapping control and caps lock. Sun does this all the time. Or at least used to. It's been years since I used one of their systems. On a windows system, this can be accomplished by swapping the functionality of the keys. This page has all the details you need. Summary for the lazy:
Add a binary registry key called "Scancode Map" at
"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout" with the value of "00000000 00000000 03000000 3A001D00 1D003A00 00000000".

Anyhow, swapping the functionality of these two keys does a few things.
  1. Reduces the distance my pinky travels to hit the control key. I used to use Emacs all day everyday - when you do that, it's essential that the control key is easily accessible. Even in a Windows world, it's still kind of nice since a lot of shortcuts use the control key.
  2. Reduces the number of times that I mistakenly hit the CAPS LOCK KEY AND END UP WITH A BUNCH OF TEXT IN ALL CAPS.
  3. Causes other people grief when they try to use my keyboard and end up with a 'S' in their document when all they wanted to do was save something by hitting 'Ctrl+s'.
  4. Causes me grief because Remote Desktop is crap.

Just so we are clear here, I am talking about the control key at the bottom left of the keyboard. It's the only one I ever use. The one on the right side might as well not even exist.

More Posts Next page »