If you have been in a situation where things are in a big hairy mess, you probably would follow the process of elimination to ensure you are not chasing the wrong items down the rabbit hole.

Now consider you are working with SharePoint and you are in a tight spot as mentioned above. You probably want to ensure that WSS/MOSS has been configured properly and that the problem is not with the webpart you are working on, for example.

Here’s a quick and easy way of writing a “hello world” webpart that doesn’t involve features and layouts and WSPs and stsadm commands and etc.

1. Open up Visual Studio 2008 and create a new class library project (name it something unique, for example, DingDongBellWebPart) and add the following code in Class1.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Web.UI.WebControls.WebParts;

namespace DingDongBellWebPart

{

public class Class1 : WebPart

{

protected override void RenderContents(System.Web.UI.HtmlTextWriter writer)

{

writer.Write(“DingDongBell test”);

base.Render(writer);

}

}

}

}

2. Check the “Sign the assembly” checkbox in Project properties “Signing” tab as shown below

Project properties

(Click on image above for better resolution)

3. Under “Choose a strong name key file” dropdownlist, select “New”.

4. Uncheck “Protect my key file with a password” as shown below

Create Strong Name Key

5. Give it a name and click OK.

6. Build the project.

7. Drag the project’s dll from the bin folder and drop it in C:\Windows\assembly folder. This registers the DLL in the GAC.

8. Replace the values for the attributes where necessary in the line below and add this line in the <SafeControls> section in the web.config file of the website you are trying to deploy this webpart to. (You can even try the SharePoint’s central admin’s web.config file. should work.)

<SafeControl Assembly=”DingDongBellWebPart, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1af588c27b5f26e0″ Namespace=”DingDongBellWebPart” TypeName=”*” Safe=”True” />

**NOTE**: Don’t forget to replace the PublicKeyToken above. There are multiple ways to fetch the PublicKeyToken of your DLL. Here’s one way. Go to C:\Windows\assembly and right click on your assembly and click properties as shown below.

Webpart properties

9. Visit the following URL – http://insert_your_website_url_here/_layouts/NewDwp.aspx [Of course replace "insert_your_website_url_here" with your value]

10. It should show up in that list as shown below. (I know….it says GirishWebpart.Class1 in the screenshot below instead of DingDongBellWebpart.Class1. May be it is because I figured GirishWebpart was a much better name than the ridiculous-sounding DingDongBellWebpart.)

Webpart properties

(Click on image above for better resolution)

11. If it doesn’t work, reset IIS. And try again. Should work.

12. Enjoy.

MCPD

October 5th, 2008

MCPD That’s what I am now. An MCPD – an abbreviation for Microsoft Certified Professional Developer (Web).

I took exam 70-547 early today and scored 1000 out of 1000. LOL! Can you believe it? I scored 100%. Sometimes I surprise myself. ;)

So this, in addition to exams 70-528 and 70-536 that I had passed earlier this year, makes me an MCPD.

Yay! :D

Alright Microsoft. You win. I have officially started working with Sharepoint now. I’m now one of the thousands of .Net developers that have been slowly but steadily and methodically, sucked into dark side of the “portal” world. A bunch of us in my company were hoping and praying that we don’t get placed on a project that would force us to learn this technology especially because of the horror stories we’ve heard. When someone like Rob tells you that sharepoint is the shittiest piece of software he’s ever worked on, that is saying something.

Anyways, enough of bitching. Every Sharepoint developer that i knew, installed VMWare on their machines that ran Windows 2003, SQL Server 2005 and VS 2005/2008 and used that as their development environment. Why? Because WSS 3.0 or MOSS 2007 runs only on server operating systems. Brilliant! Let me get this straight. We are supposed to build applications that would run on “portal” software that are hosted on servers, and so we are supposed to do our development on server operating systems? Of course! Makes perfect sense! Yay Microsoft!

