Tuesday, December 11, 2007

Final Post?

For the last year I have been using this blog as a sort of playground, however, now that the mirror site is up internally on Microsoft at http://sharepoint.microsoft.com/blogs/levelorange I feel that it may be prudent to start directing people that way.

Thank you for all the support that I have received and this may or may not be the last post ;) We shall see.

Cheers

Monday, December 10, 2007

Finding Assembly Information

Once again, in an attempt to segment information to prevent information overload, this is a simple one. In MOSS development, you will many times have to reference assemblies by class name and assembly name along with the public key token. To accomplish this I use a tool called .NET reflector which can be located here.

If you drag your assembly on the user interface of the tool, you can click on it and see the assembly information as such:


If you drill down to the actual class, you can see the class information as such:


Promised it would be short but invaluable if this is the first time you've seen the tool.

GAC’ing an assembly

Probably not a blog-able subject but wanted something to link to so here goes.

  1. First thing to do here is strong-name your assembly. Simply go to properties on the project and signing section.


  2. Build your assembly by pressing F7 or however you wish
  3. From here you can use gacutil, add gacutil to a post-build event or simply navigate to dll and drop it into "c:\windows\assembly"

Find GUID of List

Ok, I have decided to compartamentalize 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=: )


 

Generating a new GUID

Inevitably in MOSS if you are doing custom development there will come a point where you will have to generate new GUIDs for your features, lists, fields and whatever else. There is a quick and easy way of doing this from Visual Studio.

Simply open Visual Studio and go to Tools à Create GUID



 

Choose Registry Format and then Copy. Done and Done. Know that certain GUIDs in MOSS will complain if you have curly braces {} and some will not.

If you are more of a command-line person you can get to the same screen by typing:

guidgen


 

in the Visual Studio Command Window

Tuesday, November 27, 2007

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.

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.

Monday, November 26, 2007

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

Provision a New List with Data

This is going to be a first in a larger series related to the SharePoint provisioning concept that may be re-written in a more organized fashion, but I figured while it was on my mind, the prerogative of a blogger J

So as many of you may or may not have heard the way to deploy new "stuff" in SharePoint is by means of a feature deployments and this phantom thing called "provisioning". We will go over specific feature deployments in a later post but for now, I wanted to take the easy way and show you how to take the pre-built definitions for VSE and build a new list complete with data.

Let us say I want to create a new list that has lookup data in it (Wait for another post and you will be awed and amazed at how we will build on top of this listJ.

We will store Types of People in this list so I will split it up for now between Business Contacts and Personal Contacts. We will also store some other piece of information related to this obscure level of data. Let's make it Send Christmas Cards Boolean. I know that typically this would be stored at a contact level, but just appease me here. We'll assume that this will be a default and that individuals can override the base setting.

So essentially our list is going to look something like:

Contact Type

Send Christmas Cards

Business

FALSE

Personal

TRUE


 

Pretty easy so far right? It really is, however, as a colleague of mine recently stated: "this type of info seems kinda hard to find, like it is somekind of arcane tribal knowledge not-often shared with outsiders".

So first things first, let's go ahead and download the SharePoint Extensions for Visual Studio 2005 located at: http://www.microsoft.com/downloads/details.aspx?familyid=19F21E5E-B715-4F0C-B959-8C6DCBDC1057&displaylang=en.

Before we move on, I have to say if this is your first development experience inside of MOSS, you may want to read my article on MOSS Development 101.

Now open Visual Studio 2005 and create a new Project. You will notice some new cool templates when this occurs.


Pretty cool stuff yes? Now, in a later post, I will outline some of the stuff this will be doing for you behind the scenes but this is just basics right now.

You will get a pop-up when you choose ok with a drop-down and two checkboxes.


The drop-down outlines which SharePoint list you wish to inherit from. Depending on what you choose, we will get different fields pulled in. For purposes of this example we will be choosing "Custom List".

The first checkbox essentially is asking if you want to pre-populate this list with values. Note that these values can be changed once this list is provisioned or created in the site. For this example we definitely want to do this.

The second checkbox is asking if you want to write code when an event fires for this list. We are not going to do this for this list but we will be doing this in a later post.

After choosing ok on this window, Visual Studio will create all the necessary code to create a list and deploy this list in a solution package. We do, however, need to configure it the way we wish.

This will be done in two steps:

  1. Configure the Fields we want to use
  2. Configure the Data we want to pre-populate

For the first step, we are going to focus on the newly created schema.xml file.


Note specifically the <Fields> Section. Here is the actual:

        <Fields>

<Field
ID="{244AB5C6-102E-4355-905A-8A4C1F394C19}"
Name="ContactType"
DisplayName="Contact Type"
Type="Text"
Group="Sample Fields" />

<Field
ID="{BB365ADB-3B48-4bc5-B57C-9063226B5C31}"
Name="SendChristmasCards"
DisplayName="Send Christmas Cards?"
Type="Boolean"
Group="Sample Fields" />

        </Fields>


 

Notice the IDs. You may wonder where I got these. Well, truth be told, I made them up, or rather, I had Visual Studio do this for me.

Creating New GUIDs: To create new GUIDs, simply open up Visual Studio 2005, choose Tools, Create New Guid and select Registry setting. Then copy to clipboard and paste. Ta-da! Keep in mind that some items in SharePoint require the curly braces {} and some do not.


 

Now for step two (Creating the Data):

Here we are going to focus on the newly created instance.xml.


In this case, you will notice that we added the <Data> tags. We can at this point build and deploy. When building it will create a set.bat in the debug/release folder and you can modify this to point to the correct site.

Adding Users to a SharePoint List

Say you have a list and you wish to copy and paste from excel through the Grid-View Function. You will notice two things as it relates to the People and Groups Field.

  1. It will not take users that do not already exist in SharePoint
  2. It will not copy at all if the people and groups has the "Allow Multiple Selections" checkbox checked

Well now that's a bummer.

The following solution is just what I came up with:

What we are going to do is make a new field that will store a semi-comma delimited list and populate the users in there. We are then going to write some quick c# do take the data from that column and populate correctly across to the correct column.

The first function we will write will take in the SPWeb that you wish to do this for as well as the semi-comma delimited list.


//Return properly validated and added users


private SPFieldUserValueCollection UserValidation(SPWeb web, string Users)

{

SPFieldUserValueCollection userCollection = new SPFieldUserValueCollection();


string FormatedUsers = string.Empty;


string[] UserArray = Users.Split(';');


foreach (string sUser in UserArray)

{

SPUser user = null;


try

{

user = web.AllUsers[sUser];

}


catch { }


 


if (user == null)

{


try

{

web.AllUsers.Add(sUser, "", sUser, "");

web.Update();

user = web.AllUsers[sUser];

}


catch { }

}


 


if (user != null)

{

userCollection.Add(new SPFieldUserValue(web, user.ID, user.LoginName));

}

}


 


return userCollection;

}

}


 

