The Engine Room
The engine room is a place for people to contribute ideas on the development of Sharepoint, Visual Studio and information technology.

Attachments in a WSS List

Sharepoint list attachments

 

Using out of the box sharepoint functionality, it is easy to add and view attachments to list items.

 

However, a common issue in WSS 3.0 is that customised list views do not support attachments ... or, "attachement".  The error "This form was customized not working with attachement" is displayed.

 

The only supported way of storing attachments to a list item, is to use the default newform.aspx page, associated with the given list.

This works, but has a number of restrictions:

Branding

It is difficult to brand or customise the upload form. Even though an upload.aspx file is associated with the list, it is not used (by default). The actual upload form which is used, is located in the 'Layouts' directory, on the webserver; any customisation of this would change the uploading form for all sites in the site collection. This is not desirable.

Views

The default newform.aspx used a listview to display the fields associated with the list. Unfortunately, there is no easy way to change the fields that are displayed to the user; all fields associated with the list are shown by default.

Customisation

With respect to general customisation of the newform.aspx, it is also possible to view the data using dataview webparts, and custom list forms. Unfortunately, both of these approaches appear to strip support for attachments; dataview webparts do not support an upload control, and custom list forms throw the error in the screenshot above.

 

Solution

 

In order to overcome the above issues, it is fairly simple to implement a custom webpart using the Visual Studio extensions for WSS.

The general process is as follows:

 

Setup the project

Firstly, create a new webpart project, using the VSeWSS. Then, change the class declaration to inherit from

 

Microsoft.SharePoint.WebPartPages.WebPart

 

The existing class definition inherits from the standard ASP.NET 2.0 WebPart class – this ensures interoperability with existing .NET webparts, but does not provide access to all of the sharepoint WebPart features.

 

Create the code structure

The default WebPart project contains a single overridable method "Render". The render method outputs straight html, via the use of a HtmlTextWriter. This method is not useful for our purposes: delete it. Create two new methods: CreateChildControls(), and RenderWebPart() – both should be defined as "protected override void".

 

The CreateChildControls() method instantiates the ASP.net controls that you want to use – in this case, a HtmlInputFile (for the attachment). Make sure you declare the controls globally. The RenderWebPart() method adds the controls to the Html, using the format

 

myControl.RenderControl(output)

 

Add your submission eventhandler

 

In your CreateChildControls() method, add a button with an event handler – this will be used to submit the entire form. Make sure you also render this button in the RenderWebPart() method.

In the eventhandler, create a SPList object pointing to the list you want to add an item to, and add an SPListItem to the list, using:

 

    SPListItem myItem = myList.items.add()

 

Now, add any properties to the listitem using:

 

    myItem["Title"] = "{title here}";

 

And, add the attachment, using:

 

    Stream fstream = myHtmlInputFile.PostedFile.InputStream;

    byte[] contents = new byte[fstream.length];

    fstream.Read(contents, 0, (int)fstream.length);

    fstream.Close();

    fstream.Dispose();

 

    myItem.Attachments.Add(Path.GetFileName(myHtmlInputFile.PostedFile.FileName), contents);

 

Finally, make sure you commit these changes to the listitem, using

 

    myItem.Update();

 

Summary

 

Hopefully, a future sharepoint release will solve the current implementation issues with list attachments. In the meantime, you may need to either use the default sharepoint behaviour (without customisation), or create a custom webpart. If you choose to follow the latter route, the preceding instructions should provide you with all of the tools you need to get started.

 

TF30162: Task "SharePointPortal" from Group "Portal" failed

This is one of the things that has been keeping me awake at night. Out of the blue (and yes, I know there will be a reason, but right know... I’m still investigating) I lost the ability to create Team Projects. Not only it fails but it locks my account.

I know it is permissions related, I know it is WSS related but I don’t seem to find exactly where the root of the problem is. At the MSDN forums, I got the following response from:

A Team Foundation Server administrator must be a member of the following groups:

1)      Team Foundation Administrators.

2)      SharePoint Administration group in SharePoint Central Administration.

3)      SQL Server Reporting Services Content Manager

4)      SQL Server Reporting Services System Administrator.

I am a member of the Administrators group of the machine, so that shouldn’t be a problem.

1)      Checked.

2)      I made myself secondary owner of the site collection

3)      I made myself a content manager in SQL Reporting

4)      I made myself a Reporting Services Sys Admin.

And the result was: FAIL! I still have the same problem. Will keep posting until I figure out the issue.

Quick Sharepoint Web Part Creation

Overview

