Tuesday, June 7, 2011

Intro To .net Rx Extensions

Attached is the presentation and the code used in the ODNC presentation on June 6, 2011.

Visual Studio Code and presentation.
Intro To Rx Extensions Presentation

Monday, January 24, 2011

Ottawa IT Camp 2011 is scheduled

I am looking forward to Ottawa IT Camp (previously called Code Camp) 2011 scheduled for Saturday, April 16, 2011. 

IT Camp is a one-day training event for developers, database administrators and IT people.

We will be there to talk about some topic in Jetfire.

Wednesday, November 24, 2010

Building an Admin Panel using Web Parts Presentation

Today I presented this topic at the Ottawa Dot Net Community.  Good turn-out with about 20 people.  This was a one-hour lunch-time presentation.

The agenda covered:

  • Web Parts Overview
  • Admin Panel mini-spec
  • Admin Panel Code Demo

The overview is a series of slides in the PowerPoint presentation providing a quick summary of Web Parts from Personalization tables to Zones for browsing, editing and catalogs.

The mini-spec is a one page summary of the key points for the Admin Panel (see slide 14).

Let’s Code

Finally the last 35 minutes looked at the key design issues and how to solve them in code:

  • Instantiation vs Reflection
  • Only display the active Web Part
  • Initializing the Panel

In designing an Admin Panel, I am adamant that labels on the user interface be totally customizable. This means that the labels not only map to the Web Part properties, such as Title, but also track personalization changes that a customer makes to a Web Part. 

Instantiation creates objects where the properties have default values. Reflection tries to find the Web Part on the page and use the values saved in the Personalization database.

When there over three Web Parts on an Admin Page, it is important to hide the Web Parts that are not in use. I call this a “Point, click, Use” interface.  Point the mouse at the link for the web part that you want to use. Click the link. Use the Web Part that appears on the screen.  There should only be one Admin Web Part visible on the page.

Finally the panel is initialized when we use reflection to create Web Parts. This means that the first time that the page is displayed, all Web Parts are automatically added to the page.  We are ready to customize them.

Slides and sample Demo Admin Panel Web Part code are included.

Contents include:

  • PowerPoint slides
  • DemoAdminPanelWebPart.cs
  • L.cs (a collection of useful statics for manipulating Web Parts)

Tuesday, November 23, 2010

Jetfire Version 1.3

This new version of the dynamic programming language Jetfire (available for download on Codeplex) provides a number of new features and improvements.  To provide these new features and improvements a new expression parser has been written to employ Linq expression trees.   Version 1.3 contains both the new expression parser and the original expression interpreter.  This allows the original expression interpreter to be used by simply changing a setting should any problems be encountered.

Version 1.3.x will provide the following:

  1. Improved Performance
    The expectation over the next few releases is that performance of the Jetfire code will be close to that of C#.   Jetfire version 1.3.0 is already 2x faster than V1.2.x.  Benchmarks on parts of the expression parser that are still in lab indicate performance parity between C# and Jetfire.  This is an ambitious, perhaps even outrageous,  goal for a dynamic language.  We do have a high degree of confidence that we can meet this goal.
  2. Duck Typing:
    Version 1.3.0 now supports ‘duck’ typing.   This provides a very simple alternative to Interfaces.   Jetfire ‘duck’ typing will be enhanced in coming releases with a simple, yet effective construct that will aid in compile time checking and  auto complete (intellisense) for IDEs such as Visual Studio.
  3. Dynamic operators:
    Operators can now be dynamic.  For example the following is valid Jetfire code.
    string s = Add(“my”, “string”);
    int i = Add(1, 6);

    public object Add(object a, object b)
    {
        return a+b;
    }
  4. ReadOnly objects:
    Now complete objects can be made ‘read only’ which compliments the existing ‘read only’ property functionality using roles.   With release 1.3.0 the first use of a ‘read only’ object is ‘Empty’; however with future updates it will possible for objects to be dynamically ‘read only’ based on roles.   This will allow an object to be ‘read write’ by, for example the object owner, some users can only read the object and while other users have no access at all to the object.   When a read only object is used an exception occurs if an attempt is made to write a ‘read only’ object.
  5. Improved Void Safety
    Void safety has made a step forward as all objects are automatically assigned the ‘read only’ ‘Empty’ object instead of null.  It is still possible to assign objects to null (and still get the dreaded ‘null object exception’), but the ‘Empty’ object greatly enhances void safety.  ‘Empty’ objects can be created programmatically via Jetfire software, otherwise they are automatically created.
  6. Easy Reflection:
    The plan is to add a very simple mechanism to support calling methods (very simple delegate mechanism) and creating new workflows based on string variables.  For example:
    string s = “MyMethod”;
    Call s();
    Or
    string s = “MyClass”;
    MyClass myClass = new s();

Monday, October 25, 2010

Auto-generate Documentation for Web Parts

As a designer, I constantly struggle with the time required for designing great software programs and writing user documentation that helps people understand how to use the program. [Some people argue that if it’s a great program, it doesn’t need documentation, but I know that even the brightest users often need a push in the right direction for how to get the most out of the product.]

I am particularly interested in auto-generating documentation for Web Part Properties. The CMS Admin Panel got me thinking about this problem. The Admin Panel needed an Admin Help Index – a list of the Web Parts in the Admin Panel, who can access them and a short summary of what they do. Since this information is readily available in the Web Part itself, I decided to auto-generate this documentation.

Auto-generating the Admin Help Index

I auto-generated the Admin Help Index in a Web Part using the following algorithm:

// Order the Web Parts in alphabetical order
WebPart[] webParts = new WebPart
[mgr.WebParts.Count];
mgr.WebParts.CopyTo(webParts, 0);

IEnumerable<WebPart> parts = webParts.OrderBy(x => x.DisplayTitle);
foreach (WebPart wp in
parts)
{
IAdminRole admin = wp as IAdminRole
;
if (admin == null
)
continue
;
C.AddBreak(2, this
);
C.AddLabel(String.Empty, "Title: " + C.AddStyle2H3(wp.DisplayTitle), Unit.Empty, this
);
C.AddBreak(1, this
);
if (admin.AdminRole != String
.Empty)
{
C.AddLabel(String.Empty, "* Roles required to access: " + admin.AdminRole, Unit.Empty, this
);
C.AddBreak(1, this
);
}
C.AddLiteral("* Description: " + wp.Description, this);
}

Code Snippet 1: Generate an Admin Help Index
Some notes about the algorithm used in Code Snippet 1:
  1. Use the WebPartManager to find all Web Parts on the Page. The Admin Panel is on a page that contains all Web Parts indexed from the Admin Panel.
  2. Using LINQ, order the Web Parts alphabetically. In this case, I used the DisplayTitle property as the key.
  3. The ‘IAdminRole’ interface is used in Web Parts to identify the none, one or more roles that can access the (admin) Web Part. This comes in handy in filtering out the Admin Web Parts on the page. [There are other Web Parts on the page used for image header and navigation menu.]
  4. Format the output as shown below.

Title: Assign Roles to CMS User
* Roles required to access: WebMaster,Admin
* Description: TrackerRealm Assign Users Web Part assigns roles to a user.


The Admin Help Index uses Web Part Properties: DisplayTitle, Description and the IAdminRole interface to create a help index.

Auto-generating Documentation for Web Part Properties

Auto-generating Documentation for Web Part properties needs to use reflection to find the properties for the Web Part (because we only have the base class). I decided to write a Web Part for auto-generating documentation for Web Part Properties. This allows me to dynamically add the Web Part to a page and change the default property values.Here are the requirements for the AutoGenWebPart:
  • Accept input from the query string for the type of Web Part requested.
  • Generate a header and list of properties showing each display name, description and default value, if used.
  • Output the documentation in html for display on a web page, plain text, or wiki, for inclusion in a wiki.

Query String input

/// <summary>
///
Gets and Sets the format that the documentation is output: wiki, text, html
/// </summary>
[Category("Display"), Browsable(true), Personalizable(PersonalizationScope.Shared),
WebDisplayName
("Output Type"), DisplayName("Output Type"),
Description("Describes the format that the documentation is output: wiki, text, html.")]
public OutputType
OutputType
{
get { return this
.op; }
set { this.op = value; }
}

Code Snippet 2: Sample Property for a Web Part Property

The property in Code Snippet 2 shows the Display Name and Description used in the documentation. This is meaningful to the user because the Web Part editor displays the Display Name for each Property.
string wpType = this.Context.Request.QueryString.Get("name");
if (wpType == null
)
this.OutputText("No request received");
Type type = System.Web.Compilation.BuildManager.GetType(wpType, false);
if (type == null
)
this.OutputText("Cannot find " + wpType);
WebPart wp = Activator.CreateInstance(type) as WebPart;
if (wp == null
)
this.OutputText(wpType + " is not a Web Part");

Code Snippet 3: Create the Web Part
The first step in the Web Part is getting the requested (type) name for the Web Part from the query string. If there is no parameter for ‘name’, then the user receives no output ("No request received").

With a text version of the type present, we can use reflection to get the Class and then create an instance of the class. If the type is not a Web Part class, then the user receives no output ("Cannot find " + wpType).

Auto-generate the Documentation

sb.AppendFormat("{0}{1}{2}{3}", this.h4s, wp.Title, this.h4e, this.br);
sb.AppendFormat(
"{0}Description{1}: {2}{3}", this.bs, this.be, wp.Description, this
.br);
sb.AppendFormat(
"{0}Properties{1}{2}", this.h5s, this.h5e, String
.Empty);
sb.AppendFormat(
"Properties are listed alphabetically{0}", this.br);
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(wp);
PropertyDescriptor[] props = new PropertyDescriptor
[properties.Count];
properties.CopyTo(props, 0);

IEnumerable<PropertyDescriptor> pds = props.Where<PropertyDescriptor>(x => x.Category == "Display")
.OrderBy(x => x.DisplayName);
// Sets an PropertyDescriptor to the specific property.
foreach (PropertyDescriptor p in
pds)
{
switch (p.Name)
{
case "Title"
:
case "Description"
:
continue
;
}
sb.AppendFormat(
"{0} {1}{2}{3}: {4}{5}", this.star, this.bs, p.DisplayName, this.be, p.Description, this
.br);
object
o = p.GetValue(wp);
if (o == null
)
continue
;
string
value = o.ToString();
if (value != String
.Empty)
sb.AppendFormat(
"{0}{1} Default Value: {2}{3}", this.tab, this.star, value, this
.br);
}

Code Snippet 4: Auto-Generate the Property list for a Web Part
Code Snippet 4 shows the steps involved in auto-generating the documentation for the Web Part. It looks unnecessarily complicated with the formatting options defined by the instance variables. Let’s dissect the first statement: sb.AppendFormat("{0}{1}{2}{3}", this.h4s, wp.Title, this.h4e, this.br);

I wanted to dress up the title, so I included text formatting in the formatter.
  • wp.Title is the Title of the Web Part
  • this.h4s is the starting format for the title
  • this.h4e is the ending format for the title
  • this.br is the break between lines
Each variable was initialized with the wiki syntax. I then created a method for initializing the output of html and plain text.The key statement in the mix is getting the properties:
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(wp);
This statement uses reflection to get the properties of the Web Part.
IEnumerable<PropertyDescriptor> pds = props.Where<PropertyDescriptor>(x => x.Category == "Display")
.OrderBy(x => x.DisplayName);
Copy the properties into an array and then using System.Linq extensions, we find the Display Category properties and order them by DisplayName.

Display the Output

