Adventures of Sudheer

A Resource Puller’s Blog

Uploading an Image and Creating a Thumbnail in ASP.NET October 19, 2009

Filed under: DotNet — Sudheer @ 5:12 am
Tags: , , , ,

There are literally thousands of facets to the .NET Framework, and writing them down functions as a way to learn, memorize or work out the details. This is especially useful for things you use infrequently, such as thumbnail images. I wrote an application several years ago to manage label images, but when I sat down to try to upload an image, I discovered that I had forgotten how to create a thumbnail image—a subject that makes a useful article topic.

This article shows you how to use an <input> control to browse and upload images, and then convert those images to thumbnail versions for display on the web site. The code is straightforward without a lot of sanity checking, as is the ASPX, and works fine for example purposes, but for a production application you’ll want to add validation and error checking (but that’s another article).

Uploading Files with the <input> Element

The <input> HTML element is a versatile HTML control. Based on the value you supply for the element’s type attribute, the <input> element can function (and display) as a general-purpose button, a radio, reset, or submit button, a checkbox, a file uploader, a hidden control, an image, a password field, or a text control. For the file uploader, set the <input> element’s type attribute to file, and the <input> control displays a textbox and a button labeled “Browse.” While you can code this manually, the easiest way to display a file uploader is to select the Input (File) item from the HTML tab of Visual Studio’s Toolbox.



Figure 1. Design-Time View:
From this design-time view, you can see how the sample page uses the table to lay out the other HTML elements.

The sample ASPX page contains this type of <input> element, as well as a label, a button to submit a selected image file, and an image element. The server creates a thumbnail of that image and returns it to the browser, which displays it in an <img> element on the same page. An HTML table handles the control layout (see Listing 1). At design-time, the page looks like Figure 1.

// HTML tables are pretty versatile and easy to use. If you want a simple spreadsheet-like table then use <tr> elements to add rows and <td> elements to add cells. If you want a single cell to span multiple rows then set the <td> element’s rowspan attribute, or to span multiple columns, set its colspan attribute.

The only other interesting aspect of the HTML in Listing 1 is that the <img> control (in column 2 in Figure 1) has an ID attribute, and its runat attribute is set to server. Setting the runat attribute lets you manipulate the <img> control in the server-side code behind. You’ll use this to display the created thumbnail image.

Saving the Uploaded Image

When an <input> control has its type attribute set to file, a user can click the Browse button to select a file. After selecting a file, when the user submits the page the <input> control will have a populated PostedFile property, which is a class that will contain the file’s contents and other file information, such as its file name. To be specific, PostedFile is an instance of the HttpPostedFile class.

To use the GUI, a user clicks the Browse button, selects a file, and then clicks the Upload button. On the server, you can save the posted file by calling the <input> control’s PostedFile.SaveAs method, passing the path and file name where you want to save the file. The following code shows just how easy this part of the process is:

Private Const imagePath As String = “~/Images/”

Private Sub SaveUploadedFile(ByVal filename As String)

File1.PostedFile.SaveAs(MapPath(imagePath) + filename)

End Sub

In the preceding code, File1 is the ID of the <input> control. (The <input> control has the runat=”server” attribute set, so even though it’s an HTML control, it is available on the server side too.)

Creating and Display the Thumbnail

The sample program uses a Button control to submit the default form containing the <input> element. The <input> element has the posted file. The complete code, shown in Listing 2, performs four steps:

  1. Extract the file name from the posted file path
  2. Save the uploaded file to a pre-determined server path
  3. Save a thumbnail copy of the image
  4. Set the <img> element’s src attribute to the thumbnail’s location

When the user submits the file, File1.PostedFile.FileName contains the client’s local path (the location of the file on the user’s machine). You will want to extract the filename without the path, which you can do with the System.IO.Path class’s GetFileName method.

The SaveUploadedFile method shown earlier uses the PostedFile.SaveAs method to save the file. Note that it uses the MapPath method, which maps a server-side relative path to its physical path. It appends the file name to that path, which creates a complete pathname where it saves the uploaded file. (You could also save the file to a database or display the file contents on the web page.)

The next step is to create the thumbnail image. The SaveThumbnail method creates a thumbnail copy of the image.

Private Sub SaveThumbnail(ByVal filename As String)

Dim image As Image = image.FromStream( _

File1.PostedFile.InputStream)

Dim thumbnail As Image = image.GetThumbnailImage( _

100, 100, AddressOf Callback, IntPtr.Zero)

thumbnail.Save(MapPath(GetThumbnailPath(filename)))

End Sub

Private Function GetThumbnailPath( _

ByVal filename As String) As String

Return “~/Images/” + _

String.Format(thumbnailMask, filename)

End Function

The SaveThumbnail method creates an in-memory System.Drawing.Image instance from the HttpPostedFile’s InputStream property by passing the input stream to the Image.FromStream method. Next, it creates a thumbnail copy of the image by calling the Image’s GetThumbnailImage method. GetThumbnailImage has some odd arguments, mostly because its implementation calls into unmanaged code. The first two arguments are the width and height of the thumbnail image, the third argument is an unused callback delegate, which you must provide, even though it’s unused. The fourth argument is another unused relic to satisfy the native code call. The final argument must be IntPtr.Zero. (Obviously, a better thumbnail wrapper probably needs to be created.) Finally, the method saves the thumbnail in the same location as the original image, but with the prefix thumbnail_ added to the file name.

Finally, the SetPreviewImage uses the virtual path for the thumbnail and assigns it to the <img> element’s src property.

Private Sub SetPreviewImage(ByVal filename As String)

PreviewImage.Src = GetThumbnailPath(filename)

End Sub

The topic of uploading files is a bit of an oldie, but it is still a goody. Creating and showing thumbnails is a good way to let users preview numerous images, and then select a full-sized version. The GetThumbnailImage method makes a call into unmanaged native code, so it has some unused “junk” arguments that make it a little cumbersome to use—but now you have the CliffNotes.

Uploading an Image and Creating a Thumbnail in ASP.NET

 

Obtaining Client-Specific Information with a Web Application September 30, 2009

Filed under: DotNet — Sudheer @ 4:28 am
Tags: , , , ,

Obtaining Client-Specific Information with a Web Application

Introduction

An Editor friend and some of my co-workers have taken occasion to remind me that some people don’t like Internet Explorer or don’t see why anyone would ever develop Web applications just for Internet Explorer. Some of these same smart people have expressed the opinion that they don’t like ActiveX in Web applications much either. I respect their opinions. Everyone is entitled to an opinion.

I understand. I have read the Cathedral and the Bazaar by Eric Raymond. I have even exchanged a couple of emails with him. I understand that some people think open source software and uniform standards is the way to go. However, I think about these kinds of issues-open source versus proprietary solutions and IE-only development versus multi- browser platform development-differently, from my own perspective.

First, IE is the most popular browser and is the most widely used. Second, I have actually worked on applications that were Web-based intranet applications and the customer requested IE only. The latest two applications had multi- million dollar budgets. If you are targeting the World Wide Web then IE only development may be short sighted. And, when it comes to ActiveX I think of all available code and solutions as possibilities. Most code has pluses and minuses. My criteria for using something are really just a matter of does it solve the issue expediently, efficiently, and cost effectively and are the risks manageable. Other than that I don’t care where the code comes from, which language it is in, or what coding standard was applied.

This article is limited to IE web-based development and just a few odds and bobs that let your JavaScript code obtain some client/user specific information.

Enabling and Disabling Script Debugging in IE8

Visual Studio 2008 automatically enables script debugging for Internet Explorer 8 sessions started from Visual Studio. You know longer have to uncheck this option (Disable script debugging (Internet Explorer)) in the IE Tools|Options in the Advanced tab. In fact, regardless of the debugging settings script debugging will be enabled for IE8 sessions started from Visual Studio.

There exists a potential for performance problems associated with script debugging always being on. For a registry hack that disables script debugging refer to my DevExpress blog entry here.

Enabling ActiveX in IE8

Internet Explorer security is established by zone. There are five zones: Internet, Local Intranet, Trusted Sites, Restricted Sites, and My Computer. The Internet zone is represented by Web sites on your computer that haven’t been assigned to another zone. The Local Intranet zone is represented by network connections established using a UNC path, Web sites that by-pass the proxy server, or sites that have not been assigned to the Restricted or Trusted zone. Also, if you use a fully qualified domain name (FQDN) or IP address then the site is considered part of the Internet zone. The Trusted Sites zone is for adding web sites that you trust, like FedEx.com, Dell.com, Amazon.com, and the Restricted Sites zone is for web sites that you don’t trust. My Computer is exactly what it sounds like.

If you want to enable ActiveX support for desktop development then you want to adjust the Local Intranet zone. If you add ActiveX controls to your public web site then your users will need to adjust the Internet zone.