The following will help you to quickly create a new sharepoint webpart, deploy it, activate it, and place it on a page in your sharepoint site.

Before you begin, ensure that you have a test WSS site set up, and the permissions necessary to alter it.

Install the VS templates

Microsoft recently released a set of additions to Visual Studio 2005, called the WSS 3.0 Tools: VS 2005 Extensions.  You can download these here.  Once installed, a number of new project templates will be available in Visual Studio 2005.

Create your project

Once you have installed the additions, open Visual Studio  2005, and create a new project.  From the available project types, select Visual C#->Sharepoint.  Now, select “Web Part” from the available templates.

Give your project a name, and click ‘Ok’.

In the Solution Explorer view, navigate to the root of your newly created project, right click, and select properties.

Select the ‘debug’ tab on the left hand side of the property view.  Navigate to the “Start Browser with URL:” textbox, and insert the url of your test site.  If the home page of your test site is http://wsstestsite/sites/new/default.aspx, enter http://wsstestsite/sites/new/

Save these updated properties, and press F5 (or, right click on your project in solution explorer, and select ‘deploy’).

If everything has gone smoothly, the toolbar in Visual Studio will state the Deploy has Succeded.

Write your webpart

In order to display content in your webpart, you need to finish the implementation given by the Render() stub.

This method includes a single HtmlTextWriter parameter, which you must use to output the html to be displayed in the webpart.

The simplest way of doing this is to create a String of html content, and then use the writer.write() method to write the html content.

As an example, you could enter the following code:

string sHtml = “Hey there “ + SPContext.Current.Web.CurrentUser.Name + “!”;

                writer.Write(sHtml);

Once you have created and written your html string, deploy the solution again.

View your webpart

In order to view your webpart on your wss site, you will need to place the webpart on a page.

Open a web browser, and navigate to your test site.

Click on ‘site actions’, and select ‘edit this page’.

Once the page has entered editing mode, navigate to the right hand column of the page, and select ‘Add a Web Part’.

A window will now pop up, with the available Web Parts.  Select the checkbox to the right of your webpart, and select ‘Ok’.

Your new webpart will now be inserted at the top of the right hand column.

Editing your webpart

Now that your webpart has been placed on the page, you may make any future changes in visual studio.  After redeploying the webpart, you may view any changes in your web browser simply by refreshing.

Adding an embedded XSLT to your WebPart

In order to ensure an appropriate separation of your view, from your controller (Following the MVC design pattern), it is often desirable to keep your XSLT files separate from your dll’s.  Nevertheless, in some circumstances it is useful to encapsulate your XSLT files within your program dll; for instance, in situations where your program is performing one simple operation, and it is necessary to cleanly package this as a single redeployable executable.

When creating a Sharepoint WebPart, it is possible to either include a reference to an existing XSLT, or to package this XSLT as an embedded file.  By packaging your xslt’s together into the executable dll, we may simplify the deployment process.

To include an XSLT as an embedded resource: 

First, add the file to your project.  Second, use the solution explorer to navigate to your newly added XSLT file, right click, and select properties.  In the properties panel, click the “Build Action” drop-down box, and select “Embedded Resource”.

Your xslt file will now be included as an embedded resource file, in your program dll.

To reference this file from your code:

First, add the reflection namespace to your class.

             Using System.Reflection;

Second, create a reference to the currently executing assembly, and get the xslt resource by passing in the full name of the resource – this is of the format: [Assembly name].[Default nameapace].[resource name]

XslTransform xslTransform = new XslTransform();

Assembly currentAssembly = Assembly.GetExecutingAssembly();

// The following line assumes that both your assembly name, and namespace are set to

“SharepointWebPart”

XmlTextReader transformStream = new XmlTextReader

(currentAssembly.GetManifestResourceStream

(“SharepointWebPart.

SharepointWebPart.resourceFileName.xslt”));

xslTransform.Load(transformStream);

 

At this point, you have added an XSLT as an embedded resource, and utilised it in your code.  You may now compile your WebPart into a single deployable executable.

Creating a custom search results page for a (searchresults.aspx) Windows Sharepoint Services (WSS) Site

When creating a site using Windows Sharepoint Services, search is typically managed at the web application level.  This means that although the pages you create for your site will inherit the styles and layout designated in your site masterpage, any search results will be displayed using the default web application theme. By taking the following steps, it is possible to customise the way search results are shown, without affecting other sites operating in your WSS web application.

Create a custom searchresults aspx page