private void OutputText(string text)
{
if (this.outputType == OutputType
.Html)
{
  System.Text.StringBuilder sb = new System.Text.StringBuilder();
string styleSheet = String.Format("http://{0}{1}/app_themes/{2}/stylesheet.css",
context.Request.Url.Authority, context.Request.ApplicationPath,
"default"
);
sb.AppendFormat(
@"<html><head><link href=""{0}"" type=""text/css""
rel=""Stylesheet""/></head><body>"
, styleSheet);
sb.Append("</body></html>");
// Write the content to the Web Page
context.Response.ContentType =
"text/HTML";
context.Response.Write(sb.ToString());
context.Response.End();
  return;
}
// Display the Documentation as a text file (applies to txt and wiki options)
this.Context.Response.ContentType = "text/plain"
;
this
.Context.Response.Write(text);
this.Context.Response.End();
}

Code Snippet 5: Output the text

The wiki and plain text format are output by writing the text to the browser.
Writing html is essentially the same, but is complicated because I like seeing the documentation with a good looking style sheet, in this case the style sheet from the default theme.
The following table shows a partial sample output of documenatation auto-generated for the CMS Admin Panel Web Part.

The following information is a brief description and list of properties for a Web Part developed by TrackerRealm. It is meant as a help summary.

CMS Admin Panel


Description: TrackerRealm CMS Admin Panel Web Part presents the administrative options for the site. The Correct Web Part is displayed for the selected action.

Properties


Properties are listed alphabetically
* Admin Role: The roles allowed to access this Web Part.
* Default Value: Admin
* Allow login to Jetfire?: Check if the login to Jetfire is allowed for users
* Default Value: False
* Back Color: Back Color for the Web Part.
* Default Value: Color [Empty]
* Devices: Devices that are allowed to see this WebPart: All, Normal, Mobile.
* Default Value: AllDevices

<--snip-->

Friday, October 22, 2010

Building a News Scroller with Jetfire

Making an impact on web pages is about keeping the information concise and attractive. Most home pages use a scroller for news and/or events.

The Jetfire News Scroller makes it easy to add news to your home page. It includes:

  • Jetfire code
  • A Web Part with a Rich Text Editor for creating a news item
  • A Web Part with a scroller for displaying news items
  • jquery javascript for implementing the scroller

Jetfire code

Jetfire Persistent Scripting Language is an open source, object oriented, scripting language designed to make persistent programs, sometimes called workflows, very easy to write and maintain. The News Item displayed in the scroller is a simple program, which consists of:

  • Some properties that are displayed on the web page
    • Title of the News Item
    • The body of the News Item (photos and text)
    • An expiry date
    • Who created the news item
    • When the news item was created
  • A method for identifying that the News Item is Current
  • States for the news item
    • Active: Display the news item
    • Inactive: Don’t display the news item
namespace JetfireApps
{
// This workflow creates News Items with an expiry date.
// Use 'IsCurrent' to check the Expiry Date and identify if the News Item is current.
// state Active means that the News Item is current.
public workflow NewsItem
{
// Add workflow constructor
public NewsItem()
{
Tags = new List();
enterstate Start();
Created_Date = DateTime.Now;
Created_By = User.Login.Name;
Expiry_Date = DateTime.Today.AddYears(1);
}

// Add states to the workflow
public Start() { }
public Active() { }
public Inactive() { }

// Add Properties
// Use Subject as News Title
// Use ToolTip as News Description
// Add Expiry Date
public bool Never_Expires
{
get;
set;
}
public DateTime Created_Date
{
get;
private set;
}
public plainString Created_By
{
get;
private set;
}
public DateTime LastUpdated_Date
{
get;
private set;
}
public plainString LastUpdated_By
{
get;
private set;
}
public DateTime Expiry_Date
{
get;
set;
}
public List Tags
{
get;
private set;
}
public bool IsCurrent
{
get
{
if (Never_Expires)
{
return true;
}
if (DateTime.Now.Preceeds(Expiry_Date))
{
return true;
}
// This news item is now expired
enterstate Inactive();
return false;
}
}

// Add Command Methods
public void FinishEdit() : states(Start,Active)
{
if (Subject == "")
{
throw exception("Enter Title");
}
if (ToolTip == "")
{
throw exception("Enter Description");
}
LastUpdated_Date = DateTime.Now;
LastUpdated_By = User.Login.Name;
enterstate Active();
}
public void Set_Inactive() : states(Active)
{
enterstate Inactive();
}
public void Set_Active() : states(Inactive)
{
enterstate Active();
}
}
}

