Static Versioning in a WebPart EditorPart

Where you put WebPart versioning is something that is up to debate, discussed previously here.

Today a client asked me if it was feasible to construct a custom EditorPart control to display such information in a reasonable manner, so that versioning data could be shown only when modifying the WebPart on the web surface. The code to do this is pretty simplistic, and one can hydrate the versioning either ala Reflection or if desired by using static string literals. Doesn’t really matter.

The first thing is a static method using an HtmlTextWriter consuming two string values representing the version of the WebPart and the friendly name of the product. This could be reflected on within this method if the parameters being abstracted is desired, or supplied when the method is called. I’m just going to use string literals because this is just an example.

[csharp]
public class VersionInfo
{
public static void CreateVersionSegement(HtmlTextWriter writer, string version, string name)
{
var tbl = new Table { HorizontalAlign = HorizontalAlign.Center };
var row = new TableRow { HorizontalAlign = HorizontalAlign.Center };
var versionRow = new TableRow { HorizontalAlign = HorizontalAlign.Center };
var cell = new TableCell { HorizontalAlign = HorizontalAlign.Center, Text = string.Format(“{0}”, name) };
var versionCell = new TableCell { HorizontalAlign = HorizontalAlign.Center, Text = string.Format(“{0}”, version) };
row.Cells.Add(cell);
versionRow.Cells.Add(versionCell);
tbl.Rows.Add(row);
tbl.Rows.Add(versionRow);
tbl.RenderControl(writer);
}
}
[/csharp]

Next, we are going to create a EditorVersionPart superclass that inherits from the EditorPart concrete class. This is the class that will be called from the WebPart superclass, and will leverage the CreateVersionSegement method from above. Because of the class inheritance, we are going to have to implement some abstract inherited methods but are just going to use orthodox filler since we don’t need to implement any sort of behavior for them.

[csharp]
public class EditorVersionPart : EditorPart
{
public string _version;
public string _name;

public EditorVersionPart(string webPartID, string name, string version)
{
Title = “WebPart Versioning”;
ID = string.Format(“MyEditorPart{0}”, webPartID);
_name = name;
_version = version;
}

protected override void RenderContents(HtmlTextWriter writer)
{
base.RenderContents(writer);
VersionInfo.CreateVersionSegement(writer, _version, _name);
}

public override bool ApplyChanges()
{
EnsureChildControls();
return true;
}

public override void SyncChanges()
{
EnsureChildControls();
}
}
[/csharp]

Moving right along, the WebPartSuperClass while inheriting from the WebPart base class also will inherit from the IWebEditable inertface to specify custom editing controls associated with the WebPart control. In the IWebEditable.CreateEditorParts() method we are going to call our custom EditorPart, then supply the requisite string values.

[csharp]
public class WebPartSuperClass : WebPart, IWebEditable
{

public WebPartSuperClass()
{
ExportMode = WebPartExportMode.All;
}

EditorPartCollection IWebEditable.CreateEditorParts()
{
var editors = new List<EditorPart> { new EditorVersionPart(ID, “My WebPart”, “1.0.0.0”) };
return new EditorPartCollection(editors);
}

object IWebEditable.WebBrowsableObject
{
get { return this; }
}
}
[/csharp]

That’s it!

Share

SharePoint WebPart Versioning

WebPart versioning is a discussion that I have with clients, as well as internally, consistently. Largely this is because it can hit sensitive organizational points (if they have a reasonable software development initiative) and is terribly prone to developer opinion. It can rapidly move from a pragmatic to esoteric discussion.

For these reasons, it is challenging to structure a best practice regarding WebPart versioning, since there really is no best practice. However, after presenting some options I think it is reasonable to assume that an organizational best practice can be cultivated and everyone can be happy.

To try to get those gears turning, I am going to fly through at a 10,000 foot view of various problems typically encountered when implementing a WebPart versioning strategy, some approaches, and a base class that I use that leverages one of the discussed version approaches using a display vehicle I like the most.

Before I continue, let me state that the remainder of this post is going to assume strong named/signed assemblies, as well, these assemblies are being stored in the GAC.

Problems with Versioning

Arguably, the most difficult segment to tackle when dealing with WebPart versioning is that the AssemblyVersion attribute tends to be of little use because WebParts can be considered to use static versioning. AssemblyVersion within orthodox managed development tends to be heavily leveraged because it defines an integral number regarding the assembly’s identity. So, why is the AssemblyVersion such an ineffective mechanism to rely on when dealing with SharePoint WebPart development?
There are three main reasons:

Referencing the AssemblyVersion attribute, as managed assemblies in the GAC do, will break if this value changes.

