Home | Blog | Screencasts | Projects
# Saturday, October 17, 2009

I came across a rather interesting problem the other day (interesting enough to blog anyway).

We have a development server that we are building some SharePoint web parts on, all of the developers have local admin rights to the box. We asked a normal user to have a look at some functionality that should be available to them, but when they browsed to the site they got a 403 forbidden error message. However when the developer requested that very same page it rendered fine. The weird thing was that if the original user (not the dev) then requested the page once again, it all rendered fine.

We had a look in the SharePoint Logs and found that the assembly in the bin folder was denying access to the non developer, but once a dev hit the box the assembly was loaded fine and stayed in memory until the app pool was recycled.

So the solution was to grant all users access to the bin directory. This wouldn’t be an issue in production because we will eventually GAC deploy these assemblies.

But I did think it was a fun little exercise to track down the root cause.

Saturday, October 17, 2009 4:30:00 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Tip | Work
# Tuesday, October 07, 2008

I put in an entry into this year’s devsta competition, since the submission display page doesn’t work too well, I thought I’d post the full description of my entry here:

 

Console Connect – The Connected Console

 

What would Facebook like if it was around in the green screen terminal days? Console Connect provides this experience, it's the socially connected console, with ASCII art profile pictures and a friend list that is updated in real time when your friend's status changes or they come online enabling you to keep connected with your friends with real time messaging.

The console is delivered via a Silverlight control which provides the user with 3 rich green screen games: the classic pong game, space invaders and bomb drop. Your high scores are posted to a shared scoreboard for all to marvel.

Nothing says old school like a green screen ... are you ready to get connected?

 

 

ConsoleConnect

 

Once you login to your console session, you are presented your friends list with indicators that let you know when they come online.

You can search for new friends and instantly start following their status and online indicator. If your feeling happy and you want all your friends to know it, then select [1] and enter your status for all your friends to see.

The console supports messages, so you can instant message your friends, simply select the send message [2] menu option and type your message,
your friend will receive the message if they are logged into the console and it will also display next time they login.

To test these features you should open two consoles and login to each as a different user (the user 'demo' and 'sally').

 

 

Space

 

Any good social networking tool needs to have games that users can compete against each other, of course being a green screen application means
that all those fancy graphics are non existent. Select the applications menu [4] and select the [2] space invaders option. Level 1 is pretty easy if you move quickly to the right and attack slowly, level 2+ adds more difficulty when the alien ships start moving.

Your score will be posted to a shared scoreboard, so all your friends will be able to compete with you. Maybe you can find the hidden way to cheat this game?

 

 

 

 

 

 

 

PongAndBomber

 

If space invaders isn't your thing, how about a hard core pong session, this is a game of endurance, how hard core are you about beating your friends score?

The bomb drop game gives you control of a bomber (yes imagination is required ... you still have one? ) that needs to bomb a building. Each miss will take one of your three lives. When you score a direct hit the plane will fly at a higher altitude and the building will move closer. If you keep progressing your aircraft will be fitted with missiles that drop at a faster speed further increasing the challenge.

Again your scores will be posted to a shared scoreboard, your friends can be amazed that you played pong for an hour straight!

Tuesday, October 07, 2008 8:31:40 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [1] - Trackback
Work
# Monday, September 29, 2008

I’ve been doing some thinking around how MOSS can be integrated into a large and complex organisation, an organisation that has many disparate applications which act as an information silo. Most developers who are not intimately familar with MOSS will suggestion just using the page viewer web part if the external system is web based. The page viewer web part is basically an IFrame, so MOSS is in effect a window to the external application.

The benefits to this approach are:

  • Low Cost – The external system has already been developed, so it’s not going to cost you anything significant in terms of developer hours. This is assuming that no technical hurdles exist in simply referencing the application via a page viewer. I’ll discuss the authentication issues in the disadvantages section.
  • Quick – Its quick and easy to do, if you plan to redevelop your system to be MOSS aware, this is a good interim measure.

 

The disadvantages are:

  • Systems remain isolated – You still have to maintain that existing system, this might be OK but, it’s likely to be mature and stable.
  • The information is still in a silo – This continues from the last point,MOSS isn’t taking full advantage of the system, you can’t personalise the information from the system, you can’t drop a filter web part on the page and get the exact data your looking for. Sure you might be able to crawl the external site and provide it via the Search Centre, but can your users build a custom list and use this information in a way that makes sense to them?
  • Authentication – How is your authentication handled, MOSS is just providing a window to the external application, your external system has to do all the heavy lifting in terms of authentication and authentication.
  • Inconsistent User Experience – Your external system probably has its own navigation, style and theme that probably isn’t the same as the MOSS implementation that your trying to sell to your users. It has gives off this feeling that its all held together by sticky tape.

I think this approach is fine if you fully understand what your doing, I plan on discussing some of the other approaches in some upcoming posts.

Monday, September 29, 2008 9:22:00 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint | Work
# Thursday, September 25, 2008

I’ve previously posted a demo that made use of a tag suggestion web part, as you type the web part will make an ajax call which will return the tags that match the current input. The user can click on the suggestion tag and it will populate the textbox, multiple tags can be entered into the textbox.

image

 

The most interesting part of this web part is the server side call, which I’ve implemented as a HttpHandler in the Tags.ashx file:

 

public class Handler : IHttpHandler {

    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "text";

 

I’ve made use of the System.Web.Extensions JavaScriptSerializer to render the string array of tags to JSON:

   1: List<string> tagList = new List<string>();
   2:  
   3: //add all the tags to a collection, JSON serialize the list
   4:  
   5: System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
   6:  
   7: context.Response.Write(serializer.Serialize(tagList.ToArray()));
   8:  

I’ve put this handler in the /_vti_bin/ directory of SharePoint which maps to the ISAPI folder under the 12 hive.

 

I’ve used the same code to generate the tags as I did with the tag cloud web part, so once again the generation of these tags won’t scale to large lists, this is just an example of how to implement a JQuery based Tag Suggestion web part.

 

The source code for this web part can be found here.

Thursday, September 25, 2008 7:39:59 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | Sharepoint | Work
# Monday, September 22, 2008

If you work in an organisation that has an organisation hierarchy it might be worth setting this up within MOSS, so that when you view a user’s profile you will get the following view:

OrgHeir

 

This is driven off the Manager profile field, it can be setup so that it is driven off either active directory or a custom source such as a SQL database in which case the BDC will need to be used. The Colleague suggestions and notifications make use of the organisation hierarchy as well, so it is worthwhile to set it up.

One thing but, regardless of your localisation settings, the heading ‘Organization Hierarchy’ will be spelt with a ‘z’, so for us Aussie’s we just have to cop the American spelling.

Monday, September 22, 2008 9:33:00 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint | Work
# Monday, September 15, 2008

I found this fantastic post today that I just had to comment on:

 

In a SharePoint entry form the user can select multiple values from a list. This should include an “All” option so in a long list the user can select or de-select all values with one click.

 

The idea is to use JQuery to perform a select 'All' on all the checkboxes in a list.

DannyE posted this JavaScript:

 

$(”.ms-RadioText[title=’All’] :checkbox”).click(function(){
   var otherids = (this.id).substring(0, (this.id).length-2 );
   $(”input[id^=’”+otherids+”‘]”).attr( “checked” , (this.checked)?”checked”:”" );
});

 

It looks for all the items with the ms-RadioText class that also have a Title attribute that equals 'All', it adds a click handler that will then toggle the checked status of the checkbox, its extremely cool, way better than the latest block buster movie ...

 

Anyway, that's all well and good, I'm not adding much value reposting his stuff, so I'd just like to improve on his deployment recommendation.

Instead of adding a script reference to the master page and then inserting a content editor region to paste the JavaScript in, I would suggest using the JQuery Script Manager:

 

So the idea is to use SharePoint Designer to register the control with the JavaScript. Note here to use the ScriptTemplate you'll have to grab my latest script manager control from here.

<cc1:jQueryManager ID="JQueryManager1" runat="server">        
<ScriptTemplate>
$(".ms-RadioText[title='All'] :checkbox").click(function(){
 var otherids = (this.id).substring(0, (this.id).length-2 );
 $("input[id^='"+otherids+"']").attr( "checked" , (this.checked)?"checked":"" );});
</ScriptTemplate>
</cc1:jQueryManager>

This will insert the JQuery Script Manager and declaratively add the JavaScript code to the page. This way you don't need to worry about the script resources or having multiple client side load functions.

How can you not love JQuery after seeing the power of the above code? it's just that awesome!

Monday, September 15, 2008 10:47:30 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | JQuery | Sharepoint | Work

I've previously posted a demo that illustrated a tag cloud web part, I've now posted the code.

First let me warn you that the method I've used to get the tag list will not scale, so please disregard the TagBuilder method, you'll need to implement that yourself.

tagcloud

 

I've based this tag cloud control loosely on the tag cloud control from codeproject, I've refactored most of it, but have kept the maths behind generating a weighting.

 

Using the control is pretty simple, you just need to measure the tags and then pass in a collection of CloudItems:

 

//tagList is a dictionary with the tag and count
Dictionary<string, int> tagList = new Dictionary<string, int>();

foreach (string tag in tagList.Keys)
{
    CloudItem cloudItem = new CloudItem();
    cloudItem.Text = tag;
    cloudItem.Weight = tagList[tag];
    cloudItem.Href = "/SearchCenter/Pages/Results.aspx?k=tags:" + tag;
    Items.Add(cloudItem);
}

There are a number of ways to perform the measurement, if you were to count the number of times a tagged resource was accessed, you would end up with a heat map of popular items. Alternatively you could simply count up the number of times a tag has been used (I think this is the most common use, I've done it this way in my demo). In any case the exact implementation details have been left up to you.

Monday, September 15, 2008 9:32:34 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | Sharepoint | Work
# Sunday, September 14, 2008

The web part that I'm presenting today is more of a building block, it doesn't do much on its own. It makes use of the JQuery Corners Plugin.

 

image

 

To set the corner types you can modify the Corner Type setting:

 

image

 

The above example will cause the following JavaScript to be output:

 

jQuery('cornerDiv').corner('tr 25px');
 

This web part makes use of the JQuery Script Manager that I've posted about previously.

 

As usual the source can be found here.

 

A screencast of the control in action can also be found here.

 

Sunday, September 14, 2008 9:02:49 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | JQuery | Screencast | Sharepoint | Work
# Friday, September 12, 2008

I've just rolled off a project that made use of the Business Data Catalog (BDC), I thought I'd share my experiences.

Firstly I'll give a quick heads up on the BDC, you've probably seen a diagram similar to the following one, basically it shows all the features in MOSS that hang off the BDC:

bdc

 Business Data Web Parts - These are the out of the box list web parts, they provide enough functionality out of the box to at the very least expose the user to the data.

SharePoint Lists - A user can create a column of type 'Business Data' this is very handy for end users, for example they may want to create an Asset register for locations, the locations that are relevant to them maybe exposed via the BDC, this would then save the user the task of maintaining the location list.

 Search - Provide a consistent search experience across all the enterprise data.

 User Profile Importer - Use business data to enhance the profile information you have about your user base, from the example above, you could import the base location into your profile property, then web parts could be built to personalise the information that is displayed to you.

 Custom Solutions - Use the BDC as a data access layer.

 

 

 

 

 

 

 

 

So anyway the application that I did some work on fits into the custom solution box mostly, but with a little bit of thought you can generally make it cross over a number of areas (search, profile import etc) and by doing so create a greater experience for your end users.

For example, our BDC profile import process imported a whole range of properties, one in particular was a business unit code. So by creating a custom metadata property, the people search was able to become a business unit people searcher. We then build some custom web parts that visualised the data on some maps and in some other ways that were relevant to the business, we constructed links that pointed to the people search which made use of the location code, much in the same way that I created tag links in the search demo.

We added the BDC data to the search centre but changed the result links to point to pages with our custom web parts, so now the search centre feeds into the custom visualisations, so no matter where the user comes from, either search or navigation they are going to get sucked into our experience.

 

So my tips are simple:

  • Plan your navigation experience - does search play a part in your experience?, its such a powerful concept to ignore, more people especially the younger generation are very search centric.
  • The BDC is best for read only type data - do you need to push back information? might be other easier ways to go about it.
  • Try to use all the options like web parts, search and profile information to be part of your overall custom solution.
  • Can users use your data in lists? Would it make the end users job easier?
Friday, September 12, 2008 12:37:59 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint | Work
# Wednesday, September 10, 2008

I've posted a couple of articles on JQuery and it's use in SharePoint and also provided some sample web parts. Recently I was putting together these web parts into a single project and I ran into a problem. Each web part was adding the JQuery script resources to the page as if it was the only control on the page, for example the ImageCarousel and the Tag Suggestion web parts both had code that needed to be run on the JQuery load event, this problem would also crop up when multiple instances of the same web part were added to the page. What was outputted to the page was something like:

 

$(document).ready(function(){ 
//function call for webpart1
}
$(document).ready(function(){ 
//function call for webpart2
}
$(document).ready(function(){ 
//function call for webpart2 instance 2
}
 

So I started developing a Script Manager control that I could add to the page that would output the JQuery load event just once, but with all the calls for the page inside this event. As with anything programming related these days, I found what I was looking for at http://codeplex.com/JQueryScriptManager/ I've changed a bit of the implementation, but the basic intent has remained the same. Hopefully I'll be able to get these changes updated to codeplex.

 

Looking at the revised code for the ImageCarousel web part:

 

jQueryManager jqueryManager = null;

protected override void OnInit(EventArgs e)
{
    
    jqueryManager = jQueryManager.GetCurrent(Page);
    if (jqueryManager == null)
    {
        jqueryManager = new jQueryManager();
        Page.Controls.Add(jqueryManager);
    }
    Page.ClientScript.RegisterClientScriptInclude("JCarousel", Page.ClientScript.GetWebResourceUrl(this.GetType(), 
        "JQueryWebParts.js.jquery.jcarousel.pack.js"));
    base.OnLoad(e);
}
 
 

Now inside the PageInit we check for the presence of a JQueryManager script control, if we don't find one, we add it to the controls collection. Just like the ASP.NET Ajax ScriptManager control, there can only be one per page.

 

Now to add code that is globally scoped which also resides in the same script block where our OnLoad event lives:

 

jqueryManager.RegisterScript("-- javascript code without <script> blocks");
//example:
jqueryManager.RegisterScript("var someItems = [5,4,3]");
            
 

To get javascript to run when the page is loaded (this will bundle calls into a single load event):

 

jqueryManager.ReadyFunctions.Add(new RegisterStartFunction("jQuery('#carousel').jcarousel();"));

Use the ReadyFunctions collection which takes a RegisterStartFunction object as a parameter.

 

Internally the JQuery script manager control is performing the following:

 

StringBuilder Start = new StringBuilder();

if (Scripts != null)
{
    foreach (RegisterScriptBlock r in Scripts)
        Start.Append(r.ScriptBlock + Environment.NewLine);
}

if (ReadyFunctions != null)
{
    Start.Append("$(document).ready(function(){");

    foreach (RegisterStartFunction r in ReadyFunctions)
        Start.Append(r.FunctionName + Environment.NewLine);

    Start.Append("});\n\n");
}

Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "JQuery", Start.ToString(), true);

 

The source code can be downloaded here. This includes the updated JQuery Script Manager and the ImageCarousel web part that I've previously posted about.

 

I think this approach will provide a nice platform to continue building web parts based on JQuery Plugins, have fun.

Wednesday, September 10, 2008 10:44:47 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | JQuery | Sharepoint | Work
# Monday, September 08, 2008

One of my favourite features of SQL Server 2008 is the Merge or 'upsert' Statement. Lets say we have an ETL process that prepares a data stage table, without the merge statement you might first delete all the records from the staging table and then insert them all again. If you have large data sets this can become quite time consuming and well frankly it doesn't seem very elegant. Another alternative is to use a cursor to iterate over each record and look for changes, you might also have data that has a timestamp which might help you write a set based operation, both of these approaches are less than ideal.

Well as of SQL 2008 you can use the Merge Statement:

 

Lets say you have a simple table like:

 

CREATE TABLE People
(
  ID       INT PRIMARY KEY,
  Name     Varchar(50) NOT NULL,
  Position Varchar(50) NOT NULL,
  Age      INT NOT NULL
);

 

Assuming our StagedPeople table is the same structure the merge statement would look like:

 

MERGE INTO People
USING StagedPeople
 ON People.ID = StagedPeople.ID
WHEN MATCHED THEN
-- if we find a match, then perform an update  
UPDATE SET
  Age = StagedPeople.Age,
  Name = StagedPeople.Name,
  Position = StagedPeople.Position
WHEN NOT MATCHED THEN
 -- if we don't find a match, then insert a new record
 INSERT (ID, Name, Position, Age)
 VALUES (StagedPeople.keycol, StagedPeople.Name, StagedPeople.Position, StagedPeople.Age)
WHEN SOURCE NOT MATCHED THEN
 -- we could delete the record, since it's not found in the Staged table
DELETE;
OUTPUT $Action

 

 

The $action variable returns a varchar(20) of the operation that has taken place,  i.e. 'INSERT', 'UPDATE', 'DELETE'

The operations and full reference can be found here.

It seems like a pretty fundamental operation, glad it only took till 2008 for us to have it :)

Monday, September 08, 2008 11:01:17 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | SQL Server | Work
# Thursday, September 04, 2008

Recently I posted about using JQuery in SharePoint web parts in this post I wrapped up the JCarousel plugin. Instead of requiring the JCarousel.js file to be included into the master page, I instead made the web part inject the HTML to cause the JavaScript file to be loaded.

The first step was to include the packed version of jquery.jcarousel.pack.js into my project:

 

image

 

Notice the Embedded Resource setting for the build action.

 

Now if we add the following code to our assembly.cs file:

 

[assembly: System.Web.UI.WebResource("SPImageCarousel.jquery.jcarousel.pack.js", "text/javascript")]

 

The above line now makes our embedded resource available for use in our web part which is done by the following code:

 

protected override void OnInit(EventArgs e)
{
    Page.ClientScript.RegisterClientScriptInclude("JCarousel", Page.ClientScript.GetWebResourceUrl(this.GetType(), "SPImageCarousel.jquery.jcarousel.pack.js"));
    base.OnLoad(e);
}

 

This code will ensure that the script is only added to the page once since the key "JCarousel" is the first parameter, remember that more than one web part can be added to a page at the same time, so we need to consider this as we develop our web parts. OnInit is the perfect event to call RegisterClientScriptInclude it's nice and early in the page lifecycle.

 

So hopefully you'll find this a nice and easy way to include your JavaScript resources, it does have the disadvantage of requiring a recompile to include a later version of the JavaScript file, so your mileage may vary if this is a concern.

 

Better still if your using .NET 3.5 Service Pack 1, you could make use of the CompsiteScript element of the script manager to combine the javascript files so the browser makes fewer calls to the server.

Thursday, September 04, 2008 11:52:17 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | JQuery | Sharepoint | Work
# Tuesday, September 02, 2008

I've mentioned before that I'm partial to JQuery, I consider it to be the Jessica Alba of JavaScript.

With all the work that has been done creating awesome JQuery based UI components, it seems like such a shame that us SharePoint developers aren't making more use of them.

So I present to you my first JQuery based web part, the Image Carousel:

image

Based on JCarousel, this web part presents the contents of a picture library in a carousel that can be scrolled by the navigation buttons.

 

The web part simply imports the jcarousel.js file, the web part then injects a JavaScript array of the images that reside in the selected picture library along with some javascript that initialises the carousel. The code to find the SharePoint picture library list is trivial:

 

SPSite site = SPContext.GetContext(HttpContext.Current).Site;
SPWeb web = site.OpenWeb();

foreach (SPList list in web.Lists)
{
    if (list.BaseTemplate == SPListTemplateType.PictureLibrary)
    {
        //grab the images from this list
        jsArray.Append(ProcessList(list));
    }
}

 

The web part makes use of custom toolpart for the selection of the picture list:

 

image

 

I think this provides a good template and starting point to start putting more of those JQuery plugins to use inside SharePoint

 

A small screencast of the control in action can be found here.

 

The end effect is some exceptional functionality for little development effort, which is really what JQuery is all about.

Some of the things that you need to think about when integrating:

  • Make sure that the injected div tag that will be used at the host has a unique id, remember that more than one webpart can be added to a page, if you hard code the html to have specific ID's, you will run into problems.
  • Make sure the JavaScript gets injected into the right part of the page, also just like the above point, ensure that each injected bits of code have a unique name, so that multiple webparts on the same page don't cause problems.
  • Use the packed version of the component, SharePoint is bloated enough already, use the smallest possible footprint you can.

 

The source code can be found here.

Tuesday, September 02, 2008 1:23:35 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | JQuery | Sharepoint | Work
# Thursday, August 28, 2008

In my first post dissecting the portal connection code, I showed the following code:

 

PortalConfig portalConfig = 
(PortalConfig)curSite.WebApplication.Farm.GetObject
(
    new Guid(curSite.WebApplication.Properties[PROP_KEY].ToString())
);

 

Notice the line: curSite.WebApplication.Properties[PROP_KEY].ToString()

The properties collection is scoped at the web application level. So if someone was to build a tool that called the Clear() method on this collection it would cause issues inside the Portal Connection tool.

So my point is to use the web application properties with other applications in mind, only clear your own state.

Thursday, August 28, 2008 8:01:40 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | Sharepoint | Work
# Tuesday, August 26, 2008

If your profile properties includes the organisation hierarchy, you may have noticed that when an AD account is deleted or deactivated the manager of that person is sent an email notifying the manager that the site is scheduled for deletion and that they now have permissions to the mysite so they can clean it up. Of course the MySite will only be deleted if the Automatic Site Deletion is enabled. Be aware that if the AD account is deleted and Automatic Site Deletion is enabled, the manager won't have access because the site will be deleted.

image

Lets say you work in an organisation that wants to suppress this email (I know it sounds silly), how would you go about that? The first thing to understand is the process that caused that email to be sent in the first place.

The first step is the profile import will detect if the AD account has been deleted or disabled and will change the bDeleted flag to 1 in the UserProfile_Full table of the SSP database.

 

The next step of the process is handled by the My Site Cleanup Job:

 

image

 

If you disable this job then you will prevent the notification email being sent. However you will still need to have a process in place to clean out the mysites and the profiles. The crawler will still find the profiles and index them (so your people searches will include outdated people). The MySites will still be around taking up disk space.

One potential solution is to call the profile stored procedure manually:

 

DECLARE @UserID uniqueidentifier
DECLARE @NTName nvarchar(400)
DECLARE @SID varbinary(512)

DECLARE userCursor CURSOR FOR
SELECT Userid, NTName, SID from userprofile _full where bdeleted = 1

OPEN userCursor

FETCH NEXT FROM userCursor INTO @UserID, @NTName, @SID

WHILE @@FETCH_STATUS = 0

BEGIN

EXEC profile_RemoveUser @UserID, @NTName, @SID

FETCH NEXT FROM userCursor INTO @UserID, @NTName, @SID

END

CLOSE userCursor
DEALLOCATE userCursor
Tuesday, August 26, 2008 9:48:14 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | Sharepoint | Work
# Saturday, August 23, 2008

In a previous post I introduced the Automatic Portal Connection tool, which can be used to automatically setup the portal connection on new and existing sites.

I thought I would take a peek at how I've made this happen:

Firstly I'd like to introduce the SPPersistedObject:

The description MSDN uses is:

 

The SPPersistedObject class provides a base class for all administration objects. It serializes all fields marked with the Persisted attribute to XML and writes the XML blob to the configuration database. The SPPersistedObject class contains code to serialize all its members that are base types, other persisted objects, and collections of persisted objects. Configuration data that is stored in persisted objects is automatically made available to every process on every server in the farm.

 

The Portal Connection tool has a class called PortalConfig which derives from SPPersistedObject this class holds the configuration information such as the portal name and portal URL:

 

/// <summary>
/// Simple persisted object that stores the portal connection name and the portal connection url
/// </summary>
public class PortalConfig : SPPersistedObject
{
    [Persisted]
    private string portalName = string.Empty;

    public string PortalName
    {
        get { return portalName; }
        set { portalName = value; }
    }

    [Persisted]
    private string portalUrl = string.Empty;

    public string PortalUrl
    {
        get { return portalUrl; }
        set { portalUrl = value; }
    }

    public PortalConfig()
    {

    }
    public PortalConfig(string name, SPPersistedObject parent, Guid guid)
        : base(name, parent, guid)
    {

    }
}

SPPersistedObject is a very handy class, especially for configuration type scenario that is used in this solution, a method that makes use of this object is:

/// <summary>
        /// Simple method to persist our settings to the site
        /// </summary>
        /// <param name="curWeb"></param>
        /// <param name="curSite"></param>
        public static void ApplyPortalConnectionSettings(SPWeb curWeb, SPSite curSite)
        {
            PortalConfig portalConfig = (PortalConfig)curSite.WebApplication.Farm.GetObject(
                                        new Guid(curSite.WebApplication.Properties[PROP_KEY].ToString())
                                        );

            if (curWeb.IsRootWeb)
            {
                curSite.PortalName = portalConfig.PortalName;
                curSite.PortalUrl = portalConfig.PortalUrl;
            }
            curWeb.Update();
        }

 

This object is filled out and persisted by the central admin page, then a feature staple gets this information when the site is created and applies it, but I'll expand on this in future posts.

Saturday, August 23, 2008 11:08:40 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | Sharepoint | Work
# Thursday, August 21, 2008

The portal connection is pretty useful, say you have a web application for team sites and have self service site creation turned on you would probably like the portal connection to be set to your portal homepage. Just as a refresher the portal connection is the link at the top of your site:

image

 

I've put together a tool that will give you the ability to set the portal connection for new sites and also for newly created sites. Once the solution has been deployed and the features activated, from central admin you will see a new link:

image

Following this link you will be presented with the following page:

image

From here you can select the web application to work with and you can set the portal name and URL. By selecting the 'Apply To Existing Sites' checkbox, you will set portal connections to all the sites on that web application.

The SharePoint solution can be downloaded here, I'll be releasing the code soon, I want to release it to Codeplex, I just need to set it up first.

Here is a small screencast showing the tool in use

 

Edit: I've now setup the Codeplex project: http://codeplex.com/SPPortalConnection

Thursday, August 21, 2008 10:36:14 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | Sharepoint | Work
# Tuesday, August 19, 2008

If your experiencing long initial page load times and your servers are configured so they can't connect out to the internet, you can reduce this time by either allowing the servers access to crl.microsoft.com or by deselecting the 'Check for publisher's certificate revocation' option from within Internet Explorer. The Internet Explorer option can be found under the Tools menu, then Internet Options:

 

image

 

Another option is to add a host file entry so that crl.microsoft.com points to the localhost (127.0.0.1)

Tuesday, August 19, 2008 11:53:12 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint | Work
# Monday, August 18, 2008

There is so much great content on MSDN, but often it's hidden away, so I like to blog about these finds so I have a chance to find them in the future.

Today's find is the Design Logical Architecture for Collaboration Sites.

In particular I like the advice surrounding team sites:

 

Design guidance for team sites includes the following recommendations, each of which is elaborated in the following sections:

  • Host team sites in a dedicated Web application.

  • Apply Web application general settings, such as quota and life-cycle management settings at the Web application level to manage growth of team sites and to keep content current.

  • Design content database settings for appropriate storage and scale and to ensure that you can back up and restore databases of the designed size.

  • Automatically delete sites that are not used.

  • Use paths to organize team site URLs.

  • Plan for appropriate policies and permissions.

 

Some of my notes:

  • Hosting the team sites in a dedicated web app - This gives you the power to apply web application policy (this goes for the last point as well), what we normally do is have a zone like admin.yourteamsiteurl, then we use policy so that our administrators have full access over the web application. This means they can go into any team site if needed.
  • In large organisations keeping an eye on the growth of the team sites is important, you need to know how large the content database is and when to expand out to more databases. Make sure you setup site level warnings, so your administrators are on top of the situation.
  • Ensure that the procedures for notifying users of inactive sites is occurring, you really want to be able to claim that space back.
  • A nice path is helpful for your end users, we normally opt for team.yoursiteurl/sites/<teamsitename> (the default setting)

This article also feeds into another great find Logical Architecture Sample Design: Collaboration Sites

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

JQuery is my all time favorite JavaScript library, it's so simple to use and incredibly powerful, but if you include all the plugins that are available, I just don't think that you would find a better tool for client side scripting.

My favorite validation plugin is the 'Validation Plugin', let me give you an example of how it is used:

Lets say you have a signup form, you want the user to select a user name, a password with confirmation and an email address, assume all of this is inside a form tag named 'signup'.

All of the HTML input element ids are 'Password', 'ConfirmPassword', 'Email'.

The JavaScript would be:

 

<script type="text/javascript">
$().ready(function() {
$("#signup").validate({
        rules: {            
            UserName: {
                required: true,
                minLength: 2,
                remote: "/Account/CheckUserName"
            },
            Password: {
                required: true,
                minLength: 2
            },
            ConfirmPassword: {
                required: true,
                minLength: 5,
                equalTo: "#Password"
            },
            Email:{
                required: true,
                email: true,
                remote: "/Account/CheckEmail"
            }
        },
        messages: {
            
            UserName: {
                required: "Please enter a username",
                minLength: "Your username must consist of at least 2 characters",
                remote: jQuery.format("{0} is already in use")
            },
            Password: {
                required: "Please enter a password",
                minLength: "Your password must consist of at least 2 characters"
            },
            ConfirmPassword: {
                required: "Please provide a password",
                minLength: "Your password must be at least 2 characters long",
                equalTo: "Please enter the same password as above"
            },
            Email: {
                required: "Please enter your email address",
                minLength: "Please enter a valid email address",
                remote: jQuery.format("{0} is already in use")
            }
        }
    });
});
</script>

 

Now notice how I used the remote property with '/Account/CheckEmail' and '/Account/CheckUserName', these are URL's that will be called by the client side JavaScript, they will pass along the current value of the textbox, so you could write server side code to validate the input, an ASP.NET MVC Controller Method could look like:

 

public JsonResult CheckUserName(string username)
{
    return Json(CheckValidUsername(username));
}

 

Notice the use of a JsonResult, The ASP.NET MVC framework is great for this type of thing, combine both JQuery and the MVC framework and you have a powerful combination, Jeff Atwood has come to the same conclusion and used both of these tools to build stackoverflow.com. 

All of the above code is so clean and easy to read, can you ever remember saying that about JavaScript code?

Sunday, August 17, 2008 3:56:40 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
ASP.NET MVC | code | JQuery | Work
# 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
# Wednesday, July 30, 2008

Excel Services offers a number of Business Intelligence features such as:

 

  • Workbooks can be connected to enterprise data sources
  • The logic contained in workbooks can be reused in server based code, i.e. don’t have to rewrite code specifically for the server
  • Provides real time analysis of data
  • Full features UI experience, there is no loss of fidelity when moving to the server.
  • Sorting, Filtering and drill down all work the same, no loss of functionality.

 

It’s worth your time investigating the features offered by Excel Calculation Services

Wednesday, July 30, 2008 12:37:00 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint | Work
# Friday, July 25, 2008

I haven’t had a featured diagram in a little while so here goes:

Enterprise application integration scenario

This doesn’t have all the pretty colours of my last ones.

But this diagram does offer a great insight into how Microsoft recommend integrating the MOSS BDC and InfoPath forms service.

Friday, July 25, 2008 1:03:00 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint | Work
# Tuesday, July 22, 2008

Continuing on with my last post on great diagrams, today I bring you the SharePoint Capabilities Diagram:

Office SharePoint Server Capabilities

 

These capabilities are:

Collaboration and social computing

Portals

Enterprise Search

Enterprise content management

Business process and forms

Business intelligence

Tuesday, July 22, 2008 12:50:00 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint | Work
# Monday, July 21, 2008

I found this resource which lists the Supported Excel types and UDF arguments:

 

Office 2007 Excel Services UDFs

 

1. Types are in the System namespace. These are the only supported argument types.

2. The term "All numeric" refers to the following types: Double, Single, Int32, UInt32, Int16, UInt16, Byte, Sbyte. Specifically, Int64 and UInt64 are not supported types.

3. Date/time in Excel is a Double internally, but the representation (algorithm to encode date/time as Double) is different from the .NET Framework representation, and conversion is necessary. Therefore, UDF arguments support DateTime as an explicit type, and Excel Services convert any Excel Double into a .NET DateTime when the argument is of type DateTime (assuming that the Excel Double is actually a date/time value).

4. Scalar object arguments are not supported; only one-dimensional or two-dimensional object arrays are supported (see the "Arrays and Ranges" later in this article). This table row defines only how each cell in the range that is passed into the array is handled.

Monday, July 21, 2008 12:41:00 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint | Work
# Friday, July 18, 2008

Like me you might sometimes struggle to describe the breath of the Microsoft stack across all the various products.

I must give credit to the Microsoft people who come up with these great looking diagrams:

SharePoint Products and Technologies

Friday, July 18, 2008 12:46:00 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint | Work
# Sunday, July 13, 2008

Almost all SharePoint developers will know about the U2U CAML Query tool, I just thought I’d throw a little link love their way.

If you live under a rock, this tool provides a nice GUI for you to generate those nasty CAML queries:

 

camlcreator

 

This is a fantastic tool, I have no doubt that it will save you plenty of time.

 

Just remember to remove the <Query> opening and closing tags before you use it in your code.

Sunday, July 13, 2008 1:52:00 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint | Work
# Saturday, June 21, 2008

BDC associations allow you to create master / child type relationships with the Business Data List Web Part and the Business Data Related List Web Part.

From the MSDN article, the following points should be followed:

  • The entity that defines the association method must be below all of the entities to which it relates within the XML metadata file.
  • The association method must have input parameters that map to the identifiers of all the source entities.
  • The return parameter of the association method must include the identifiers of the destination entity.

I would recommend watching the associated 10 minute video from the MSDN article as well.

Saturday, June 21, 2008 1:25:00 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint | Work
# Friday, June 20, 2008

I’ve previously posted about a great resource for the new MOSS developer. Well here is another great resource to help the developer get their mind around the workflow’s in SharePoint.

The MSDN article is: Developer Introduction to Workflows for Windows SharePoint Services 3.0 and SharePoint Server 2007

This article covers the following topics:

Introduction to workflows

  • The workflow architecture
  • Workflow Types
  • Workflow composition
  • Workflow mark-up
  • Workflow’s that are specific to SharePoint
  • Authoring SharePoint workflows with both SharePoint Designer and Visual Studio, with topics that draw the comparisons of each product.

Again its another meaty document, I think my first resource still stands as the document for the newbie to read, if they come back for day two, maybe throw them this link.

Friday, June 20, 2008 1:44:00 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint | Work
# Friday, June 13, 2008

By default IIS does not return content that it does not have a mapping for, this will probably effect your first Silverlight deployment.

Before you deploy any Silverlight content you will need to add a mapping in IIS for the .xap extension.

 

The key is to register a MIME type for .xap for the application/x-silverlight-app type.

Also

Some Silverlight 1.0 applications may use .XAML that is being served directly from the server, so it might be prudent to also add this MIME type:

.xaml for the application/xaml+xml type

Friday, June 13, 2008 1:19:00 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Silverlight | Work
# Thursday, June 12, 2008

Today I was asked if it was possible to have a different icon display in the search results if the returned document was a PDF.

The answer was yes.

Here’s how:

 

  • Save the image to the <12 hive> \Template\Images\   directory
  • Edit the following xml file:  <12 hive>\Template\Xml\DOCICON.XML
  • Add the following line: <Mapping Key="pdf" Value="pdf.gif"/>

 

*Note the <12 hive> is normally located at: C:\Program Files\Common Files\Microsoft Shared\Web server extensions\12

Thursday, June 12, 2008 1:33:00 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint | Work
# Monday, June 09, 2008

I’m sure everyone has seen the famous ‘hamburger diagram’ (if you look closely it kind of forms the share of a hamburger)

 

hamburger

 

The diagram shows the end-to-end product offering from Microsoft. The diagram points out some MOSS specific technologies such as Excel Workbooks, but it doesn’t highlight and BDC type interactions which I’m not sure how they would be modelled on this diagram since the BDC can return data straight from the data sources at the bottom, if they did include the BDC the diagram may not look like a hamburger anymore :)

Monday, June 09, 2008 1:09:00 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint | Work
# Wednesday, June 04, 2008

Up until now I haven’t found a good resource to point a new developer who knows .NET but is new to SharePoint.

Well as what usually happens, I stumbled across this article: Introduction to SharePoint Products and Technologies for the Professional .NET Developer

  • It covers everything a newbie needs to know:
  • Benefits of SharePoint -
  • Introduction to all the SharePoint components
  • Using Visual Studio 2008 to build SharePoint solutions
  • A comprehensive glossary of common terms
  • A getting started guide

So I would add this to the list of must read items for that new starter, they have to start drinking from the fire hose at some stage!

Wednesday, June 04, 2008 12:57:00 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint | Work
# Monday, May 12, 2008

Continuing on from Part 1 and Part 2 where I discussed Zones, Authentication providers and Policy, this time I would like to discuss Site Collections.

A site collection is a container, it forms the basis of an information architecture where you can create sub sites to build out your information architecture.

Windows Sharepoint Services (WSS) allows the user to create one site collection, that is all of your content will be housed in a single site collection.

MOSS takes a different approach and allows you to create as many site collections as you need, if you turn on self service site creation for team sites, then every site will be a site collection. Even the My Sites are in fact a site collection.

Using managed paths, you can create site collections that form parts of your information architecture.

So what are the benefits of a site collection? The first is distributed administration, each site collection can have different administrators, the other big features are a separate recycle bin and the ability to enforce a quota (as well as the features not covered here).

Each site collection is an isolated collection of sites, you can't use the content query web part to roll up content across site collections (although you could use RSS feeds to do this). This might sound like a bad thing, but lets consider it with an example.

From Part 1 we put forward a scenario where we have staff members and external people accessing a portal, both of these groups need to view different information depending on who they are. Lets assume we had one single site collection, without item level security (which isn't an out of the box feature) all users could see information they shouldn't. Or assume we did have item level security, it would only take a simple mistake to assign the wrong permissions for information to leak.

It might sound like a good idea to have a single site collection, but after you think about it a little more it becomes obvious that it doesn't work when you get past a simple implementation (like what WSS is designed for).

Looking at the reference diagram from Part 1, we see that Microsoft has indeed separated the partner content and internal content into separate site collections.

Monday, May 12, 2008 7:56:25 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint | Work
# Monday, May 05, 2008

I've been working on a large MOSS project for the past few months, I've learned a lot about designing and building the logical architecture of a MOSS instance. I thought that I might try to put some of my findings into words. Firstly I'd like to set the scene to some hypothetical scenario:

You have just walked into the offices of Golf Corp, they are a national company that manages the golf handicap and scoring system of 150 golf courses. They have chosen to implement Microsoft Office Sharepoint Server to serve their 1000 staff and 20,000 users. Your mission should you choose to accept it, is to design the logical architecture and the server topology.

From your first meeting you discover the following facts:

  • Approved Golf Corp staff can add and edit golf scores and content
  • Approved golf course staff can add and edit golf scores only of it's members
  • The portal will be the homepage for all Golf Corp staff
  • Golf Corp currently uses Active Directory for it's corporate network
  • Users should be able to view their previous scores
  • Golf Corp already has a SQL Server database with all users and current scores and handicaps.

The first place a new MOSS consultant should look for logical architecture guidance is at the Microsoft reference. The key points are the use of web applications, zones and policy. It has been my experience that consultants who have only worked on smaller MOSS projects (single site collection, default zone, etc) haven't really looked at these concepts.

 

I will make this a multi-part series, for this Part 1, lets first look at the basics of Zones and Authentication.

 

A Zone is a URL that users enter your portal on - you can create a total of 5 zones with the names of: Custom, Intranet, Default, Extranet, Internet.

That leads us to our next important bit, each Zone can have a different authentication provider these might include, NTLM / Kerberos, Forms, Anonymous etc.

 

The next important concept that a MOSS consultant should have is an idea about this diagram:

 

This diagram is also from the Microsoft reference design, an original Visio version can be found here. This excellent post from the Sharepoint team further explains the concepts that I have touched on here. The post raises a very important point:

 

When a user request cannot be associated with a zone, the authentication and policies of the Default zone are applied. Consequently, the Default zone must be the most secure zone

 

This diagram says so much, I will be referring to it in future posts as I cover more topics, the main point of this post however is to cover the top of the diagram, which lists the Zones and the types of users that make use of the zone. It is very important that your MOSS consultant understands these concepts, the next topic of Zone policy will build on top of what I have covered here.

 

Does your MOSS instance have a Logical Architecture diagram like the one above?

Monday, May 05, 2008 2:38:57 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Work
# Friday, May 25, 2007

Well its all official I've got my Tech-Ed 2007 ticket, I can't wait!

I last attended in 2005 and had a ball. This time I know a few more people who are also attending so it going to be so much better.

 

I'm looking forward to hopefully attending some sessions on silverlight and WPF.

Friday, May 25, 2007 3:13:13 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Work
# Tuesday, May 22, 2007

After having a good read of the Family.Show reference application I've been blown away with the power of data binding. I think that with all the hype over how easy it is to now create fancy UI's, WPF may be overlooked for general business development, when in fact its perfect for your average business process application.  Of course that's not to say that these applications couldn't use an interaction specialist to help improve the users productivity, until business catch on that WPF has a slightly different development model (one with more focus on usability) it might be hard to justify the extra cost initially.

 

I've also just read Paul Stovell's data binding example based on winforms technology, it's not be as widely written about, but it seems that some pretty powerful data binding features exist in winforms today, it's just a matter of getting into the mind set. Its pretty cool how WPF databinding is introducing some new concepts to old technology.

 

Tuesday, May 22, 2007 11:47:36 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Work
# Monday, May 14, 2007

I've spent some time looking at the Vertigo WPF reference application Family.Show. It's a really cool application, while I was playing around with it Rebecca saw it and immediately wanted it installed on her computer, she's been busy entering data into it. I hope an open source community forms around it.

 

The most interesting thing I found was a presentation by Scott Stanfield at Mix 07, he describes some of the lessons learnt from building this application. From the sounds of it the problem domain caused the bulk of the problems. It's certainly a testament to the design of the WPF that guys who have never used it before can produce something so stunning and the code is very nicely laid out.

Monday, May 14, 2007 11:35:58 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [2] - Trackback
Work
Statistics
Total Posts: 190
This Year: 3
This Month: 0
This Week: 0
Comments: 38