Showing posts with label Sharepoint Tutorials. Show all posts
Showing posts with label Sharepoint Tutorials. Show all posts

Thursday, January 1, 2009

SharePoint 2007 Filter webparts - using the Page Field Filter webpart on a Lookup field

The issue
In our intranet we were setting up a product catalog. The documentation for the products are stored in 1 document library. This doclib has a (multivalued) lookup field to the products list. We wanted to create 1 page per product in the same publishing site. This page will the the landing page for a product. It will show general information and the available documentation. To do this we added a lookup field to the Pages library to the same product list and added the PageFieldFilter webpart to the page. Turns out this does not work for a lookup field (the same applies to a user/group field).
Here is how you recreate this (it also shows the reasons why it doesn’t work):
  • Create a Publishing site
  • Create a list “Products” and add some items
  • Create a document library “Documentation” and add some documents
  • Add a (multivalued) lookup field to the document library
  • Select product(s) for the documentation:
    Filters1
  • Add a (singlevalued) lookup field to the Pages library
  • Add a new page and select one of your products:
    Filters2
  • Add the “Documentation” library to the page and show the name and product fields.
  • Add the Page Field Filter webpart to the page and select the “Product” field.
  • Connect the filter webpart to the Documentation list.
  • Check-in and notice that the list shows no documents:
    Filters3
The filter webpart does not provide the correct value to the consuming webparts. In the screenshot below you will see why.After adding a TextFilter webpart to the page, you can set the default value for this text filter from the Page Field Filter webpart.
Filters4
This shows our problem; the value is not the title of the selected item, but it is the value that SharePoint uses internally to store the value. This applies to both Lookup and Person or Group fields.
The solution
The solution for this is to build our own custom Page Field Filter webpart. You can do this by creating a new webpart that inherits from the ContextFilterWebPart in the Microsoft.SharePoint.Portal.WebControls namespace. Below I describe the most important bits to include in your code. My webpart is called “WebpageFieldFilter”.
  • Create a private member and a property of type Guid (called “PageFieldID”)
  • Create a new EditorPart that renders a dropdown showing all field in the pages library. These fields can be added directly from the context:

           SPContext.Current.List.Fields
    Also implement the ApplyChanges and SyncChanges methods:

    public override bool ApplyChanges()
    {
    WebpageFieldFilter webpart = WebPartToEdit as WebpageFieldFilter;
    webpart.PageFieldID = new Guid(_selectField.SelectedValue);
    return true;
    }
    public override void SyncChanges()
    {
    EnsureChildControls();
    WebpageFieldFilter webpart = WebPartToEdit as WebpageFieldFilter;
    _selectField.SelectedValue = webpart.PageFieldID.ToString("B");
    }
  • Implement the IWebEditable interface on your webpart. Implement CreateEditorParts. This should return the new EditorPart we just created, but also the EditorParts that are generated by the base webpart, otherwise we won’t have our filter options:
    .cf { font-family: Courier New; font-size: 9pt; color: black; background: white; } .cl { margin: 0px; } .cb1 { color: teal; } .cb2 { color: blue; }
    EditorPartCollection IWebEditable.CreateEditorParts()
    {
    List<EditorPart> newEditors = new List<EditorPart>();
    EditorPartCollection editors = base.CreateEditorParts();
    foreach (EditorPart part in editors)
    newEditors.Add(part);
    newEditors.Add(new SelectListFieldEditor());
    return new EditorPartCollection(newEditors);
    }
  • In the webpart class, override FilterConfigured and return true if our PageFieldID has a valid Guid value.
  • In the webpart class, override DesignTimeHtml to return the correct text for your webpart in design mode.
  • Override GetRawFilterValues to return the values for the field that was chosen by the user:

    protected override string[] GetRawFilterValues()
    {
    SPListItem listItem = SPContext.Current.ListItem;
    if (listItem != null && PageField != null)
    {
    SPField field = SPContext.Current.List.Fields[PageFieldID];
    return GetFieldValues(listItem[PageFieldID], field);
    }
    return null;
    }
    In GetFieldValues I implemented the code to extract the value for the lookup and user field and return a string array with the value or the values in case of a multi valued field. You can find the code to do this in the ZIP file (see attachments).
