Wednesday, July 28, 2010

How To: Add a new Content Database in SharePoint 2010

You can use the procedures that are described in this article to create a new content database and attach it to a Web application.

In this article:
  • To add a content database to a Web application by using Central Administration

  • To add a content database to a Web application by using Windows PowerShell

To add a content database to a Web application by using Central Administration

  1. Verify that the user account that is being used to perform this operation is a member of the Farm Administrators SharePoint group. If you are using Windows authentication to connect to SQL Server, the user account must also be a member the SQL Server dbcreator fixed server role on the SQL Server instance where the database will be created. If you are using SQL authentication to connect to SQL Server, the SQL authentication account that you specify when you create the content database must have dbcreator permission on the SQL Server instance where the database will be created.
  2. On the SharePoint Central Administration Web site, click Application Management.
  3. In the Databases section, click Manage content databases.
  4. On the Manage Content Databases page, click Add a content database.
  5. On the Add Content Database page:


    1. Specify a Web application for the new database.

    2. Specify a database server to host the new database.

    3. Specify the authentication method that the new database will use and supply an account name and password, if they are necessary.


      Important:
      The account name and password must already exist as a SQL Server login.
    4. Specify the name of the failover database server, if one exists.

    5. Specify the number of top-level sites that can be created before a warning is issued. By default, this is 9,000.

    6. Specify the total number of top-level sites that can be created in the database. By default, this is 15,000.


      Note:
      For information about how to determine the number of top-level sites that the system can support, see Performance and capacity technical case studies (SharePoint Server 2010).
    7. Click OK.

To add a content database to a Web application by using Windows PowerShell

  1. Verify that you meet the following minimum requirements: See Add-SPShellAdmin. If you are using Windows authentication to connect to SQL Server, the user account must also be a member the SQL Server dbcreator fixed server role on the SQL Server instance where the database will be created. If you are using SQL authentication to connect to SQL Server, the SQL authentication account that you specify when you create the content database must have dbcreator permission on the SQL Server instance where the database will be created.
  2. On the Start menu, click Administrative Tools.
  3. Click SharePoint 2010 Management Shell.
  4. At the Windows PowerShell command prompt, type the following command:

    New-SPContentDatabase -Name  -WebApplication 
    Where is the name of the content database to create and is the name of the Web application to which the new database is attached.
    For more information, see New-SPContentDatabase.

    Adopted from: Microsoft TechNet Article

Creating Site Collection in a separate Content Database

Since, most of us ignore the site collection basics and seldom plan our site collection content database storage needs. We are often unaware of SharePoint limitations in terms of content storage which affects our design at a later point in time.

Here is the simple yet very powerful stsadm command to create a site collection with a separate content database:

stsadm -o createsiteinnewdb -url http://webspinners/dept/hr -owneremail SharePoint@webspinners.com -ownerlogin Webspinners\SPAdmin -sitetemplate sts -title “Human Resources” -databaseserver "SERVER5" -databasename “HR Content Database”

In this example, a new site collection is created at the URL http://webspinners/dept/hr.
The Site Collection Owner is set to Webspinners\SPAdmin and the Site Collection owner email is set to SharePoint@webspinners.com.
The default team site template is used to create the site (the template is simply named ‘sts’, without the quotes.)
The database server is SERVER5 and the name of the database created is HR Content Database.
There are some reasons, why you could have a different content databases per site collections:

1. MS recommends to have content database not more the 100Gb for MOSS 2007 and 200GB for SP 2010.

2. It simplifies your backup and restore operation

3. It provides flexibility for Disaster Recovery (DR) strategy.

4. Modularity and Flexibility of data storage eliminates maintenance nightmares.

Possible Scenarios:
a. Media management for a site collection that stores heavy audio/video media files like .avi, .mpeg, .wav, .mp3

b. Knowledge Management requirement where you might think of implementing a separate KM site collection for managing thousands of word, excel, powerpoint, visio, pdf artifacts etc.

These scenarios need you to have a separate Content Database for your site collections, otherwise the overall application performance would degrade, searching these documents will be affected, backup and recovery will be a nightmare and moving these site collections into separate SP farms will be trouble some.

If you have already made the mistake of not having a separate content database store for your Site Collection, and want to move your Site Collection to a separate Content database in MOSS 2007, please follow these links :
http://msmvps.com/blogs/laflour/archive/2008/10/14/tips-to-create-a-site-collection-in-new-content-database.aspx
 and
http://blogs.msdn.com/b/mcsnoiwb/archive/2007/08/20/how-to-create-site-collection-in-a-specific-content-database.aspx

For moving site collection to a new Content DB in SharePoint 2010,  follow directions given by Microsoft : http://technet.microsoft.com/en-us/library/cc825328.aspx

Monday, March 29, 2010

Creating a Multiple selection List Box in browser enabled InfoPath form

InfoPath 2007 browser enabled forms (a part of InfoPath Form services) does not support Multi-select List Box control. Read some other InfoPath Form services limitations here: http://office.microsoft.com/en-us/infopath/HA102040851033.aspx

I had a tough time explaining and convincing clients about this and they got another excuse of blaming it all on Microsoft, so I finally decided to solve this problem on my own.

The overall solution looks like this:
a. Create a  custom Data structure in InfoPath 2007 browser enabled form.
b. Bind a Repeating Table with our custom Data Structure and tweak the look and feel to make it look more like a Multi-select List box.
c. Use Form Load event for programmatically loading Multi-Select List options.
d. On Submit button click, Save the multi-selected List box items as a semi-colon separated string in another InfoPath text field.

I will explain the above solution Step-by-Step with snapshots to make it more easier to implement.

a. Create a Data Structure in InfoPath 2007: See the snapshot below:

i) In this case, my field name for storing the values selected in the multi-select List items is WorkcenterAssignment. You can give any name you want to the Group and the field. Values selected by the user will be stored in this field.

ii) For MultiSelectOptions, follow the same structure as mentioned below:
-MultiSelectOptions(Repeating Group) - Will be applied as a repeating table in Step b.
    - selectedOption (True/False Boolean field) - This will be converted into Checkbox on the UI
    - optionDescription (Text string field) - This will be used for storing the multi-select List Item options

b. Bind a Repeating Table with the Data Structure
i) Right click on the above schema -> Choose Repeating table as follows:

ii) It will look like this on the InfoPath form:
iii) Format it to look more like a multi-select ListBox on your form:
Note: You can also wrap it inside a Table with a fixed width and fixed height, so that Listbox items can act like scroll bar for options)

c. Programmatically loading Multiple items in the List Box from SharePoint List/Library:
Now that our schema and control are all set, we need to load values into multiselect Listbox control.
The key event here is the InfoPath form load event. 

The strategy here is to bind the repeating table created above programmatically using Visual Studio for Applications. I prefer to write the code in C# .NET.

Here is my Form Load event, I call the generic method LoadMultiSelectListBox() method, copy the code below:

 public void FormEvents_Loading(object sender, LoadingEventArgs e)
        {
            try
            {
                this.Errors.DeleteAll();

                    XPathNavigator root = MainDataSource.CreateNavigator();
                    XPathNodeIterator listItems = root.Select("/my:Request/my:WorkCenterAssignments/my:MultiSelectOptions", NamespaceManager);

                    if (listItems.Count == 1)
                    {
                        //Load Multi-Select List Box
                        LoadMultiSelectListBox();
                    } 
            }
            catch (Exception exp)
            {
                ThrowException(exp);
            }
        }



