Wednesday, January 25, 2012

Cannot Delete Files From Document Library

The problem:

I needed to delete several files from my document library. I tried to do it using the ribbon. Alas, nothing was deleted. Fiddler brought to my attention that the request was nioved; the ULS log informed me that a new request to the AccessDenied.aspx page was created. I never saw the AccessDenied.aspx page, so the results were not clear at all.

The solution:

I looked at the log again and learned that, when you are deleting the files using the ribbon, the Web request goes to the WCF client.svc web service (http://site_root/_vti_bin/client.svc/ProcessQuery).

My next step was checking the authentication for my Web application. It turned out that for this particular web application, Anonymous Authentication was disabled. When I enabled it back, everything started working.

Lesson learned:  Disabling anonymous authentication can bring some unpredictable effects.

Tuesday, January 24, 2012

Site Templates vs. Solutions

The problem:

We migrated our farm from MOSS 2007 to SharePoint 2010. Yesterday, he called us telling us that in his new environment, his new site templates are now saved in _catalogs/solutions/Forms, rather than _catalogs/wt/Forms where he expects them to see. He manages to access the _catalogs/wt/Forms path, but finds this gallery empty.

The solution:

Remember that in SharePoint 2010, there are no STP site templates! They are now replaced with solutions (which have WSP extensions) that live in _catalogs/solutions/Forms . Two gotchas there, though:

1) On migrated sites, the _catalogs/wt/Forms path is still valid. But, it now just points to a list, not a site template gallery. The STP files that lived there in MOSS 2007 are not migrated to SharePoint 2010, though, because, I repeat, there are no STP site templates in SharePoint 2010.

2) Even though there are no STP site templates in SharePoint 2010, there are STP list templates. This can cause some confusion. So, remember, STP files are only used as list templates in SharePoint 2010, not as site templates!

Tuesday, January 17, 2012

Adding a Converted File to the Same Document Library

The problem:

Sometimes, it is desirable to convert some document to PDF (or some other format) and do it automatically, whenever the document appears in the document library.

The solution:

First of all, there is no easy way to convert a document to PDF without using a third-party product. I use Muhimbi Converter for SharePoint (http://www.muhimbi.com/).

If you want to create a converted document whenever the source document appears in the document library, you need a list item receiver. Override the ItemAdded() and ItemUpdated() methods.

You will need to add a service reference to the Muhimbi Document Converter WCF service. Then, you will need to create a document converter service client to interact with that service. For more information, read

A little problem with this example is that it reads a file from the file system, rather than from the SharePoint library. You will need to get the byte array for the source document file. A good way to do it is:

SPFile spFile = copyItem.File;
string sourceFileName = spFile.Name;
byte[] sourceFile = spFile.OpenBinary();

The Convert() method takes this byte array, the open options, and the conversion settings as parameters and returns the byte array for the new file. Now you will need to add it as a new file to SharePoint. A good way to do it is:

spFolder = (copyItem.Folder == null ? copyItem.ParentList.RootFolder : copyItem.Folder);
string newFileUrl = string.Concat(spFolder.Url, "/", Path.GetFileNameWithoutExtension(sourceFileName), ".", conversionSettings.Format);
SPFile newFile = spFolder.Files.Add(newFileUrl, convFile);
newFile.Update();

Wednesday, December 21, 2011

Date Picker in Visual Web Parts

The problem:
I need to create a Visual Web Part where one of the fields should be a date. Using the SharePoint DateTimeControl does not work, because, when displayed in a user control, the calendar it shows looks horrible. Apparently the SharePoint DateTimeControl is meant to be used in an application page rather than a user control. There has to be a better way!

The solution:

A good alternative is a DatePicker jQueryUI plugin. You will have to add a LAYOUTS mapped folder to your project and create the css and js folders. In the js folder, put the jquery-1.6.1.min.js as well as jquery-ui-1.8.16.custom.min.js files; in the css folder, there should be the base folder where there will be three CSS files (jquery.ui.core.css, jquery.ui.datepicker.css, and jquery.ui.theme.css) as well as the images folder with all the images for the base theme. Then, in your ASCX file, make sure you have the following lines:

<link rel="stylesheet" type="text/css" media="all" href="_layouts/jQuery/css/base/jquery.ui.core.css" />
<link rel="stylesheet" type="text/css" media="all" href="_layouts/jQuery/css/base/jquery.ui.datepicker.css" />
<link rel="stylesheet" type="text/css" media="all" href="_layouts/jQuery/css/base/jquery.ui.theme.css" />       
<script type="text/javascript" src="_layouts/jQuery/js/jquery-1.6.2.min.js"></script>
<script type="text/javascript" src="_layouts/jQuery/js/jquery-ui-1.8.16.custom.min.js"></script>
<script type="text/javascript">
    $(function () {
        $('input[id*="dtDatePicker"]').datepicker({ dateFormat: 'mm/dd/yy' });
    });
</script>

For the actual date field, put this line into your ASCX file:

<asp:TextBox ID="dtDatePicker" runat="server" />

That's it. Whenever the focus is on the dtDatePicker control, the little pretty calendar will appear and the user will be able to pick the date. You also might want to use the jQueryUI date validator plugin to validate the date entered.

Sunday, December 18, 2011

Submitting an InfoPath Form

The problem: The requirements state that the InfoPath form should be submitted in the same location where it is located, and that, upon submission, it should no longer be editable (the submitter should have the read-only access to the form she has submitted.) Furthermore, the submitter should lose the Contribute access to that form and only have Read access.

The solution: 
1) Make a new field in the schema, called Submitted. It should be Yes/No and default to False.
2) Create a new view that is a copy of the original view, minus the Submit button. Make that view read-only and disable view switching on the ribbon.
3) Configure the submit options to be rule-based, so that, upon submission, three things happen:
    a) The Submitted field is assigned the value of True.
    b) The form is submitted to the submit data connection.
    c) The view is switched to the read-only one.
4) Publish the form and make sure that the Submitted field is promoted.
5) Add some event receiver to the form library that is triggered whenever a form residing there is being updated. In the ItemUpdated event, make changes to the updated item whenever its Submitted field changes.

Monday, December 12, 2011

Saving an InfoPath Form

The problem:
The requirements state that the browser-based form I designed should first be saved in the forms library as an empty form (this is done by some code), the permission inheritance for the corresponding list item should be broken, and then the Contribute permissions should be granted to some particular user (this is also done by some code.) Thus, this user will only be able to see and fill out his or her particular forms. Any time the user submits the form, the form should be submitted to its form library and its file name should not change (otherwise a new entry will appear in the Forms library and it will not have the same permissions as the original entry... which is not so great – remember, each form should only be visible to one particular user!)
While configuring the submit options for the form, I created a new Submit data connection. However, the Data Connection Wizard asks for the file name with which the form will be submitted. How to populate that field? It comes from the SharePoint list, but there is no way to query the SharePoint list from the Data Connection Wizard.
The solution:
1)      Create the new field for the file name (give it a name, say, strFileName).

2)       In the Form Options, make sure that the Save As button is NOT displayed. Since it is the code and not the user who creates the original empty form, the Save button as well as the Close buttons should not be displayed, either.

3)      While configuring Submit Options, specify this field as the file name with which the form will be submitted. Also make sure that the Overwrite checkbox is checked.

4)      Now we need to think of how to populate that particular field. It has to be populated when the form is loading. Thus, we need to add some code to the form loading event handler. What kind of code?

       To answer this question, look at the URL for the request when the form is displayed in the browser. The  file name can be found in the query string, in the XmlLocation parameter. (If the form does not have a file name yet, the XmlLocation parameter is missing.) Thus, the code we need to write is something like this:

public void FormEvents_Loading(object sender, LoadingEventArgs e)
      {
            // Write your code here.
            string xmlLocation = String.Empty;
            e.InputParameters.TryGetValue("XmlLocation", out xmlLocation);
            if (!String.IsNullOrEmpty(xmlLocation))
            {
                string[] parts = xmlLocation.Split(new char[] { '/' });
                string fileName = parts[parts.Length - 1];

                XPathNavigator form = MainDataSource.CreateNavigator();

form.SelectSingleNode("/my:myFields/my:strFilename", NamespaceManager).SetValue(fileName);
            }
 }

When the form is displayed, nothing is done if the file name for the list item is now known yet, because the XmlLocation parameter is missing. But when the file name is known for the list item, the XmlLocation parameter is parsed to find the file name. Then, the new strFileName field is populated. When the form is submitted, the old file that has this file name is overwritten. Voila!