The second function we will write will be to take the list, and actually update the list based on the previous method.

public
void UpdateMyList()

{


try

{


//Should do something like:


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


string TopLevelSite = "http://r2-basemachine:1111";


using (SPSite SPSSite = new SPSite(TopLevelSite))

{


using (SPWeb sPWeb = SPSSite.OpenWeb())

{


string listName = "DatasheetTest";

SPList list = null;


DataTable dt = null;

SPListItemCollection listCol = null;


 

list = sPWeb.Lists[listName];

listCol = list.Items;

dt = listCol.GetDataTable();


 


foreach (DataRow dr in dt.Rows)

{

SPFieldUserValueCollection userCollection = new SPFieldUserValueCollection();

userCollection = UserValidation(sPWeb, dr["Multi"].ToString());

SPListItem ListItem = list.GetItemById((int)dr["Id"]);

ListItem["PersonField"] = userCollection;

ListItem.Update();

}

}

}

}


catch (Exception ex)

{


Console.WriteLine("Error: " + ex.ToString());

}

}


 

Happy coding!

Thursday, September 27, 2007

SQL: Search Procedure

This is another useful tool.

This Stored Procedure will allow for searching every table and every field and return a passed value. Essentially, if you forgot where something was, you could use this as a diagnostic tool. It is not recommended for programmatic execution as you could imagine, dependent on optimization of your db structure it could take a while.

/****** Object: StoredProcedure [dbo].[SearchAllTables] Script Date: 09/27/2007 10:06:17 ******/

SET
ANSI_NULLS
ON

GO

SET
QUOTED_IDENTIFIER
ON

GO

ALTER
PROC [dbo].[SearchAllTables]

(

@SearchStr nvarchar(100)

)

AS

BEGIN

-- Copyright © 2002 Narayana Vyas Kondreddi. All rights reserved.

-- Purpose: To search all columns of all tables for a given search string

-- Written by: Narayana Vyas Kondreddi

-- Site: http://vyaskn.tripod.com

-- Tested on: SQL Server 7.0 and SQL Server 2000

-- Date modified: 28th July 2002 22:50 GMT

CREATE
TABLE #Results (ColumnName nvarchar(370), ColumnValue nvarchar(3630))


SET
NOCOUNT
ON


DECLARE @TableName nvarchar(256), @ColumnName nvarchar(128), @SearchStr2 nvarchar(110)

SET @TableName =
''