If you write some JavaScript that uses an ActiveX object and your browser isn’t configured to permit ActiveX objects then you will get an error dialog like the one shown in Figure 1. To configure support for ActiveX controls on your workstation or laptop, the machine you are developing on, follow these steps (using Figure 2 as a guide):

  1. In Internet Explorer 8 select Tools|Options
  2. Change to the Security tab and click Local intranet in the zones section
  3. Click Custom level
  4. In the Security Settings dialog scroll to the ActiveX controls and plug-ins
  5. Change the “Initialize and script ActiveX controls not marked as safe for scripting” from Disable to Enable or Prompt. (If you want to remember that you have turned on ActiveX support then select Prompt)
  6. Click OK to close the Security Settings dialog
  7. Click OK to close the Internet options dialog



Click here for larger image

Figure 1: If you see this dialog then you need to enable ActiveX objects for the Local Intranet zone.


Figure 2: To let ActiveX objects that you create in script run on your workstation’s browser set “Initialize and script ActiveX controls not marked as safe…” to Enable or Prompt.

Creating an ActiveX Object

ActiveX objects for ascertaining client information include WScript.Network and WScript.Shell. WScript.Network can be used to determine the active user, for example, and WScript.Shell can be used to query information like the path to the MyDocuments folder. For a complete reference for these ActiveX libraries refer to the MSDN help documentation.

Tip: You can use script languages to run JavaScript at a command prompt by running the .js script file in the WScript.exe host.

To create an instance of the desired ActiveXObject you can invoke new ActiveXObject passing in the name of the library as a string that you want to create. The following code demonstrates how to use the debugger; statement to break into the code and create an instance of WScript.Network and WScript.Shell. With these two objects the UserName and the path to the special folder MyDocuments is obtained (refer to Listing 1).

Listing 1: Some JavaScript in a Web page that obtains client-specific information using ActiveX.

// <script type=”text/javascript”>

debugger;

var o = new ActiveXObject(“WScript.Network”);

//UserDomain

//ComputerName

//UserName

alert(o.UserName);

var w = new ActiveXObject(“WScript.Shell”);

alert(w.SpecialFolders(“MyDocuments”));

//CreateShortcut

//SpecialFolders

var jsonObject = { “UserName”: o.UserName,

“MyDocuments”: w.SpecialFolders(“MyDocuments”)

};

</script>

The end of the listing contains a statement that starts with var jsonObject. Programmers used to create objects by writing new Object() and referring to the desired properties. The revised syntax above is part of JSON (pronounced Jason), or JavaScript Object Notation. JSON is a lightweight data-interchange format that is a subset of JavaScript. JSON is used in objects and arrays in a highly readable form, and the technology plays in the same space as XML. The statement above creates an object with two properties: UserName and MyDocuments.

Summary

Now that you have the tools to configure a browser for ActiveX features and obtain client-specific information, it is up to you to figure out how you are going to use it. To recap JavaScript debugging is enabled automatically when Visual Studio starts an instance of IE8. Security settings like ActiveX support are managed by zone. For local workstation ActiveX support modify the Local Intranet zone. You can choose between enabling ActiveX support or prompting for permission. (I choose the latter, so I turn it off when not needed.) Finally, two of the objects that support discovering client-side information are WScript.Shell and WScript.Network. You can explore the integrated MSDN help for more information.

As a final note JavaScript Object Notation (JSON) was briefly introduced. JSON is subset of JavaScript and is a lightweight data-interchange format. JSON is picking up steam and becoming more popular, so I wedged it into the sample.

Biography

Paul Kimmel is the VB Today columnist for www.codeguru.com and has written several books on object- oriented programming and .NET. Check out his upcoming book Professional DevExpress ASP.NET Controls (from Wiley) now available on Amazon.com and fine bookstores everywhere. Look for his upcoming book Teach Yourself the ADO.NET Entity Framework in 24 Hours (from Sams). You may contact him for technology questions at pkimmel@softconcepts .com. Paul Kimmel is a Technical Evangelist for Developer Express, Inc, and you can ask him about Developer Express at paulk@devexpress.com and read his DX blog at http:// community.devexpress.com/blogs/paulk.

Ref: Obtaining Client-Specific Information with a Web Application

 

Implementing Skins and Themes for ASP.NET September 30, 2009

Filed under: DotNet — Sudheer @ 4:18 am
Tags: , , , ,

Implementing Skins and Themes for ASP.NET

This article will show you how to define both a custom skin and a theme for a web application.

Adding a Theme to Your Web Application

You can add a custom theme to your web project from the Solution Explorer. Right-click the root project name and click “Add ASP.NET Folder” from the context menu, and then select the Theme item. This step adds an App_Themes folder containing a Theme1 subfolder. The intent is that each theme subfolder should contain all the elements for a particular theme. Therefore, if you want to have multiple themes, simply add additional Theme sub-folders to the App_Themes folder.

Author’s Note: You can also click App_Themes, select Add ASP.NET Folder and pick “Theme” from the context menu after you’ve added the

App_Themes

folder to your project.

Defining a Skin File

Skin files are XML files with a .skin extension. To add a skin file to your web project’s Theme folder, right-click the Theme folder (Theme1 in this example), and select Add New Item. From the Add New Item dialog select the Skin File item.

Visual Studio inserts a skin file template that initially contains a comment and some boilerplate heading information that shows you two examples:

<%--
Default skin template. The following skins are provided as examples only.
1. Named control skin. The SkinId should be uniquely defined because
   duplicate SkinId's per control type are not allowed in the same theme.
<asp:GridView runat="server" SkinId="gridviewSkin" BackColor="White" >
   <AlternatingRowStyle BackColor="Blue" />
</asp:GridView>
2. Default skin. The SkinId is not defined. Only one default
   control skin per control type is allowed in the same theme.
<asp:Image runat="server" ImageUrl="~/images/image1.jpg" />
--%>

Figure 1. Associating Controls with Skins:
If your skin files contain control properties with a SkinId attribute set, then you can select a specific value for the control’s SkinID property.

The first example in the preceding skin file contains a SkinId, while the second example does not. That’s important, because when a skin element has a SkinId it belongs to the group of items having that same SkinId. However, elements without a SkinId become part of the default Skin definition.

A skin file can contain multiple skins. You can have one default skin—control properties without a SkinId—and as many named skins as you want: control properties with SkinId attributes. If your skin elements have a SkinId then Visual Studio will let you select the various SkinId values from a control’s SkinID property (see Figure 1).

One reasonable way to define control properties for a skin file is to format the item’s appearance directly in an ASP.NET web page—and then copy and paste the applicable elements from the ASPX file to the .skin file. The following code shows the skin file elements defined for the example application:

<asp:GridView runat="server"
  AllowPaging="true" Font-Names="Tahoma"
  Font-Size="9pt" CellPadding="4">
  <HeaderStyle BackColor="#C1DBFA" />
  <AlternatingRowStyle BackColor="#ECF4FE" />
  <RowStyle />
  <PagerStyle CssClass="PagerStyleClass" BackColor="#C1DBFA" />
</asp:GridView>

Figure 2. Skinned GridView:
Here’s how the GridView looks with a skin file applied.

Notice that the boilerplate comments were removed from the preceding code, which provides HeaderStyle, AlternatingRowStyle, and PagerStyle settings. The skin contents also look very similar to the HTML/XML that defines a GridView in an ASPX page.

These control properties define a default skin. The skin specifies BackColor attributes for the header and alternating rows, and references a cascading style sheet class for the PagerStyle (discussed in more detail in the next section). It’s worth noting that the runat attribute has to be set to server in the .skin file. Figure 2 shows the result when this skin file is applied to a GridView.

Building Out a Cascading Style Sheet

While writing my latest book, I got so used to looking at the Aqua theme provided with the DevExpress controls that I decided to approximate it for the demo. The style employs a subtle contrast between the header and footer and the alternating rows. The preceding skin file defines the control properties, including fonts and colors; however, skin files do not support style information for HTML elements. You need to define those in a cascading style sheet. The good news is that adding a cascading style sheet to your theme automatically incorporates it as part of the theme, without you having to add a specific reference in your web page.

The example in Figure 2 shows a GridView populated with information from the Northwind database’s Customers table. The grid is inside a <div> tag with some padding applied, and the table header <th> and table cell <td> use a solid thin blue border. (Remember that controls such as GridViews are rendered as HTML.) The pager is also rendered as an HTML table, but I didn’t want a border around the pager items. To eliminate the border around the pager items the PagerStyleClass uses a combinatory * and td to indicate that descendant td elements inside of the PagerStyleClass will use the PagerStyleClass settings. Here’s the CSS file added to Theme1:

body {
}
.divClass
{
  border:solid thin Silver;
  margin: 10px 20px 10px 20px;
  padding: 10px 20px 10px 20px;
}
.PagerStyleClass * td
{
  border-style: none;
}
th, td
{
  border:solid thin #A3C0E8;
}

The .divClass entry defines a border, margin, and padding. This .divClass is assigned to the page’s main <div> tag’s class attribute. The element styles for the th (table header) and td (table cell) define a solid, thin, bluish border. All <th> and <td> elements will employ this style unless it’s overridden by some other style. You could also define a specific style class for the grid using the combinator approach used with the .PagerStyleClass. Finally, the .PagerStyleClass * td uses the combinator * to mean that the style information applies to descendant table cells.