Rich Text Editor in a Web Part

Someone has to create the news that is displayed on the website. Figure 1 shows a portion of a Jetfire page that we use to create our news. There are two Web Parts displayed on the figure.

  • The Web Part on the left is a Workflows Navigation Web Part that is configured to display a list of all News Items.
  • The Web Part on the right is the News Item Editor. It contains:
    • State of the News item
    • Some commands that the user can to manage the news item
    • The Properties of the News Item: Title, Never Expires, Expiry Date and Body

The Body of the News Item is a Rich Text Editor that allows the user to input rich text, images and links.

NewsScroller-Editor

Figure 1: News Editor in web page

News Scroller Web Part

NewsScroller

Figure 2: News Scroller in web page

Figure 3: A subset of properties used to configure the News Scroller (below)

NewsScroller-EditPropertiesFigure 2 shows the News Scroller in the home page of http://www.jetfire.ca. The Web Part is configured to display a new item every 400 milli-seconds. The user may also choose to manually select a News Item.

The News Item program can be configured in different ways by a Web Master for display on the web page. Options include:

  1. Display the Active News Items
    • Let the news item editor manage the states of the News Items. When a News Item has out-lived its time, the editor sets the state to Inactive
  2. Display News Items that have not expired
    • Let the news item editor establish an expiry date for each news item. Some companies expect news items to be displayed at least 2 weeks. Then the news item is delisted. This option tracks expiry for the editor.

Figure 3 shows a subset of the edit properties for the News Scroller. The Web Master has a number of options that describe how the News Scroller will operate.

  1. Select what News Items are displayed using the first propery: Filter. By providing a list of name/value pairs, the software converts this into a filter used to get the list of News Items.
  2. Display the header option? If Checked, then the “Created on …..” is displayed. The Web Master can create the header format by editing the Header Property. The format is “Created on {0} by {1} to {2}” where {0} is the value of the Created by Property, {1} is the value of the Created Date Property and {2} is the value of the Workspace where the News Item is stored.
  3. Auto-rotate may be enabled/disabled.
  4. The Rotation interval may be set.

jquery javascript library

jQuery is a fast and concise JavaScript Library that simplifies HTML document traversing, event handling, animating, and Ajax interactions for rapid web development. We use this as our AJAX JavaScript library. jquery has an active community, who are constantly submitting new programs. One such program is Featured Content Glider: by http://www.dynamicdrive.com. It includes the javascript and the css stylesheet used in the news scroller.

Change Session State Programmatically

Customers using Jetfire Workflows rely on websites with good connectivity to stay connected to their business and keep their business processes up-to-date. Recently, our ISP moved their Data Center to be better served by a higher speed internet connection. Web pages are definitely served faster, but I also noticed busy intervals during the day leading to page rendering delays and often dropped logins for customers. The dropped logins require users to re-login – a nuisance when you are busy.

Session State in the web.config file is set up as ‘InProc’, meaning that the Session State is stored in memory. By changing Session State to ‘SqlServer’, the goal was to avoid unnecessary re-logins.

In a hosted environment, this procedure is:

  1. Run the sql script for the ASPState database on the local server
  2. Change the Session State parameter in web.config to ‘SqlServer’
  3. Set the parameters for the SqlServer Session State

In an ISP environment, step 1 is changed to create the database and upload the database schema.

For our lazy deployment person (that’s me), even this simple procedure was too complicated. I needed a one-click procedure to SessionState-Memorymanage the transition automatically and minimize the amount of effort required to convert each site.

