Monday, December 11, 2006

ASPMENU Source Code is now available !

The underivable AspMenu class that shipped with WSS 3.0 is now unsealed ! The class source code has been released lately to allow developers to extend its functionality. Download the MOSSMenu source code here and you can treat the class as your base class for your own custom menu.

Check Customizing the WSS 3.0/MOSS 2007 Menu Control -- MossMenu source code released for more information.

Inflexibility of WSS 3.0 Customization

Recently I came across the page customization in WSS 3.0 (Creating new custom page that using application.master under _layouts folder), and I found out that the master page is likely not edited for the company branding purpose because the master page is used and shared by all sites in the WSS v3. Any changes upon the application.master would eventually applied to the rest of the sites too.

This would be a PAIN for developers where easier customization feature is not ready for them. The very easy and straightforward solutions to the matter that I can think of are:

1. Clone the application.master and rename it to your own name. Change and apply the custom master page separately.

2. Develop a custom web control that check current SPSite or SPWeb to change master page accordingly.

Perhaps, there are more elegant solutions that can resolve this problem.

Tuesday, December 05, 2006

Installing Custom Group and Actions in WSS/MOSS Features

Another customization in WSS/MOSS! You can install your own custom feature other than out-of-box features that offered WSS/MOSS. You can add new actions or menus in any location in WSS/MOSS like Site Settings, Site Actions, Item Context Menu, and etc in Standard Menu.

By default, there have 5 groups - Look and Feel, Users and Permissions, Gallaries, Site Administration, Site Collection Administration.

To install new custom feature, create a new folder in C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES. I name the folder as MyCustomGroupAndAction. Then we need to create an XML called feature.xml and another xml file that contains the feature definition. (featuredef.xml)

Feature.xml has several elements - <Feature>, <ActivationDependencies>, <ElementManifests> and <Properties> but the important ones are :

1. <Feature> (the root element) - Defines feature ID, scope (site, collection, etc), description and title.

2. <ElementManifests> - defines the feature definition, which links to the xml file that contains the definition.

In feature.xml

<?xml version="1.0" encoding="us-ascii"?>
<Feature Id="F863C1CF-897D-49c6-8600-7E6F3FC9D653"
Title="My New Feature"
Description="This is my new feature"
Scope="Web"
xmlns="http://schemas.microsoft.com/sharepoint/">
<ElementManifests>
<ElementManifest Location="featuredef.xml" />
</ElementManifests>
</Feature>


The ID of the feature is unique GUID. You need to generate new GUID for each new feature being created. To generate the GUID, you can go to Visual Studio -> Tools Menu -> Create GUID or launch the tool at C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\guidgen.exe.



The location attribute of <ElementManifests> specifies the location of feature definiton XML file.

In featuredef.xml

<?xml version="1.0" encoding="us-ascii"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomActionGroup
Id="MyCustomGroup"
Location="Microsoft.SharePoint.SiteSettings"
Title="My Custom Group" />

<CustomAction Id="MyCustomFeature"
GroupId="MyCustomGroup"
Location="Microsoft.SharePoint.SiteSettings"
Title="New Custom Feature"
Sequence="50">
<UrlAction Url="_layouts/layoutdesign.aspx"/>
</CustomAction>
</Elements>


The <CustomActionGroup> specifies the definition of new group to be created. Location attribute specifies where the custom group will reside. In this example, "Microsoft.SharePoint.SiteSettings" indicates that the new group will be in the Site Settings menu of WSS sites. Check Location and Group ID in MSDN for more information. Text in the Title attribute is the name of the group.

<CustomAction> is where the custom feature definition set. The location attribute MUST BE same as the location being specified in the group that the custom feature points to (in GroupID attribute). <UrlAction> element merely specifies URL of the custom application page.

It is about to install the feature ! Go to the command prompt, type

C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN>stsadm -o installfeature -name MyCustomGroupAndActions


The feature has just been installed. However, you need to activate the feature before using it. To activate it, you can type

stsadm -o activatefeature -filename MyFeature/feature.xml -url <server url>


or

go to http://<server name>/_layouts/manageFeatures.aspx, and you will see this



Click "Activate" button to activate the feature. Go to "Site Settings" and you will see this




You have completed installation of new custom group and feature !!

Monday, December 04, 2006

Converting String GUID to System.Guid

Simple matter. I was trying to convert the GUID in string to type of System.Guid and the code below apparently did not work for me.

System.Guid guid = (System.Guid)strGUIDInString;

I was given invalid specified cast error message and I noticed that direct casting wasn't the way. I ended up with

System.Guid guid = new System.Guid(strGUIDInString);


This was the final solution I could think of, so far !

Monday, November 27, 2006

MOSS 2007 and WSS3 Functional Architecture Diagram