The SharePoint WebPart Description File (.webpart or .dwp) references the AssemblyVersion attribute within the type element in its XML structure. This element consists of a string with type and assembly information about the corresponding webPart element. As a result, any description files already instantiated on a page won’t bind right due to an incorrect assembly version number.

Without modifying the safe controls entries for the SharePoint site, there will be an assembly mismatch when altering the AssemblyVersion number, resulting in a safe control error when attempting to render the WebPart (if already on a page, otherwise it won’t be allowed on the WebPartPage). This can be solved with solution redeployment or manual web.config modifications; however you are following still subject to the same problem as described above so while fixable, isn’t a rational solution.

There are some more issues, most I consider negligible so I won’t go over them; however those are the largest ones.

Versioning Storage

In order to resolve not having a dependency on the AssemblyVersion, a margin of people rely on the AssemblyFileVersion attribute since this can arbitrarily change with little effect on the WebPart. Use of this also provides the same experience as using the AssemblyFileVersion since this value is mutable from VS.NET with nearly the same invocation. As well, for people that are using Reflection in order to hydrate objects with the relevant assembly information, the mechanics are consistent once you have an Assembly object.

Otherwise, static string representation is simple and popular. This involves setting the values of the version and build name within the assembly, a satellite assembly, or from some other arbitrary source. It could be a wide range of objects, even from a tabulated text file, it doesn’t really matter. All that matters is that the version information is read from a source, and that source is not the calling assembly.

Choosing a Display Vehicle

The display mechanisms for versioning vary depending on the organization. I have seen in the majority of projects these four major types:

Toggle the corresponding SharePoint Feature description element prior to the SharePoint solution packaging.

Just format and dump it out to directly out to standard output as part of the control.

Add a new WebPartVerb object to the current instance WebPartVerbCollection with the version information.

Add a new EditorPart to the current instance EditorPartCollection with the version information

Making It Work

As an example, I am going to use the last option, and place my versioning information in an EditorPart object. In order to consistently enforce this across multiple WebPart type projects, a new base WebPart class for subclass use will be defined which contains all the relevant code to handle the versioning. In order to pass unique values for the program name and the version number, the derived class constructor will be used. The approach is similar to using the WebPartVerb approach, and could easily be ported over to that construct if EditorPart  objects don’t really blow your back.

To do this, three different classes are used. VersionInfo contains a static method that renders to standard output the required strings using strongly typed formatting objects. EditorVersionPart inherits from the EditorPart class, and contains two backing fields that are toggled in the constructor. EditorVersionPart calls the static VersionInfo.CreateVersion method to build out the visual representation of the version information. The WebPartBase class inherits from the WebPart, and IWebEditable interface. Regarding the latter of these, its type members are implemented, which call the custom EditorVersionPart class.

As a result of using this class, you will be presented with the following when using it as your base class, demonstrated in a trivial WebPart.

In order to provide the required strings, in the WebPart constructor the desired values are being provided.

As a result, the WebPart class structure will take on the following form:

[csharp]
namespace buenz.SharePoint.WebParts
{
public class VersionDemo : WebPartBase
{
public VersionDemo()
{
_name = “My WebPart”;
_version = “1.0.0.0 (Debug / Checked)”;
}
}
}
[/csharp]

And the related classes to achieve this effect are:

[csharp]
using System;
using System.Collections.Generic;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using midwave.SharePoint.WebParts;

namespace buenz.SharePoint.WebParts
{
public class VersionInfo
{
public static void CreateVersionSegement(HtmlTextWriter writer, string version, string name)
{
var tbl = new Table {HorizontalAlign = HorizontalAlign.Center};
var row = new TableRow {HorizontalAlign = HorizontalAlign.Center};
var versionRow = new TableRow {HorizontalAlign = HorizontalAlign.Center};
var cell = new TableCell {HorizontalAlign = HorizontalAlign.Center, Text = string.Format(“{0}”, name)};
var versionCell = new TableCell {HorizontalAlign = HorizontalAlign.Center, Text = string.Format(“{0}”, version)};
row.Cells.Add(cell);
versionRow.Cells.Add(versionCell);
tbl.Rows.Add(row);
tbl.Rows.Add(versionRow);
tbl.RenderControl(writer);
}
}
}

public class EditorVersionPart : EditorPart
{
public string _name;
public string _version;

public EditorVersionPart(string webPartID, string name, string version)
{
Title = “WebPart Versioning”;
ID = string.Format(“MyEditorPart{0}”, webPartID);
_name = name;
_version = version;
}

protected override void RenderContents(HtmlTextWriter writer)
{
base.RenderContents(writer);
VersionInfo.CreateVersionSegement(writer, _version, _name);
}

public override bool ApplyChanges()
{
EnsureChildControls();
return true;
}

public override void SyncChanges()
{
EnsureChildControls();
}
}

