Home | Blog | Screencasts | Projects
# Friday, August 15, 2008

Something a little less SharePoint. If you wanted to consume an RSS feed (such as my homepage) and your using .NET framework 3.5+, then you could use the following code:

 

XDocument rssFeed = XDocument.Load(@"http://httpcode.com/blogs/SyndicationService.asmx/GetRss");

var posts = from item in rssFeed.Descendants("item")
    select new
            {
                Title = item.Element("title").Value,
                Published = DateTime.Parse(item.Element("pubDate").Value),
                Url = item.Element("link").Value,

            };
//BlogPosts is a ListView
BlogPosts.DataSource = posts;
BlogPosts.DataBind();

How about taking my last 5 twitter posts, but lets remove my name:

 

XDocument twitterFeed = XDocument.Load(@"http://twitter.com/statuses/user_timeline/14554389.rss");

var titterPosts = from item in twitterFeed.Descendants("item")
            select new
            {
                Title = item.Element("title").Value.Replace("DanielPollard:","")                       

            };
//TwitterPosts is a ListView - Notice the Take(5) below
TwitterPosts.DataSource = titterPosts.Take(5);
TwitterPosts.DataBind();

 

There's a lot to love about Linq.

Friday, August 15, 2008 9:42:50 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | Work
# Tuesday, August 12, 2008

I was reading this MS KB article 'How to point to a custom 404 error page in Windows SharePoint Services 3.0 or in MOSS'. I thought I'd throw together a simple administrative page to pull it all together. I've packaged this up in this solution file.

Once you active the 'Manage Custom 404 Page' feature, you will get a new menu item in the Application Management page in Central Admin:

image

From here you get a simple page that you can type the 404 page name for the selected web application:

image

 

The code is super simple:

 

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Portal.WebControls;
using Microsoft.SharePoint.Administration;
using System.Web.UI.WebControls;

namespace SP404Handler
{
    public class SP404HandlerPage : LayoutsPageBase
    {
        protected WebApplicationSelector lstWebApps;
        protected PageLevelError pageLevelError;
        protected Button ButtonDoneOK;
        protected TextBox txt404PageName;
        protected Microsoft.SharePoint.WebControls.InputFormSection I404Section;

        protected void lstWebApps_OnContextChange(object sender, EventArgs e)
        {
            try
            {
                SPWebApplication webApp = lstWebApps.CurrentItem;
                BindData(webApp);
            }
            catch (Exception err)
            {
                pageLevelError.ErrorText = err.Message;
            }

        }

        protected void DoneButtonOkClick(object sender, EventArgs e)
        {
            SPWebApplication webApp = lstWebApps.CurrentItem;
            try
            {
                webApp.FileNotFoundPage = txt404PageName.Text;
                webApp.Update();
            }
            catch (Exception ex)
            {
                pageLevelError.ErrorText = ex.Message;

            }
        }

        private void BindData(SPWebApplication webApp)
        {
            txt404PageName.Text = webApp.FileNotFoundPage;

        }
    }
}

The source can be downloaded from here, or a complied solution from here.

Tuesday, August 12, 2008 10:05:20 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | Sharepoint | Work
# Monday, August 11, 2008

I read with interest the recent example solution architecture article posted on Technet. It goes through the logical architecture of a School MOSS implementation. They have some good recommendations on hosting hardware and have some interesting comments on the way they handle media hosting.

Of Course being good consultants they provide nice visio overlays of the logical architecture:

 

 

However I was surprised to see the following:

 

The solution is composed of two sets of sites:

  • Sites for Twynham students, staff, and parents

  • Sites for hosted schools

Each set of sites is grouped in a separate application pool.

Basically they are saying that staff sites and student sites are hosted in the same web application. I hope staff aren't going to put sensitive information into their sites, because it would only take one human error assigning permissions to give students access to the site. However if the students and staff are in separate web applications you could use web application policy to block students, so even if they were accidentally given access by a human, they would be blocked.

I'm sure this has been thought about by these guys because further on in the article we find:

 