These are the design steps used to add the session state tables to an existing database and then create a Web Control to change the session state.

  1. Create the ASPState tables in my local database
  2. Create a script for the ASPState tables
  3. Put a C# code wrapper around the ASPState sql script
  4. Create a Web Control that changes Session State with one-click

The figure on the right shows the desired end result – a web control that changes Session State from memory storage to database storage and simple enough that the customer administrator can do it.

ASPState Tables

The .NET Framework includes an install database and tables script for ASP State. Since we are adding the ASPState tables to an existing database, we need to create an sql script that only addresses the tables (and stored procedures).

This involves installing the ASPState tables in my development system. The sql script, InstallSqlState.sql, to do this is found in one of the following folders; system drive\ Windows\ Microsoft.NET\ Framework\version\.

SQL Script for ASPState Tables

Once the ASPState database and tables are created, generate the script for the ASPState tables. I used the Database Publishing Wizard found in codeplex project: http://sqlhost.codeplex.com. Just follow the instructions.

C# code wrapper about sql script

The sql script is not a slam dunk at this point. There are a few gotchas that need to be addressed.

  1. The sql script does not contain the name of the customer’s database. When ISP hosting is used, it is highly likely that every database that the ASPState tables are added to has a different name. Therefore, a name, such as ‘DatabaseNamePlaceHolder’ is embedded in the file in multiple places. (there were over 80 places where this occurs)
  2. Delete the GO statements. Do a replace all ‘GO’ strings with ‘’ (an empty string).
  3. strings in the file, e.g. “2” need to be converted to “”2””. [there was only one instance to change.]

SessionStateSqlScript

Code Snippet 1: SQL Script for ASPState tables

The above code snippet shows a portion of the SQL script for installing ASPState tables.

Note: The sql script is over 1100 lines of code, which is why it is not included in its entirety.

SessionStateCreateTables

Code Snippet 2: Create the ASPState Tables

The above code snippet creates the tables for the ASPState tables.

  1. Get the Connection String where the tables will be added.
  2. Instantiate an SqlConnection object. This is used to get the name of the customer’s Database.
  3. Get the sql script and replace ‘DatabaseNamePlaceHolder’ with the name of the customer’s Database.
  4. Execute the modified script on the database.

The end result is tables: ASPStateTempApplications and ASPStateTempSessions, along with all Stored Procedures are installed in the target database.

Web Control that changes Session State with one-click

This section addresses how to change the mode for Session State programmatically. (The user interface code is straight-forward.) The Session State is located in the web.config file at the root of the website. It is retrieved using the code found in Code Snippet 3.

this.config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~/");
SystemWebSectionGroup webGroup = this.config.GetSectionGroup("system.web") as SystemWebSectionGroup
;
this.sessionState = webGroup.SessionState;

Code Snippet 3: Get the Session State from web.config

The ‘ChangeMode’ method, shown in Code Snippet 4, is called from the link click event of the Web Control. Key points include:

  • Only SQLServer and InProc modes are supported
  • The session State object is updated for the selected mode
  • A message is printed to the user providing a positive indication of what has changed
  • The change is saved in the web.config file.
  • Text displayed on the Web Control is updated.

SessionState-ChangeModeCode

Code Snippet 4: Change the Mode of the Session State

There is a lot of flexibility in the SQLServer mode for Session State. Read the MSDN help closely to ensure that you engineer the correct operation for your application.

When the customer Administrator converts the storage of Session State from memory, ‘InProc’ to database, ‘SQLServer’, all users need to re-login because when the web.config is changed for this procedure and of course, because the Session State for each user is now null.

SessionState-Database

Object Serialization Gotchas

Further web testing showed that my work was not finished. There was one object that was stored correctly when the Session State Mode was ‘InProc’. However, it was real clear that the object needed to be serialized to the database when the Session State was changed to ‘SQLServer’. Whereas, ‘InProc’ stores a reference to the object in the Session memory, ‘SQLServer’ serializes the complete object to the database for each Session.

This required some re-work of the class in question and the code that used the object.