public class WebPartBase : WebPart, IWebEditable
{
public string _name;
public string _version;

EditorPartCollection IWebEditable.CreateEditorParts()
{
var editors = new List {new EditorVersionPart(ID, _name, _version)};
return new EditorPartCollection(editors);
}

object IWebEditable.WebBrowsableObject
{
get { return this; }
}
}

}

[/csharp]

Happy Versioning! :)

Share

Using the Wizard Control In WebParts

The ASP.NET 2.0 WizardControl is pretty awesome, especially if you are building a WebPart that goes through a sequential period of steps while collecting information, either delegating that information to other sources, or aggregating the total data for a computation of some sort. In essence, the WizardControl is a way to build a WebPart that will contain several steps for user interaction by using familiar child controls, such as buttons that leverage the next/previous/final application architecture. I am using it pretty heavily when building form type scenarios when I don’t have the availability of Office Forms Server 2007 since I can accomplish some of the same kind of business optimization through electronic conversion benefits.

As you navigate throughout the net, you will find very little documentation on using the WizardControl outside of how to drag it from the toolbox onto the design surface for a WebForm, which is not particularly useful for control / WebPart developers. Since I had to use the WizardControl recently for my current project, I thought I would save some people the time of researching information and go over how to consume it in a basic WebPart. At the end of this post, you will see how to design the control, wire appropriate control delegates for master step output, as well as how to bind events to the particular buttons to really build a great sequential WebPart. If you are reading this, I am going to assume that you are already familiar with WebPart development, so am not going to go over the WebPart basics, however on the primary sharepointsecurity.com site, here is an article that details how to create a basic SharePoint 2007 WebPart.

First thing is first, and like I said, this post assumes you are familiar with settings up the WebPart class file. If you are targeting your WebPart to consume from the SharePoint WebPart base class, you are going to need a reference in your using statements to System.Web.UI.WebControls since the Wizard class derives from there, so the top of your WebPart class file should have the following references established:
[csharp]
using System.Web.UI.WebControls;
[/csharp]

Once you have the references prepared, you must declare that you are going to use a wizard control. Under class, prepare the following for use:

[csharp]
private Wizard _stepwizard;
[/csharp]

The assignment that you are making is going to be used throughout the rest of the code file for properties, attributes, and event wiring.

Navigate to your CreateChildControls() method in the WebPart class file, which should only currently have base.CreateChildControls() in it in order to ensure that the appropriate child controls are registered on the page by the WebPart.

[csharp]
protected override void CreateChildControls()
{
base.CreateChildControls();
}
[/csharp]

In this method you are going to add the appropriate code to create the Wizard, which can then parse out in the Render method using Control.RenderChildren out of the System.Web.UI namespace which allows the content to be parsed to an HtmlTextWriter object for display on the screen. We will look at this more later, but for a reference it will be something as simple as:
[csharp]
this.EnsureChildControls();
RenderChildren(output);
[/csharp]

Back to the Wizard functionality. In the CreateChildControl method where the Wizard is going to be instantiated from, you are going to perform two major tasks, design the overall Wizard, and design the Wizard steps that build up that aggregate Wizard control. The first thing to accomplish is to create the new Wizard object:

[csharp]
protected override void CreateChildControls()
{
base.CreateChildControls();
_stepwizard = new Wizard();
}
[/csharp]