Here is the colourful and comprehennsive diagram illustrating the functional architecture of the most latest of Microsoft Office Sharepoint Server 2007 and Windows Sharepoint Services 3.0.

Saturday, November 25, 2006

Release of WSS RTW and MOSS Standard and Enterprise Edition

YOu can download the Release-To-Web version of WSS (Windows SharePoint Services) and Microsoft Office SharePoint Server 2007 Evaluation version at

1. Microsoft Office SharePoint Server 2007 x86 English Evaluation
2. Windows SharePoint Services 3.0

CD Keys available for standard and enterprise edition are

SharePoint Server Standard Trial: XJMKW-8T7PR-76XT6-RTC8G-VVWCQ
SharePoint Server Enterprise Trial: F2JBW-4PDJC-HKXTJ-YCKRP-T2J9D

For more resources about installation, upgrade, versioning, check this link, from Microsoft SharePoint Products and Technologies Team Blog

Thursday, November 23, 2006

Efficient String Concatenation in JS

In .NET, we use StringBuilder if we need to concatenate strings for better string manipulation performance. For instance,

StringBuilder builder = new StringBuilder();
builder.append("This");
builder.append("is");
builder.append("really");
builder.append("good");
builder.append("for");
builder.append("performance");

string str = builder.ToString();

In JS, we can also do the same thing for better memory allocation in string concatenation too.

var builder = new Array();
builder.push("This");
builder.push("is");
builder.push("really");
builder.push("good");
builder.push("for");
builder.push("performance");

var str = builder.join("");


This method will perform faster if the number of string concatenation is huge. THe normal += operator will win, otherwise.

Check Efficient JavaScript for more information on optimizing JS code

Tuesday, November 21, 2006

Invoking Executeable File from ASP.NET Web Services

Below is the code snippet on how to invoke the executable file (exe) from the cmd.exew being executed.

// Execute the Command Prompt
ProcessStartInfo psi = new ProcessStartInfo("cmd.exe");

// Indicating the input read from the process's standard input
psi.RedirectStandardInput = true;
psi.UseShellExecute = false;

// Do not show the GUI of the running app
psi.CreateNoWindow = true;

Process process = null;
try
{
// Execute the cmd.exe
process = Process.Start(psi);

StreamWriter writer = process.StandardInput;

// Write the command to the command prompt
writer.WriteLine("notepad");

}
catch (Exception ex)
{
// do something here
}
finally
{
if (process != null)
{
process.Close();
}
}


The code will simply run the notepad from the cmd.exe. You can just call "notepad" from at line the of ProcessStartInfo psi = new ProcessStartInfo("notepad");, but I am showing how are you going to write the command to the cmd using the StandardInput of Process object.

Similarly, you can call batch file from the cmd to execute command in the batch file too, or store those static command in the resource files (resx) inside the app_GlobalResources folder and get from the key by

Resources.<Resource file name>.<key name>

MSDN Magazine - HTML Help Downloads

If you want to read MSDN Magazine contents wherever you are, you can download the dozens of MSDN Magazine in portable chm format at http://msdn.microsoft.com/msdnmag/htmlhelp.aspx

Use of ResolveClientUrl() method in getting browser-acceptable relative URL

In .NET, we always use tilde (~) to refer to root virtual directory of the web application. For instance,

<asp:Image runat="server" ImageUrl="~/images/mypic.gif" />

However, in order to generate a URL that can be used by client-side browser, the URL is actually resolved in the AddAttributesToRender() of the Image server control.

writer.AddAttribute(HtmlTextWriterAttribute.Src, ResolveUrl(ImageUrl));

That is the reason why you can use "~" in the ImageUrl property. But I afraid this might be the case if you do the same thing upon the normal HTML elements or HtmlGenericControl, such as :

<img src="~/images/mypic.gif" alt="" />

because the browser does not recognise what the "~" symbol stands for. In order to workaround with that, this is where the ResolveClientUrl() method comes into place.

<img src='<%= ResolveClientUrl("~/images/mypic.gif") %>' />

Apart from using it in HTML, it can also be used in code-behind that involves in getting the relative path for the URL. For instance, ResolveClientUrl() method is handy when we are trying to register the javascript reference in code-behind,

this.Page.ClientScript.RegisterClientScriptInclude(this.GetType(),"MyScript", this.ResolveClientUrl("~/images/myscript.js"));

Not only that, you will always need this method in your custom server control development.

Thursday, November 02, 2006

Debugging JS in VS 2005 using Script Explorer

Breakpoint is one of the useful features available in Visual Studio 2003/2005 to allow developers to trace the current value of variable at the location where the debugger is currently running at. Nevertheless, you can set any breakpoint in the code-behind of the aspx page, but not in declaractive page. No particular client-side javascript function codes can simply be set as breakpoint in Visual Studio.