Here is the code for Loading Multi-Select items into the repeating table programmatically. I first need to get all my List item options from my SharePoint List/Library, I have created a XML Receive Data connection in InfoPath, you can alternatively get all the options from SharePoint List/Library using the SharePoint object model, copy code below:

        private void LoadMultiSelectListBox()
        {
            try
            {
                this.Errors.DeleteAll();

                //Query Get Approvers From SharePoint List data connection
                FileQueryConnection queryConnection = (FileQueryConnection)this.DataConnections["WorkCenterXML"];
                queryConnection.Execute();

                //Get all nodes from the Work Center XML
                XPathNavigator connectionNav = DataSources["WorkCenterXML"].CreateNavigator().SelectSingleNode("//rs:data", this.NamespaceManager);
                XPathNodeIterator allItems = connectionNav.Select("//z:row", this.NamespaceManager);

                //Iterate via all records
                foreach (XPathNavigator item in allItems)
                {
                    AddMultiSelectListItems(item);
                }

                //Delete the first row of InfoPath Repeating table programmatically
                if (GetCurrentXPathNav("/my:Request/my:WorkCenterAssignments/my:MultiSelectOptions[1]") != null)
                {
                    GetCurrentXPathNav("/my:Request/my:WorkCenterAssignments/my:MultiSelectOptions[1]").DeleteSelf();
                }
            }
            catch (Exception exp)
            {
                ThrowException(exp);
            }
        }

This method adds values into our custom repeating table data structure:

        private void AddMultiSelectListItems(XPathNavigator item)
        {
            try
            {
                this.Errors.DeleteAll();

                //Get Reference to Multi-Select List Options
                XPathNavigator Item = GetCurrentXPathNav("/my:Request/my:WorkCenterAssignments/my:MultiSelectOptions");

                //Create a new Item node for Multi-Select List items
                XPathNavigator newItemNode = null;

                if (Item != null)
                {
                    //Clones the new item w.r.t repeating table structure
                    newItemNode = Item.Clone();
                }

                //Get Reference to Option description
                XPathNavigator optionDescription = newItemNode.SelectSingleNode("/my:Request/my:WorkCenterAssignments/my:MultiSelectOptions/my:optionDescription", this.NamespaceManager);

                //Set Option description values
                optionDescription.SetValue(item.GetAttribute("ows_Workcenter", String.Empty));

                //Add a new Item in the Multi-Select List options
                Item.InsertAfter(newItemNode);

                optionDescription = null;
                newItemNode = null;
            }
            catch (Exception exp)
            {
                ThrowException(exp);
            }
        }

Updated as on 5th April, 2010: GetCurrentXPathNav is a generic method used to get the handler on the particular node/field in InfoPath, copy the code below:

///
/// Get XPath Navigator gets the Navigator object for the passed in XPath expression.
/// This method should be used as a helper function at all times
///
/// XPathNavigator
public XPathNavigator GetCurrentXPathNav(String XPath)
{
    XPathNavigator DataSource = MainDataSource.CreateNavigator();
    XPathNavigator XPathNav = DataSource.SelectSingleNode(XPath, NamespaceManager);
    return XPathNav;
}

Preview your InfoPath form, your control should load all the options dynamically and look like this:

d. Saving the values selected from the Multi-select List box item on saving the form:
Assume user selects multiple items, we will have to save the values selected in our Multi-select Listbox control using a separate field in the InfoPath form, in this example, we created the WorkcenterAssignment text field in Step a.

Again we will use the programming approach to iterate through the repeating table nodes, identify the list items selected and store them as semi-colon (;) separated values in the WorkcenterAssignment InfoPath field.

WorkcenterAssignment can be further promoted as a SharePoint column using Property Promotion feature in the InfoPath form. To know more on publishing and deployment of InfoPath forms, see my detailed post on Publishing and Deploying browser based InfoPath forms


Here is the code to Save the selected Multi-select Listbox items:

private void SaveMultiSelectListItems()
        {
            try
            {
                this.Errors.DeleteAll();

                XPathNavigator root = MainDataSource.CreateNavigator();
                XPathNodeIterator listItems = root.Select("/my:Request/my:WorkCenterAssignments/my:MultiSelectOptions", NamespaceManager);

                String optionsSelected = String.Empty;
                StringBuilder selectedListItems = new StringBuilder(String.Empty);

                int counter = 0;

                while (listItems.MoveNext())
                {
                    optionsSelected = listItems.Current.SelectSingleNode("my:selectedOption", NamespaceManager).Value;

                    //Check whether the Check box against the option was selected or not
                    if (Boolean.Parse(optionsSelected) == true)
                    {
                        if (counter == 0)
                        {
                            selectedListItems.Append(listItems.Current.SelectSingleNode("my:optionDescription", NamespaceManager).Value);
                        }
                        else
                        {
                            selectedListItems.Append("; " + listItems.Current.SelectSingleNode("my:optionDescription", NamespaceManager).Value);
                        }

                        //increment the counter
                        counter++;
                    }

                    //Clear variable
                    optionsSelected = String.Empty;
                }

                //Set all the multi-selected List Box values
                GetCurrentXPathNav("/my:Request/my:WorkCenterAssignments/my:WorkcenterAssignment").SetValue(selectedListItems.ToString());
            }
            catch (Exception exp)
            {
                ThrowException(exp);
            }
        }