You want to use zone policies to enforce permissions at the Web application level. For example, you can create a policy to deny write access to all unauthenticated users who view content on the public-facing sites.

This is a classic example of where web application policy is so helpful and why it really pays to have a think about the implications of your design.

Monday, August 11, 2008 11:23:33 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint | Work
# Sunday, August 10, 2008

I came across this white paper titled 'Office SharePoint Server Web Browser Support', it covers the how SharePoint supports level 1 and 2 browsers, but the authors have done extensive testing on the most common features in SharePoint and provided a matrix of what does and doesn't work. They even cover some work around's like using the Telerik RAD editor for SharePoint.

I'm blogging about this as much for my own memory as anything else, you always come across these great resources and can never find them again.

Sunday, August 10, 2008 3:16:43 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint | Work
# Friday, August 08, 2008

I came across an interesting issue the other day with a Virtual Earth web part that we have developed. If you scrolled down the page and hovered over a pushpin, in IE the info window would be displayed higher than the pushpin, i.e. they weren't aligned properly.

I found the answer to my problem, the master page that the site was using did not have the following:

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

The missing doctype tag was putting IE in quirks mode and this caused the scroll behavior mentioned above. Heather Solomon has a discussion on Sharepoint master pages and the missing doctype. Unfortunately for us the master page couldn't easily be changed without making changes to a number of CSS classes.

I guess my point is that your sharepoint designer should know about this sort of stuff and design from the outset with the doctype tag.

Friday, August 08, 2008 10:25:29 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [1] - Trackback
Sharepoint | Work
# Wednesday, August 06, 2008

I'm sure you've done work in an organisation that wants to exert its control over users, one of the common things that I've seen is the disabling of menu items like the 'delete this web site' option.

menuitem

The last thing you want to do is edit the pages on the file system, this will just cause issues when you apply a service pack or if you bring a new WFE online because each server will need the same hack.

Instead you should build a solution that makes use of the HideCustomAction definition.

For the above delete site link, the Elements.xml file should look like:

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<HideCustomAction Location="Microsoft.SharePoint.SiteSettings"
        GroupId="SiteAdministration" HideActionId="DeleteWeb"
        Id="HideDeleteWeb" />

</Elements>

From here it's just a matter of referencing the above elements.xml in your feature.xml file and building the solution in the normal way.

To find out what the ActionId, GroupId and Location you can refer to this MSDN page.

Now you can safely change the menu items, but be aware that the files still exist on the file system, so in the example above if a user still knew the location of the delete web page they could still delete their site.

Wednesday, August 06, 2008 10:39:55 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint | Work
# Monday, August 04, 2008

Depending on your hardware if your crawling your own content, or if you are crawling external content you might like to know what the three settings for the crawler performance settings really mean.

I ran across this article Change the Indexer Performance Settings which provides the following table:

 

 

Indexer Performance setting

Total threads available for crawling

Maximum threads available for crawling any particular host

Reduced

Number of processors on the index server

Number of processors on the index server

Partially reduced

4 times the number of processors on the index server

Number of processors on the index server plus 4

Maximum

16 times the number of processors on the index server

Number of processors on the index server plus 4

Monday, August 04, 2008 11:00:46 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint | Work
# Sunday, August 03, 2008

I had the task of writing a web part that had a lot of UI code and one of the requirements was that a designer could change the look and layout as a toolpart setting. The smartpart stuff is OK, but it doesn't really provide the kind of flexibility that I was after. I came up with a neat solution that I think is pretty powerful.

We've all seen the example webpart code that has lots of layout controls like tables defined in the CreateChildControls method, it's awful to write and its not easy to change. What we really need is a way to define a template that is provided by an external source and then to hookup our code to perform operations on it.

 

Lets have a look at some sample code:

using System;
using System.Web.UI;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.WebControls;

namespace Template
{
    
    public class Template : System.Web.UI.WebControls.WebParts.WebPart
    {
        //string with UI code to be added to the page
        protected string templateHTML = string.Empty;

        //Control IDs, the template must use these ID's
        private string searchButtonID = "searchImgBtn";
        private string allTextID = "allTxt";
        //controls that will be found from the template
        protected TextBox allTxt = null;
        protected ImageButton searchBtn = null;

        public Template()
        {            
        }

        protected override void CreateChildControls()
        {
            if (templateHTML != string.Empty)
            {
                try
                {
                    //create a control that has been parsed by asp.net
                    Control template = Page.ParseControl(templateHTML);
                    //add it to the page
                    this.Controls.Add(template);
                    //search for the known controls
                    allTxt = template.FindControl(allTextID) as TextBox;                    
                    searchBtn = template.FindControl(searchButtonID) as ImageButton;
                    //hook up any events
                    if (searchBtn != null)
                    {
                        searchBtn.Click += new ImageClickEventHandler(btnSearch_Click);
                    }

                }
                catch (Exception err)
                {
                    this.Controls.Add(
                        new LiteralControl(string.Format("Error applying template: {0}", err.Message))
                        );
                }
            }
            else
            {
                this.Controls.Add(new LiteralControl("Please enter a template in the toolpart settings"));
            }

            base.CreateChildControls();
        }

        void btnSearch_Click(object sender, ImageClickEventArgs e)
        {
            //if the template included the textbox, show its results
            if (allTxt != null)
            {
                this.Controls.Add(new LiteralControl("Searched On: " + allTxt.Text));
            }
        }

        [System.Web.UI.WebControls.WebParts.WebBrowsable(true),
        System.Web.UI.WebControls.WebParts.WebDisplayName("Layout Template"),
        System.Web.UI.WebControls.WebParts.WebDescription("Template that is used for layout"),
        System.Web.UI.WebControls.WebParts.Personalizable(
        System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared),
        System.ComponentModel.Category("Template Settings"),
        System.ComponentModel.DefaultValue("")
        ]
        public string TemplateHTML
        {
            get
            {return templateHTML;}

            set
            {templateHTML = value;}
        }
        
    }
}

The template that is set with the toolpart should look like this:

 

<table>
    <tr>
        <td>Search On:</td>
        <td><asp:TextBox ID="allTxt" runat="server" />
    </tr>
    <tr>
        <td colspan="2"><asp:ImageButton runat="server" ID="searchImgBtn" ImageUrl="Search.gif"/>
    </tr>
<table>

Notice how the control IDs match the values in the code, that is important, because we use FindControl to bind the code to the UI.

So what we end up with is a flexible way to define our UI code in a way that most of us are used to. I've used this in a number of places now and haven't seen any issues, drop me a line if you start using this approach.

Sunday, August 03, 2008 1:59:28 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | Sharepoint | Work

I've written a Sharepoint feature that will modify the web.config file and add the entries needed to enable the ASP.NET AJAX Control Toolkit.

 

I've made the feature scoped to the web application level, so to activate the feature (which will write to the web.config file) go to Application Management in central admin, then to Manage Web application features:

 

Next step is to activate the feature:

 

 

 

I was thinking that I would just provide the source code and that you could include it in your solution project as this functionality doesn't do much as a stand alone feature.

 

To use this feature you will need the source, I'm thinking about uploading to CodePlex, I'm just not sure if one code file is enough to warrant this.

To add this feature to your existing project you should include the following information in your feature.xml:

 

<?xml version="1.0" encoding="utf-8" ?>
<Feature xmlns="http://schemas.microsoft.com/sharepoint/"
         Id="YOUR GUID ID"
         Scope="WebApplication"
         Title="ASP.NET Ajax web.config update tool"
         Description="Adds web.config entries to enable ASP.NET Ajax"
         ReceiverAssembly="Full name and version of your assembly"
         ReceiverClass="Features.AjaxWebConfigInstaller"
         Hidden="False"
         >

</Feature>
Sunday, August 03, 2008 1:17:56 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | Sharepoint | Work
Statistics
Total Posts: 134
This Year: 0
This Month: 0
This Week: 0
Comments: 20