With the theme complete, you can remove all redundant control properties from the ASPX pages to unclutter the ASPX code. You don’t have to do this because theme information overrides local property settings—but doing so may eliminate some confusion. Here’s the ASPX code for the sample solution:

<%@ Page Language="VB" AutoEventWireup="false"
  CodeFile="Default.aspx.vb" Inherits="_Default" %>

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

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
      <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
        DataKeyNames="CustomerID" DataSourceID="SqlDataSource1">

        <Columns>
          <asp:BoundField DataField="CustomerID" HeaderText="CustomerID" ReadOnly="True"
            SortExpression="CustomerID" />
          <asp:BoundField DataField="CompanyName" HeaderText="CompanyName"
            SortExpression="CompanyName" />
          <asp:BoundField DataField="ContactName" HeaderText="ContactName"
            SortExpression="ContactName" />
          <asp:BoundField DataField="ContactTitle" HeaderText="ContactTitle"
            SortExpression="ContactTitle" />
          <asp:BoundField DataField="Address" HeaderText="Address"
            SortExpression="Address" />
          <asp:BoundField DataField="City" HeaderText="City" SortExpression="City" />
          <asp:BoundField DataField="Region" HeaderText="Region"
            SortExpression="Region" />
          <asp:BoundField DataField="PostalCode" HeaderText="PostalCode"
            SortExpression="PostalCode" />
          <asp:BoundField DataField="Country" HeaderText="Country"
            SortExpression="Country" />
          <asp:BoundField DataField="Phone" HeaderText="Phone" SortExpression="Phone" />
          <asp:BoundField DataField="Fax" HeaderText="Fax" SortExpression="Fax" />
        </Columns>
        <PagerStyle BorderStyle="None" />
      </asp:GridView>
      <asp:SqlDataSource ID="SqlDataSource1" runat="server"
        ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
        SelectCommand="SELECT * FROM [Customers]"></asp:SqlDataSource>
    </div>
    </form>
</body>
</html>

Adding the Theme to a Web Page

You can apply a theme to an individual web page by adding either a Theme or a StyleSheetTheme attribute to the page’s @Page directive. The following code fragment demonstrates how to use the Theme attribute; you use the StyleSheetTheme attribute in the same way:

<%@ Page Language="VB" AutoEventWireup="false"
  CodeFile="Default.aspx.vb" Inherits="_Default" Theme="Theme1"%>

Author’s Note: The difference between Theme and StylesheetTheme is that if you apply the Theme attribute then the theme’s control property settings take precedence over any local property settings. In contrast, if you apply the StylesheetTheme attribute, local property settings take precedence over theme-based settings.

Adding a Theme to an Entire Web Application

If you want to apply a theme to your entire web application, then you set the theme attribute of the <pages> tag in the web.config file as shown below:

<pages theme="Theme1">

You’ve seen the rudiments of custom themes, skin files, and cascading style sheets, including the subtle yet important difference between the @Page Theme and @Page StylesheetTheme attributes. For some great ideas for defining custom themes, look at some of the pre-defined themes used for other sample projects and existing web sites. You can also check out DevExpress’s ASP.NET controls for good theme ideas. You can download trial versions at http://www.devexpress.com.

About the Author

Paul Kimmel is the VB Today columnist for www.codeguru.com. He has written several books on object-oriented programming and .NET. Check out his latest book Professional DevExpress ASP.NET Controls (from Wiley), and watch for his upcoming book Teach Yourself the ADO.NET Entity Framework in 24 Hours (from Sams). Paul is also a Technical Evangelist for Developer Express, Inc. You can ask him about Developer Express or read his DX blog here.

Ref: Implementing Skins and Themes for ASP.NET

 

Sending Email Both in HTML and Plain Text July 9, 2009

Filed under: DotNet — Sudheer @ 9:37 am
Tags: , , , ,

In this article you will learn how to send email using ASP.NET. Yes, there are plenty of other articles that cover sending email via .NET, but after spending a day doing research, I was amazed at how many articles failed to provide either a correct solution or a real world example. I found that many articles suggest you create your HTML email by using a string with the HTML markup in it. That’s crazy and not at all a real world solution, at least not for most situations. In this article we will look at a more realistic solution. One in which we use a regular HTML file as our template for the email. The template file will be a standard HTML file with the exception of some placeholders that we will use to populate our content and images right before we send the email. Think mail-merge in Microsoft Word. Finally, we will also learn how to send the email in such a way that if the email recipient’s mail-client can’t render HTML they will get an alternate plain text version.

Let’s start by looking at the code in its entirety; the people that just want to grab the code and use it can do so. I will then explain the code.

PLAIN TEXT

C#:

  1. // CREATE EMAIL
  2. // first we create a plain text version and set it to the AlternateView
  3. // then we create the HTML version
  4. MailMessage msg = new MailMessage();
  5. msg.From = new MailAddress(TextBoxYourEmail.Text);
  6. msg.Subject = “Event: ” + labelEventName.Text;
  7. msg.To.Add(TextBoxEmail1.Text);
  8. // create a string to hold all email addresses
  9. StringBuilder sbEmailTo = new StringBuilder();
  10. sbEmailTo.Append(TextBoxEmail1.Text);
  11. if (!String.IsNullOrEmpty(TextBoxEmail2.Text)) { msg.To.Add(TextBoxEmail2.Text); sbEmailTo.Append(“, ” + TextBoxEmail2.Text); }
  12. if (!String.IsNullOrEmpty(TextBoxEmail3.Text)) { msg.To.Add(TextBoxEmail3.Text); sbEmailTo.Append(“, ” + TextBoxEmail3.Text); }
  13. if (!String.IsNullOrEmpty(TextBoxEmail4.Text)) { msg.To.Add(TextBoxEmail4.Text); sbEmailTo.Append(“, ” + TextBoxEmail4.Text); }
  14. if (!String.IsNullOrEmpty(TextBoxEmail5.Text)) { msg.To.Add(TextBoxEmail5.Text); sbEmailTo.Append(“, ” + TextBoxEmail5.Text); }
  15. String plainEmail = TextBoxYourName.Text + ” has invited you to an event! \r\n \r\n” +
  16. “Event Name: ” + labelEventName.Text + “\n” +
  17. “Event Date: ” + eventTextBox.Text + “\n” +
  18. “Event Description: ” + labelEventDescription.Text + “\r\n \r\n” +
  19. “Message: ” + TextBoxPersonalMessage.Text;
  20. //first we create the Plain Text part
  21. AlternateView plainView = AlternateView.CreateAlternateViewFromString(plainEmail, null, “text/plain”);
  22. msg.AlternateViews.Add(plainView);
  23. //now create the HTML version
  24. MailDefinition message = new MailDefinition();
  25. message.BodyFileName = “email.htm”;
  26. message.IsBodyHtml = true;
  27. message.From = TextBoxYourEmail.Text;
  28. message.Subject = “Zoo Event: ” + labelEventName.Text;
  29. //embed images for the email
  30. EmbeddedMailObject emo = new EmbeddedMailObject();
  31. emo.Path = @”~\Images\email\hdr_roar.gif”;
  32. emo.Name = “hdr”;
  33. EmbeddedMailObject emo2 = new EmbeddedMailObject();
  34. emo2.Path = @”~\Images\email\box_top.gif”;
  35. emo2.Name = “box_top”;
  36. message.EmbeddedObjects.Add(emo);
  37. message.EmbeddedObjects.Add(emo2);
  38. //Build replacement collection to replace fields in email.htm file
  39. ListDictionary replacements = new ListDictionary();
  40. replacements.Add(“<%EVENTDATE%>”, eventTextBox.Text);
  41. replacements.Add(“<%EVENTNAME%>”, labelEventName.Text);
  42. replacements.Add(“<%FROMNAME%>”, TextBoxYourName.Text);
  43. replacements.Add(“<%EVENTDESCRIPTION%>”, labelEventDescription.Text);
  44. replacements.Add(“<%PERSONALMESSAGE%>”, TextBoxPersonalMessage.Text);
  45. //now create mail message using the mail definition object
  46. //the CreateMailMessage object takes a source control object as the last parameter,
  47. //if the object you are working with is webcontrol then you can just pass “this”,
  48. //otherwise create a dummy control as below.
  49. MailMessage msgHtml = message.CreateMailMessage(sbEmailTo.ToString(), replacements, new LiteralControl());
  50. AlternateView htmlView = AlternateView.CreateAlternateViewFromString(msgHtml.Body, null, “text/html”);
  51. msg.AlternateViews.Add(htmlView);
  52. // send email now (check web.config)
  53. SmtpClient smtp = new SmtpClient();
  54. smtp.Send(msg);

The Setup

Add the System.Net.Mail namespace. The System.Net.Mail namespace contains everything we need to send email using a Simple Mail Transfer Protocol (SMTP) server for delivery.

Modify the Web.config file to include the below:

PLAIN TEXT

CODE:

  1. <system.net>
  2. <mailSettings>
  3. <smtp from=”admin@company.com”>
  4. <network host=”localhost” port=”25″  />
  5. </smtp>
  6. </mailSettings>
  7. </system.net>

The kicker and not well documented part to note is the from=”admin@company.com” in the smtp tag. You can change the from address later, but the MailDefinition class needs this here.

That’s it for setup. Now let’s look at the first chunk of code.

Create The Plain Text Version

PLAIN TEXT

C#:

  1. MailMessage msg = new MailMessage();

The MailMessage class represents an email message that can be sent using the SmtpClient class.

PLAIN TEXT

C#:

  1. msg.From = new MailAddress(TextBoxYourEmail.Text);
  2. msg.Subject = “Event: ” + labelEventName.Text;
  3. msg.To.Add(TextBoxEmail1.Text);

Pretty straight-forward. This just assigns the From, Subject and To properties to our mail message.

PLAIN TEXT

C#:

  1. // create a string to hold all email addresses
  2. StringBuilder sbEmailTo = new StringBuilder();
  3. sbEmailTo.Append(TextBoxEmail1.Text);
  4. if (!String.IsNullOrEmpty(TextBoxEmail2.Text)) { msg.To.Add(TextBoxEmail2.Text); sbEmailTo.Append(“, ” + TextBoxEmail2.Text); }
  5. if (!String.IsNullOrEmpty(TextBoxEmail3.Text)) { msg.To.Add(TextBoxEmail3.Text); sbEmailTo.Append(“, ” + TextBoxEmail3.Text); }
  6. if (!String.IsNullOrEmpty(TextBoxEmail4.Text)) { msg.To.Add(TextBoxEmail4.Text); sbEmailTo.Append(“, ” + TextBoxEmail4.Text); }
  7. if (!String.IsNullOrEmpty(TextBoxEmail5.Text)) { msg.To.Add(TextBoxEmail5.Text); sbEmailTo.Append(“, ” + TextBoxEmail5.Text); }

In this example they have the option of sending the email to more than one recipient. So we perform a check on the four optional text-boxes to see if they have email addresses and if they are not empty then we add them to our MailMessage instance. In addition, we append them to our StringBuilder instance which we will end up using later.

PLAIN TEXT

C#:

  1. String plainEmail = TextBoxYourName.Text + ” has invited you to an event! \r\n \r\n” +
  2. “Event Name: ” + labelEventName.Text + “\n” +
  3. “Event Date: ” + eventTextBox.Text + “\n” +
  4. “Event Description: ” + labelEventDescription.Text + “\r\n \r\n” +
  5. “Message: ” + TextBoxPersonalMessage.Text;
  6. //first we create the Plain Text part
  7. AlternateView plainView = AlternateView.CreateAlternateViewFromString(plainEmail, null, “text/plain”);
  8. msg.AlternateViews.Add(plainView);

Here we simply create a string which we’ll use as our plain-text email message. But remember, we only want to use the plain-text version of the email if their mail client does not support HTML. Therefore we use the AlternateView class and add it to our MailMessage instance. We could have chosen not to use the alternate view and just made it the body of our MailMessage instance, but not this time.

That’s it for the plain-text version, now we will handle the HTML version.

Create The HTML Version

PLAIN TEXT

C#:

  1. //now create the HTML version
  2. MailDefinition message = new MailDefinition();
  3. message.BodyFileName = “email.htm”;
  4. message.IsBodyHtml = true;
  5. message.From = TextBoxYourEmail.Text;
  6. message.Subject = “Zoo Event: ” + labelEventName.Text;

Notice we use the MailDefinition class this time and not the MailMessage class as we did with the plain-text version. That’s because it’s the MailDefinition class that allows us to to create an email from an HTML file. Notice the BodyFileName property that we have set to our “email.htm” file. This is just a regular old HTML file. Lastly, we set the IsBodyHtml property to true.

PLAIN TEXT

C#:

  1. //embed images for the email
  2. EmbeddedMailObject emo = new EmbeddedMailObject();
  3. emo.Path = @”~\Images\email\hdr_roar.gif”;
  4. emo.Name = “hdr”;
  5. EmbeddedMailObject emo2 = new EmbeddedMailObject();
  6. emo2.Path = @”~\Images\email\box_top.gif”;
  7. emo2.Name = “box_top”;
  8. message.EmbeddedObjects.Add(emo);
  9. message.EmbeddedObjects.Add(emo2);

The above code adds two images to the HTML file. The EmbeddedMailObject represents an item to embed in a mail message. Notice the Name property. This is important because in our HTML file (email.htm) we have this <img src=”cid:hdr” alt=”" /> code which is where it maps to the image. This way of adding images to our MailDefinition object will send the images with the email. If you don’t wish to send images with your email you may choose to simply add absolute paths to your images in your HTML file like normal. Just make sure the paths are absolute.

PLAIN TEXT

C#:

  1. //Build replacement collection to replace fields in email.htm file
  2. ListDictionary replacements = new ListDictionary();
  3. replacements.Add(“<%EVENTDATE%>”, eventTextBox.Text);
  4. replacements.Add(“<%EVENTNAME%>”, labelEventName.Text);
  5. replacements.Add(“<%FROMNAME%>”, TextBoxYourName.Text);
  6. replacements.Add(“<%EVENTDESCRIPTION%>”, labelEventDescription.Text);
  7. replacements.Add(“<%PERSONALMESSAGE%>”, TextBoxPersonalMessage.Text);

This is an important part. This is where we pass in fields to our HTML template. Within our HTML file we find this <%EVENTDATE%> . This is a placeholder that we use to pass in content. Pretty cool eh? Almost like a mail-merge in Word. So all the above gets mapped into our HTML template. Now we see the power of this solution. It sure beats creating a huge string. We have a regular old HTML file with the placeholders that we pass in the content. Any future changes can be done right in the HTML file. Nice…

Now the last code section:

PLAIN TEXT

C#:

  1. //now create mail message using the mail definition object
  2. //the CreateMailMessage object takes a source control object as the last parameter,
  3. //if the object you are working with is webcontrol then you can just pass “this”,
  4. //otherwise create a dummy control as below.
  5. MailMessage msgHtml = message.CreateMailMessage(sbEmailTo.ToString(), replacements, new LiteralControl());
  6. AlternateView htmlView = AlternateView.CreateAlternateViewFromString(msgHtml.Body, null, “text/html”);
  7. msg.AlternateViews.Add(htmlView);
  8. // send email now (check web.config)
  9. SmtpClient smtp = new SmtpClient();
  10. smtp.Send(msg);

The CreateMailMessage method creates the email message and does the merging of our replacement list with the placeholders. We also pass in the string that we created earlier. Remember the string held all the email recipient addresses. The last parameter is looking for a control that owns the MailDefinition. We don’t have one so we just pass in a dummy control.

All that remains is to send the email message via the smtp protocol. If everything in your Web.config file is set up correctly your email should be on the way.

 

Java Internationalization Made Easy June 25, 2009

Filed under: JAVA — Sudheer @ 8:01 pm
Tags: , ,

Gone are the days when your application would be geared only for local users. Today, every application must support internationalization: being accessible to users across the world and customized to the respective local users. As one of the most widely used programming languages, Java must support this requirement.

This article explains how to support internationalization in Java. Java internationalization is a simple concept, and when it is implemented correctly, long-term management requires only minimal or no code changes—even when requirements such as additional lingual support keep accumulating.

Author Note: The industry abbreviation for internationalization is i18n, which is the letters i and n with a count of the letters between the two (both inclusive).

Building internationalization support isn’t very difficult. In fact, once you get acquainted with the implementation methodology, you will find it is one of the easiest Java development tasks that you will perform. You can use it as a best practice to ensure internationalization support in all your future applications.

How i18n Works

The classes ResourceBundle and Locale in the java.util package are the building blocks for internationalization. As an example, consider the following code fragment for an application that displays a thank you message to the user along with a localized message:

import javax.swing.*;

public class GenericClass
{
   public static void main(String args[])
   {
      GenericClass genericClass = new GenericClass();
      genericClass.askQ();

   }

   private void askQ()
   {
      JOptionPane.showMessageDialog(null, 

      "The text displayed is specific to locale", 

      "Thanks to visit", JOptionPane.INFORMATION_MESSAGE);
   }
}

Figure 1 shows the output from the above code.

Figure 1: Thank You Message to the User

Figure 1: Thank You Message to the User

Imagine customizing this application to your locale without needing to rewrite it. With Java, you just add a few lines of code and the rest is simple customization.

Take a look at how you would transform the above code using internationalization:

import javax.swing.*;
import java.util.*;

public class InternationalizedClass
{
   //This are the stuff that will help you internationalize
   private static String language = "en"; //Initialize with en
    private static String country = "US"; //Initialize with US
   private static Locale currentLocale;
   private static ResourceBundle localMessagesBundle;

