Friday, May 20, 2011

Deploying a Document Library including content using a Feature

Recently I needed to deploy a SharePoint document library as a feature, but with some documents already in it. In my case it was because of demo content, the customer wanted to do some training and needed a pre-filled document library. I can see this useful in other times however, such as including templates for documents, etc.

The solution for this is not difficult, but since I could not find any instructions online for this I thought I'd write a post.

In short, you need to create a feature that includes two components. A list instance based on a document library and then a module with the documents that you want to add to your library. The module has to point to your newly created library and all is well.

Let's walk through this. Start up Visual Studio and create a new empty SharePoint project. You can choose to use a sandbox solution, this code works just fine in both sandbox and farm modes.


Next add a new item, of type list instance.



Choose 'Document Library' as the base type, and make sure to clean up the display name and URL. I personally hate the defaults that Visual Studio creates for these.


Next add another new item to your project, this time of type module.


Delete the sample file from the module, and add the documents that you want to automatically be part of the feature rollout. I copy the files using windows explorer to the appropriate place and the use the "show all documents"button in Visual Studio to include them in the project


Once you have added all the required files and removed the sample file from your module, the elements.xml file of the module should look something like:
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Module Name="DemoDocumentContent">
  <File Path="DemoDocumentContent\demo1.docx" Url="DemoDocumentContent/demo1.docx" />
</Module>
</Elements>

This needs to be modified so that the documents end up in the new library you are creating. First open up the elements.xml file of the list instance you created, and copy the Url attribute.
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <ListInstance Title="Demo Documents"
                OnQuickLaunch="TRUE"
                TemplateType="101"
                FeatureId="00bfea71-e717-4e80-aa17-d0c71b360101"
                Url="Lists/DemoDocuments"
                Description="">
  </ListInstance>
</Elements>


Now paste that Url attribute in the Module element of the elements.xml file for the module. Then remove all but the filename form any Url attributes of individual file elements in that file.
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Module Name="DemoDocumentContent" Url="Lists/DemoDocuments">
  <File Path="DemoDocumentContent\demo1.docx" Url="demo1.docx" />
</Module>
</Elements>

The next step is to add the Type="GhostableInLibrary" attribute, otherwise your files will not be visible in the browser.

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Module Name="DemoDocumentContent" Url="Lists/DemoDocuments">
  <File Path="DemoDocumentContent\demo1.docx" Url="demo1.docx" Type="GhostableInLibrary" />
</Module>
</Elements>

Lastly you should rename the feature that Visual Studio created for you by default, fill in a Display name and optionally a description and ensure that the List instance and Module elements are included in the feature.


When you deploy this solution to a SharePoint site, it will create a document library with the documents in it, as desired.

In case you are working on a similar situation as I was and are creating this for demo purposes, there is one last very useful piece. That is cleanup. I have added a feature event receiver to my solution that deletes the document library when the feature is deactivated. This ensures that the person delivering the training can very quickly recreate the document library with the initial content by deactivating and reactivating the feature. The code needed for this is:

public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            //Delete the demo list with all content
            if (properties.Feature.Parent is SPWeb)
            {
                SPWeb web = (SPWeb)properties.Feature.Parent;
                SPList list = web.GetList("/Lists/DemoDocuments");
                web.Lists.Delete(list.ID);
            }
        }

So to summarize, it is very easy to build a feature (which can run in the sandbox) that creates a document library including some default documents already in the library. The feature should be web scoped, include a list instance element and a module element with all the necessary content files. By changing the url parameter in the module we can ensure that the documents are placed in the new document library.

15 comments:

andrew said...

Great stuff! Thanks.
But when I tried it, it seemed that only the document library was correctly created, but the file was not uploaded to the list.

Joe said...

@andrew I can only guess, but double check the URL location of the files and the module. This is the most common error that I have, that the combined URL of these two is not correct.

andrew said...

Strange thing: When I used sharepoint designer to check all the files on the site, I found that the files were indeed uploaded to the list. However, it still showed in the browser that the list was empty.

Joe said...

@andrew, good catch. I was copying the code samples from somewhere by hand (and some from memory) and forgot one step.

You need to add Type="GhostableInLibrary" to the file element, else you will see exactly the behavior you describe.

I have updated the article, sorry for the bad info and thanks for the help!

andrew said...

Thanks!
Now everything works.

Rajan said...

Very good! very helpful.

Thanks

Javier Hernandez said...

hi joe. I am a student of Computer Engineering of Malaga. I want to know how to do the same but for Sharepoint 2007. Deploying a Document Library using a feature sharepoint 2007. I'm trying but I can not remove the Document Library with FeatureDeactivating

Joe said...

@Javier There are many things that can go wrong, you need to be more specific with what error you are experiencing. I would suggest visiting the MSDN forums or sharepoint.stackexchange.com and ask your specific question. One thing that comes to mind - make sure the feature is web scoped. Good luck.

Petr Kubát said...

I love you! Very detailed info. Helped me a lot!

dave.dolan said...

I know this is kind of an old thread, but is there a way to set properties (say a Title attribute) in the items distributed, specified somehow in CAML?

a said...

Great, clean solution. Best online !

Stine & Bjørn said...

Hi Joe!

Good post :-)
I have a couple of questions:

- Can you also set custom properties for the documents? Say I have added a custom schema to the document library which specifies a column 'Doc category'. How can I set the value for this category on the file?

- What about upgrading if this feature? Say that, sometime after activating this feature on a server, I need to add more documents to the library. What is the best way to achieve this?

Thanks again!

Best regards,
-Bjorn

Joe Capka said...

Fort those looking to set a property like Title or a custom property on the document, notice that the File element in the XML can have Property elements where you can specify this. See http://msdn.microsoft.com/en-us/library/ms459213.aspx

Purnendu said...

Hi Joe,
Nice Post. I am looking to use list instance to create a document library with some custom columns. I am not getting a good article on the part where I can add a custom columns (not site columns) with the list instance.

Do you have any thoughts on the same.

Regards,
Puru

Jeremy Leff said...

Any thoughts on how to do this and set Title and ContentType properties? I have the following, but it's not working: