Gunnar Peipman's ASP.NET blog

ASP.NET, C#, SharePoint, SQL Server and general software development topics.

Sponsors

News

 
 
 
DZone MVB

Links

Social

January 2009 - Posts

SharePoint: why are my custom content type forms empty?

Okay, this is the hit of the month for me. Well, we had to use custom forms with some content types. Everything went fine until all those custom forms showed up empty. No errors on screen, no errors in log files, no errors in event log. Also diagnostic messages were not helpful. But … solution was simple.

To get some idea about those forms check out an article called Creating Custom Form Templates from MSDN Library. If you are already familiar with those forms then you should know that there are templates like this:

<SharePoint:RenderingTemplate ID="AssignmentEditForm" runat="server"> 
    <Template> 
        <!—Template Body -->
    </Template> 
</SharePoint:RenderingTemplate>

On MSDN article referred above you can see how those forms are bound to content type definitions. Now there is a little trick we discovered. You must have all those forms defined in user controls otherwise custom forms doesn’t show up. You can see just a blank form with no controls.

It seems to affect only the content types that came with same feature. Controls from some other feature will still work. To help other guys out with these time wasting horror I end this blog entry with something that robots like to eat.

SharePoint content type custom form empty blank problem

Posted: Jan 30 2009, 08:46 PM by DigiMortal | with 3 comment(s)
Filed under:
Creating downloadable calendar item of SPListItem

Recently I prepared some code to download calendar item from SharePoint web part to user computer. I was lucky because the web part will only be used on details view of one list. The testing code I wrote was simple and short.


protected void downloadButton_Click(object sender, EventArgs e)

{

    SPListItem item = SPContext.Current.ListItem;

 

    try

    {

        string location = item["Location"] as string;

        string subject = item.Title;

        string description = item["Description"] as string;

 

        var beginDate = (DateTime)item["From"];

        var beginDateString = beginDate.ToUniversalTime().ToString("yyyyMMdd\\THHmmss\\Z");

 

        var endDate = (DateTime)item["Thru"];

        var endDateString = endDate.ToUniversalTime().ToString("yyyyMMdd\\THHmmss\\Z");               

 

        string[] contents = {

                      "BEGIN:VCALENDAR",

                      "PRODID:-//My company//My product//EN",

                      "BEGIN:VEVENT",

                      "DTSTART:" + beginDateString,

                      "DTEND:" + endDateString,

                      "LOCATION:" + location,

                      "DESCRIPTION;ENCODING=QUOTED-PRINTABLE:" + description,

                      "SUMMARY:" + subject, "PRIORITY:3",

                      "END:VEVENT",

                      "END:VCALENDAR" };

 

        HttpResponse response = HttpContext.Current.Response;

 

        response.Clear();

        response.ContentType = "text/calendar";

        response.AddHeader("Content-disposition", "attachment;filename=event.ics");

        response.Write(string.Join("\r\n", contents));

        response.Flush();

        response.End();

    }

    catch (System.Threading.ThreadAbortException taex)

    {

        // Ignore this exception

    }

}


Feel free to use this code if you like it.

Posted: Jan 24 2009, 04:15 PM by DigiMortal | with 8 comment(s)
Filed under:
Creating SharePoint global calendar

Creating global calendar that shows data from different calendars is something that SharePoint doesn’t have out-of-box. Using site data query and calendar view control we can easily create global calendar and make it show data from lists we want.

data-from-multiple-calendars

Before you start you should create two calendars to SharePoint site where you want to show global calendar. I tested my code on MOSS 2007 but it should also work on WSS 3.0. If you want to get done fast then you can create new web part and paste all these methods to web part class. Don’t forget to change list GUID-s before deploying your code.

Creating the calendar control

As a first thing let’s update CreateChildControls method. We don’t write calendar creation code here because in this method we want things to be simple and clear.


/// <summary>

/// Called by the ASP.NET page framework to notify server controls

/// that use composition-based implementation to create any child

/// controls they contain in preparation for posting back or
/// rendering.

/// </summary>

protected override void CreateChildControls()

{

    base.CreateChildControls();

 

    try

    {

        AddCalendar();

    }

    catch (Exception ex)

    {

        Controls.Add(new LiteralControl("<b>Error</b> "));

        Controls.Add(new LiteralControl(ex.ToString()));

    }

 

}


As a next thing let’s add code for AddCalendar method. In this method we control the process of calendar creation. We need reference to current web and then we play with data. GetQueryData returns us DataTable and GetCalendarItems converts this DataTable to SPCalendarItemCollection. Then we detect calendar view type (day view, week view,  month view) by request variables and as a last thing we bind data to calendar and add calendar to web part controls collection.


/// <summary>

/// Adds the calendar to web part.

/// </summary>

private void AddCalendar()

{

    var web = SPContext.Current.Web;

    var results = GetQueryData(web);

    var items = GetCalendarItems(web, results);

 

    var calView = new SPCalendarView();

    calView.ViewType = GetCalendarType(Page.Request["CalendarPeriod"]);

    calView.DataSource = items;

    calView.DataBind();

    Controls.Add(calView);

}


Quering lists

Now let’s ask data for calendar. We have to create SPSiteDataQuery that is able to query all the lists in site or site collection. This is a little bit tricky class and you can read about it blog posting SPSiteDataQuery Samples for WSS v3 from thekid.me.uk blog. We will write now our GetQueryData method that creates site data query and returns results. We are able to get these results only as DataTable. Why separate method? Just look at this method – it is pretty long.


/// <summary>

/// Executes the query against the web and returns
/// results as DataTable.

/// </summary>

/// <param name="web">The web that is queried.</param>

/// <returns>Query results as DataTable.</returns>

private DataTable GetQueryData(SPWeb web)

{

    var query = new SPSiteDataQuery();

 

    query.Lists = @"<Lists>

                        <List ID='{56F5E040-D547-4BF5-8C99-F019D54F9997}' />

                        <List ID='{92A87CB9-E39B-4C2D-B37D-5721E6C7FECD}' />

                    </Lists>";

 

    query.Query = @"<Where>

                        <Gt>

                            <FieldRef Name='ID' />

                            <Value Type='Number'>0</Value>

                        </Gt>

                    </Where>";

 

    query.Webs = "<Webs Scope='SiteCollection' />";

 

    query.ViewFields = "<FieldRef Name='Title' />";

    query.ViewFields+= "<FieldRef Name='ID' />";

    query.ViewFields+= "<FieldRef Name='EventDate' />";

    query.ViewFields+= "<FieldRef Name='EndDate' />";

    query.ViewFields+= "<FieldRef Name='Location' />";

    query.ViewFields+= "<FieldRef Name='Description' />";

    query.ViewFields+= "<FieldRef Name='fRecurrence' />";

 

    query.RowLimit = 100;

 

    return web.GetSiteData(query);

}


NB! The first block of XML is lists definition. Replace GUID-s of lists with GUID-s of your lists! Also don’t remove row limit. You can change the value but if you remove it then you get no results.

Transforming results

GetSiteData returns results as DataTable. SPCalendarView accepts DataTable as data source but it shows calendar empty. We need SPCalendarItemCollection to get results to calendar. For this conversion we write the method GetCalendarItems. This method takes DataTable returned by GetSiteData and returns results as SPCalendarItemCollection.

The code for calendar actions is borrowed from Tom Stegeman blog posting Using SPCalendarView to show items in a calendar.


/// <summary>

/// Gets the collection of calendar items based on site
/// data query results.

/// </summary>

/// <param name="web">The web that was queried.</param>

/// <param name="results">The results of query.</param>

/// <returns>Collection of calendar items accepted by
/// calendar component
</returns>

private SPCalendarItemCollection GetCalendarItems(SPWeb web, DataTable results)

{

    var items = new SPCalendarItemCollection();

    foreach (DataRow row in results.Rows)

    {

        var listGuid = new Guid(row["ListId"] as string);

        var list = web.Lists[listGuid];

 

        SPCalendarItem item = new SPCalendarItem();

 

        foreach (SPForm form in list.Forms)

            if (form.Type == PAGETYPE.PAGE_DISPLAYFORM)

            {

                item.DisplayFormUrl = form.ServerRelativeUrl;

                break;

            }

 

        item.ItemID = row["ID"] as string;

        item.StartDate = DateTime.Parse(row["EventDate"] as string);

        item.EndDate = DateTime.Parse(row["EndDate"] as string);

        item.hasEndDate = true;

        item.Title = row["Title"] as string;

        item.Location = row["Location"] as string;

        item.Description = row["Description"] as string;

        item.IsAllDayEvent = (int.Parse(row["fAllDayEvent"] as string) != 0);

        item.IsRecurrence = (int.Parse(row["fRecurrence"] as string) != 0);

        item.CalendarType = Convert.ToInt32(SPCalendarType.Gregorian);

        items.Add(item);

    }

 

    return items;

}


This method has one little trick. We need URL template to assign it to DisplayFormUrl. When calendar is rendered then parameter ID will be added to this URL.

Why we don’t ask it from list and then use it as constant? Okay, results are coming from more than one list. Each list has separate display form and therefore separate display form URL. To get correct URL-is it is good idea to ask them directly from list Forms collection.

Detecting calendar type

As a last thing we have to add one utility method to our web part class. We need to know what view calendar has to show. There three views:

  • day view,
  • week view,
  • month view.

When we switch view then view type is given to calendar over query string. As query string is something that everybody can easily change we need to make sure that we assign correct view type to calendar. Otherwise exception will be thrown.


/// <summary>

/// Gets the type of the calendar view.

/// </summary>

/// <param name="type">The type to be checked.</param>

/// <returns>Correct view type of calendar.</returns>

private static string GetCalendarType(string type)

{

    if (type == null)

        type = string.Empty;

 

    switch (type.ToLower())

    {

        case "day":

            return "day";

        case "week":

            return "week";

        case "timeline":

            return "timeline";

        default:

            return "month";

    }

}


How it’s time to compile the code and deploy it to server. If you or I have make no mistakes in code then you should see familiar SharePoint calendar that shows results from more than one calendar.

Calendar based on site data query

You can click on image to see how it looks full size. Training info comes from list Calendar and meeting information comes from Rooms Calendar.

Happy SharePointing!

Posted: Jan 24 2009, 12:53 PM by DigiMortal | with 62 comment(s)
Filed under:
whitehouse.gov runs on ASP.NET

I found some information about www.whitehouse.gov web site and it turns out that this site runs on ASP.NET. Some interesting characteristics:

  • web server is IIS 6.0,
  • ASP.NET version is 2.0.50727,
  • they use jQuery 1.2.6 but jQuery scripts are not hosted in Google global script hosting service,
  • pages are GZIP compressed and they seem to use pretty high compression level,
  • JPG files are highly compressed to make page load faster.

Here’s the screenshot of www.whitehouse.gov page that this posting is about.

Screenshot of www.whitehouse.gov

You can read more about this page from Dot Net Perls article whitehouse.gov Website Code.

Posted: Jan 23 2009, 12:30 AM by DigiMortal | with no comments
Filed under:
Refactoring: introduce constant

One way to write messy code is to use constant values in code without any explanations about their values or purpose. Sometimes it feels like too small problem to think about, specially when there are only couple of constants, but I am sure that hard coded constants may waste developers valuable time more than one may think at first place. To make this kind of code easier to read and understand we can use refactoring method called introduce constant.

Let’s look at the following code.


public class TerminalConnector 
{ 
    private TerminalConnection _connection; 

    ... 

    public int ReadCurrentValue() 
    { 
        _connection.SendCommand(new byte[] { 0x34, 0x33, 0x00 }); 
        return _connection.Read(0x03); 
    } 
}

We can see there some constants in hex format and some byte arrays. Nothing tells us what these values mean. Although we may think that it is easy to understand to everybody when we write the code it is not so. After month or two we don’t remember the meaning of these values anymore. Other developers who read this code understand it even less.

Let’s make our previous code more easily readable now. Each refactoring takes only three steps here:

  1. define new constant with meaningful name,
  2. assign hard coded value to it,
  3. replace hard coded value with constant.

After refactoring our code will look like this.


public class TerminalConnector 
{ 
    private TerminalConnection _connection; 

    private byte[] const _currentValueCommand = new byte[] { 0x34, 0x33, 0x00 }; 
    private int const _readIntegerCommand = 0x03; 

    ... 

    public int ReadCurrentValue() 
    { 
        _connection.SendCommand(_currentValueCommand); 
        return _connection.Read(_readIntegerCommand); 
    } 
}

As a result of introduce constant refactoring our code is now much easier to read than before. If somebody else has to modify this code then he or she can easily understand what this code does.


kick it on DotNetKicks.com pimp it Shout it
Windows 7 on my development machine

Okay, my Windows Vista found its sad end couple of days ago. There was almost nothing to do without going out of sleeping time. Many broken installation packages, large amounts of space were gone somewhere, some processes ate free memory and after each 10 seconds there was 10 seconds delay because something was busy doing something. One thing more – reading and writing USB hard discs was suddenly very-very slow. So it was time to use the moment and try out something new before going back to good old Windows XP.

Then I installed Windows 7 on my machine to try out what happens if I try to use it as my development machine. Here are some little pieces of information about my development machine.

  • Lenovo T60 with 4GB RAM and 120 GB HDD.
  • Operating system is Windows 7 Beta.
  • I have 320 GB Verbatim USB hard disc connected to my machine.
  • All my virtual machines are located on USB hard disc (if I need faster I/O then I can copy specific virtual machine to my hard disc).
  • Some services I don’t need are disabled.

I got Virtual PC 2007 SP1 running smoothly on my development machine and everything works this far very well. No stability and performance problems anymore. After Virtual PC I got somehow brave and installed some more software I use almost everyday. Here’s the list.

  • Microsoft Office 2007 Professional,
  • Windows Live Messenger,
  • Windows Live Writer,
  • Skype,
  • FeedReader,
  • some other small tools.

Okay, my first day went extremely well on Windows 7. All my virtual machines and programs worked like expected. There were no errors, no problems, no mysteries. All Office programs, Windows Live programs and other programs worked like charm. So, let’s see what happens during one week from now.

Posted: Jan 21 2009, 11:42 PM by DigiMortal | with 3 comment(s)
Filed under: ,
Refactoring: delete unneeded code

It is not a miracle that during coding developers produce code that is later not needed anymore. It is also not a miracle that unneeded code will stay in project files waiting for the day when somebody finds this code useful (again). But this far this code is just sitting there and causing problems to people who look at these modules first time.

Let’s look at the following code.


public class Invoice
{
    private IList<InvoiceLine> _lines; 

    ...

    public decimal Sum()
    {
        decimal sum = 0;

        foreach(InvoiceLine line in _lines)
        {
            decimal lineSum = line.CalculateTotal();
            // lineSum = lineSum * (1 - lineSum.Discount)
            // lineSum = lineSum * 1.12
            // lineSum = lineSum * 1.01
            sum += lineSum;
        }

        // sum = sum * 1.12
        // sum = sum * 1.01

        return sum;
    }

    public void ValidateInvoice()
    {
        if(_lines.Count == 0)
            throw new Exception("Invoice body cannot be empty!");
        if(_lines == null)
            throw new Exception("Invoice lines collection is null");
    }
}

This code has some things I don’t like. And I think these things doesn’t like also to other developers who have to work with this code.

  • The code is hard to read. Tracing working code between uncommented blocks is not fun. It makes code hard to read and it is almost sure that one day somebody has to waste his or her valuable time to crawl through this horror.
     
  • Somebody may get wrong directions from commented code. It may easily happen to somebody new who reads the code to understand how this part of system is working. “Dirty code” like this may contain references to erroneous solution but there is no comment telling us why this code is like it is and how safe it is to use.
      
  • Somebody may want to update and use commented code. Newcomers may also want to use that code if they have idea how to modify it. But this code may have deeper problems than they know. It is better to avoid confusing elements in code.
     
  • How do I know why this code is here? We can see no comments or explanations about why this code is here. If it is workaround to some problem and this code is there so everybody can use it in the case of emergency then this code needs comments. It must be clear that this code can be used and it is safe to use.

Now there is one more problem. The last method in our example class is not used. But it is there and it has very sweet name. It like says to us that this method must be used somewhere. If somebody starts debugging this class then he or she may try to use this method to get correct results. So it is better to remove this method if it is not used.

As a last thing let’s look at our class when we have removed all the waste.


public class Invoice
{
    private IList<InvoiceLine> _lines;

    ...

    public decimal Sum()
    {
        decimal sum = 0;

        foreach(InvoiceLine line in _lines)
        {
            decimal lineSum = line.CalculateTotal();
            sum += lineSum;
        }

        return sum;
    }
}

The code looks much better now, it is easier to read and it doesn’t contain any informational noise. If you ask me where to keep maybe-in-the-future-needed pieces of code then my answer is simple – put up wiki for your developers and let them keep information there.


kick it on DotNetKicks.com pimp it Shout it
EnumHelper class

Some time ago I wrote blog posting Extension method for enumerators where I showed how to use extension methods to make using of enumerators more convenient. Today I found very interesting posting from Grant Barrington blog where he describes the class called EnumHelper.

As enumerator values are often used on web forms as dropdown lists then we need a way to show nice options to users. Something like BrightPink or MyHomeAddress may confuse them. Grant offers us a nice solution – we can use description attributes to bind user readable values to enumerator members.

Take a look at the following code sample I took from Grant’s blog. It is the best illustration about his work.


using System.ComponentModel; namespace Ellington.EnumHelperExamples { public enum UserColours { [Description("Burnt Orange")] BurntOrange = 1, [Description("Bright Pink")] BrightPink = 2, [Description("Dark Green")] DarkGreen = 3, [Description("Sky Blue")] SkyBlue = 4 } }

It seems cool to me. Thanks Grant!

Refactoring: expose static method

You may discover sometimes that some of your classes have method you would like to use without creating new instance of that class. In this case we have to use expose static method refactoring to make this method static.

Let’s say you have class called MailValidator that  validates your e-mail objects so your system sends out only messages that follow the set of custom business rules. One of the methods is called IsValidAddress. The code of IsValidAddress method is borrowed from The Code Project article Effective Email Address Validation.


