March, 2010

  • Visual Studio SharePoint Development Blog

    Importing fields using the Import SharePoint Solution Package project

    • 1 Comments

    A SharePoint Content Type project allows the user to create a content type based on the built-in SharePoint content types. But what about situations where one would want to re-use a built-in field(s) in SharePoint? One way to do this is to use the "Import SharePoint Solution Package" project. This article provides the simple step-by-step procedures on how to achieve this.

    To begin, let's first create a subsite. Imagine this as the site you want to copy the field from. This may or may not be on the same development machine that you're using.

    To create a subsite in SharePoint:

    1. Using Internet Explorer, browse to http://<machinename>
    2. Click on Site Actions | New Site.


    3. Fill-in the following values for the form:
      1. Title: SourceSite
      2. URL name: SourceSite
    4. Click the Create button.

    The “SourceSite” subsite is now created. Let's now use SharePoint's "Save site as template" feature to export the entire subsite to a .wsp file.

    To export a subsite to a .wsp file:

    1. Using Internet Explorer, browse to http://<machinename>/SourceSite
    2. Click on Site Actions | Site Settings.
    3. Click on Save site as template.
    4. Fill-in the following values for the form:
      1. File name: SourceSite
      2. Template name: SourceSite
    5. Click the Ok button.
    6. After the operation completes successfully, click the Solution Gallery link.
    7. Click SourceSite and save the wsp file to your disk.

    We're now ready to import the field into Visual Studio.

    To import a field into Visual Studio:

    1. Start Visual Studio in admin mode.
    2. Create a new C# Import SharePoint Solution Package project.


    3. In Page 1 of the wizard, leave all default values as-is. Click the Next button.
    4. In Page 2 of the wizard, click the Browse button and browse to the directory where you previously saved the SourceSite.wsp file. Click the Next button.
    5. In Page 3 of the wizard, unselect all SharePoint items (Tip: This can easily be done by typing "Ctrl+A" and then hitting the space bar).
    6. Look for the following fields and check them (Tip: This can easily be done by typing the fields you're looking for).
      1. Address
      2. City
      3. State/Province
      4. \Zip/Postal code
    7. Click the Finish button.

    A project will be created that contains the Fields project item. Double-clicking on this project item will show the contents of its Elements.xml:

    Let's now create a content type that will use these fields that we just imported.

    To add a Content Type project item:

    1. From the main menu of Visual Studio, select Project | Add New Item.
    2. In the Add New Item dialog, select Content Type and click Add.
    3. In Page 1 of the wizard, select "Issue" as the base content type. Click the Finish button.

    We now modify the content type to reference the imported fields.

    To reference the fields in the content type:

    1. In Solution Explorer, double-click the Fields project item.
    2. Copy the Fields:


    3. In Solution Explorer, double-click the Content Type.
    4. Paste the Fields into the Content Type so that it would look like this:
    5. Note:
      o Make sure you change the Field tags to FieldRef.
      o Only the ID, Name, and DisplayName attributes are needed.

    We are now ready to debug and deploy the content type and fields.

    To debug the content type and fields:

    1. Set the content type as the default startup item:
      1. Right-click the content type in Solution Explorer.
      2. Select "Set as Startup Item" in the context menu.
    2. Press F5 to start debugging.
    3. Click the content type under the "Custom Content Types" group.

    You'll see the Address, City, State/Province and Zip/Postal Code fields in the columns section.The next step is to create a List Definition and List Instance based on the Content Type.

    To create a List Definition and List Instance based on the Content Type:

    1. From the main menu of Visual Studio, select Project | Add New Item.
    2. In the Add New Item dialog, select the List Definition from Content Type and click the Add button.
    3. Use the defaults in the List Definition wizard. Visual Studio automatically detects the Content Type in your project and uses this.


    4. Click the Finish button.

    A List Definition and List Instance project item are added to the project.


    To debug the List Definition and List Instance:

    1. Set the List Instance as the default startup item:
      1. Right-click the List Instance in Solution Explorer.
      2. Select "Set as Startup Item" in the context menu.
    2. Press F5 to debug. The List Instance will be loaded in IE.
    3. Click the Add new item link.
    4. You'll find the fields at the bottom of the New Item form:


    5. Fill-up the form and click Save.

    You'll notice the Address, City, State, and Zip fields are not displayed in the list. To display them, follow these steps:

    To display certain fields in the list:

    1. Click the List tab under the List Tools tab.
    2. Click Modify View in the ribbon:


    3. Check the fields you want to be displayed in the list view.

    That's it! You've now inherited fields, referenced them in a content type, created a list definition based on the content type, and displayed the fields in the list instance. Hope this helps! :)

    Ian Ching

  • Visual Studio SharePoint Development Blog

    List Definition from Content Type using Event Receiver

    • 1 Comments

    As a SharePoint developer, you’ve probably heard of VSeWSS (Visual Studio extensions for Windows SharePoint Services). A co-worker wrote this post which is an example of how to use VSeWSS to implement a SharePoint solution. I’d like to take that example and show you how adapt it to use the new Visual Studio 2010 SharePoint Developer Tools. Thanks to Pranab for allowing us to use his walkthrough as a point of comparison. Take a moment to read over his introduction for further background on this walkthrough. In short, we will implement a transcript document library using a Content Type with custom fields. When the user uploads a file, it is parsed by an Event Receiver and the custom properties of the item are populated with data from the file. Before proceeding ensure you have the necessary prerequisites: http://msdn.microsoft.com/en-us/library/ee231582(VS.100).aspx.

    Start Visual Studio as administrator and create a SharePoint Content Type project. To do this, click File -> New -> Project… , select Visual C# -> SharePoint -> 2010, select the Content Type project template, name it “ContosoTranscriptDoc” and name the solution “ContosoTranscriptDocLib”, then click OK. In the first page of the project wizard set the Site URL field to match the site you’ll be using for deployment and debugging, then select Deploy as farm solution trust level and click Next (sandboxed trust is possible but requires changes to the sample code below). As shown below, choose the “Document” base Content Type and click Finish.

    clip_image002

    Next we’ll add fields to the Content Type. Expand the ContosoTranscriptDoc node in the Solution Explorer and open the Elements.xml file. Add the following lines within the <FieldRefs> tag.

          <FieldRef ID="{672B4E30-1FDD-48F3-AABC-546404D3D483}" Name="Patient" Required="TRUE" ShowInDisplayForm="TRUE" ShowInNewForm="FALSE" ShowInEditForm="TRUE" />
    
          <FieldRef ID="{3EC8A782-F667-4FB9-970D-D14372811E85}" Name="Doctor" Required="TRUE" ShowInDisplayForm="TRUE" ShowInNewForm="FALSE" ShowInEditForm="TRUE" />
    
          <FieldRef ID="{04D116F7-1381-4CB1-A60C-87A222FB86CB}" Name="PNumber" Required="TRUE" ShowInDisplayForm="TRUE" ShowInNewForm="FALSE" ShowInEditForm="TRUE" />
    
          <FieldRef ID="{25644618-1C4F-49EB-96DC-C1BD5BCD5253}" Name="ServiceDate" Required="TRUE" ShowInDisplayForm="TRUE" ShowInNewForm="FALSE" ShowInEditForm="TRUE" />
    

    I’ve generated the GUIDs using the Tools -> Create GUID feature in Visual Studio.

    Add the following lines before the </Elements> tag while making sure the GUIDs match what you used above:

    <Field ID="{672B4E30-1FDD-48F3-AABC-546404D3D483}" Type="Text" Name="Patient" DisplayName="Patient Name" Sealed="TRUE" StaticName="Patient"> 
    
    </Field> 
    
    <Field ID="{3EC8A782-F667-4FB9-970D-D14372811E85}" Type="Text" Name="Doctor" DisplayName="Attending Doctor" Sealed="TRUE" StaticName="Doctor"> 
    
    </Field> 
    
    <Field ID="{04D116F7-1381-4CB1-A60C-87A222FB86CB}" Type="Text" Name="PNumber" DisplayName="Patient Number" Sealed="TRUE" StaticName="PNumber"> 
    
    </Field> 
    
    <Field ID="{25644618-1C4F-49EB-96DC-C1BD5BCD5253}" Type="DateTime" Name="ServiceDate" DisplayName="Date of Service" Sealed="TRUE" StaticName="ServiceDate"> 
    
    </Field> 
    

    Our Content Type is ready for use; next up is to create the List Definition based on this Content Type. Right click the project node and select Add -> New Item, SharePoint -> 2010 and select the “List Definition from Content Type” project item template, name it “ContosoTranscriptDocLib”. The wizard opens and you can see that our Content Type is automatically selected (see screenshot below). Keep the default options and click Finish. A new List Definition using the custom Content Type is created, as well as a List Instance. Rename the ListInstance1 node in the Solution Explorer to “ContosoTranscripts”.

    clip_image004

    The final step of our implementation is to hook-up an event receiver which pulls data from the document and populates the custom fields of our “ContosoTranscriptDoc” list item. Right click the project node in the Solution Explorer and select Add -> New Item, SharePoint -> 2010, select the “Event Receiver” project item template and name it “ContosoTranscriptDocLibItemEventReceiver”. Note that the event source is already selected for the List Definition. Select both the “An item is being added” and “An item was added” events (see screenshot) and click Finish. This creates an Event Receiver class and hooks up the events you specified to the list.

    clip_image005

    The event receiver file opens automatically. Add the following code within the ContosoTranscriptDocLibItemEventReceiver class to drive the data extraction. Include the using statement “using System.IO;” at the top of the file and overwrite the generated ItemAdding and ItemAdded methods.

            /// <summary>
    
            /// String between MR# and DATE
    
            /// +4 is because "MR#:" itself has the length of 4 characters
    
            /// </summary>
    
            /// <param name="str"></param>
    
            /// <returns></returns>
    
            private string GetNo(string str)
    
            {
    
                int first = str.IndexOf("MR#:") + 4;
    
                int last = str.LastIndexOf("DATE:");
    
                string ouput = str.Substring(first, last - first);
    
                return ouput.Trim();
    
            }
    
            /// <summary>
    
            /// String between DOCTOR and SUBJECTIVE
    
            /// </summary>
    
            /// <param name="str"></param>
    
            /// <returns></returns>
    
            private string GetDoctor(string str)
    
            {
    
                int first = str.IndexOf("DOCTOR:") + 7;
    
                int last = str.LastIndexOf("SUBJECTIVE:");
    
                string ouput = str.Substring(first, last - first);
    
                return ouput.Trim();
    
            }
    
            /// <summary>
    
            /// String between DATE and DOCTOR 
    
            /// </summary>
    
            /// <param name="str"></param>
    
            /// <returns></returns>
    
            private string GetDate(string str)        
    
            {
    
                int first = str.IndexOf("DATE:") + 5;
    
                int last = str.LastIndexOf("DOCTOR:");
    
                string ouput = str.Substring(first, last - first);
    
                return ouput.Trim();
    
            }
    
            /// <summary>
    
            /// String between NAME and MR 
    
            /// </summary>
    
            /// <param name="str"></param>
    
            /// <returns></returns>
    
            private string GetPatient(string str)
    
            {
    
                int first = str.IndexOf("NAME:") + 5;
    
                int last = str.LastIndexOf("MR#:");
    
                string ouput = str.Substring(first, last - first);
    
                return ouput.Trim();
    
            }
    
           /// <summary>
    
           /// An item is being added.
    
           /// </summary>
    
           public override void ItemAdding(SPItemEventProperties properties)
    
           {
    
               base.ItemAdding(properties);
    
               string extension = properties.AfterUrl.Substring(properties.AfterUrl.LastIndexOf(".") + 1);
    
               if (extension != "txt")
    
               {
    
                   properties.Cancel = true;
    
                   properties.ErrorMessage = "Please upload only text files";
    
               }
    
           }
    
           /// <summary>
    
           /// An item was added.
    
           /// </summary>
    
           public override void ItemAdded(SPItemEventProperties properties)
    
           {
    
               base.ItemAdded(properties);
    
               int itemID = properties.ListItem.ID;
    
               string siteUrl = properties.WebUrl + "/";
    
               string listTitle = properties.ListTitle;
    
               // extract the content of the file in a string 
    
               TextReader tr = new StreamReader(properties.ListItem.File.OpenBinaryStream());
    
               string content = tr.ReadToEnd();
    
               tr.Close(); 
    
               string patient = GetPatient(content);
    
               string doctor = GetDoctor(content);
    
               string serviceDate = GetDate(content);
    
               string patientNo = GetNo(content);
    
               properties.ListItem["Patient Name"] = patient;
    
               properties.ListItem["Attending Doctor"] = doctor;
    
               properties.ListItem["Patient Number"] = patientNo;
    
               properties.ListItem["Date of Service"] = DateTime.Parse(serviceDate);
    
               properties.ListItem.Update();
    
           }
    

    That’s it! We’re ready to deploy and test the customization. Remember that our tools automatically add the SharePoint Items to the feature, which is by default included in the package. Here is a screenshot of the feature designer which shows the included SharePoint items and files for deployment. Feel free to update the feature title and description with more descriptive text as I’ve done below.

    clip_image007

    Let’s test our solution. Start debugging of the project (F5) and wait for the SharePoint site to appear. The new ContosoTranscriptDocLib – ContosoTranscript List should be visible in the quick-launch bar. Open the document library and then click the “Add new item” link. A zip file is attached to this post which contains sample input files (there are also some on Pranab’s original post). Browse to the sample file of your choice and click OK. The event receiver will execute and automatically populate the custom fields. Here is a screenshot with the results of the parsing. You can add breakpoints to the event receiver to step through the code.

    clip_image009

    As you can see, the new Visual Studio 2010 SharePoint Developer tools enable rapid implementation and deployment of SharePoint solutions. We’re excited to hear any feedback you have on our feature set.

    - Erik Cutts

  • Visual Studio SharePoint Development Blog

    Deploying files using Mapped Folders

    • 7 Comments

    With Visual Studio 2010 SharePoint Developer Tools, the concept of the Mapped Folder was introduced. A mapped folder is a convenient way for developers to specify a location for any files that need to be deployed on to the SharePoint file system, all from within in a Visual Studio solution. Mapped folders can be included as part of a deployment package (.WSP) and the files will get copied to the correct location when the WSP is installed on to the server.

    Let’s take a quick look at how a developer might use a mapped folder. Say a developer wants to develop a custom application page for their SharePoint site that will consume a custom image. The SharePoint server has a designated location for both application pages and images. With mapped folders, the developer can ensure that their files will be deployed to the correct location. Here’s an example:

    First we need to create a project. In this example, we will start by creating an Empty SharePoint project (Installed Templates->Visual Basic/C#->SharePoint->2010).

    Next, we’ll create our custom image that we want to display. First, let’s setup a mapped folder to the Images directory on the SharePoint farm. To do this, we simply right-click on the project node and select “Add->SharePoint “Images” Mapped Folder”:

    This will create a mapped folder named “Images” in our project. (You can also create it via the “Project->Add SharePoint “Images” Mapped Folder on the main menu bar”)

    In the Solution Explorer, mapped folders look very similar to normal folders but have a small green globe in the bottom right corner of the icon. You’ll notice that underneath the mapped folder there is a sub folder with the same name as the project. This is to help organize images specific to your project and keep developers from inadvertently overwriting another item with the same name.

    Also, if you select the mapped folder and open the property window (F4), you’ll see two entries: Folder Name and Deployment Location. The Deployment Location indicates the location relative to the SharePoint root directory ({SharePointRoot}) on the SharePoint farm.

    Now that we have our mapped folder, we can right-click on the project directory underneath it and add our image file (“Add->New Item’). In this example, I’ve added a bitmap image named ”Bob.bmp”.

    The next step is to create the application page and modify it to show our image. To start, right-click on the project node in the Solution Explorer and select “Add->New Item”. When the Add New Item dialog appears, the “2010” node under SharePoint will be selected. From the list of templates, select the “Application Page” item, give it the name you want, and click “Add”. You’ll notice that when the application page is added to the project, it automatically gets created under the “Layouts” mapped folder, which is the default location on the SharePoint file system for application pages:

    Following its creation, the .aspx file we just added should be opened in the designer. Locate the <asp:Content> element with the ID equal to “Main”. Within that element add an image element and set the ImageUrl attribute to point to the image in your product. It should look like this:

    <asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
    <asp:Label ID="Label1" runat="server" Text="Label" Font-Size="Medium">This is Bob.......</asp:Label>
    <asp:Image ID="Image1" runat="server" ImageUrl="~/_layouts/Images/SharePointProject1/Bob.bmp" />
    </asp:Content>

    The last thing we’ll want to do to make testing our project easier is to set the application page to be our startup item when we F5. To do this, select the project node in the Solution Explorer and open the property window (F4). In the property window, select the “Startup Item” property and choose our application page from the drop down list. Now when we F5, it will take us right to our application page:

    A couple of things to know about mapped folders. First, since mapped folders effectively deploy files onto the SharePoint file system, they are only allowed in farm level solutions. Sandboxed solutions are restricted to only deploying content to the content database on the server. In VS, when you try add a mapped folder to a sandboxed solution, the package validation will generate an error regarding this.

    Second, as you saw when we added the application page, some items go into certain mapped folders by default when they are added to the project. Another example is User Control items (.ascx) which are automatically placed into the User Control mapped folder. While these are the SharePoint “default” locations, there may be times you need to place one of these files in a different location, and this can be done by mapping the folder to a different location.

    Finally, you can create a mapped folder to any folder under the SharePoint root on the farm by opening the Add SharePoint Mapped Folder dialog (Project->Add SharePoint Mapped Folder… from main menu, Add->SharePoint Mapped Folder… from project context menu:

    For instance, if you had a custom web service you wanted to deploy to the SharePoint server, you could simply add a mapped folder that points to the ISAPI directory on the SharePoint file system and dropped the web service in there. Then, when the package gets deployed to the server, the web service will automatically be placed in the ISAPI directory and available for consumption.

    Additional Resources

    MSDN: How to: Add and Remove Mapped Folders

    Scot Moorhead

Page 1 of 1 (3 items)