After installing the webpart, you can add the new WebpageFieldFilter to the page and connect that to the Documentation library. When modifying the properties of the webpart, things look a bit different, because of the implementation of our custom EditorPart:
Filters6
And when we look at the page, the documentation is now filtered as expected:
Filters5
http://www.tonstegeman.com/Blog/Lists/Posts/Post.aspx?ID=29

Accurate Metadata Values May Be Difficult to Maintain Over Time in SharePoint Server 2007

In working with Content Types and metadata, I've learned of a situation that I hope will be resolved either in a service pack or the next version of SharePoint Server. Please read and follow these steps and you'll see what I mean. What I'm proposing is that there is an inherent flaw in how metadata is saved and stored between Office 2007 and SharePoint Server 2007. I'm assuming a collaboration portal template for this post. Specifically, metadata saved for a particular Custom metadata field is not always over-written by metadata values that we enter into the SharePoint Edit Properties interface. This can lead to confusion about which metadata value is the most accurate and/or the most recent description of the document and potentially impair the integrity of your document taxonomy efforts.
In this post, I'll go over the steps that lead to this problem and then offer some best practices for working with content types, metadata and documents in Office SharePoint Server 2007.

Create a New Content Type

To create a new content type, go into the Content Type gallery and create a new content type based on the Document content type. To do this, follow these steps:
  1. From Site Actions, click on Site Settings, then Modify All Site Settings.
  2. Click on the Site Content Types link
  3. From the Site Content Type Gallery page, click on the Create link
  4. Configure the page as shown below, and then click OK.

Now, you have created a new content type that is based on the default Document content type. Why did we do this? Because it is best practice to not modify the Out-of-the-Box (OOB) content types. Service pack upgrade and/or hotfix upgrades can over-write your modifications to default objects in SharePoint. We always recommend that you not modify OOB files and objects in SharePoint for this reason.
Now, let's add this new content type to a document library and then give the Test Document Template content type some unique metadata. First, to add the content type to a document library, open the document library, click on Settings, then Document Library Settings and then click on the Advanced link. Select "Yes" for the Allow Management of Content Types? Configuration, as shown here:

Click OK (not illustrated) and then navigate back to the Customize Documents page by clicking on the Settings link. In the Content Types section, click the Add from Existing Site Content Types link and the select the new document content type to add to the document library.

Now I'll modify the content type to include new metadata. I'll add a simple column called "document type". Back in the content type gallery, I'll click on the test document template content type and then click the link to Add from New Site Column under the Columns section. I'll configure it as a single line of text data type and accept the other defaults, then click OK.

Create a New Document Based on the New Content Type

Now, I'll go back to the document library that this content type is associate with and click the New drop down list and select the Test Document Template content type to create a new document based on this content type. In Word 2007, you can see that the "document type" metadata field appears in the Document Information Panel.

Once saved, you'll find that the document's metadata appears in the SharePoint interface, as illustrated here:

Now, what's interesting is that this metadata field has been added to the document's Custom properties but the field is not populated. Even if I change the value to Type100, it is not saved to the document's Custom tab. I can save this over and over again, publish it, check it out, check it in, publish again, save it again and the Type100 value is not saved to the document's Advanced Properties on the Custom tab.
So, now, I'll go back to the content type and add another metadata field (column) called Doc Num. I'll populate that field with a value of 1234. (I'll also remove the pending states from the documents in this library to eliminate that variable.) Now, what happens when I remove the Document Type column from the content type? Well, the field's values are automatically written to the Advanced properties of the document on the Custom tab and that field no longer appears in the SharePoint interface.
Now, if I go back and remove the Doc Num column from the Test Document content type and re-add the Document Type column, the Type100 value will not be pulled from the Advanced properties of the document to pre-populate the Document Type metadata field. So, you'll be able to enter a new metadata value for this field, such as TypeABC and save it in the SharePoint interface. Note also that the Doc Num field is written to the Custom tab in the Advanced Properties field since it is no longer available as part of the content type.

When we open the Advanced Properties and look at the Custom metadata on the document, we see that the Doc Num field has been written to the Custom tab but the Type100 value has not been over-written by the new value of TypeABC. This is true, even if we publish, save and re-save the current document in SharePoint with the TypeABC metadata assigned to the Document Type metdata field.

The real problem with this scenario is that the crawler in SharePoint will crawl both metadata values and return the same document for both values for the same metadata field. Consider these two screen shots:


There are several problems here:
  1. Since Site Collection Administrators can create and modify content types, there exists a strong need to educate them about when and how to create and modify content types. You will not be successful if you implement content types without forethought, planning and education. Their education should be based on your organization's taxonomy plan and structure.
  2. If you remove the content type's metadata (columns) after the document's metadata has been populated, you'll have to manually visit each document to remove the old metadata.
  3. Confusion can be created if the old metadata on a document persists and is considered to be wrong if the users can still find a document using the old metadata.
  4. Old metadata assignments that persist might violate some legal and industry compliance rules.


"How to" - Sending an email with SharePoint 2007 (MOSS)

In the entry labeled (above link) "How to extract an email address from an email sent to your Document Library for Workflow." I gave a detailed explanation of how to extract an email address from a document stored in a document library. In this example, I will show how to use that email address (or a static email address) to send an email to a Person, Distribution Group, or dynamically based on the email address of the person who sent the document to the document library.
My scenario, in case you have not read the earlier entries, is a resume processing workflow, in which people can email their resumes to some company (jobs@somecompany.com) and the workflow would run based on a new resume showing up in the document library. This workflow step could be modified to ask the user for an email address to send to "using the Initiation button" (not shown here) or it could be "hard-coded" to send the email (with the attached document link) to a person or Distribution Link.
This demonstration presumes that you have access to SharePoint Designer. If you do not, you can download an evaluation copy (see this article).
As a part of my resume processing scenario, I am sending an "Automated" email response to the applicant who sent their resume into our Job Site email address, using the email address attached to their resume in the document library and extracted and broken up into two parts (see my earlier article for why I broke the email up into two parts) .
Open SharePoint Designer to the site where the document library (associated with this workflow) exists. Use the "Open Site" menu from the File Menu and put in the URL of your SharePoint Team Site, or wherever you document library exists.
  • Open your existing workflow, or create a new one.
  • Give the workflow a name (assuming that you've started a new Workflow)
  • Decide if you want the workflow to Manually, Automatically, or whenever an item is changed.
    • My suggestion is "Manually" while in development at the minimum. This will keep you from having to continuously upload new documents to test the workflow. You can upload one "test document" and keep using it, by manually starting the workflow on that document.
    • If you want "Automatic" starting of the workflow, turn that on after you are done testing/building, if you'd like, but if you are building this workflow on an "already existing" document library, you don't want your workflow to inadvertently run while you are building it, should someone put a file in the folder.
    • Be careful of the "Automatically Start....an item has changed" option, as this has some unintended consequences, which I will explain in a subsequent blog entry.

  • Hit the "Next Button" (Bottom Right)
  • Give the this step a name, like "Send an Automated Email Response"
  • The next thing that we need to do is to setup the "Conditions" and the "Actions"
    • In this case, we won't have a condition, because we want to always send an Automated email to the person who submits a resume. I will talk more about conditions in a future blog entry, but if they are relatively simple to understand.

Skip this step if you want to hard code an email address

    • First we need to get the email address from the SharePoint Document List, which as I've said before has been broken into two parts. See this blog entry to understand why: How to extract an email address from an email sent to your Document Library for Workflow
      • In the article, I explained that you have to separate the email into 2 pieces to get past a SharePoint "issue" when dealing with email address and workflow.
      • So, we need to recombine the email address, into a normal email address, like: someone@somecompany.com
      • We will use the "Build Dynamic String" Action to do this.
        • Choose the Action from the action menu
        • Set the Variable name to something that you will remember, like "Applicant Email Address".

IS CHANGED TO....

        • Click on the "dynamic string" link and recombine (concatenate) the email address back into one string, which will be stored in the workflow variable that you created ("Applicant Email Address" in my case).
        • When you click on it, you get a "String Builder" form like this one:

      • Hit the "Add Lookup" button (Bottom Left) to add the two SharePoint Custom Columns that we created, when we broke the email into two pieces (again, see the earlier post link above for details)
        • When you hit the "Add Lookup" button, you get the "Define Workflow Lookup" form
          • Select "Current Item" as the source, which refers to the SharePoint list that the workflow is attached to ("Incoming Resume" document library in my case)
          • Then select the variable that holds the first part of the email address as the field ( "WFV Email Address Part before @ Symbol", in my case.)
          • Hit the OK button to add that field
          • Now, without adding any spaces, do the same thing and add the second part of the email address, which in my case will be called "WFV Email Address Part from the @ Symbol on," which by the way, if you followed my suggestions on how to extract the email address will contain the "@" symbol in the email address and everything to the right of the @ symbol.
Your screen should look like this:

    • Hit the OK button
    • Next we add the "Send an Email" action.

    • Select the this message link
    • Now you should have the "Define E-Mail Message" form open
    • Hit the "Address book" button on the "To" line. BTW, if you wanted to hard code an email address, just type in in here and skip the next step.

    • Now, in the "Select Users" box, you can either select an:
      • Individual user
      • Email Distribution List
      • Multiple users (Hold down your CTRL key as you select each user)
      • or, all of the above

    • In our case, we are going to use the the "Workflow lookup" option to select our user from the Workflow variable "Applicant Email address" that we defined above.

    • Select "Workflow Lookup" and then hit the "Add >>" button (on the right) and your screen will now look like this:

    • Select "Workflow Data" as the "Source". This will allow us to select the field that we built using the Build Dynamic String action (earlier).
    • Now, select the "Variable: Applicant Email Address" and hit the OK button to close the "Define Workflow Lookup"

  • Hit OK again, to close the "Select Users" Form
Your screen should look like this:

  • Now you can put in a message in the "Subject" Box
  • Put a message in the "Body" of the email
    • Note: If you wanted to send the link for the document (which in our scenario wouldn't make sense, because it would be a link to the internal portal) you would follow these steps:
      • Hit the "Add Lookup to Body" button
      • Choose "Current Item" as the Source
      • Choose "Encoded Absolute URL" as the field
      • Then wrap the whole thing in an HTML Link tag, so that it looks like this:
My screen looks like this (assuming that you do not want to include the document link):

  • Hit the OK button
  • If you want, you can Log the action, by using the "Log to Workflow history action" and enter a simple message, like "Send automated email response."
  • Click the "Check Workflow" button (button left), to make sure that you've made no mistakes.
  • Click the "Finish Button" (bottom right) to have the workflow attached to your SharePoint list (Document Library in my case)
  • Go back to your SharePoint Site and to your SharePoint List that has the workflow attached to it
  • Make sure that you have a document with an email address associated with it
  • Click on the document, and pull down it's "actions" menu.
  • Hit the "Workflow" Action

  • Select your workflow (Click on it)

  • Hit the Start Button (You wont get this page, unless you chose "Allow Manual Start of Workflow (earlier step)"

  • If everything worked, you should get see a "Workflow Completed" column on your SharePoint List and an Email should've been sent.




Wednesday, December 31, 2008

Moving on with WebParticles 1 Deploying to the _app_bin folder

This post adds to Tony Rabun's post "WebParticles: Developing and Using Web User Controls WebParts in Microsoft Office SharePoint Server 2007". In the original post, the web part DLLs are deployed in the GAC. During the development period, this could become a bit of a pain as you will be doing numerous compile, deploy then test cycles. Putting the DLLs in the _app_bin folder of the SharePoint web application makes things a bit easier.
  1. Make sure the web part class that load the user control has the GUID attribute and the constructor sets the export mode to all.
Figure 1 - The web part class

2. Add the AllowPartiallyTrustedCallers Attribute to the AssemblyInfo.cs file of the web part project and all other DLL projects it is referencing.
Figure 2 - Marking the assembly with AllowPartiallyTrustedCallers attribute

3. Copy all the DLLs from the bin folder of the web part project to the _app_bin folder of your SharePoint web application. Make sure all the DLLs are signed.
Note: You should copy the .pdb files as well to be able to debug the user control code
Figure 3 - Bin folder for web application project referencing DLLs from other projects
Figure 4 - DLLs added to _app_bin folder of the web application

4. Edit the web.config file of the SharePoint web application as follows:
5. Add the web part assembly to the safe controls section.
Figure 5 - Adding the web part assembly to the safe controls

6. Add the web part assembly to the assemblies section.
Figure 6 - Adding the web part assembly to the assemblies section

7. Now create the .webpart file then add the web part to your SharePoint site web part gallery.
Figure 7 - The .webpart file

SharePoint 2007 URL Quick List

The following is a list of SharePoint URLs to get to commonly used administrative functions on a MOSS or WSS v3 site. Not all links listed on this page are accessible to all user levels of a site. This is a quick list for speedy reference as compared to tracking down links through the admin screens or for faster jumping around sites within a site collection.
FunctionAdd to the URLNotes
Add Web Parts Pane?ToolPaneView=2Add to the end of the page URL; WILL ONLY WORK IF THE PAGE IS ALREADY CHECKED OUT
Create New Site Content/_layouts/create.aspx
List Template Gallery/_catalogs/lt
Manage Site Collection Administrators/_layouts/mngsiteadmin.aspx
Manage Sites and Workspaces/_layouts/mngsubwebs.aspx
Manage People/_layouts/people.aspx
Manage User Permissions/_layouts/user.aspx
Master Page Gallery/_catalogs/masterpageAlso includes Page Layouts
Modify Navigation/_layouts/AreaNavigationSettings.aspx
Recycle Bin/_layouts/AdminRecycleBin.aspx
Site Column Gallery/_layouts/mngfield.aspx
Site Content Types/_layouts/mngctype.aspx
Site Content and Structure Manager/_layouts/sitemanager.aspx
Site Settings/_layouts/settings.aspx
Site Template Gallery/_catalogs/wt
Site Usage Summary/_layouts/SpUsageWeb.aspx
User Alerts/_layouts/sitesubs.aspx
View All Site Content/_layouts/viewlsts.aspx
Web Part Gallery/_catalogs/wp
Web Part Page Maintenance?contents=1Add to the end of the page URL
Workflows/_layouts/wrkmng.aspx


Tuesday, December 30, 2008

Enforcing Required Fields on SharePoint Server 2007 Publishing Pages via Content Types and Page Layouts

Applies to:
  • Office SharePoint Server 2007
Additional Tools Used:
  • Office SharePoint Designer 2007

Overview

Office SharePoint Server 2007 supports the creation of content types. Content types bundle metadata, security and retention policies, and workflow. An item saved in a SharePoint list – a document library, for example – can be assigned a predefined content type. This allows us to move beyond managing items by file format (.doc, .pdf, etc.) and focus on the intent of the content.
Let's say, for example, that we are creating an intranet site that will be the location to which company operating procedures are published as web pages. When someone writes a new policy, we want to be sure and collect some specific information like what the policy impacts, when it goes into effect, and who approved it. When we attach define metadata on libraries designed to store standard documents, client applications like Word and PowerPoint will help us out with the collection of the data. When we're trying to do this with a web page, we need to do a little more work.

Define a Content Type

The first thing we need is a content type with which to work. In this example, we'll create a content type defining a standard operating procedure for the fictitious Litware, Inc. We'll ignore workflow and other policies and focus on a few pieces of metadata.
To begin, we will add the site column definitions that will make up our content type. Adding a site column allows us to define a column once, and reuse it in any number of lists. Go to the Site Settings page of the top-level site collection.

Under Galleries, click on Site Columns. We'll add a new column by clicking Create.

Add a column titled "Procedure Name".

Define a new group named "Litware SOP" in which to organize the new columns.

Finally, mark the field as required. This is a critical step as we'll depend on SharePoint enforcing this setting.

Follow the same steps as above to create three more columns as detailed below:
Column Name Information Type Values Category Required
Procedure Category Choice Cashier Audit
Daily Opening
Daily Closing
Medical Emergency
Litware SOP Yes
Owning Department Choice Finance
Food and Beverage
Merchandising
Operations
Litware SOP Yes
Procedure Full HTML Content Litware SOP No
On each of the Choice columns, be sure to clear the default value. We don't want any accidental entries being made.
We now have four columns that can be used in our content type.

Return to the Site Settings page for the top-level site collection. Chose Site Content Types under Galleries.

Select Create. We're going to add a Litware SOP content type. Our intention is for these procedures to be web-based, so we'll inherit from the existing Page content type.

The list of columns you see in our new Content Type comes from the Page content type.

We now want to add the columns we previously defined for the Litware SOP. Click Add from Existing Site Column.

Select Litware SOP to narrow our choices and add the four columns.

You'll get a warning about the Procedure column, since this is an HTML field that most desktop applications won't be able to write to.

That's fine for our scenario. Hit OK and continue. When finished, we now have a defined Content Type. Now, we need a page layout to support editing.

Creating the Page Layout

Our users need access to our columns in order to fill them out. We need to create a page layout that includes fields that map to our columns. This is where we will make sure that required columns are completed before they are saved to a list.
Open SharePoint designer, and open the top-level site collection from File -> Open Site…
When the site is open, click File -> New -> SharePoint Content

In the New dialog box, choose SharePoint Publishing from the left column and Page Layout from the right. Choose Litware Content Types as the Content Type Group, and Litware SOP as the Content Type Name. Fill in the URL Name and Title as below:

Click OK.
We now have a blank page that we can use to layout our fields. Notice in the toolbox that the site columns we defined are available to place on the page.

To aid formatting, I'll insert a table with one column and three rows. Remember, this is an ASP.NET page, so anything we'd put in a normal web application can go here!

Now, drag the Procedure Name field onto the first row of the layout table, and Procedure Category onto the second row. In the third row, we're going to do something a little different.

EditModePanel

Let us assume, for our example, that the Owning Department field should not be viewed by just anybody. Maybe it is a value that is only important as a workflow variable, or simply used in managing the content in the library. It should only be visible to people who are editing the page. In order to do this, we'll place the Owning Department inside of an EditModePanel control.

This is a SharePoint Server control that does not render its contents unless the page is in edit mode. Add the EditModePanel to the third row of our table. You will want to adjust its width attribute to 100% so that it fills the row. You can now add the Owning Department field inside of the EditModePanel.
Now you can add the Procedure field. Make sure that it is placed outside of our little layout table.
This isn't a fancy layout, but it is enough for this example. Hit Save, and switch back over to your SharePoint site.

Adding the Content Type to a Site

Because we derived our Litware SOP content type from the existing Page content type, we constrained ourselves. We need to use our content type with a site template that has Web Content Management (WCM) turned on. WCM adds a Pages library to the site, and turns on a few extra features. If your site was created using one of the Publishing Site templates, then you're all set. I'm going to assume that we don't already have a publishing site available and need to create one. From the top-level site collection, choose Create Site from the Site Actions menu.

Name the site SOP, and choose the template, "Publishing Site with Workflow"

Once the site is created, click on "View All Site Content" in the Site Actions menu. Choose the Pages library, and click on Document Library Settings.

The Pages library already supports managing multiple content types, so we don't have to do any extra work. Other lists would have required us to go to the Advanced Settings page and turn on management of content types.
We're going to add our Litware SOP content type to the list of content types supported by the Pages library. Click on "Add from existing site content types".

Select Litware SOP from the list, click Add, and then OK. Back in the Pages library, click the drop-down menu arrow next to New, and select Litware SOP from the menu.

Now we'll create a page titled Open Doors. Be sure to choose "(Litware SOP) New Standard Operating Procedure" as the Page Layout.

Select your newly created page from the Library, and place the page in edit mode by selecting "Edit Page" from the Page Editing Toolbar.

What you should see now is a nice, blank page just like we had lain out in SharePoint Designer:

Remember, we marked the Procedure Name, Procedure Category, and Owning Department columns as required. To test that, go ahead and click the Check in to Share Draft button on the Page Editing Toolbar. You should see some lovely red messages like below:

We know that works… go ahead and fill in some values and check in the page. Notice that the value for Owning Department does not display. Remember that we put this inside an EditModePanel so only page editors would see it!

Conclusion

That's it! We used Site Columns in SharePoint to define required information. We added those columns to a new Content Type and built a Page Layout to support entering data into those columns. We also made some of that data visible only during page editing by using a SharePoint EditModePanel.