I don’t know man…i just didn’t want to load yet another software on my box and do all the configuration. Luckily for me, Bamboo Solutions had figured out a way to get MOSS 2007 to run on Vista/XP operating systems. As always, i started off my learning process by opening up a brand new word document and taking screenshots of each and everything i did, right from scratch. That includes pictures of installation wizards, “This program has performed an illegal operation” errors (sugar coated for Vista), dashboards, Visual Studio IDE, etc.

The end result of all this pain is a document that has some blurry images but decent content on how to write a “Hello world” web part and successfully deploying it to a sharepoint portal, all starting from scratch. This tutorial would make more sense if you are a .Net developer and have been doing custom application development for a while. It is meant for someone that has no idea where to begin, in their attempt to learn Sharepoint. So if you feel some of the screenshots in the document insult your intelligence, just remember that not all people are as smart as you, wise guy.

Here’s the doc in PDF – How to get MOSS 2007 development environment setup in Vista.pdf

Enjoy!

I have compiled a 10 step tutorial on how to add logging to your .Net application. Could be pretty handy for quick reference. Here we go…

  1. First download log4net from – http://logging.apache.org/log4net/download.html
  2. Extract the log4net.dll from the bin folder of the downloaded zip file into your solution’s Library folder or bin folder or wherever you want to.
  3. Add this dll to each of your projects listed under the solution that require logging functionality, using the “Add reference” feature.
  4. Set up your config file now (web.config or app.config) – Add a new section for log4net under configSections.

    <configSections>
    <!-- Add a new section for log4net under configSections -->
    <section name="log4net"
    type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
    </configSections>
  5. Now configure the log4net section. Add this section right after <system.web> section.

    <!-- Configure log4net -->
    <log4net>
    <!-- Add an appender of type FileAppender to configure log4net to log messages (error, information, debug etc.) to a text file -->
    <appender name="LogFileAppender" type="log4net.Appender.FileAppender">
    <param name="File" value="Log.txt" />
    <param name="AppendToFile" value="true" />
    <layout type="log4net.Layout.PatternLayout">
    <param name="Header" value="Hit header" />
    <param name="Footer" value="Fit footer" />
    <param name="ConversionPattern" value="%d [%t] %-5p %c %m%n" />
    </layout>
    </appender>
    <!-- Add an appender of type AdoNetAppender to configure log4net to log messages (error, information, debug etc.) to a table in the database -->
    <appender name="DatabaseAppender" type="log4net.Appender.AdoNetAppender">
    <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    <connectionString value="data source=localhost;initial catalog=insert_your_database_name_here;integrated security=true;persist security info=True;" />
    <commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Message]) VALUES (@log_date, @thread, @log_level, @logger, @message)" />
    <parameter>
    <parameterName value="@log_date" />
    <dbType value="DateTime" />
    <layout type="log4net.Layout.PatternLayout" value="%date{yyyy'-'MM'-'dd HH':'mm':'ss'.'fff}" />
    </parameter>
    <parameter>
    <parameterName value="@thread" />
    <dbType value="String" />
    <size value="255" />
    <layout type="log4net.Layout.PatternLayout" value="%thread" />
    </parameter>
    <parameter>
    <parameterName value="@log_level" />
    <dbType value="String" />
    <size value="50" />
    <layout type="log4net.Layout.PatternLayout" value="%level" />
    </parameter>
    <parameter>
    <parameterName value="@logger" />
    <dbType value="String" />
    <size value="255" />
    <layout type="log4net.Layout.PatternLayout" value="%logger" />
    </parameter>
    <parameter>
    <parameterName value="@message" />
    <dbType value="String" />
    <size value="4000" />
    <layout type="log4net.Layout.PatternLayout" value="%message" />
    </parameter>
    </appender>
    <root>
    <level value="DEBUG" />
    <!-- Set the appenders here depending on where you want the messages to be logged. -->
    <appender-ref ref="LogFileAppender" />
    <appender-ref ref="DatabaseAppender" />
    </root>
    </log4net>
  6. If you are using the AdoNetAppender, you need to create a table in the database to hold these messages. Here’s a SQL code for the log table that will work with this example

    CREATE TABLE [dbo].[Log] (
    [ID] [int] IDENTITY (1, 1) NOT NULL ,
    [Date] [datetime] NOT NULL ,
    [Thread] [varchar] (255) NOT NULL ,
    [Level] [varchar] (20) NOT NULL ,
    [Logger] [varchar] (255) NOT NULL ,
    [Message] [varchar] (4000) NOT NULL
    ) ON [PRIMARY]

    GO

  7. In your code, where you wanna add logging, add namespace at the beginning of the file:

    using log4net;

  8. Declare the logger variable or type ILog at the beginning of the class at a global level.
    static readonly ILog Logger = LogManager.GetLogger("Log4net");

  9. Add this line to the constructor of your class or in the Initialization method.

    log4net.Config.XmlConfigurator.Configure();

  10. Start logging away!

    Logger.Debug("Logger debug works!");
    Logger.Info("Logger info works!");
    Logger.Fatal("Logger fatal works!");