I think the above code is self-explanatory. This is how we simulate a Multi-select List control using the repeating table model and dynamic options loading in a browser enabled InfoPath form.

Feel free to share your comments.


References: InfoPath Team blog

Sunday, March 7, 2010

Enable Forms Based Authentication (FBA) in SharePoint 2010

Upcoming Posts: Have not been regular with my blogging in the last month, did lots of R&D on the InfoPath 2007 browser enabled forms and Form services, my future posts will be in the following areas:

A) Multi-select List Items in a browser enabled InfoPath form, which was earlier thought not to be possible with Form Services, stay tuned for that post.

B) Cascading dropdowns using code-behind InfoPath solution and owssvr.dll for dynamic filtering within the dropdowns using XML.

Coming back to Forms Based Authentication, here is a nice step-by-step tutorial, I found on Enabling Forms Based Authentication in SharePoint 2010: http://blog.summitcloud.com/2009/11/forms-based-authentication-sharepoint-2010-fb/

For enabling FBA on SharePoint 2007, refer:  http://blog.summitcloud.com/2009/10/enable-forms-based-authentication-for-sharepoint/

Stay tuned for my interesting hacks on InfoPath 2007. Till then Happy Programming :)

Thursday, January 14, 2010

Nintex My Workflow tasks webpart - Redirect to Custom InfoPath Task form

My earlier post related to a unique problem in Nintex OOTB "My Workflow Tasks" webpart. The job of this webpart is to show all Workflow Tasks assigned to the currently logged in user.

The problem occurs when InfoPath forms come into picture, since we might have a custom InfoPath task form, and the default behavior of the webpart directs the user to the Nintex OOTB task form, so it is has no provision for redirecting users to a Custom InfoPath Task form.

There are 2 possible ways to overcome this limitation:

Approach 1: in this approach I create a new custom InfoPathApproveReject.aspx form which overrides the OOTB Nintex ApproveReject.aspx Task form and hides certain section of the form like the Approve/Reject radio buttons. Check out Approach 1 here
 
Approach 2: Is modifying the existing Nintex OOTB ApproveReject.aspx task form in the 12 Hive layouts directory. The approach is to identify whether the ItemProperties contain .xml as an extension or not, so we use the following code in the ApproveReject.aspx page:

 if (this.itemProperties.Item.Name.ToString().Contains(".xml"))
   {
          string redirectUrl = this.itemProperties.Item.Web.Url + "/_layouts/FormServer.aspx?XmlLocation=" + this.itemProperties.Item.Web.Url + "/" + this.itemProperties.Item.Url.ToString() + "&OpenIn=browser";
          Response.Redirect(redirectUrl);
   }

This will work for all web applications in your SharePoint environment. If it is a custom InfoPath form in the Item Properties object, then it simply redirects the logged in user to the Custom InfoPath task form, otherwise it shows up only the OOTB Nintex task form.

Click here to download the customized version of Nintex ApproveReject.aspx form.  

NOTE: Take a back up of your existing copy of OOTB ApproveReject.aspx page from the following location C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\NINTEXWORKFLOW.

Then replace the customized version of ApproveReject.aspx page in the above mentioned location.

Test your changes:
To test the new change, you need to have a workflow enabled List/Library with a custom infopath form and Nintex OOTB My Workflow Tasks webpart on any of your site page.

Now when the task gets created it shows up in the webpart and when you click on the Item it opens up the InfoPath custom task form.

However, if you have a standard workflow on a SharePoint list/libray without InfoPath form, then you need not worry, since it would automatically open up the OOTB Nintex task form as it never found .xml within the ItemProperties object.