   public static void main(String args[])
   {

      if(args.length == 2)
      {
         language = new String(args[0]);
         country = new String(args[1]);
      }
      currentLocale = new Locale(language, country);

      localMessagesBundle = ResourceBundle.getBundle("LocalMessagesBundle",currentLocale);

      InternationalizedClass internationalizedClass = new InternationalizedClass();
      internationalizedClass.askQ();
   }

   private static void askQ()
   {
      JOptionPane.showMessageDialog(null,
         localMessagesBundle.getString("localeInfo"),
         localMessagesBundle.getString("thanks"),
         JOptionPane.INFORMATION_MESSAGE);
   }
}

When you run the transformed code with the arguments fr and FR, you will see the output shown in Figure 2.

Figure 2: Message Localized to France

Figure 2: Message Localized to France

If you have used the .properties file in Java, you already know how the preceding example worked. It is no different from the key-value pair mapping of information. There are different .properties files created for every locale; the file contents have the same key but different values. In i18n code, you always refer to the key, and based on the values specified for the locale and the country, you retrieve the correct resources and use them in your application.

The internationalization in the above code is supported by the files LocalMessagesBundle_en_US.properties and LocalMessagesBundle_fr_FR.properties (which you can download). The .properties file name is derived from a combination of the filename, language, and country code. For example, the file name LocalMessagesBundle_en_US.properties is for United States of America, with the language (English) denoted by en and the country code by US. Similarly, LocalMessagesBundle_fr_FR.properties is built for France with fr for French and the country code FR.

Transforming Your App for Different Locales

When you have your i18n infrastructure in place, it’s just a matter of minutes to transform your application for any locale you wish. Java supports a set of locales by default. The following snippet helps list the supported locales. The result will vary depending on the platform you use.

import java.util.*;
import java.text.*;

public class SupportedLocales{
   public static void main(String args[])
   {
      Locale list[] = DateFormat.getAvailableLocales();
      //Displays language and the country code
      for (int i=0; i< list.length; i++) {
         System.out.println(list[i].toString());
      }
      System.out.println("----------------------------------------------");
      //Displays the Language; more user readable
      for (int i=0; i< list.length; i++) {
         System.out.println(list[i].getDisplayName());
      }
   }
}

When Things Get a Bit More Complicated

So far, you have seen messages that are simple and mostly just a few words. In real-world scenarios, you may know only part of the message that needs to be localized and the remaining values will be computed at runtime or come from some other source.

For example, consider the following message:

I was born at 5:45 on January 25, 1971

The message contains distinct information (in boldface) that are part of a single statement. The code for this would still be:

ResourceBundle messages = ResourceBundle.getBundle("Messages",locale);

The resource bundle Messages.properties would contain the following:

msgRules = I was born at (2,time,short) on (2,date,long)

The following class uses the above resource bundle to display the desired message:

import java.util.*;
import java.text.*;

public class MessageFormatter
{
   public static void main(String args[])
   {
      showMessage();
   }

   static void showMessage()
   {
      //Defaulting to US
      showMessage("en","US");
   }

   static void showMessage(String language, String country)
   {
      Locale locale = new Locale(language,country);
      ResourceBundle messages = ResourceBundle.getBundle("Messages",locale);

      Object[] messageArguments =
      {
         new Date(74,6,8,12,5,0)
      };

      MessageFormat formatter = new MessageFormat("");
      formatter.setLocale(locale);

      formatter.applyPattern(messages.getString("msgRules"));
      String formattedMessage = formatter.format(messageArguments);

      System.out.println(formattedMessage);
   }
}

Figure 3 shows the output from the above code.

Figure 3: Birth Date and Time Message

Figure 3: Birth Date and Time Message

Not only are the i18n techniques described here simple, but they also have the long-term benefit of enabling you to add internationalization support to applications that are already deployed. In effect, you can utilize the concept in almost every aspect of information display that you can imagine.

Code Download

  Java i18n _src

For Further Reading

  “Java Internationalization” (from Sun Developer Network)

 

Browser Compatibility Development Guide June 25, 2009

Filed under: Development — Sudheer @ 7:53 pm
Tags: , , , , , , ,

Introduction

Creating cross browser web applications impacts the entire Software Development Life Cycle (SDLC). Impacted roles include project managers, web designers, architects, developers and quality assurance.

This guide for browser compatibility development has been designed to answer the following questions about developing cross browser web applications:

  1. Is the browser compatibility problem a business problem?
  2. What is the recommended browser compatibility solution?
  3. What browser families do I need to support?
  4. What environments and tools are required?
  5. What are design and development best practices?
  6. What are design and development pitfalls?
  7. What additional resources are recommended?

The goal of this article is to provide the information needed to start or enhance a browser compatibility development practice in your organization.

Browser Compatibility Now and Then

At the turn of the century, web developers created applications which worked across Netscape and Internet Explorer (IE) browser families as each browser competed for market share. This was an arduous task due to evolving web standards and the lack of adoption across vendors. In the ensuing years, Internet Explorer won the market share battle, but not the war. The additional effort for building applications to work with Netscape was not warranted for many applications.

From the perspective of market share, the current situation looks much more like 2000 than 2003. There are now two very popular browser families, IE and Firefox. Other browsers such as Safari, Chrome and Opera have a significant presence as well.

From the perspective of web standards, it is a totally different game. Browser standards are stable and mature. Their adoption across vendors is very broad. While not a trivial task, it is much easier today to build web applications which work across browser families if standards are followed. Browser compatibility is more of a developer than a vendor problem today.

The Browser Compatibility Problem

Wikipedia defines “cross browser” as the ability for a website to support multiple web browsers. This is essentially what we mean by browser compatibility. In the past, new features were added to IE and Netscape without any coordination between vendors. This resulted in differences between how features worked ranging from slight cosmetic differences to profound conceptual differences.

Today, the maturity and adoption of web standards by vendors has standardized the feature set to a great extent. This is fortunate because the marketplace demands browser agnostic web applications. If your organization creates applications tied to a specific browser, it puts itself at the risk of turning away consumers and partners who prefer to interact with a particular browser. This is the browser compatibility business problem. If your website does not render or operate correctly on a user’s browser, it negatively affects your organizations image and brand. This means your applications should be browser agnostic to the highest degree practical.

The Browser Compatibility Solution

In the past, the requirement for cross browser applications was solved for by creating “forks” in the code to handle the peculiarities of supported browsers. This made it costly and difficult to create and maintain websites due to the redundant development and testing of the various code branches. When new browser versions were introduced, poorly designed forks often created additional work due to the change in browser behavior.

Web standards provide a much simpler solution for building cross browser applications. The web application is designed from the start to support web standards–not a particular browser. To a certain degree, this future proofs the web application from the introduction of new browsers and browser versions.

Structure, Presentation and Behavior Standards

There are three sets of World Wide Web Consortium (W3C) standards which describe the structure, presentation and behavior of a web page. There is also a key Ecma standard tied to manipulating the behavior.

The structure of the web page document is defined by markup language standards (HTML, XHTML, XML). The DOCTYPE descriptor tells the browser what document type definition to use in validating the structure and how strict to apply validation rules. The following DOCTYPE statements instruct the browser to strictly adhere to the HTML 4.01 and XHTML 1.0 specifications in validating the page.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN">

The presentation of the web page uses the CSS standard to control the colors, fonts and layout. CSS separates the content described in the document structure from how it is viewed in different contexts.

The behavior of the web page is controlled by the ability to manipulate a standard document object model (DOM) representation of the structure and presentation elements. ECMAScript, the standard version of JavaScript is the standard language used to manipulate the object model.

Adherence to structure, presentation and behavior standards (and not vendor specific adaptations of these standards) is the essence of the browser compatibility solution.

What Browser Families Should You Support?

You need to consider which browser families, operating systems and configurations are preferred by your customers, partners and employees. In order to understand your audience specifically, you will need to examine the web analytics particular to your web application.

There are many industry resources which provide browser usage analytics. These should be reviewed regularly to stay top of trends. An example is the following W3C website: http://www.w3schools.com/browsers/browsers_stats.asp.

In general, Firefox and IE are the most popular browsers. A good starting point in your browser compatibility practice is to minimally provide formal support for these two browser families, meaning you will fully verify them through the entire software development life cycle. By following web standards, you will be well positioned to support additional families such as Chrome, Safari, Opera or others if required by your audience with minimal additional effort.

In addition to the browsers supported, you should also pay attention to the types of devices and operating system versions being used as well so you can test your applications in environments similar to those being used by your customers, partners and employees.

What Environments and Tools are Required?

A browser compatibility solution requires the properly configured development and quality assurance environments to support web designers, architects, developers and quality assurance personnel throughout the software development life cycle (SDLC).

Development Environment

Web designer and developer desktops will need to be configured with the primary supported browsers. Firefox and Internet Explorer should be considered at minimum. If your audience demands it, other browsers such as Chrome, Safari and Opera should also be included.

Because Firefox more strictly adheres to structure, presentation and behavior standards, it should be the primary browser for development. Firefox should be configured as the default browser on the desktop and in your IDE (Integrated Development Environment), for example, Eclipse. Although Internet Explorer is not the primary browser, it should be utilized in unit testing.