If everything worked fine, you should be able to see the messages in your datastore you set up in the config file – either the database or the flat file as per this example.
If you used the example above and used the flat file appender, you should see the file alongside bin folder (not *in* the bin folder) that has messages in it.
If you used the example above and used the database appender, you should see the messages in the Log folder.

(SELECT * FROM [Log])

So in this project that i’m working on at my workplace, we have a bunch of products’ details displayed in a grid whose prices can be overridden by the admin user. The user has to check a “Override” checkbox, which would enable the price textbox. Uncheck obviously means the price cannot be overridden and textbox would be disabled. For business reasons, we had to use the autopostback option for the override checkboxes.

Anyways…the challenge was that there were atleast 25 or more products displayed in the grid and thus as you can imagine, when the user checked the bottom most product’s override checkbox the page posted back and auto-scrolled to the top of the page. This could be very annoying to the user and apparently, Smart Navigation was neither smart nor navigated anywhere expected and forced me to rely on Javascript to solve this issue.

After some googling, here’s how i fixed it.

There’s a javascript property called location.hash

bq. hash is a property of both the Link and the Location objects and is a string beginning with a hash (#). It specifies an anchor name in an HTTP URL.

For example, if the url is something like http://www.example.com#anchor

then #anchor is the hash property.

What this means is that if you have the id of an element in the page, you can set the focus to that element, when the page loads by using the location.hash property.

If you are using the a element , then you may use either the id attribute or the name attribute.

So i wrote a little procedure in the aspx’s code-behind that looks like this:

Private Sub anchorScript(ByVal productId As String)
     Dim Script As String
     Script &= "" & Environment.NewLine
     Script &= "var anchorLocation='#" & productId & "';" & Environment.NewLine
     Script &= "location.hash=anchorLocation;" & Environment.NewLine
     Script &= "" & Environment.NewLine

     If (Not Page.IsStartupScriptRegistered("anchorScript")) Then
           Page.RegisterStartupScript("anchorScript", Script)
     End If
End Sub

And called this procedure after doing the necessary stuff in the checkbox’s CheckedChanged event handler. Typically this would be the last line in the sub.

The above procedure registers a javascript function that when rendered, would look like this :

var anchorLocation='#'
location.hash=anchorLocation;

This would tell the browser to focus on the element that has an id(passed into the anchorScript procedure).

Simple. Worked like a charm.

One of the most popular questions in the .Net world is “What’s the difference between the Datagrid, the Datalist and the Repeater? And why would you choose one over the others?”

Though this question has been answered in hundreds of blogs and articles online, some of us still consider this to be a grey area and leave it mostly to the developer’s preference.

Well…here’s what i understand about these web controls.

First of all, all the three controls were created with the same objective, which is to display data. So why are there 3 different controls?

When these controls are bound to a datasource, for each entity in the datasource an “item” is created and added to the collection of items for the control.

Each Webcontrol’s “item” belongs to a different class. For example, a DatagridItem class is derived from TableRow class. This is because the HTML rendered by a datagrid is nothing but an HTML table with rows and columns based upon the datasource it was bound to. Hence each item in a datagrid collection is nothing but an HTML table row, when it is displayed in the browser.

One big advantage of the datagrid is that it is very simple to use and easily customizable with some cool color settings for borders,backgrounds etc. It also supports paging and sorting which also is accompanied by some customizable features for example, the way the page index can be displayed, as numbers or “previous and next” links etc.

So if you have a source of data that needs to be displayed with no customization or no complex stuff, datagrid is the best choice.

But remember, you will have no control over the HTML table that is being rendered.

Like the rows, each column in a DataGrid is an instance of a class that is derived from the DataGridColumn class. There are five built-in DataGrid column types:

* BoundColumn
* ButtonColumn
* EditColumn
* HyperLinkColumn
* TemplateColumn

Besides these built-in data types we can also create our own customized DataGrid column types by creating a class that derives from the DataGridColumn class.

Most of the newbies out there do not pay attention to the most important issue in datagrids ; Viewstate. ViewState produced by the DataGrid can be humongous if it contains a considerably large number of rows and thus be detrimental to performance. Of course, you DO have the option to turn the viewstate off but then that doesn’t help you if you are planning to use sorting, paging and editing features in the datagrid.

Apparently the datagrid has the worst performance of all the 3 web controls.

The Repeater Web control offers the most flexibility as far as control of the rendered HTML is concerned. The datagrid and datalist controls place the content within a HTML tag like <table> or <span> automatically. That’s how they are rendered. But a Repeater control renders ONLY what is specified by the developer. For this reason, if you wish to display data in some way other than in an HTML <table> tag or in a series of <span>tags, Repeater control is the best choice.

A Repeater is designed to let the user customize its output and thus have complete control over what is being rendered. So understandably RepeaterItem class is not derived from the TableRow class.

Just like in the DataList, with Repeater you specify the markup using templates. The Repeater contains the following five templates:

* AlternatingItemTemplate
* FooterTemplate
* HeaderTemplate
* ItemTemplate
* SeparatorTemplate

An important thing to remember about the Repeater is that, it is not derived from the WebControl class, like the DataGrid and DataList due to which it lacks the stylistic properties common to both the DataGrid and DataList. So if you want to make things look pretty in a repeater, write it yourself ;) . But in most cases this is what i want : Complete control over what is being rendered.(Yupp… i AM a control freak!)