I rarely debug the client-side JS codes, or I can say NEVER! I have tried to debug it using Script Explorer today and it impressed me. To debug the client-side JavaScript functions, you can use the only-visible-in-debugging-environment Script Explorer in Visual Studio 2003/2005. There are few steps need to be followed:

1. Enable Client-side Script Debugging

IE -> Tools Menu -> Options Menu -> Advanced Tab -> Untick " Disable script debugging check box" in Browsing category.



2. In VS environment, write a simple JS function in external functions.js

function MyLoad(name)
{
var message = "Welcome, " + name;
alert(message);
}

Then, invoke the function in body's load() event in ASPX page.

window.onload = MyLoad("Alvin");

3. Press F5 to debug the page. In debug mode, go to Debug Menu->Windows-> Script Explorer (this option only appears in debug mode). The window of Script Explorer will be shown.



4. Once you debugging the page, you will see list of JS files/resources shown in Script Explorer in tree view.



Double click the "functions.js" and set the breakpoint at particular line. The debugger will stop at that line when it passing through it.




Additionals
If your javascript functions are in the aspx page, you can add breakpoint by

Debug Menu -> "Add Breakpoint" -> "Break At Function" -> type your method name there and choose right language.




Read more in MSDN
1. How to: Debug a Client-Side Script from Microsoft Internet Explorer
2. How to: Enable Client-Side Script Debugging
3. How to: Set a Function Breakpoint


I need a break....

Tuesday, October 31, 2006

Accessing GridView's DataControlFieldCell Programmatically

How would you access the auto-generated control in the HyperLinkField (HyperLink control) and ButtonField (LinkButton or Button control) in RowDataBound event ? You will find out that FindControl() method would no longer be working since there is no concrete ID is assigned to the control, and you are not intelligent enough to know what ID will be assigned automatically by the compiler. There are two workarounds, in which the second one is new in ASP.NET 2.0.

Assuming that the HyperLinkField is at 4th column.

First Workaround

protected void GridView1_RowDataBound(object sender,
GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
HyperLink hl = e.Row.Cells[3].Controls[0] as HyperLink;
hl.Text = "Changing Text here";
}
}

This workaround is pretty straightward. Cells[3] refers to 4th column (index starting from 0) ; Controls[0] means the first control in that column, which is HyperLink control.

The first workaround is apparently classic way that we used in DataGrid control. But here is the another workaround, which works in different way !


Second Workaround

protected void GridView1_RowDataBound(object sender,
GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DataControlFieldCell dField = e.Row.Cells[3] as
DataControlFieldCell;
HyperLinkField hlf = dField.ContainingField as HyperLinkField;
hlf.Text = "Changing Text here";
hlf.DataNavigateUrlFormatString = "nextpage.aspx?id={0}";
}
}

As you can see, I am accessing the HyperLinkField itself, and I am able to assign the DataNavigateUrlFormatString property in the RowDataBound event too. Of course, if you would like to access the control in that field, it can be done by

HyperLink hl = dField.Controls[0] as HyperLink;



Hope this helps...

SQL Server Connection Timeout !

Frustrated ! I was given an error message of "Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding." when I was trying to connect to SQL Server 2000 with VS 2005. The connection string was correct and I tried several connection strings :

1. Server=ALVIN;Initial Catalog=pubs;UID=sa;
2. Server=ALVIN;uid=sa; database=pubs";
3. packet size=4096;user id=sa;data source=ALVIN;persist security info=False;database=pubs