Debugging tools are essential in developing cross browser applications. Firebug and Web Developer are two essential plug-ins which should be included in your Firefox configuration. A rich toolset and plug-in ecosystem is another advantage of the Firefox browser for designers and developers.

QA Environments

Quality assurance environments may be provisioned on site, or remote services may be used. A remote service may be useful for testing odd or uncommon browser and operating system combinations.

Whereas developers and designers should be using Firefox as their primary browser, quality assurance personnel should spend more time with Internet Explorer. This creates balance in the development and testing activities across the primary browser families.

Browser Compatibility Design and Development Best Practices

The following is a starter list of best practices for browser compatibility design and development.

1. Use Firefox as the primary browser for development
The Mozilla team designed Firefox to support W3C standards from the ground up. Because Firefox adheres more strictly to standards, it is much easier to develop a web application on Firefox and then get it to work in Internet Explorer than the reverse. Development IDE such as Eclipse should be configured so that Firefox is the default browser.

2. In development, periodically test the application in Internet Explorer and other supported browsers
Throughout the development phase, test the application in IE. Prior to Quality Assurance, thoroughly test the application in IE. Utilize your onsite or remote compatibility lab to test different versions within the supported browser families.

3. Use IE as the primary browser for Quality Assurance
A significant percentage of end users prefer Internet Explorer. Quality assurance testing the application developed primarily with Firefox on IE will ensure that any IE compatibility issues missed by developers in their unit testing will be identified. The application should also be regression tested versus all supported versions in the IE and Firefox browser families as well as other formally supported browsers.

4. Specify a DOCTYPE to explicitly declare the structure of the web page
A DOCTYPE specifying strict use of HTML or XHTML is recommended. Not being careful in the DOCTYPE declaration can throw a browser into what is known as “Quirks Mode” which allows invalid and vendor specific markup. A page developed unknowingly in quirks mode will not render consistently if at all with other browsers. The strict DOCTYPE keeps you honest in adhering to standard and valid markup document structure.

In Firefox, the “Page Info” dialog box (available from Tools, Page Info) specifies the rendering mode currently in effect. In addition, the document.compatMode property can be checked programmatically.

Although a “strict” DOCTYPE and standards compliance mode are recommended, each project must determine the level of warnings which are acceptable. It is quite possible to have an application that works fine with Firefox and IE, but still has items flagged by validators such as missing alt tags.

5. Utilize global CSS to separate document structure from presentation and to abstract browser presentation differences
Utilize CSS libraries to control the presentation across the site and encapsulate browser differences in the box model which controls white space around block level elements. Any presentation code such as font tags should be forbidden from the markup document and included in the CSS.

6. Use 3rd party libraries in lieu of custom JavaScript code for cross browser support
If you find yourself writing cross browser code, it should raise a red flag. It is a much better practice to use a 3rd party library which has been built and tested for cross browser support. For example, Ajax solutions such as Dojo provide JavaScript libraries which were built from the ground up for cross browser support and accessibility.

7. Utilize Firebug and Web Developer Plug-ins
The Firebug and Web Developer Plug-ins provide a wide variety of features designed to help validate, analyze, debug and correct browser compatibility issues. Try to avoid putting alerts in your JavaScript and markup for debugging which must later be removed. It is very easy to inspect and manipulate the structure, presentation and behavior elements of your web page at run time using these tools.

8. Develop a Browser Compatibility Knowledge Base
Create a Browser Compatibility Knowledge Base to catalog and share browser compatibility lessons learned, perhaps beginning with the previous seven items outlined here. This knowledge base can be as simple as a shared document or wiki.

Browser Compatibility Design and Development Pitfalls

The following is a starter list of pitfalls to avoid in the design and development of cross browser applications.

1. Avoid browser specific plug-ins – The whole purpose of creating cross browser applications is not being tied to a specific browser family. Browser specific plug-ins such as ActiveX controls are a detriment to compatibility.

2. Avoid code forks – If you find yourself coding JavaScript which says if(isIE6), you are introducing a fork, and a non standard feature into the web application. This will create duplicate development, QA, maintenance and production support activities. In addition, this code is likely to cause additional re-work as new IE or Firefox versions are introduced or other browsers such as Chrome or Safari are supported.

Your first course of action is to use standards to meet the stated requirement. If the requirements cannot be met without standard features, then it is better to create a fork which tests for a particular feature such as if (document.getElementById).

3. Not considering the implications of what CSS hacks are used – CSS hacks take advantage of browser deficiencies in supporting standards. These hacks may be used to encapsulate browser compatibility issues. However, care must be used to ensure they do not create maintainability issues, nor impede behavior in future browser versions.

Summary

Browser compatibility is more than a technical problem. It is a business problem. If your website does not render and operate properly on the browsers your customers and partners prefer to use, it may harm the reputation of your organization and turn customers away.

Ensuring browser compatibility of your web applications begins with understanding your end users needs. Compatibility development standards and practices to meet these needs must be defined for your organization and embedded into the entire software development lifecycle. Creating browser compatible applications affects the day to day job of project managers, web designers, architects, developers and quality assurance personnel.

Web standards which define the structure, presentation and behavior of a website are the cornerstone of a browser compatibility development practice. Adhering to these standards make what was once a very arduous job more manageable.

The proper environments and tools are needed for developers and quality assurance personnel to test for browser compatibility and to debug problems. These tools and environments should be designed and configured to simulate the user experience of your audience.

There are a number of best practices and pitfalls shared in this article. Creating a browser compatibility knowledge base will help capture the lessons learned and to share them with the broader development community.

Do you have the statistics which show what browsers your customers, partners and employees prefer to use? Do you have defined standards for creating web applications which will support these browsers? Do you have the appropriate environments and tools to test and debug for browser compatibility? Do you have a knowledge base to share lessons learned and best practices? If your answer is no to any of these questions, consider using the information presented here to start or enhance a browser compatibility development practice in your organization. The rest is up to you!

Browser Compatibility Resources

Anyone wanting to study browser compatibility in more detail would do well to start here.

Developing Web Applications Using Standards

Designing With Web Standards by Jeffrey Zeldman
Migrate Applications from IE to Mozilla by Doron Rosenberg
Using Web Standards by Mozilla
Web Standards Checklist by Max Design
The Business Benefits of Web Standards by Mozilla

Validation Services

W3C markup validation service
W3C CSS Validation Service
Mozilla DOCTYPE Sniffing

 

Adobe® Flash® Catalyst – rapidly creating user interfaces without coding June 22, 2009

Filed under: Flash — Sudheer @ 12:36 pm
Tags: , , ,

Adobe® Flash® Catalyst™ is a new professional interaction design tool for rapidly creating user interfaces without coding.

  • Transform artwork created in Adobe Photoshop® and Adobe Illustrator® into functional user interfaces.
  • Create interactive prototypes with the ability to leverage them in the final product
  • Publish a finished project as a SWF file ready for distribution
  • Work more efficiently with developers who use Adobe Flash Builder™ 4 to create rich Internet applications (RIAs). Designers use Flash Catalyst to create the functional user experience then provide the project file to developers who use Flash Builder to add functionality and integrate with servers and services.

Create the user experience through an approachable interaction design tool for designers with no coding required:

  • No coding required: Create the user experience and make it functional without coding.
  • Sell your ideas: Be able to show a functional design instead of static screenshots to communicate your ideas.
  • Ensure your creative vision is accurately expressed: Design with the expressiveness of Flash Player including graphics, typography and 3D effects.

Rapidly create and deliver a finished SWF file or collaborate more effectively with developers:

  • Fast learning curve: If you can use Photoshop or Illustrator you can quickly learn to use Flash Catalyst.
  • Fast Interaction Design: Transform native Photoshop and Illustrator files into functional user experiences. Publish finished projects for distribution as a SWF file.
  • Collaborate more effectively with developers: Provide Flash Catalyst projects to developers who use Flash Builder to add additional functionality and integrate with servers and services.

Flash Catalyst and Flash Builder are based on the open source Flex 4 framework.

 

Extend Your SharePoint Control with Custom Stsadm Commands June 19, 2009

Filed under: DotNet — Sudheer @ 1:39 pm
Tags: , , ,

The SharePoint Team Services Administration application (stsadm), a command-line tool Microsoft introduced with SharePoint 2003, is the default way to administer and configure Windows SharePoint Services (WSS 3.0) and Microsoft Office SharePoint Server (MOSS), the company’s premier tools for collaboration and knowledge workers. The 2007 version of stsadm offers an extended, richer set of commands, and introduces the ability to develop and configure custom commands.

Stsadm is a command-line program that doesn’t provide an interface or other interaction with the user, making it a perfect candidate for use in scripts and automated operations. The program needs to run locally in one of the front-end SharePoint servers in the farm, and requires users to have administrative rights.

