Skip Navigation Links
Level Orange > Categories
Intro to Features

This will not be an extensive look at features but I figured it was about time to at least write a feature and explain a little about them.

What is a feature?

Wow, I am so glad you asked that. A feature in MOSS is simply a set of files, be it code, XML, web pages or CAML that will be "installed" into the SharePoint system. This being said, what you can do is actually add or "staple" this feature to a site definition so that when a new site is created, the feature will be activated as well. What you can put in a feature is really whatever you can dream up. You can add web parts, master pages, lists, fill lists with data, event receivers attached to the lists, etc. Hopefully, you are starting to understand the real scope of this here. As you can see, this is the recommended way of deploying your SharePoint Changes through the normal SDLC.

A feature can be installed on many levels or "scopes".

  • Farm
    • A farm feature is always activated and would be things like links to _layouts pages
  • Web Application
    • These would be items like Admin Links and global assemblies
  • Site Collection
    • These could be items like Web Parts, Workflows and Content Types
  • Site
    • These could be things like item receivers and list instances.

There are three types of file groups that are involved in a feature

  • The first and most obvious file will be the Feature.xml file. This file will be in a subdirectory (usually your feature name) under the 12 hive (\program files\common files\microsoft shared\web server extensions\12\templates\features. We are going to call our feature ItemReceivers in our example.
  • The second is the Element Manifest XML file. This file is referenced by the Feature.xml file and houses pointers to all the files that will be provisioned as well as any setup for those files including CAML code.
  • The third are the files referenced by the Element Manifest file. These files would include aspx pages, dll's, and anything else you would likely deploy to SharePoint

We are now going to write an example feature that will attach an Item Event Receiver to a list.

Feature

The first thing that you obviously have to do is decide on what you are going to build and add as a feature. We are going to deploy the item receiver that we built here as a feature.

Feature File

In building the feature file you will first need to generate a unique GUID for the feature itself. You can find instructions for this here. After this you will have to point to write the base XML for the feature file. It will look something like this:

<Feature Title="ItemReceivers" Id="4f43db6e-74d3-4806-a118-bf543796663e" Description="" Version="1.0.0.0" Scope="Site" Hidden="FALSE" DefaultResourceFile="core" xmlns="http://schemas.microsoft.com/sharepoint/">

<ElementManifests>

<ElementManifest Location="elementManifest.xml" />

</ElementManifests>

</Feature>

 

Manifest File

Your manifest file will act exactly as it sounds by outlining all files and placement of these files and will look something like this:

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

<Receivers ListTemplateId="10001">

<Receiver>

<Name>Field Added</Name>

<Type>FieldAdded</Type>

<Assembly>MSIT.ItemReceivers, Version=0.0.0.0, Culture=neutral, PublicKeyToken=6546c52e1a7f48a0</Assembly>

<Class>MSIT.ItemReceivers.UpdateContactsEvent</Class>

<SequenceNumber>1000</SequenceNumber>

</Receiver>

<Receiver>

<Name>Field Updated</Name>

<Type>FieldUpdated</Type>

<Assembly>MSIT.ItemReceivers, Version=0.0.0.0, Culture=neutral, PublicKeyToken=6546c52e1a7f48a0</Assembly>

<Class>MSIT.ItemReceivers.UpdateContactsEvent</Class>

<SequenceNumber>1000</SequenceNumber>

</Receiver>

</Receivers>

</Elements>

Please note that the Assembly and Class information were retrieved using the mechanism described here.

Important: Please note that there are a couple limitations to using the "Receivers" approach. You cannot associate this to a particular list instance only a type of list. You will probably want to make your own type anyway; however, this is a limitation. Also, you can only scope this at a site level. Both of these limitations can be overcome by using solution packages which will be discussed in a later post.

 

Manually Deploying your Feature

The first thing you will have to do is make sure that the files are copied to the correct place. You will open the command prompt and navigate to your bin folder for SharePoint.

xcopy "c:\[PathToFeatureFiles]" "c:\program files\common files\microsoft shared\web server extensions\12\templates\features" /s /y

Please GAC the assembly of your receiver by following the instructions here.

You then will need to install the feature to your SharePoint Server

stsadm -o installfeature –filename Receivers\feature.xml

Finally, you will have to activate your feature for the site

stsadm -o activatefeature -filename Receivers\feature.xml -url http://[YourSite]

 

Deploying your Feature as a Solution Package

This is a topic for a future post and I will modify this link to have the link at that time.

SharePoint Blog Navigator Web Part

Intro

Ok, ladies and gents, I just couldn't take it any longer! The out of the box navigation for blogs is less than ideal and although I will be soon investigating different content query web parts to accomplish the same thing, I went ahead a build a new one. For the finished product and POC please visit http://www.codeintegrators.com/blog to see it in action. Essentially, I wanted a grouping of blog articles in some sort of tree view as a web part. Simple right? The answer to this is actually yes. What I will plan to do here is simply write a quick code base and deploy to my site. At that point, I can just add my web part and ta-da, workie workie.

Implementation

  1. Create a CAML query based on the "Posts" list that just orders the posts by publish date. This will look something like:

using (SPWeb spWeb = SPContext.Current.Web)

{

string DocumentLib = "Posts";

string sUrl = spWeb.Url;

string PostDate = string.Empty;

SPList list = spWeb.Lists[DocumentLib];// here DocumentLib is name of the name of documentlibrary we are passing

SPQuery docQuery = new SPQuery();

docQuery.ViewFields = @"<FieldRef Name=""LinkTitle""/>";

docQuery.ViewFields += @"<FieldRef Name=""PublishedDate""/>";

string CamlQ =

@"<OrderBy>

<FieldRef Name=""PublishedDate"" Ascending=""False"" />

</OrderBy>";

docQuery.Query = CamlQ;

 

  1. Loop through these posts creating a string representation of XML that looks something like:

sBlogs = @"<?xml version=""1.0"" encoding=""utf-8"" ?>";

sBlogs += @"<BlogPosts>";

SPListItemCollection docList = list.GetItems(docQuery);

foreach (SPListItem item in docList)

{

DateTime PublishedDate = DateTime.Parse(item["PublishedDate"].ToString());

if (PostDate != PublishedDate.ToString("MMMM yyyy"))

{

//Make sure not first time through loop

if (PostDate != string.Empty)

{

sBlogs += @"</PostMonth>";

}

PostDate = PublishedDate.ToString("MMMM yyyy");

sBlogs += @"<PostMonth name=""" + PostDate + @""">";

}

sBlogs += @"<PostName name=""" + item["LinkTitle"].ToString() + @""" url=""" + sUrl + @"/Lists/Posts/Post.aspx?ID=" + item.ID.ToString() + @"""/>";

}

sBlogs += @"</PostMonth>";

sBlogs += @"</BlogPosts>";

}

return sBlogs;

}

 

  1. Create an XML Data Source and attach your bindings accordingly

XmlDataSource xBlogPosts = new XmlDataSource();

xBlogPosts.EnableCaching = false;

XmlDocument xXMLDoc = new XmlDocument();

TreeNodeBinding tnbTop = new TreeNodeBinding();

TreeNodeBinding tnbMonth = new TreeNodeBinding();

TreeNodeBinding tnbName = new TreeNodeBinding();

string sXMLDoc = string.Empty;

try

{

if (!Page.IsPostBack)

{

//Create XML

sXMLDoc = GetBlogPosts();

//Load XML DataSource

xXMLDoc.LoadXml(sXMLDoc);

xBlogPosts.Data = xXMLDoc.InnerXml;

 

  1. You will then set your XPath to narrow down your tree

xBlogPosts.XPath = "BlogPosts/PostMonth";

 

  1. Create a Treeview and set the XML Datasource be the binding

//Create TreeNode Bindings

tnbTop.DataMember = "BlogPosts";

tnbTop.Text = "Blog Posts";

tnbMonth.DataMember = "PostMonth";

tnbMonth.TextField = "name";

tnbName.DataMember = "PostName";

tnbName.TextField = "name";

tnbName.NavigateUrlField = "url";

//Associate TreeView Bindings

tv.DataBindings.Add(tnbTop);

tv.DataBindings.Add(tnbMonth);

tv.DataBindings.Add(tnbName);

//Bind

tv.DataBind();

tv.CollapseAll();

 

  1. Add the tree view through the RenderChildren method as explained in an earlier post here.

this.Controls.Add(tv);

 

  1. Make sure you dispose your objects that you explicitly instantiate

xBlogPosts.Dispose();

xBlogPosts = null;

xXMLDoc = null;

tnbTop = null;

tnbMonth = null;

tnbName = null;

tv.Dispose();

tv = null;

 

  1. Build and deploy your finished webpart
  2. Add the webpart to the page(s) in question

 

Finishing touches

For full sample of the code, simply email me or send comment. I have uploaded the cs file, however, anonymous access is not yet enabled. I was tired of writing the code in the blog all the time, so figured I would try a different approach this time.

The end product looks something like:

 

Pretty cool huh?

Attaching a Receiver using Code

Intro

So I have built a new receiver (You can review the article found here). Now what?

Well, the answer is that you have to attach it somehow. In this post, I plan to demonstrate how to do this via code. In a later approach I will be reviewing feature based development.

Implementation

The first thing we are going to do is create a new project in visual studio. In this case we will make it a console application just for a POC:

We then of course are going to add the Microsoft.SharePoint.dll reference. You can find this in my previous article located here.

Finally we are going to write the following code:

using System;

using System.Collections.Generic;

using System.Text;

using Microsoft.SharePoint;

namespace MSIT.Samples

{

class Program

{

static void Main(string[] args)

{

SPSite spSite = null;

SPWeb spWeb = null;

SPList spList;

try

{

spSite = new SPSite("http://r2-basemachine:1111");

spWeb = spSite.OpenWeb();

spList = spWeb.Lists["Contacts"];

//spList = spWeb.Lists["ContactType"];

string asmName = "MSIT.ItemReceivers, Version=0.0.0.0, Culture=neutral, PublicKeyToken=6546c52e1a7f48a0";

string className = "MSIT.ItemReceivers.UpdateContactsEvent";

spList.EventReceivers.Add(SPEventReceiverType.ItemAdded, asmName, className);

spList.EventReceivers.Add(SPEventReceiverType.ItemUpdated, asmName, className);

spList.Update();

}

catch

{}

finally

{

spList = null;

spWeb.Dispose();

spSite.Dispose();

spWeb = null;

spSite = null;

}

}

}

}

 

You simply run this code and run IISReset and you are golden (ready for test)

Building MOSS Item Event Handlers

Intro

So you have a list in MOSS, now what? I want to have a unique index field or I want to update contents of the list with other lists, or I want to start a process, etc. To extend a list, one of the many things you can do is to build an event handler for that list. Similar to other .NET objects, a SharePoint List has Event Handlers that can be tied to certain actions triggered by usage of that object. It is important to know that there are two kinds of execution patterns depending on the event that is coded for.

Synchronous Event Handlers:

The first is synchronous event handlers. These would be where you could stop the execution of the thread before completion. If you take a look at the Item Adding event for instance, you could check to see if you are violating a specific business constraint and stop the execution or add process if the validation fails. Pretty much a rule of thumb on these is that they all end in "ing" so Item Adding, Item Updating, Item Deleting, etc. Think of the power of this if I get to write any .NET code on this particular delegate.

Asynchronous Event Handlers:

The second would be asynchronous event handlers. These would be when a new thread would be started to run this code. If you take a look at Item Updated, we could possibly retrieve data from another list and cross populate into your list based on a lookup field or any number of items. This is the exact sample that we will be addressing in this article.

Writing the code:

The first thing we will do is open visual studio and create a new project. It can be a simple class library:

We are then going to add the Microsoft.SharePoint.dll as a reference:

Now we are ready to write our code. Remember for this that we are going to simply take the contents of one list and based upon a lookup value, populate based on contents of another list.

using System;

using System.Collections.Generic;

using System.Text;

using Microsoft.SharePoint;

namespace MSIT.ItemReceivers

{

class UpdateContactsEvent : SPItemEventReceiver

{

public override void ItemUpdated(SPItemEventProperties properties)

{

UpdateContents(properties);

}

public override void ItemAdded(SPItemEventProperties properties)

{

UpdateContents(properties);

}

void UpdateContents(SPItemEventProperties properties)

{

using (SPWeb spWeb = properties.OpenWeb())

{

//Get Lookup List

SPList ContactType = spWeb.Lists["ContactType"];

//Get List Item to be updated

SPListItem Contact = properties.ListItem;

string sContactType = string.Empty;

sContactType = Contact["ContactType"].ToString();

//Get ListItem of Lookup List

SPListItem ContactTypeItem = null;

foreach (SPListItem ContactTypeLoop in ContactType.Items)

{

//We are doing a contains because this is an array lookup but we could explicitly do something like:

//If (ContactTypeLoop["ContactType"].ToString() == Contact["ContactType"].ToString().Split(';')[1].Replace('#','')

if (sContactType.Contains(ContactTypeLoop["ContactType"].ToString()))

{

ContactTypeItem = ContactTypeLoop;

break;

}

}

if (ContactTypeItem == null)

{

throw new Exception();

}

//Update Original ListItem

Contact["ExtraData"] = ContactTypeItem["SendChristmasCards"].ToString();

Contact.Update();

}

}

}

}

     

Build and GAC the Receiver

What you are going to have to do now is GAC the assembly. Instructions can be found in my blog posting here.

Associate Receiver to List

Finally, the moment of truth, let's attach the code to the list that we want. There are two main ways we can accomplish.

Code Approach

The instructions for Code Approach can be found here.

Feature Approach (Recommended)

The instructions for Feature Approach can be found here.

Find GUID of List

Ok, I have decided to compartmentalize some of these into just a couple searchable topics that I can link to in other things so this is simply going to find out the GUID of an existing list. There are several ways we can do this including simply writing a quick code snippet. Technically, we should even be able to write a quick Console App that spits out the GUID based on a URL. However, we can simply look at the URL after going to the list we want.

   

See (If you look at the URL you will see a URLEncoded GUID at the List=: )

   

Implementing a New Authorization Provider

Membership Provider Setup

Tools Needed and other Assumptions

The following is assuming you have a working Central Administration Site and Website you wish to apply the custom membership provider to. You will also need access to the latest of the following files:

  • Security.dll (Custom Membership and Role Provider)

In implementing the custom membership provider we are also assuming that you will have access to the custom provider database. Please note anything bold and red is configurable.

We also must note that these instructions apply to the changes that need to be made to the MOSS Server and will need to be done on each WFE that you wish to host the custom membership on.

Once you have completed the following directions to configure the custom provider for your site, the Sharepoint Designer application will not be able to connect to it. For this reason, I recommend you extend your web application to the "intranet" zone with AD credentials and let the designers know the URL to connect to for Sharepoint Designer.

Please keep in mind that without the SP1 of the .NET 2.0 Framework, the below will throw http Cookie exceptions in the Event viewer. If you cannot implement the Service Pack, please change CacheRolesInCookie to equal False.

GAC

The first thing we will do is GAC the following files:

  • Security.dll

Machine.config

We are now going to modify the machine.config located at C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config. We will make the following entries:

<membership>

<providers>

    <add name="sqlmembershipproviderName" type="Security.sqlmembershipproviderName, Security, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d003b67fe3e7980d" />

     <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="LocalSqlServer" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="true" applicationName="/" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="7" minRequiredNonalphanumericCharacters="1" passwordAttemptWindow="10" passwordStrengthRegularExpression="" />

</providers>

</membership>

<profile>

<providers>

<add name="AspNetSqlProfileProvider" connectionStringName="LocalSqlServer" applicationName="/" type="System.Web.Profile.SqlProfileProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />

</providers>

</profile>

<roleManager>

<providers>

    <add name="sqlroleproviderName" type="Security.sqlroleproviderName, Security, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d003b67fe3e7980d" connectionStringName="OdbcServices" applicationName="sqlmembershipproviderName" />

<add name="AspNetSqlRoleProvider" connectionStringName="LocalSqlServer" applicationName="/" type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />

<add name="AspNetWindowsTokenRoleProvider" applicationName="/" type="System.Web.Security.WindowsTokenRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />

</providers>

</roleManager>

 

These entries will take the place of the existing <Membership>, <Profile>, and <Role Manager> tags.

Central Administration Web.config

Add the Membership and Role Providers directly under <System.Web>

<membership defaultProvider="sqlmembershipproviderName">

<providers>

<remove name="sqlmembershipproviderName" />

<add connectionStringName="LocalSqlServer"

passwordAttemptWindow="10"

enablePasswordRetrieval="false"

enablePasswordReset="true"

requiresQuestionAndAnswer="true"

applicationName="sqlmembershipproviderName"

requiresUniqueEmail="false"

passwordFormat="Hashed"

description="Stores and retrieves membership data from the Microsoft SQL Server database"

name="sqlmembershipproviderName"

type="Security.sqlmembershipproviderName, Security, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d003b67fe3e7980d" />

</providers>

</membership>

<roleManager defaultProvider="AspNetWindowsTokenRoleProvider"

enabled="true"

cacheRolesInCookie="true"

cookieName=".ASPROLES"

cookieTimeout="30"

cookiePath="/"

cookieRequireSSL="false"

cookieSlidingExpiration="true"

cookieProtection="All" >

<providers>

</providers>

</roleManager>

 

Replace the <PeoplePickerWildcards/> with the following keys

<PeoplePickerWildcards>

<clear />

<add key="sqlmembershipproviderName" value="%" />

<add key="sqlroleproviderName" value="%" />

<add key="AspNetSqlMembershipProvider" value="%" />

</PeoplePickerWildcards>

 

Add the following directly under </appsettings>

<connectionStrings>

<add name="SQLDB"

connectionString="Data Source=SQLServer;Initial Catalog=WSS_Membership;User ID=sa; Password=password"

providerName="System.Data.SqlClient" />

</connectionStrings>

 

Web Application Web.config

Add the Membership and Role Providers directly under <System.Web>

<membership defaultProvider="sqlmembershipproviderName">

<providers>

<remove name="sqlmembershipproviderName" />

<add connectionStringName="LocalSqlServer" passwordAttemptWindow="10" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="true" applicationName="sqlmembershipproviderName" requiresUniqueEmail="false" passwordFormat="Hashed" description="Stores and retrieves membership data from the Microsoft SQL Server database" name="sqlmembershipproviderName" type="Security.sqlmembershipproviderName, Security, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d003b67fe3e7980d" />

</providers>

</membership>

<roleManager defaultProvider="sqlroleproviderName" enabled="true" cacheRolesInCookie="true" cookieName=".ASPROLES" cookieTimeout="30" cookiePath="/" cookieRequireSSL="false" cookieSlidingExpiration="true" cookieProtection="All">

<providers>

</providers>

</roleManager>

 

Replace the <PeoplePickerWildcards/> with the following keys

<PeoplePickerWildcards>

<clear />

<add key="sqlmembershipproviderName" value="%" />

<add key="sqlroleproviderName" value="%" />

<add key="AspNetSqlMembershipProvider" value="%" />

</PeoplePickerWildcards>

 

Add the following directly under </appsettings>

<connectionStrings>

<add name="SQLDB" connectionString="Data Source=SQLServer;Initial Catalog=WSS_Membership;User ID=sa; Password=password" providerName="System.Data.SqlClient" />

</connectionStrings>

 

Set Authentication Provider for Web Application

Log in to your central administration site and go to Application Management à Authentication Providers. This can be accessed at http://ServerName/_admin/authenticationproviders.aspx.

Make sure that you are in the right web application that you wish to implement the provider for.

Click on the default zone which should be the only one listed at this moment.

Choose forms authentication type and type in [membershipproviderName],[sqlroleproviderName] in the appropriate boxes. Choose Save.

Set Policy Administrator for your web application

Since you have now changed the authentication for your web application, no one can actually log in quite yet. What you want to do is set the administrator for the account. I do not recommend setting more than one or two at this level.

Log in to your central administration site and go to Application Management à Policy for Web Application. This can be accessed at http://ServerName/_admin/policy.aspx.

Click on "Add Users" and choose Default zone

Choose Next

Use the People Picker to set your administrator

Choose Full Control and click on Finish.

Writing your First Custom Authorization Provider

Intro

There are several people who are experts in the area of Custom Authorization Providers in MOSS. I want to thank each one of them who have helped me over the last year on my authorization provider. First and foremost I would like to thank Steve Peschka in relation to the base structure and more recently Mitch Prince both from MSFT. What I would like to demonstrate in this post is writing a brand new Custom Authentication Provider for MOSS for the beginner. I will make mention that in a different Post I will be addressing Site Minder integration with the custom provider, however, what you need to know here is that this provider will work regardless.

I will be utilizing a basic SQL table structure although you will see that it is not necessary, however, for simplicity sake, I figure it will be the easiest to demonstrate.

Creating the Data Structure

The first thing we are going to do is just set up some simple tables that we are going to store our users and roles (groups) in.

CREATE TABLE dbo.spUser(

    username VARCHAR (50) NOT NULL,

    email VARCHAR (200) NOT NULL,

)

 

GO

 

CREATE TABLE dbo.spRole(

    spRole VARCHAR (200) NOT NULL

)

 

GO

 

CREATE TABLE dbo.spRole_spUser(

    username VARCHAR (50) NOT NULL,

    spRole VARCHAR (200) NOT NULL,

)

 

Normally, you would add identities, primary keys, foreign keys with relationships etcetera but you get the point. We have a table to store users a table to store roles and an association between the two. Once again, this could be whatever data store you wish and have whatever other attributes like telephone number, password, hair color….

Understanding the Methods (Membership)

Now that we have the base data structure we are going to open up .NET and build our role Provider. In this case, I will be hooking each critical method up to a SQL Stored Procedure simply because I am more comfortable with this approach.

The first thing we will do is have an understanding of the methods and what they are used for. I will be only going over the necessary overloads that you must implement and correctly write for your provider to work. There will be several other properties and methods that you must override, but we will simply throw an exception on these.

public override void Initialize(string name, NameValueCollection config)

 

Initialize simply will set the properties of the provider. Usually these properties are set in the web.config and read in as a NameValueCollection.

public override bool ValidateUser(string name, string password)

 

The Validate User method simply takes in a user name and password and returns true or false based on your credential cache. Here is where you would authenticate. Your login page then would check this method first and based on the result do something.

public override MembershipUser GetUser(object userId, bool userIsOnline)

 

This Overload of the Get User method will simply return a Membership User object based on an object. The way that I normally implement this is to actually take the ID, and pass to the other Get User Method as a .ToString(). This way there is only one code base.

public override MembershipUser GetUser(string name, bool userIsOnline)

 

Here we will be getting the Membership User based on name. Use intellisense on the new MembershipUser(

public override string GetUserNameByEmail(string email)

 

I have searched and searched but cannot find where this method is actually called, however, easy enough to implement and so just get the string that you would pass to the GetUser method based on the email passed in.

public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)

 

This method is called on the people picker and will be hit when searching for a person. Simply pass in the email and set the totalRecords (you can do this with your MembershipCollection.Count property and you are good to go.

public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)

 

This method is also hit as part of the people picker. It is the most important people picker method in my opinion and you can write your own wildcard characters. So something like:

SELECT username, Email FROM spUser WHERE UserName LIKE %userNameToMatch%

 

The following methods we will not implement even though "must override" is on. We will set Booleans to false or throw not implemented exceptions here.

public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)

public override bool DeleteUser(string name, bool deleteAllRelatedData)

public override int GetNumberOfUsersOnline()

public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)

public override bool ChangePasswordQuestionAndAnswer(string name, string password, string newPwdQuestion, string newPwdAnswer)

public override string GetPassword(string name, string answer)

public override bool ChangePassword(string name, string oldPwd, string newPwd)

public override string ResetPassword(string name, string answer)

public override void UpdateUser(MembershipUser user)

public override bool UnlockUser(string userName)

public override bool EnablePasswordRetrieval

public override bool EnablePasswordReset

public override bool RequiresQuestionAndAnswer

public override string ApplicationName

public override int MaxInvalidPasswordAttempts

public override int PasswordAttemptWindow

public override bool RequiresUniqueEmail

public override MembershipPasswordFormat PasswordFormat

public override int MinRequiredPasswordLength

public override int MinRequiredNonAlphanumericCharacters

public override string PasswordStrengthRegularExpression

Recurse Through SharePoint Using OM

I figured that today I would write a quick blog on how to recurse through the sharepoint sites and pages with minimal code so here goes:

SPSite SPSSite;

public void DoWork()

{

string TopLevelSite = ConfigurationSettings.AppSettings["Site"];

Console.WriteLine("**** RUN DATE: " + System.DateTime.Now);

Console.WriteLine("**** CONNECTING TO SITE: " + TopLevelSite);

SPSSite = new SPSite(TopLevelSite);

Console.WriteLine("**** CONNECTION SUCCESS");

ArrayList newList;

 

try

{

foreach (SPWeb sPWeb in SPSSite.AllWebs)

{

if (sPWeb.Url.ToLower().StartsWith(TopLevelSite.ToLower() + "/vso"))

{

try

{

 

SPList sPList = sPWeb.Lists["Pages"];

Console.Write("Processing Site: " + sPWeb.Name + "\n");

ProcessPages(sPList, sPWeb);

}

catch (Exception ex)

{

Console.WriteLine(sPWeb.Name + ": " + ex.ToString());

}

}

}

}

catch (Exception ex)

{

Console.Write ("Error DoWork: " + ex.Message);

}

}

 

#region private void ProcessPages(SPList PagesList, SPWeb sp)

private void ProcessPages(SPList PagesList, SPWeb sp)

{

try

{

//Set Hidden Field

string dName = "Pages";

SPFolder dFol = sp.Folders[dName];

SPDocumentLibrary docLib = (SPDocumentLibrary)sp.Lists[dName];

SPView dv = docLib.Views["All Documents"];

SPListItemCollection dItems = docLib.GetItemsInFolder(dv, dFol);

 

foreach (SPListItem it in dItems)

{

try

{

Console.WriteLine("Pages: " + it.Name)

}

catch (Exception ex)

{

Console.WriteLine("Page Enumeration Error " + it.Name.ToString() + ": " + ex.ToString());

}

}

}

catch (Exception ex)

{

Console.Write("Error ProcessPages: " + ex.Message);

}

}

 

Stick this code into a quick console app and include the Microsoft.SharePoint.dll as a reference and there you go.

I know not much but hey, that was the point right?

Building a Custom Flash Control for SharePoint

Media Control

Please note that this code is taken directly from Microsoft's website: http://msdn2.microsoft.com/en-us/library/aa981226.aspx

The Media Class File should look something like this:

using System;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

using Microsoft.SharePoint;

using Microsoft.SharePoint.Utilities;

using Microsoft.SharePoint.WebControls;

using Microsoft.SharePoint.Publishing.WebControls;

using Microsoft.SharePoint.Publishing.Fields;

namespace VZ.Controls.CustomFieldControls

/// A Field control that binds to fields of type LinkField and is

/// specialized to select and render embedded media files.

/// The RenderFieldForDisplay function generates the HTML markup to

/// display the media file. The MediaSelector control is

/// used at edit time to allow authors to select a media file in

/// the Asset Picker dialog box.

{

public class MediaPlayerFieldControl : BaseFieldControl

{

private MediaSelector mediaSelector = new MediaSelector();

public MediaPlayerFieldControl()

{

}

/// Gets and sets the value in the edit controls

public override object Value

{

get

{

LinkFieldValue mediaUrlValue = new LinkFieldValue();

mediaUrlValue.NavigateUrl =

this.mediaSelector.MediaUrl;

mediaUrlValue.Text =

LinkFieldValue.GetDefaultDisplayText(mediaUrlValue.NavigateUrl);

return mediaUrlValue;

}

set

{

LinkFieldValue mediaLinkFieldValue =

value as LinkFieldValue;

if (null != mediaLinkFieldValue)

{

this.mediaSelector.MediaUrl =

mediaLinkFieldValue.NavigateUrl;

}

else

{

this.mediaSelector.MediaUrl = String.Empty;

}

}

}

/// Get the default name used to find the template and

/// control for the MediaPlayerSelector in the control

/// template ASCX files.

protected override string DefaultTemplateName

{

get { return "MediaPlayerFieldControl"; }

}

private const string AllowExternalUrlsViewStateKey = "AllowExternalUrls";

/// A flag that determines whether to allow saving of external

/// media URLs.

public bool AllowExternalUrls

{

get

{

// Return true by default if not already in view state.

if (ViewState[AllowExternalUrlsViewStateKey] == null)

{

return true;

}

return (bool)ViewState[AllowExternalUrlsViewStateKey];

}

set

{

ViewState[AllowExternalUrlsViewStateKey] = value;

}

}

/// Creates the edit control when not in display mode.

protected override void CreateChildControls()

{

base.CreateChildControls();

if (this.ControlMode != SPControlMode.Display)

{

MediaSelector mediaSelectorInTemplate =

this.TemplateContainer.FindControl(this.TemplateName)

as MediaSelector;

if (null == mediaSelectorInTemplate)

{

// No media selector was found in the control

// template ASCX files. Add the default selector.

this.Controls.Add(this.mediaSelector);

}

else

{

// Get the media selector from the control

// template ASCX file.

mediaSelectorInTemplate.MediaUrl =

this.mediaSelector.MediaUrl;

this.mediaSelector = mediaSelectorInTemplate;

}

}

}

/// Gets the current value for the media URL as stored

/// in the list item.

private string itemFieldValueMediaUrl

{

get

{

LinkFieldValue currentLinkValue =

this.ItemFieldValue as LinkFieldValue;

if (null != currentLinkValue)

{

return currentLinkValue.NavigateUrl;

}

else

{

return String.Empty;

}

}

}

/// Renders the current list item value for the media URL

/// with embedded media player markup.

/// <param name="output"></param>

protected override void

RenderFieldForDisplay(System.Web.UI.HtmlTextWriter output)

{

if (!String.IsNullOrEmpty(this.itemFieldValueMediaUrl))

{

output.Write(MediaRenderingUtilities.GetMediaPlayerHtmlMarkup(this.itemFieldValueMediaUrl));

}

}

/// Verifies that the MediaUrl is valid.

public override void Validate()

{

base.Validate();

if (this.IsValid)

{

LinkFieldValue currentMediaUrlValue =

this.Value as LinkFieldValue;

if (currentMediaUrlValue ==

null || String.IsNullOrEmpty(currentMediaUrlValue.NavigateUrl))

{

// Ensure the field is not required.

if (this.Field != null && this.Field.Required)

{

this.IsValid = false;

this.ErrorMessage =

"This field is required and must contain a media file URL.";

return;

}

else

{

// The field is empty and not required.

// The data is valid.

return;

}

}

// Perform validation on the media file URL.

HtmlValidationContext validationContext =

new HtmlValidationContext();

if (!this.AllowExternalUrls)

{

// Restrict URLs to be either from the current site

// collection or server-relative.

validationContext.RestrictUrlsToSiteCollection = true;

validationContext.GuidOfThisSiteCollection =

SPContext.Current.Site.ID;

}

bool droppedTags;

bool droppedUrls;

LinkFieldValue validatedValue =

validationContext.ValidateLinkValue(

currentMediaUrlValue,

out droppedTags,

out droppedUrls);

if (droppedUrls || String.IsNullOrEmpty(validatedValue.NavigateUrl))

{

// The media file URL in the link field value was

// not valid so report the error message.

// Setting IsValid to false stops saving the page.

this.IsValid = false;

this.ErrorMessage =

"The URL for the media file was invalid.";

if (!this.AllowExternalUrls)

{

this.ErrorMessage +=

" You must select a URL within the current site collection.";

}

}

}

}

}

/// This edit control for the MediaPlayerFieldControl has

/// a toolbar and text box for selecting a media file URL.

/// This example intentionally uses a separate toolbar button

/// and text box for the AssetUrlSelctor to show a more complex

/// example. You can use an AssetUrlSelector control instead of

/// a TextBox child control, which displays its own browse button.

public class MediaSelector : WebControl

{

private TextBox mediaUrlTextBox = new TextBox();

public MediaSelector()

{

}

/// This is the media URL value that you can edit in the text

/// box or Asset Picker dialog box.

public string MediaUrl

{

get { return this.mediaUrlTextBox.Text; }

set { this.mediaUrlTextBox.Text = value; }

}

protected override void OnInit(EventArgs e)

{

base.OnInit(e);

// This ensures that the TextBox child control receives

// its postback.

EnsureChildControls();

}

/// Gets JavaScript required to launch an Asset Picker dialog

/// box for choosing a media file URL.

private string GetAssetPickerButtonScript()

{

AssetUrlSelector mediaAssetSelector =

new AssetUrlSelector();

// When the AssetUrlSelector control is not added to the

// page control tree, the Page and ID properties are

// required because

// AssetUrlSelector.GetClientLaunchPickerReference()

// needs register script in the page.

mediaAssetSelector.Page = this.Page;

mediaAssetSelector.ID = "MediaUrlAssetSelector";

// Uses the TextBox client ID to connect the Asset Picker

// dialog box to the text box.

mediaAssetSelector.AssetUrlClientID =

this.mediaUrlTextBox.ClientID;

// Autopostback to see the new media file rendered after

// clicking OK on the Asset Picker dialog box.

mediaAssetSelector.AutoPostBack = true;

mediaAssetSelector.OverrideDialogTitle = "Select a media file";

mediaAssetSelector.OverrideDialogDescription =

"Select a media file to embed in this page";

mediaAssetSelector.UseImageAssetPicker = false;

return mediaAssetSelector.GetClientLaunchPickerReference();

}

private Literal mediaPlayerOutput = new Literal();

protected override void CreateChildControls()

{

SimpleToolbar mediaSelectorToolbar = new SimpleToolbar();

mediaSelectorToolbar.ID = "ToolBar";

this.Controls.Add(mediaSelectorToolbar);

Label mediaUrlLabel = new Label();

mediaUrlLabel.Text = "Selected media file URL: ";

mediaUrlLabel.AssociatedControlID = "MediaUrlTextBox";

this.Controls.Add(mediaUrlLabel);

this.mediaUrlTextBox.ID = "MediaUrlTextBox";

this.mediaUrlTextBox.CssClass =

"ms-input ms-lactiontable sample-mediaselector-urltextbox";

this.Controls.Add(this.mediaUrlTextBox);

// Add the button after the rest so that the text box

// ClientID is already determined and can be connected

// in the Asset Picker dialog box client script.

mediaSelectorToolbar.AddToolbarButton(

"SelectMediaFile",

"Select a media file",

this.GetAssetPickerButtonScript(),

"Open a picker to select a media file URL");

// Add a refresh button to perform a basic postback to

// to update the MediaUrl rendering.

mediaSelectorToolbar.AddToolbarButton(

"RefreshMediaFile",

"Refresh",

this.Page.ClientScript.GetPostBackEventReference(this,

String.Empty),

"Refresh the page to reload the current media file URL",

"/_layouts/IMAGES/refresh.gif");

// If there is a media file URL, this code creates

// the media player markup.

this.Controls.Add(this.mediaPlayerOutput);

}

protected override void OnPreRender(EventArgs e)

{

string mediaFileOutputHtml =

MediaRenderingUtilities.GetMediaPlayerHtmlMarkup(this.MediaUrl);

if (String.IsNullOrEmpty(mediaFileOutputHtml))

{

this.mediaPlayerOutput.Text =

"<BR>{There is no valid media file URL to display}<BR>";

}

else

{

this.mediaPlayerOutput.Text =

"<BR>" + mediaFileOutputHtml + "<BR>";

}

base.OnPreRender(e);

}

}

/// A simple toolbar class that matches the styles of the

/// publishing field control toolbars.

public class SimpleToolbar : RepeatedControls

{

public SimpleToolbar()

{

this.HeaderHtml =

"<div class=\"ms-toolbarContainer\" width=\"100%\">";

this.FooterHtml = "</div>";

this.SeparatorHtml = "";

}

public void AddToolbarButton(

string buttonId,

string buttonText,

string clientOnClick,

string tooltipText)

{

Literal buttonMarkupLiteral = new Literal();

buttonMarkupLiteral.Text = String.Format(

SimpleToolbarButtonHtmlFormat,

SPHttpUtility.HtmlEncode(buttonText),

SPHttpUtility.HtmlEncode(clientOnClick),

SPHttpUtility.HtmlEncode(tooltipText));

buttonMarkupLiteral.ID = buttonId;

this.Controls.Add(buttonMarkupLiteral);

}

public void AddToolbarButton(

string buttonId,

string buttonText,

string clientOnClick,

string tooltipText,

string buttonImageSrc)

{

Literal buttonMarkupLiteral = new Literal();

buttonMarkupLiteral.Text = String.Format(

SimpleToolbarButtonImageHtmlFormat,

SPHttpUtility.HtmlEncode(buttonText),

SPHttpUtility.HtmlEncode(clientOnClick),

SPHttpUtility.HtmlEncode(tooltipText),

SPHttpUtility.HtmlUrlAttributeEncode(buttonImageSrc));

buttonMarkupLiteral.ID = buttonId;

this.Controls.Add(buttonMarkupLiteral);

}

// {0} = Button text

// {1} = onclick script

// {2} = Tooltip text

private const string SimpleToolbarButtonHtmlFormat = @"

<DIV class=""ms-toolbarItem ms-selectorlink"">

<A href=""#"" onclick=""{1}"" title=""{2}"">&nbsp;{0}</A>

</DIV>";

// {0} = Button text

// {1} = onclick script

// {2} = Tooltip text

// {3} = Button image markup

private const string SimpleToolbarButtonImageHtmlFormat = @"

<DIV class=""ms-toolbarItem ms-selectorlink"">

<A href=""#"" onclick=""{1}"" title=""{2}"">

<IMG alt=""{2}"" src=""{3}"" border=""0"">{0}</A>

</DIV>";

}

public static class MediaRenderingUtilities

{

/// Take a media file URL and generate HTML markup

/// for playing the file.

/// <param name="mediaUrl"></param>

public static string GetMediaPlayerHtmlMarkup(string mediaUrl)

{

// HtmlUrlAttributeEncode returns an empty string if the

// URL protocol is not allowed (e.g., JavaScript:)

string encodedUrl =

SPHttpUtility.HtmlUrlAttributeEncode(mediaUrl);

if (String.IsNullOrEmpty(encodedUrl))

{

return String.Empty;

}

else

{

return String.Format(MediaPlayerHtmlMarkupFormat, encodedUrl);

}

}

// Currently, this code includes only a parameter for the media

// file URL, but it could also include parameters for the

// width, height, and other rendering properties from field

// control properties or authored data value properties.

private const string MediaPlayerHtmlMarkupFormat = @"

<object type=""video/x-ms-wmv""

data=""{0}""

width=""300"" height=""450"">

<param name=""src"" value=""{0}"" />

<param name=""autostart"" value=""true"" />

<param name=""controller"" value=""true"" />

</object>

";

}

}

 

Flash Control

I took the liberty to slightly modify the Media Control "mainly HTML markup"

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

using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Publishing.WebControls;
using Microsoft.SharePoint.Publishing.Fields;

namespace VZ.Controls.CustomFieldControls

/// A Field control that binds to fields of type LinkField and is
/// specialized to select and render embedded flash files.
/// The RenderFieldForDisplay function generates the HTML markup to
/// display the flash file.  The FlashSelector control is
/// used at edit time to allow authors to select a flash file in
/// the Asset Picker dialog box.
{
    public class FlashFieldControl : BaseFieldControl
    {
        private FlashSelector flashSelector = new FlashSelector();

        public FlashFieldControl()
        {
        }

        /// Gets and sets the value in the edit controls
        public override object Value
        {
            get
            {
                LinkFieldValue flashUrlValue = new LinkFieldValue();
                flashUrlValue.NavigateUrl =
                  this.flashSelector.FlashUrl;
                flashUrlValue.Text =
                  LinkFieldValue.GetDefaultDisplayText(flashUrlValue.NavigateUrl);

                return flashUrlValue;
            }
            set
            {
                LinkFieldValue flashLinkFieldValue =
                  value as LinkFieldValue;
                if (null != flashLinkFieldValue)
                {
                    this.flashSelector.FlashUrl =
                      flashLinkFieldValue.NavigateUrl;
                }
                else
                {
                    this.flashSelector.FlashUrl = String.Empty;
                }
            }
        }

        /// Get the default name used to find the template and
        /// control for the FlashSelector in the control
        /// template ASCX files.
        protected override string DefaultTemplateName
        {
            get { return "FlashFieldControl"; }
        }

        private const string AllowExternalUrlsViewStateKey = "AllowExternalUrls";
        /// A flag that determines whether to allow saving of external
        /// flash URLs.
        public bool AllowExternalUrls
        {
            get
            {
                // Return true by default if not already in view state.
                if (ViewState[AllowExternalUrlsViewStateKey] == null)
                {
                    return true;
                }
                return (bool)ViewState[AllowExternalUrlsViewStateKey];
            }
            set
            {
                ViewState[AllowExternalUrlsViewStateKey] = value;
            }
        }

        /// Creates the edit control when not in display mode.
        protected override void CreateChildControls()
        {

            base.CreateChildControls();

            if (this.ControlMode != SPControlMode.Display)
            {
                FlashSelector flashSelectorInTemplate =
                  this.TemplateContainer.FindControl(this.TemplateName)
                  as FlashSelector;

                if (null == flashSelectorInTemplate)
                {
                    // No flash selector was found in the control
                    // template ASCX files. Add the default selector.
                    this.Controls.Add(this.flashSelector);
                }
                else
                {
                    // Get the flash selector from the control
                    // template ASCX file.
                    flashSelectorInTemplate.FlashUrl =
                      this.flashSelector.FlashUrl;
                    this.flashSelector = flashSelectorInTemplate;
                }
            }
        }

        /// Gets the current value for the flash URL as stored
        /// in the list item.
        private string itemFieldValueFlashUrl
        {
            get
            {
                LinkFieldValue currentLinkValue =
                  this.ItemFieldValue as LinkFieldValue;
                if (null != currentLinkValue)
                {
                    return currentLinkValue.NavigateUrl;
                }
                else
                {
                    return String.Empty;
                }
            }
        }

        /// Renders the current list item value for the flash URL
        /// with embedded flash player markup.
        /// <param name="output"></param>
        protected override void
          RenderFieldForDisplay(System.Web.UI.HtmlTextWriter output)
        {
            if (!String.IsNullOrEmpty(this.itemFieldValueFlashUrl))
            {
                output.Write(FlashRenderingUtilities.GetFlashHtmlMarkup(this.itemFieldValueFlashUrl));
            }
        }

        /// Verifies that the FlashUrl is valid.
        public override void Validate()
        {
            base.Validate();
            if (this.IsValid)
            {
                LinkFieldValue currentFlashUrlValue =
                  this.Value as LinkFieldValue;

                if (currentFlashUrlValue ==
                  null || String.IsNullOrEmpty(currentFlashUrlValue.NavigateUrl))
                {
                    // Ensure the field is not required.
                    if (this.Field != null && this.Field.Required)
                    {
                        this.IsValid = false;
                        this.ErrorMessage =
                          "This field is required and must contain a flash file URL.";
                        return;
                    }
                    else
                    {
                        // The field is empty and not required.
                        // The data is valid.
                        return;
                    }
                }

                // Perform validation on the flash file URL.
                HtmlValidationContext validationContext =
                  new HtmlValidationContext();

                if (!this.AllowExternalUrls)
                {
                    // Restrict URLs to be either from the current site
                    // collection or server-relative.
                    validationContext.RestrictUrlsToSiteCollection = true;
                    validationContext.GuidOfThisSiteCollection =
                      SPContext.Current.Site.ID;
                }

                bool droppedTags;
                bool droppedUrls;
                LinkFieldValue validatedValue =
                    validationContext.ValidateLinkValue(
                        currentFlashUrlValue,
                        out droppedTags,
                        out droppedUrls);

                if (droppedUrls || String.IsNullOrEmpty(validatedValue.NavigateUrl))
                {
                    // The flash file URL in the link field value was
                    // not valid so report the error message.
                    // Setting IsValid to false stops saving the page.
                    this.IsValid = false;
                    this.ErrorMessage =
                      "The URL for the flash file was invalid.";
                    if (!this.AllowExternalUrls)
                    {
                        this.ErrorMessage +=
                          "  You must select a URL within the current site collection.";
                    }
                }
            }
        }
    }

    /// This edit control for the FlashFieldControl has
    /// a toolbar and text box for selecting a flash file URL.
    /// This example intentionally uses a separate toolbar button
    /// and text box for the AssetUrlSelctor to show a more complex
    /// example. You can use an AssetUrlSelector control instead of
    /// a TextBox child control, which displays its own browse button.
    public class FlashSelector : WebControl
    {
        private TextBox flashUrlTextBox = new TextBox();

        public FlashSelector()
        {
        }

        /// This is the flash URL value that you can edit in the text
        /// box or Asset Picker dialog box.
        public string FlashUrl
        {
            get { return this.flashUrlTextBox.Text; }
            set { this.flashUrlTextBox.Text = value; }
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            // This ensures that the TextBox child control receives
            // its postback.
            EnsureChildControls();
        }

        /// Gets JavaScript required to launch an Asset Picker dialog
        /// box for choosing a flash file URL.
        private string GetAssetPickerButtonScript()
        {
            AssetUrlSelector flashAssetSelector =
              new AssetUrlSelector();

            // When the AssetUrlSelector control is not added to the
            // page control tree, the Page and ID properties are
            // required because
            // AssetUrlSelector.GetClientLaunchPickerReference()
            // needs register script in the page.
            flashAssetSelector.Page = this.Page;
            flashAssetSelector.ID = "FlashUrlAssetSelector";

            // Uses the TextBox client ID to connect the Asset Picker
            // dialog box to the text box.
            flashAssetSelector.AssetUrlClientID =
              this.flashUrlTextBox.ClientID;

            // Autopostback to see the new flash file rendered after
            // clicking OK on the Asset Picker dialog box.
            flashAssetSelector.AutoPostBack = true;

            flashAssetSelector.OverrideDialogTitle = "Select a flash file";
            flashAssetSelector.OverrideDialogDescription =
              "Select a flash file to embed in this page";
            flashAssetSelector.UseImageAssetPicker = false;

            return flashAssetSelector.GetClientLaunchPickerReference();
        }

        private Literal flashOutput = new Literal();
        protected override void CreateChildControls()
        {
            SimpleToolbar flashSelectorToolbar = new SimpleToolbar();
            flashSelectorToolbar.ID = "ToolBar";

            this.Controls.Add(flashSelectorToolbar);

            Label flashUrlLabel = new Label();
            flashUrlLabel.Text = "Selected flash file URL: ";
            flashUrlLabel.AssociatedControlID = "FlashUrlTextBox";
            this.Controls.Add(flashUrlLabel);

            this.flashUrlTextBox.ID = "FlashUrlTextBox";
            this.flashUrlTextBox.CssClass =
              "ms-input ms-lactiontable sample-flashselector-urltextbox";
            this.Controls.Add(this.flashUrlTextBox);

            // Add the button after the rest so that the text box
            // ClientID is already determined and can be connected
            // in the Asset Picker dialog box client script.
            flashSelectorToolbar.AddToolbarButton(
                "SelectFlashFile",
                "Select a flash file",
                this.GetAssetPickerButtonScript(),
                "Open a picker to select a flash file URL");

            // Add a refresh button to perform a basic postback to
            // to update the FlashUrl rendering.
            flashSelectorToolbar.AddToolbarButton(
                "RefreshFlashFile",
                "Refresh",
                this.Page.ClientScript.GetPostBackEventReference(this,
                  String.Empty),
                  "Refresh the page to reload the current flash file URL",
                  "/_layouts/IMAGES/refresh.gif");

            // If there is a flash file URL, this code creates
            // the flash player markup.
            this.Controls.Add(this.flashOutput);
        }

        protected override void OnPreRender(EventArgs e)
        {
            string flashFileOutputHtml =
              FlashRenderingUtilities.GetFlashHtmlMarkup(this.FlashUrl);
            if (String.IsNullOrEmpty(flashFileOutputHtml))
            {
                this.flashOutput.Text =
                  "<BR>{There is no valid flash file URL to display}<BR>";
            }
            else
            {
                this.flashOutput.Text =
                  "<BR>" + flashFileOutputHtml + "<BR>";
            }

            base.OnPreRender(e);
        }
    }

    public static class FlashRenderingUtilities
    {
        /// Take a flash file URL and generate HTML markup
        /// for playing the file.
        /// <param name="flashUrl"></param>
        public static string GetFlashHtmlMarkup(string flashUrl)
        {
            // HtmlUrlAttributeEncode returns an empty string if the
            // URL protocol is not allowed (e.g., JavaScript:)
            string encodedUrl =
                SPHttpUtility.HtmlUrlAttributeEncode(flashUrl);

            if (String.IsNullOrEmpty(encodedUrl))
            {
                return String.Empty;
            }
            else
            {
                return String.Format(FlashHtmlMarkupFormat, encodedUrl);
            }
        }

        // Currently, this code includes only a parameter for the flash
        // file URL, but it could also include parameters for the
        // width, height, and other rendering properties from field
        // control properties or authored data value properties.
        private const string FlashHtmlMarkupFormat = @"
<object classid=""clsid:d27cdb6e-ae6d-11cf-96b8-444553540000""
    codebase=""http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0""
    width=""300"" height=""450"">
    <param name=""movie"" value=""{0}"" /> 
    <param name=""quality"" value=""high"" />
    <param name=""bgcolor"" value=""#ffffff"" />
    <embed src=""{0}"" quality=""high""
        bgcolor=""#ffffff"" width=""468"" height=""60""
        name=""mymoviename"" align="" type=""application/x-shockwave-flash""
        pluginspage=""http://www.macromedia.com/go/getflashplayer"">
    </embed>
</object>";
    }
}

   

   

 

Designer Changes Best Practices

Purpose

This document is going outline the Microsoft Best Practices regarding designer changes.

 

Introduction

So we all know that objects in a production environment should follow some pretty fundamental principles. Some of these would be objects should be source controlled, objects should go through test before deployment to production, objects should be performant to the best of their ability and so on.

 

With code this is pretty well documented. Use Source Safe, VSTS or some other Source Control system, create drop zones and move from environment to environment. Even the more complex GAC procedures and the like are very well documented and have several approaches to accomplish the environment issues.

 

Unfortunately, this is not the case for designer changes.

 

What are designer changes?

Designer changes consist of items such as but not limited to:

  • Master Pages
  • Layouts
  • Cascading Style Sheets
  • Themes

 

Feature Overview

To understand the solution is to understand MOSS features. The following is quote from Microsoft Office SharePoint Server 2007:

 

"New to the Microsoft Office SharePoint Server 2007 architecture, Features offer flexibility

in terms of developing and deploying extended functionality—such as page templates,

lists, content types, Web Parts, workflow, and events—to new and existing Office Share-

Point Server 2007 sites. By default, SharePoint Server 2007 includes prepackaged Features

as part of its base installation, such as a My Site Feature. The Feature framework has

been extended to allow developers to create custom Features.

If you worked with site definitions in SharePoint Portal Server 2003, you'll appreciate the

flexibility of Features! With SharePoint Portal Server 2003, if you wanted to add a list or

document library to an existing site definition, you had to work with one large

ONET.XML file to modify the XML code and then track each of those changes throughout

the ONET.XML file. Likewise, if you wanted to add items to the SharePoint toolbars

or menus, you had to work with complex Collaborative Application Markup Language

(CAML). Features overcome the complexity of injecting such changes by chunking code

into smaller, more manageable files, which can be more easily tracked, versioned, and

deployed.

Both developers and administrators will benefit from using Features throughout a Share-

Point Server 2007 deployment. Through Feature schemas, developers can scope and add

simple changes, such as provisioning new pages to a SharePoint site, or registering and

deploying complex solutions developed in Microsoft Visual Studio 2005, such as event

handlers or workflows. Developers can also work with the SharePoint object model,

which includes Feature classes to effect changes throughout the life cycle of Features.

Examples of these changes include whether certain actions or events occur when a Feature

is installed, activated, deactivated, or uninstalled. In addition, administrators can

install and deploy Features with ease, using command-line tools, and will have at their

fingertips the ability to switch Features on or off via the activate and deactivate options on

administrative user-interface pages"

 

The benefits of using features in this context are as follows:

  • Ability to leverage a rich source control management solution: Because everything is now on the file system, this is no different than your non-SharePoint ASP.NET 2.0 Web projects, or class libraries, etc... they are just files on the file system so you can easily add them to your source control management system of choice! This is HUGE!
  • Ability to package up the feature (and all it's files) in a SharePoint solution: See where I'm going? If you package up your feature and it's files into a SharePoint solution file (*.WSP) which you can then use to...
  • Deploy to all SharePoint web front end (WFE) servers in your farm at one time: Solution deployment can be scheduled to run at a future time... and the best part: SharePoint's solution framework will automatically deploy the feature to ~all~ your WFE's in the farm at that time. But that's not the only advantage of solutions...
  • Ability to retract deployed solutions: Ever had that "oh crap, we gotta get that off the servers NOW!" moment? The solution framework has the ability to yank a deployed solution back at a scheduled time as well (or immediately if you have the "oh crap" moment).
  • No need for developers to have access to your production environment: Since the files are in a feature that's packaged in a single solution (*.WSP) file, your production administrators can easily add the files to your production environment without developers having to open SharePoint Designer to make changes!
  • All files remain ghosted (uncustomized) on the file system: Remember, they are provisioned as Type=GhostableInLibrary which means the content doesn't really reside within the content database, they are on the file system. This is HUGE! This way...
  • Easier to make changes to existing files going forward: Everyone has changes to files once deployed into production. Using this mechanism, you can just upgrade the solution with an updated feature (don't change the solution or feature ID's) and every site that's activated the feature will automatically get the changes applied to their site! This is HUGE!

Deployment of Features

Now we move on to the technical implementation.

 

[Will follow up with actual technical details but essentially we will use stsadm with an upgrade flag to remove, and re-add these files]

 

Summary

The proper way to move these designer changes should be done utilizing feature deployment methodology in MOSS.

1 - 10 Next