Once you have assigned the _stepwizard, you can start to set some of the properties of the Wizard object. There are a lot of style properties, control templates, and misc. attributes that you can set for the parent Wizard control, but for the example I am building here is the relevant code to give you an idea of what you can do. Of course, you should design the control to appropriate assimilate into the design of your SharePoint master pages since the default is pretty plain.
[csharp]
protected override void CreateChildControls()
{
base.CreateChildControls();

// Create the New Wizard
_stepwizard = new Wizard();
// Set some general properties
_stepwizard.Width = Unit.Percentage(100);
_stepwizard.HeaderStyle.BackColor = Color.White;
_stepwizard.HeaderStyle.ForeColor = Color.White;
_stepwizard.HeaderStyle.HorizontalAlign = HorizontalAlign.Center;
_stepwizard.BackColor = Color.WhiteSmoke;

// Sidebar Styles
_stepwizard.SideBarStyle.HorizontalAlign = HorizontalAlign.Left;
_stepwizard.SideBarStyle.VerticalAlign = VerticalAlign.Top;
_stepwizard.SideBarStyle.BackColor = Color.LightGray;
_stepwizard.SideBarStyle.ForeColor = Color.DarkGray;
_stepwizard.SideBarStyle.Font.Underline = true;
_stepwizard.SideBarStyle.BorderColor = Color.Gray;
_stepwizard.SideBarStyle.BorderStyle = BorderStyle.Solid;
_stepwizard.SideBarStyle.BorderWidth = Unit.Pixel(2);
_stepwizard.SideBarStyle.Width = Unit.Pixel(200);
_stepwizard.SideBarStyle.Font.Bold = true;
_stepwizard.SideBarButtonStyle.Font.Bold = true;
_stepwizard.SideBarButtonStyle.ForeColor = Color.DarkSlateGray;
// Set the Button Style Properties
_stepwizard.NavigationButtonStyle.BackColor = Color.LightGray;
_stepwizard.NavigationButtonStyle.BorderColor = Color.Gray;
_stepwizard.NavigationButtonStyle.ForeColor = Color.Gray;
_stepwizard.NavigationButtonStyle.BorderStyle = BorderStyle.Solid;
_stepwizard.SideBarStyle.BorderWidth = Unit.Pixel(2);
// Start Button Properties
_stepwizard.StartNextButtonText = “Next”;
_stepwizard.StepNextButtonText = “Next”;
_stepwizard.StepPreviousButtonText = “Previous”;
// Button Finish Properties
_stepwizard.FinishPreviousButtonText = ” Previous”;
_stepwizard.FinishCompleteButtonText = “Im Done!”;
[/csharp]

Now that you have the actual Wizard Control being rendered, it doesn’t make much sense to the user if it doesn’t contain any steps! Therefore, you have to use the WizardStep class in order to make new Wizard steps. There are 5 types of steps that are offered by the Wizard control.

Auto – Wizard controsl how the step is proceeded
Complete – Basically a confirmation page displayed by the wizard
Finish – Contains the finish button, but no next button
Start – No previous button, just the next button
Step – Middle pages in the Wizard, those that have both next and previous

Getting your new steps going is pretty easy, and is really where the rubber hits the road. I am going to make three steps for my Wizard using the below code, named “one”, “two”, and “three”.

[csharp]
WizardStep firstStep = new WizardStep();
firstStep.ID = “One”;
firstStep.Title = “One”;
firstStep.SetRenderMethodDelegate(RenderOne);
_stepwizard.WizardSteps.Add(firstStep);
WizardStep secondStep = new WizardStep();
secondStep.ID = “Two”;
secondStep.Title = “Two”;
secondStep.SetRenderMethodDelegate(RenderTwo);
_stepwizard.WizardSteps.Add(secondStep);
WizardStep thirdStep = new WizardStep();
thirdStep.ID = “Three”;
thirdStep.Title = “Three”;
secondStep.SetRenderMethodDelegate(RenderThree);
_stepwizard.WizardSteps.Add(thirdStep);
[/csharp]

Every property for this seems pretty obvious like the ID and the Title stuff. There are a lot of misc. properties that you can set as well. However, there is one thing that is not entirely clear. What the hell is SetRenderMethodDelegate? SetRenderMethodDelegate from the control class is a great way that you can inject your own HTML code that will be called after the control rendering, therefore allows you to code for each specific Wizard step. For example, I have a method call to RenderOne, which in code I could make something as simple as:

[csharp]
protected void RenderOne(System.Web.UI.HtmlTextWriter output, System.Web.UI.Control Container)
{
output.WriteLine(“Testing Wizard”);
}
[/csharp]

which on the first page would render out the text “Testing Wizard”. Each of the steps could therefore have a delgate call to their relevant output method.
Lastly, the Wizard control has to be added by using the add method from the Controls property.

[csharp]
Controls.Add(_stepwizard);
[/csharp]

After you have the relevant control display in each Wizard step, you have to wire the relevant events into the Wizard. There are a total of six events that you can override to do whatever type of logic that you desire.

ActiveStepChanged – EventHandler delegate
CancelButtonClick – EventHandler delegate
FinishButtonClick – WizardNavigationEventHandler delegate
NextButtonClick – WizardNavigationEventHandler delegate
PreviousButtonClick – WizardNavigationEventHandler delegate
SideBarButtonClick – requires a WizardNavigationEventHandler delegate

You have to make sure you are using the right delegates for whatever event you are trapping and customizing. For example, the OnActiveStepChanged event requires an EventHandler delegate.

[csharp]
public void OnActiveStepChanged(object sender, EventArgs e)
{
}
[/csharp]

Whereas the NextButtonClick event requires a WizardNavigationEventHandler delegate.

[csharp]
public void OnNextButtonClick(object sender, WizardNavigationEventArgs e)
{
}
[/csharp]

When you have everything wired, just RenderChildern in your RenderWebPart or RenderContents method and you are ready to go!

This should have you pretty much all the way with getting the Wizard WebPart up and going. If you have any questions, feel free to post them in the comments and I will try my best to answer them.

Share