Among all the 3 web controls in question, Repeater offers the best performance, though only slightly ahead of the datalist but beating datagrid by a considerable margin.

Finally about the datalist.

The DataList does not use columns as in datagrid.It uses templates to display items just like Repeaters. The advantage of using a template is that with a template, you can specify both a mix of HTML content and databinding syntax.

Along with the ItemTemplate the DataList supports six other templates for a total of seven:

* AlternatingItemTemplate
* EditItemTemplate
* FooterTemplate
* HeaderTemplate
* ItemTemplate
* SelectedItemTemplate
* SeparatorTemplate

By default, the DataList displays each item as an HTML tablerow. But an important property of datalist is the RepeatColumns property. Using this property you can specify how many DataList items should appear per table row. In addition to that, you can also specify if you want the contents of the DataList should be displayed using <span> tags instead of a <table> tags. This is done by setting the RepeatLayout property, to either Table or Flow, which would render the data in HTML <table> tags or in <span> tags.

With its templates and RepeatColumns and RepeatLayout properties, it’s obvious that the DataList allows for much more customization of the rendered HTML markup than the DataGrid. Thus customization again, is the reason why one might prefer to use a datalist over datagrid.

One major advantage of using Datagrid over datalist and repeater is, as already mentioned, the sorting and paging functionality. While such functionality can be implemented with some smart logic in the code, it’s the question of how much time and effort would be involved in doing it and whether the trade-off is worth it in the application development process.

Guess …that’s about it. This is just an overall view, at a very high level.

For more information,

Read Scott Mitchell’s article on the same topic