You can find stsadm in the directory C:\Program files\Common Files\microsoft shared\Web Server Extensions\12\BIN on any server where SharePoint is installed. To make stsadm usable directly from a command prompt without having to enter the complete path, add its path to the system variables: On the server, navigate to Start → Computer → Properties → Advanced system settings. In the window that appears, select Environment Variables from the Advanced tab, and add a new System variable. The next time that you want to use the tool, you can simply enter stsadm in the command line.

Command Set

Stsadm contains 184 instructions to manage and administer different aspects of SharePoint. If you execute the stsadm command with no arguments, a complete list of commands appears on the screen. The directives can be separated into several different categories:

  • Site maintenance: create, delete and enumerate sites
  • Web maintenance: create, delete and enumerate Webs and sub-Webs
  • User maintenance: add, delete, enumerate and migrate users
  • Manipulate SharePoint Objects: backup and restore, installation and management of WebParts, Features, Solutions, and templates
  • Server management: Add, delete, or enumerate databases, managed paths, Web Applications, and SharePoint Jobs

You can perform almost all these operations from the SharePoint interface; however, there are some exceptions, which you can execute only from the command-line stsadm tool:

  • Execadmsvcjobs: Forces all configured SharePoint Jobs to run immediately.
  • Createsiteinnewdb: Creates a new Site Collection using its own database.
  • Getproperty and setproperty: Supports configuring diverse SharePoint properties
    • Configures the number of days a “New” icon appears in new List and Library items
    • Configures scanning time if new alerts need to be sent
    • Configures the maximum number of Site templates
    • Configures the maximum size of Blobs to be used in SQL server

You can find the complete command list on-line. Here’s the syntax for stsadm:

stsadm -o OperationName -ParameterValue”

For example, to review all sites under the portal, use stsadm -o enumsites -url http://ServerName, where enumsites is the operation name, url is the parameter name, and http://ServerName is the parameter value. The operation name is required; parameters may be obligatory or optional. When values contain spaces, place them inside quotation marks.

As stated previously, stsadm is not interactive, which means you must take care to ensure that parameters and syntax are written correctly. Also, if something is not defined accurately, the operation completes with an error message—leaving you to reinitiate the entire command. On the other hand, stsadm allows developers and administrators to create batch files that run various commands in a timely way. For example, an administrator might write a batch file that initiates Windows Task Scheduler and creates a new batch to generate nightly SharePoint backups. Developers might use the tool to install or uninstall SharePoint components by automatically integrating them in the Visual Studio script engine. For example, you might do this to install components after a successful compilation.

When the built-in commands aren’t enough, SharePoint 2007 supports the creation and configuration of custom stsadm operations. Although the default commands are extensive and quite complete, they don’t include some operations of potential value to developers.

Two that come to mind immediately are:

  • Enumerating features in a site
  • The ability to delete web sites recursively

When you need such capabilities, creating new specialized, automatic commands can be extremely useful. The rest of this article shows how to build and add these two specialized custom commands to stsadm.

Programming New Commands

To generate new operations you need Visual Studio (2005 or 2008) and one of its default program languages (C# or VB). Launch Visual Studio and create a new project of the type “Class Library”, giving it a unique name (ToolsSpsadm in the following example). The class should inherit from the ISPStsadmCommand Interface and must have at least two methods: GetHelpMessage and Run:

using System; 
using System.Collections.Specialized; 
using System.Text; 
using Microsoft.SharePoint; 
using Microsoft.SharePoint.StsAdmin;   
namespace ToolsSpsadm 
{
   public class ClassToolssSpsadm : ISPStsadmCommand  
   {
      public string GetHelpMessage(string command) {}
      public int Run(string command, 
         StringDictionary keyValues, out string output) {}
   }
}

The GetHelpMessage method runs with the stsadm help function and displays messages indicating its syntax and operation parameters. The example uses only one parameter (URL) to configure the URL of a site. The method looks like this:

public string GetHelpMessage(string command)
{
   return "-url <URL complete in Site and SharePoint>";
}

For example, to get help on the EnumerateFeatures command, you would use the command stsadm -help –EnumerateFeatures. That executes the GetHelpMessage method and the help message appears.

The Run method contains the source code to execute the operations. A switch statement selects one of the commands, if there is more than one in the class:

public int Run(string command, StringDictionary keyValues, 
   out string output)
{
   command = command.ToLowerInvariant();
   switch (command)
   {
      case "enumeratefeatures":  
         //Attention: all in lower case to prevent the error: 
         // 'Operation not valid because of the actual 
         // state of the object')
         return this.EnumerateFeatures(keyValues, out output); 
      case "eliminatewebrecursively ": 
         return this.EliminateWebRecursively(keyValues, out output); 
      default:
         throw new InvalidOperationException(); 
   } 
}

The example class exposes two commands: EnumerateFeatures and EliminateWebRecursively. The command parameter contains the name of the operation to be executed and the switch statement selects the matching method. Note that all strings are converted to lower case to prevent the error “Operation not valid because of the actual state of the object” that occurs if the case statement has any uppercase letters.

The first method, EnumerateFeatures, does just that: Given the URL of a site, it returns the installed and activated Features in that site:

private int EnumerateFeatures(
   StringDictionary keyValues, out string output)
{
   if (!keyValues.ContainsKey("url"))
      throw new InvalidOperationException(
         "The URL parameter was not specified"); 
   } 
   String myUrl = keyValues["url"];
   SPFeatureCollection AllFeatures = null;
   SPSite mySite = null;
   SPWeb myWeb = null;
   StringBuilder myOutput = new StringBuilder();
   try
   {
      mySite = new SPSite(myUrl);
      myWeb = mySite.OpenWeb();
      AllFeatures = myWeb.Features;
      myOutput.AppendLine("Features in '" + miWeb.Url + "':\n");  
      foreach (SPFeature oneFeature in AllFeatures)
      {
         myOutput.AppendLine(oneFeature.Definition.DisplayName + 
            "\t\t(" + oneFeature.DefinitionId + ")");
      }
   }
   catch (Exception ex)
   {
      throw new InvalidOperationException(
         "Error searching the URL '" + myUrl + 
         "'. Check the URL format and ensure that the Site exists." + 
         "Details: " + ex.Message);
   }
   finally 
   {
      if (mySite != null) mySite.Dispose();
      if (myWeb != null) myWeb.Dispose();
      myOutput.AppendLine("EnumerateFeatures finished");
   }
   output = myOutput.ToString();
   return 0;
}

The StringDictionary parameter contains pairs consisting of operation names and their values. The output parameter is a string that, at the end of the method, contains all the return data. The first lines check that the url parameter has been passed; otherwise, the method returns an error message and aborts the operation. Next, the code creates SharePoint objects to contain the Site, Web, and the Features Collection in that Web, and then instantiates them. Finally, it creates a StringBuilder to collect the output. After instantiating the SharePoint objects, it loops through the Features, appending information to the StringBuilder. If an error occurs, the method generates a general exception that indicates the type of problem. Finally, when the process completes, it disposes of the created SharePoint objects, and assigns the contents of the StringBuilder to the output string.

Adding a Recursive Site Delete Command

The second class method solves a default SharePoint issue: If there is a main web site with sub-sites, it is impossible to delete the main site directly. Instead, you must delete each sub-site before deleting the main site. This can be a messy and lengthy process if there are many sub-sites. The EliminateWebRecursively method deletes sub-sites recursively:

private int EliminateWebRecursively(

StringDictionary keyValues, out string output)

{

if (!keyValues.ContainsKey(“url”))

{

throw new InvalidOperationException(

“The URL parameter is not specified”);

}

String myUrl = keyValues["url"];

SPSite mySite = null;

SPWeb myWeb = null;

StringBuilder myOutput = new StringBuilder();

try

{

mySite = new SPSite(myUrl);

myWeb = mySite.OpenWeb();

if (myWeb == null)

myOutput.AppendLine(

“Web ‘” + myUrl + “‘ not found”);

else

{

if (mySite.Url == myWeb.Url)

{

throw new InvalidOperationException(

“Web ‘” + myUrl + “‘ not found”);

}

RecursionEliminateWebs(myWeb.Webs);

if (myWeb.Url == myUrl)

myWeb.Delete();// This is the Top level Web

}

}

catch (Exception ex)

{

throw new InvalidOperationException(

“Error searching the URL ‘” + myUrl +

“‘. Check the URL format and ensure that ” +

“the site exists.” + “Details: ” + ex.Message);

}

finally

{

if (mySite != null) mySite.Dispose();

if (myWeb != null) myWeb.Dispose();

myOutput.AppendLine(“EliminateWebRecursively is finished”);

}

output = myOutput.ToString();

return 0;

}

As you can see, the structure is very similar to the first method. It checks to ensure that the StringDictionary contains a url key and associated value, and that the value points to a valid site. After passing these checks, it calls the RecursionEliminateWebs function to eliminate all the sub-sites from the main site, from top to button:

private void RecursionEliminateWebs(SPWebCollection AllWebs)

{

foreach (SPWeb oneWeb in AllWebs)

{

if (oneWeb.Webs.Count > 0)

{

RecursionEliminateWebs(oneWeb.Webs);

}

oneWeb.Delete();

}

}

After the recursion completes, the calling code deletes the main site. The final block, again, disposes of the created objects and generates a success message.

Compile the class, signing it with a safe name, and copy the DLL to the Global Assembly Cache (GAC). To ensure that stsadm treats the code as one of its own operations, create an XML file in the directory C:\Program Files\Common Files\Microsoft shared\Web Server Extensions\12\CONFIG. The name of the file must have the form stsadmcommands.[UniqueName].xml. The example uses the name stsadmcommands.ToolsSpsadm.xml. The [UniqueName] portion may be any string or GUID and cannot be repeated in the directory. The file indicates the operation name and the class that contains the code. For this example, the XML file would look like this:

<?xml version=”1.0″ encoding=”utf-8″ ?>

<commands>

<command

name=”EnumerateFeatures”

MsoNormal” style=”margin-bottom: 0.0001pt; line-height: normal;”>      Version=1.0.0.0, Culture=neutral,

PublicKeyToken=98de5564275127d9″/>

<command

name=”EliminateWebRecursively”

MsoNormal” style=”margin-bottom: 0.0001pt; line-height: normal;”>      Version=1.0.0.0, Culture=neutral,

PublicKeyToken=98de5564275127d9″/>

</commands>

Replace the name, class, Version, and PublicKeyToken with the appropriate values for your own code. At this point, stsadm should recognize the new methods and display the new operations in its list.

One way to simplify the process is to create a custom solution to install the tools in SharePoint. The solution manifest copies the assembly to the GAC, and the XML configuration file to the correct directory:

<?xml version=”1.0″ encoding=”utf-8″ ?>

<Solution xmlns=”http://schemas.microsoft.com/sharepoint/”

SolutionId=”5470D10C-573C-6ba3-920D-ABCD2DC73325″

DeploymentServerType=”WebFrontEnd”>

<Assemblies>

<Assembly DeploymentTarget=”GlobalAssemblyCache”

Location=”ToolsSpsadm.dll” />

</Assemblies>

<RootFiles>

<RootFile Location=”CONFIG\stsadmcommands.ToolsSpsadm.xml”/>

</RootFiles>

</Solution>

Install the Solution using stsadm and activate it from SharePoint Central Administration, or by using stsadm again.

As you can see, stsadm is the tool par excellence for SharePoint administrators and developers, letting them manage and configure the system in a swift and straightforward manner. Stsadm is not an interactive tool—it has no interface—but it works well as a command-line program, and may be used in combination with scripts to automate SharePoint tasks. By default, stsadm contains an extensive list of commands that cover almost all administrative tasks, but as this article has shown, if you find yourself performing tasks that stsadm lacks, you can create custom commands to fulfill those needs.

 

Hardware’s Dirty Little Secret, or Why Software Can be Mass Produced June 19, 2009

Filed under: General Messages — Sudheer @ 12:47 pm
Tags: , ,

Over twenty years I have worked on a lot of projects. Being an author, columnist, and consultant I have heard about many more projects than I ever could have possibly worked on. The most common, glaring, obvious fact is that a great deal of software that is created from scratch never sees the light of day. Of the software that does get used by real customers, very little of it got to customers on time, on budget, or with the originally promised features.

The conventional wisdom has been that software engineering is hard, and that every application represents something new in the Universe. So it has always been, so it will always be.

Sadly, this conventional wisdom represents a fallacy.

There is a secret organization that hardware engineers belong to called the IEEE, and they have a dirty little secret that they haven’t shared with software engineers. The secret is that the power, freedom, and choices need to be eliminated. Why haven’t they shared the secret? Because most software engineers haven’t passed a standardized test, they haven’t learned the secret handshake, and they haven’t demonstrated a willingness to take a considerable pay cut.

Unlike the Illuminati, the IEEE exists and they hold the key to producing software more cheaply, more reliably, and faster than most software project managers could ever dream.

Twenty Years in the Knowing

I have been consulting, writing, and presenting to companies and for programmers for twenty years now. During some of that time I have worked on projects that directly interact with or reside on devices that aren’t exactly computers. To do so I had to actually read hardware specifications for those devices, and I found out hardware’s dirty little secret: device manufacturers rarely build anything from scratch. Hardware is assembled only from pre-existing parts and put in a shiny box. No one ever looks inside the box and few ever look at the actual blueprints of the things in the box. All the end user knows is the box is shiny and it does something like wash clothes, play music, or record television. To put it succinctly hardware is the same old parts used over and over with different shiny boxes.

When an electronic engineer (or any engineer not a programmer) graduates from college —and graduate with an engineering degree they must—they join the IEEE. (You can Wikipedia IEEE for the acronym; that’s not important.) (Anyone can be a programmer. They let Psychology majors write code.) When one joins the IEEE one takes a pledge to work for moderate pay, never invent anything new when something exists that will do the job, and to never ever start a company from their garage.

Once they have taken the pledge the new member is given a 27 page booklet. The booklet has all of the chips, parts, resistors, capacitors, and acceptable wire formulations deemed by the IEEE as being “acceptable”. The parts for everything to be built now and in the future must already exist in the booklet. On a very rare occasion something new is added to the booklet, but that new thing is voted on by secret, senior priests of the IEEE and then everyone gets a new booklet. It is important to note that only senior IEEE priests get to add anything to the list of “acceptable” things and this is done only rarely.

In software anyone with a keyboard can invent something new and with the Internet, email, and version control that something new ends up on other people’s desks pretty quickly. So much creativity is confusing. If there were a software booklet it would be 27,000,000 pages long and highly redundant. The difficulty with software engineering is that there are no high priests, everyone gets a say in the creation process, and everyone has a different opinion.

How Hardware is Built

The upshot is that when hardware is built the hardware engineer goes to a cabinet and much like preparing dinner chooses from the equivalent of chicken, pork, beef, or fish and a couple of vegetables and makes dinner. In hardware every meal time there is a meal.

Sorry, where was I? I got lost in my metaphor. Oh yeah!

Hardware engineers know several things. First, they have to assemble something to put in the box. Second, they only have a limited number of things to build from. And third, the thing will be packaged in a shiny plastic case, shrink wrapped, advertised on TV or placed in a Happy Meal, and people will purchase it. Shiny new hardware things can be created so fast and so cheaply this way that the IEEE and the hardware guys don’t even care that this system by its very nature is hit or miss.

The key to mass producing shiny hardware things is never invent new parts, even if it means you put in a part that does 100 things and only one is needed, re-organize the parts into different configurations, and change the shiny box (making it smaller if possible). (In 1978 I had a Zenith stereo that played 78 RPM record albums, it played music. In 2009, I have a wafer thin iPod (sorry Zune guys), but it just plays music. Someone just figured out how to use fewer things from the parts catalog, but most of them existed in 1978.)

How Software is Built

Continuing my meal metaphor, when it comes to software everyone misses meals, all kinds of meals. Software is like an Ethiopian famine. When it comes to software and meal time there is no fish, pork, beef, chicken or vegetables. There is no kitchen, no utensils, and no structured meal time. At meal time the average software engineer is talking about how molecules can be assembled to make proteins. (I must be hungry.)

Now, as programmers, this state of affairs is not really our fault. Programmers are smart, creative, have no controlling body or high priests. Programmers labor in a state of lawlessness where the biggest brain or the loudest voice wins the day. Programmers have too many choices, too much power, and we are just too smart for our own good.

In Truth…

Software eventually will be assembled more from existing parts. Individual factions of programmers won’t be asking themselves questions like should I use ADO.NET, SQL, LINQ, XPO, or something else to get data to and from the database. There will be one database data-getting thingy and everyone will use it. Our lists of choices will be smaller, we’ll accept lower pay, we will swear a secret oath to the high priests of software engineering, and from that day forward software projects won’t fail. Right?

In the mean time, try to build applications from code that already exists, from technologies that that you already know how to use, and that are sufficient to do the job, even if you have to mix and match a little or use something that does more than you need it to do. You will get to build more shiny software thingies if you do.

 

ThoughtWorks on App Engine for Java: An Enterprise Cumulonimbus? June 16, 2009

Filed under: JAVA — Sudheer @ 11:37 am
Tags: , ,

Enterprise software pundits are now gazing metaphorically skyward. There’s all this talk of clouds, but what kind of clouds are coming, and will they be friendly? We begin by describing some applications we’ve developed for App Engine, including implementation of other languages, such as JRuby, on top of the App Engine for Java implementation. These implementations demonstrate the breadth of capability provided by App Engine. We then examine some of the strengths and current weaknesses that we encountered. We also describe more about the implications for testing that arise when developing on App Engine. We will also present an initial framework for characterizing these differnet clouds and examine how these characteristics will impact the adoption path for enterprises and the kinds of applications these enterprises will move to the cloud. Of particular interest here is the central role of Big Table in App Engine. Broad adoption of this of this platform could lead to lots of lightening striking at the dominant role relational data base systems currently enjoy.

Download session presentation PDF.