public class MailValidator
{
    private Mail _mail;

    public MailValidator(Mail mail)
    {
        _mail = mail;
    }

    // Block of other validation rules

    private bool IsValidAddress()
    {
        string strRegex = @"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}" +
            @"\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\" + 
            @".)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";
        Regex re = new Regex(strRegex);
        return re.IsMatch(_mail.To);
    }
}

IsValidAddress is the method we are interested in. All the other validation rules in this class are very specific to those e-mails and we are not interested in those rules at more common level. But we want to use IsValidAddress method on some other parts of our system to validate e-mail addresses. Let’s suppose we have to validate e-mail addresses that users insert when they are joining with our site. In this case we don’t have e-mail object – we just want to make sure that user inserted correct e-mail address.

What we have to do is to refactor IsValidAddress method. We have to follow these steps:

  1. make IsValidAddress method publicly visible,
  2. make IsValidAddress static,
  3. add new parameter emailAddress to its signature,
  4. resolve the dependence of e-mail object.

As a result our MailValidator looks like this.


public class MailValidator
{
    private Mail _mail;

    public MailValidator(Mail mail)
    {
        _mail = mail;
    }

    // Block of other validation rules

    public static bool IsValidAddress(string emailAddress)
    {
        string strRegex = @"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}" +
            @"\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\" + 
            @".)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";
        Regex re = new Regex(strRegex);
        return re.IsMatch(emailAddress);
    }
}

Now we can use IsValidAddress method without instantiating the new instance of MailValidator class. Let’s say we have form called join.aspx and we have textbox emailTextBox defined on it. Also let there be button called joinButton. When user presses joinButton we want to validate form fields and one of these fields is e-mail address.


protected void joinButton_Click(object sender, EventArgs e)
{
    ...
    if(!MailValidator.IsValidAddress(emailTextBox.Text))
    {
        SetError("email", "E-mail address is not valid!");
        return;
    }
    ...
}

Now we can use MailValidator class to validate e-mail addresses everywhere we need in our system. And if there are more common methods besides IsValidAddress we can make those methods visible same way.

As a last thing be warned that using static methods heavily is not a good idea because you will loose many of the object-oriented programming advantages this way. You can read more about static methods from developer Fusion article A Twisted Look at Object Oriented Programming in C#.


kick it on DotNetKicks.com pimp it Shout it
Extreme Programming Explained

Extreme Programmind Explained
Extreme Programming Explained: Embrace Change (2nd Edition) (XP Series)
Extreme Programming Explained is overview and guide to extreme programming (XP). The author of this book – Kent Beck – is well known XP evangelist with great experiences on the field. XP is not very simple thing to start with when one has worked some years on “classic” way. Kent shows us the way to XP and gives great explanations and suggestion about how to get started with XP.

Extreme Programming Explained is easy to read for everyone. The book is not very hard work to deal with as there is about 160 pages to read. Reader can also find good references to other books to read when this one is finished.

The target audiences of Extreme Programming Explained include software project managers, information system managers and developers who are interested in getting better results than before. Managers can find good information about how to create XP teams. Developers may find very useful advices about how to participate in XP teams. Of course, new working methods are also very interested reading for all readers who want to use XP.

Cite from Amazon

“Generally speaking, XP changes the way programmers work. The book is good at delineating new roles for programmers and managers who Beck calls "coaches." The most striking characteristic of XP is that programmers work in pairs, and that testing is an intrinsic part of the coding process. In a later section, the author even shows where XP works and where it doesn't and offers suggestions for migrating teams and organizations over to the XP process.”

Table of contents

  • Foreword.
  • Preface.
  • 1. What is XP?
  • 2. Learning to Drive.
  • 3. Values, Principles, and Practices.
  • 4. Values.
  • 5. Principles.
  • 6. Practices.
  • 7. Primary Practices.
  • 8. Getting Started.
  • 9. Corollary Practices.
  • 10. The Whole XP Team.
  • 11. The Theory of Constraints.
  • 12. Planning: Managing Scope.
  • 13. Testing: Early, Often, and Automated.
  • 14. Designing: The Value of Time.
  • 15. Scaling XP.
  • 16. Interview.
  • 17. Creation Story.
  • 18. Taylorism and Software.
  • 19. Toyota Production System.
  • 20. Applying XP.
  • 21. Purity.
  • 22. Offshore Development.
  • 23. The Timeless Way of Programming.
  • 24. Community and XP.
  • 25. Conclusion.
  • Annotated Bibliography.
  • Index.
More Posts Next page »