SET @SearchStr2 =
QUOTENAME('%'
+ @SearchStr +
'%','''')


WHILE @TableName IS
NOT
NULL

BEGIN

SET @ColumnName =
''

SET @TableName =

(

SELECT
MIN(QUOTENAME(TABLE_SCHEMA)
+
'.'
+
QUOTENAME(TABLE_NAME))

FROM INFORMATION_SCHEMA.TABLES

WHERE TABLE_TYPE =
'BASE TABLE'

AND QUOTENAME(TABLE_SCHEMA)
+
'.'
+
QUOTENAME(TABLE_NAME)
> @TableName

AND OBJECTPROPERTY(

OBJECT_ID(

QUOTENAME(TABLE_SCHEMA)
+
'.'
+
QUOTENAME(TABLE_NAME)

),
'IsMSShipped'

)
= 0

)


WHILE
(@TableName IS
NOT
NULL)
AND
(@ColumnName IS
NOT
NULL)

BEGIN

SET @ColumnName =

(

SELECT
MIN(QUOTENAME(COLUMN_NAME))

FROM INFORMATION_SCHEMA.COLUMNS

WHERE TABLE_SCHEMA =
PARSENAME(@TableName, 2)

AND TABLE_NAME =
PARSENAME(@TableName, 1)

AND DATA_TYPE IN
('char',
'varchar',
'nchar',
'nvarchar')

AND QUOTENAME(COLUMN_NAME)
> @ColumnName

)


IF @ColumnName IS
NOT
NULL

BEGIN

INSERT
INTO #Results

EXEC

(

'SELECT '''
+ @TableName +
'.'
+ @ColumnName +
''', LEFT('
+ @ColumnName +
', 3630)

FROM '
+ @TableName +
' (NOLOCK) '
+

' WHERE '
+ @ColumnName +
' LIKE '
+ @SearchStr2

)

END

END

END


SELECT ColumnName, ColumnValue FROM #Results

END


The utilization would be something like:

SearchAllTables 'MyValueToFind'


Output would be something like:

ColumnName

Column Value

[dbo].[MyTable].[MyField1]

http://myValueToFind.net

[dbo].[MyTable].[MyField2]

http://myValueToFind.net/morevalues

SQL: Split Procedure

I decided to include a couple tools that I use quite frequently so that there is ease of use. I cannot take the credit and this is probably on many people's blogs but I wanted to centralize my most common ones. Thanks to those who contributed.

This Stored Procedure will allow for separating a comma delimited list and returning a table.

SET
ANSI_NULLS
ON

GO

SET
QUOTED_IDENTIFIER
ON

GO


 

ALTER
PROCEDURE [dbo].[Split]

(

@ItemList NVARCHAR(4000),

@delimiter CHAR(1)

)


 

AS


 

BEGIN

    DECLARE @IDTable TABLE
(Item VARCHAR(100))


DECLARE @tempItemList NVARCHAR(4000)


SET @tempItemList = @ItemList


 


DECLARE @i INT


DECLARE @Item NVARCHAR(4000)


 


SET @tempItemList =
REPLACE
(@tempItemList,
' ',
'')


SET @i =
CHARINDEX(@delimiter, @tempItemList)


 


WHILE
(LEN(@tempItemList)
> 0)


BEGIN


IF @i = 0


SET @Item = @tempItemList


ELSE


SET @Item =
LEFT(@tempItemList, @i - 1)


INSERT
INTO @IDTable(Item)
VALUES(@Item)


IF @i = 0


SET @tempItemList =
''


ELSE


SET @tempItemList =
RIGHT(@tempItemList,
LEN(@tempItemList)
- @i)


SET @i =
CHARINDEX(@delimiter, @tempItemList)


END

    SELECT Item FROM @IDTable

END


 

The utilization would be something like:

CREATE
TABLE #MgrList (ManagersUID VARCHAR(50))


 

INSERT
INTO #MgrList

EXEC Split '100,101,102,103',
','

Creating Media and Flash Controls in MOSS

Media Control

Please note that this code is taken directly from Microsoft's website: http://msdn2.microsoft.com/en-us/library/aa981226.aspx I modified the render output for streaming and cross-browser compatibility


 

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 id=""MediaPlayer""

width=400 height=300

classid=""CLSID:22D6f312-B0F6-11D0-94AB-0080C74C7E95""

standby=""Loading Windows Media Player components...""

type=""application/x-oleobject""

codebase=""http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=6,4,7,1112"">

<param name=""filename"" value=""{0}"">

<param name=""Showcontrols"" value=""True"">

<param name=""autoStart"" value=""True"">

<embed type=""application/x-mplayer2""

src=""{0}"" name=""MediaPlayer""

width=400 height=300></embed>

</object>";}

}


 

Flash Control

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

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>";
    }
}