(I used sa account for simplication, don't use it in your production site)

But none of them worked for me. I tried it in VS 2003 and unbelievably it worked! (Don't say there is any discrimination) What the heck.. Without any patience left, I saught the answer from Google and I got this link at http://msdn2.microsoft.com/en-gb/library/ms190181.aspx. It explains several causes of the problem, but one of them seemingly is the cause of my problem, which is :

"Database Engine is not listening on port 1433 because it has been changed, or because it is not the default instance, and the SQL Server Browser service is not running."

I tried to go to Client Network Utility and Server Network Utility to change my port number of TCP/IP to 1433 AND reorder it to be the first before the "Named Pipes".




After restarting the SQL Server, it eventually went fine for me. :)

Monday, October 30, 2006

New Features of my Blog

I have implemented my blogger with new Blogger Beta, and it is pretty amazing. The template in HTML is different from the classic template style. There are some new features added in this blog, such as post count in the right-hand-side sidebar, new widgets, new navigation bar. Other features such as blogs searching will be added soon. Although it is not completely nice, it nears to perfection.

For those users who use this blogger, you can visit http://beta.blogger.com/ for the version switching, or visit these sites for helps.

1. http://betabloggerfordummies.blogspot.com/index.html
2. http://groups.google.com/group/blogger-help
3. http://betabloggerfordummies.blogspot.com/


Still figuring out its features and specialities....

Saturday, October 28, 2006

Changes on my ValidTextBox Server Control

I have made some changes to my ValidTextBox server control. The changes are:

1. Supports to display error image instead of text error message when the control is invalid.
2. Supports Tooltips for error image.
3. Fixed bug of email address expression, which allows symbols.

Screenshots:






Please check http://mind.com.my/forums/1018/ShowThread.aspx#1018 for more details...

Sample Programming Interview Questions

I have found there are a set of interview books, relating to Programming - ".NET Interview Questions", "Java Interview Questions", "SQL Server Interview Questions" and so on. These questions are commonly asked by companies during their interview/recruitment process. You may take a look on sample questions at http://www.questpond.com/ , which has a lot of sample questions to be downloaded in zip format.

Some questions are tough!

[ASP.NET] Building Tag Cloud in ASP.NET

What is Tag Cloud. A tag cloud is a way to display a weighted list such that the weight of each item is reflected by the size of the item's text. Tag clouds provide a quick way for one to eyeball a list and ascertain what items are more prevalent.

Scott Mitchell has just written an article of Creating a Tag Cloud in ASP.NET. That is very cool especially you are dealing with blogging or tagging-related sites. I have tested it, and that's nothing but COOL !

Wednesday, October 25, 2006

[ASP.NET] Basic of Custom Server Control Development Part II - ParseChildren(), PersistChildren() and PersistenceMode()

Let us boils down to the three attributes that important in implementing simple properties and subproperties in the custom control development - ParseChildrenAttribute, PersistChildrenAttribute and PersistenceModeAttribute.

Default and Inner Property Persistence
Default persistence is in constrast to Inner persistence, but they are identically same for its functionality. In our control development, we may have complex properties (class). To persist them, we can use hyphenated syntax (Default Property Persistence) or nesting them within your control tags (Inner Property Persistence). Example of Inner Property Persistence,

<asp:GridView ID="GridView1" runat="server">
<HeaderStyle BorderWidth="12" />
</asp:GridView>

In the example given, the BorderWidth is the subproperties of the HeaderStyle property of GridView. To enable this inner property persistence, you need to set the ParseChildren(true) and PersistChildren(false) in your control class.

[ParseChildren(true)]
[PersistChildren(false)]
public class MyWebControl : WebControl
{
...
}


1. ParseChildrenAttribute
This attribute tells the parser to parse the parse the contents within the control tag as properties but not child controls.

To enable the inner default property persistence, you have to specify the inner default property to the second parameter of ParseChildrenAttribute.

[ParseChildren(true, "<DefaultPropertyName>")]
public class MyControl : WebControl
{
...
}


2. PersistChildrenAttribute
On the other hand, this attribute tells the designer whether the child controls of the server control should be persisted as inner child controls. Setting to false indicates inner content corresponds to properties but not to child controls.

* Therefore, the ParseChildrenAttribute and the PersistChildrenAttribute attributes use opposing conventions for the semantics of their argument. Check more difference of these two attributes at Justin Lovell's Blog - The ParseChildren and PersistChildren Attributes


3. PersistenceModeAttribute
This attribute specifies how the property of server control is persisted declaractively in ASP.NET pages. It has 3 enumerations :

EncodedInnerDefaultProperty - Specifies that the property persists as the only inner text of the ASP.NET server control. The property value is HTML encoded. Only a string can be given this designation.

InnerDefaultProperty - Specifies that the property persists in the ASP.NET server control as inner text. Also indicates that this property is defined as the element's default property. Only one property can be designated the default property.

InnerProperty - Specifies that the property persists in the ASP.NET server control as a nested tag. This is commonly used for complex objects, those that have persistable properties of their own.

Picked from http://msdn2.microsoft.com/en-us/library/system.web.ui.persistencemode.aspx

[PersistenceMode(PersistenceMode.InnerProperty)]
public virtual TableItemStyle HeaderStyle { ... }

This indicates that the designer to persist the property as inner property. By default, it is persisted by using hyphenated syntax in control tag. To persist inner default property, you need to have

[ParseChildren(true, "<DefaultPropertyName>")]
public class MyControl : WebControl
{
...
}

and

[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public virtual ListItemCollection Items { ... }



These three attributes are confusing, but are not undifferentiable.

Monday, October 23, 2006

My ValidTextBox is OUT !

After spending 3 days of custom control development, I have successfully developed the beta-period ValidTextBox server control. It basically integrates validator controls (RegularExpressionValidator and RequiredFieldValidator) and normal textbox control to reduce the developers' time and efforts. Here are some screenshots of the ValidTextBox server control.






Check more about the ValidTextBox server control at MIND Forum here