When you perform a sharepoint site search, the search results are displayed using the searchresults.aspx page.  This is located in C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS.  Copy the contents of this file.  Now, navigate to your site (using sharepoint designer), and create a new aspx page named ‘CustomSearchResults.aspx’.  Paste the contents of searchresults.aspx into your newly created page. At this point, you need to make two changes to the page.
Firstly, update the Page directive to point to your site masterpage. 
For ie, <%@ Page language="C#" MasterPageFile="~masterurl/default.master"  ... %>
In order to ensure that this is set out correctly, it is best to copy this from another page in your site that inherits from your site masterpage.
Secondly, remove unnecessary controls from the page.  There will be a number of controls registered at the top of the page; it is likely that these are already registered in your masterpage.  Therefore, remove all except the following controls:

<%@ Register Tagprefix="SharePoint" Namespace=
"Microsoft.SharePoint.WebControls" ...  %> <%@ Register Tagprefix="SearchWC" Namespace=
"Microsoft.SharePoint.Search
.Internal.WebControls"  ... %>
<%@ Register Tagprefix="WebPartPages" Namespace=
"Microsoft.SharePoint.WebPartPages" ... %>
Create a custom searchresults control
Your customised search results page is now inheriting from your masterpage.  In order to display the results of a given search, it is necessary to create a customised control to place on your masterpage. Navigate to C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\CONTROLTEMPLATES and locate SearchArea.ascx.  This is the control which displays the search bar on your site, and passes the search parameters supplied to the search results page.  Again, copy the contents of this file, and create a new CustomSearchBox.ascx control (this time, in the CONTROLTEMPLATES directory) with the pasted contents of SearchArea.ascx.
Open CustomSearchBox.ascx and make the following changes:

Firstly, update the referenced url to reflect your customised search results page, near the top of the page.


string strEncodedUrl= SPHttpUtility.EcmaScriptStringLiteralEncode(SPHttpUtility.UrlPathEncode(web.Url + "/CustomSearchResults.aspx", false, false));

Secondly, update the names of the searchscope and searchstring, near the bottom of the page.


<SELECT id='idSearchScope' name='CustomSearchScope' class='ms-searchbox' ... >>
<INPUT Type=TEXT id='idSearchString' size=35 name='CustomSearchString' display='inline'  ... >>

And, thirdly, update the javascript calls to reflect a custom search function.

<INPUT Type=TEXT id='idSearchString' size=35 name='CustomSearchString'  ... onKeyDown="return
CustomSearchKeyDown(event, <%=strEncodedUrl%>);"  ... >
<a target='_self' href='javascript:' onClick="javascript:
SubmitCustomSearchRedirect(<%=strEncodedUrl%>);javascript:return false;"  ... > </a>

Edit Core.js

In order to redirect the page to your custom search results page, we need to create a couple of custom javascript functions.  Navigate to C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\1033, and open the Core.js file.  Search for the “SubmitSearchRedirect” function.  This is the default search function.  Unfortunately, the Form actions at the end cause sharepoint to require a screen refresh each time you navigate to your custom search results page.  To solve this, we can create a new function, as follows: (the new function ensures existing site search will remain unaffected)
function SubmitCustomSearchRedirect(strUrl)
{
                var frm=document.forms["frmSiteSearch"];
                frm=document.forms[MSOWebPartPageFormName];
                var searchText=frm.elements["CustomSearchString"].value;
                var searchScope=frm.elements["CustomSearchScope"].value;
                strUrl=strUrl+"?k="+escapeProperly(searchText)
+"&u="+escapeProperly(searchScope);
                window.location = strUrl;
}
 
Likewise, search for the SearchKeyDown function, duplicate it, and edit as follows:
function CustomSearchKeyDown(event, strUrl)
{
                if (IsKeyDownSubmit(event))
                {
                                SubmitCustomSearchRedirect(strUrl);
                                return false;
                }
                return true;
}
 

Adding your custom searchresults control to the site masterpage

You have now created a customised search control, which utilises a custom search results page.  In order to utilise this in your site, it is necessary to add the control to your masterpage.
This is a simple process, consisting of the following steps:
Firstly, register your control at the top of your masterpage.
<%@ Register TagPrefix="provoke" TagName="CustomSearchBox" src="~/_controltemplates/CustomSearchBox.ascx" %>
And, secondly, place the control at the appropriate location on your masterpage.
<asp:ContentPlaceHolder ID="ProvokeCustomSearch" runat="server">
<provoke:CustomSearchBox id="CustomPlaceHolderSearchArea" runat="server"/></asp:ContentPlaceHolder>
 
At this point, you should be able to run your site search (after a hard browser refresh), and view your customised search results page.