Pages

Thursday, September 29, 2011

Create Site using Sharepoint webservices

Sharepoint is gaining traction every passing day and becoming more and more the defacto standard for collaboration and content management in Enterprise. Nowadays more and more business applications are moving into sharepoint along with Line of Business Applications. This is leading to sharepoint interfacing with variety of different applications, including SAP and other ERP systems and some times multiple Sharepoint farm. Most of the time people tend to create custom application or web services to perform basic operations of creating site or updating list item. There are times when we have to create custom web service to perform some operations and it is always case by case basis. In my experience so far i tend to not to create custom web services for some basic operations like provisioning a site or updating the list. Here I am going to show how simple is to use sharepoint web service to create site and also point out an error which causes panic with new developers consuming sharepoint webservice.

Creating site using shrepoint web service is a simple and straight forward task.

1. Add web reference to the Sharepoint Site.asmx web service.
2. use CreateWeb method on the service to create a web. If you want to create a sub site pass relative URL with parent and child site.
3.That's it the site is created.

But here come a problem. When ever you use Sharepoint web service to create site there is a bug in sharepoint site.asmx web service which will throw an SOAP exception. There is no need to panic as Microsoft did not fix this is Sharepoint 2010 as well. Just suppress the error and move on. when you go to the remote site collection you will see the site created though you got the exception. I wanted to write this down because every time a new resource who is new to sharepoint joins our organization and if he has to use site.asmx to create site in their project they get this error and often times they spend a lot of time trying to figure out why the error is happening either by playing around with parameters or trying to write a new web service to create a site.

In the code snippet I am creating a sub site at 3 levels deep hence I am passing relative url of the web that needs to be created. Replace the web name field with your name and remember web name can be different than the web tile. web title is the one that is displayed and web name is the one that forms the URL.  in the code I am writing to the event log so that I can copy the exception here. I forgot to copy it when I am writing this but I will add the exception ASAP. Code snippet also shows how to get tempalte using site.asmx and set it in. You can also refer to my blog about Web template here.

Code


SharepointSiteService.Sites siteWS = new SharepointSiteService.Sites();
                                siteWS.Credentials = new System.Net.NetworkCredential("user1", "password", "domain");
try 
{
                                       
                                            SharepointSiteService.Template[] templates;
                                            siteWS.GetSiteTemplates(1033, out templates);
                                            SharepointSiteService.Template template = (from SharepointSiteService.Template t
                                            in templates
                                                                                       where t.Title == "Test Template"
                                                                                       select t).FirstOrDefault();

siteWS.CreateWeb("<parent web name>" + "/" + <sub web name>" + "/" + <sub web name>", "Test web", "Test Web", template.Name, 1033, true, 1033, true, 1033, true, false, false, false, false, false, false); 
}
catch (Microsoft.SharePoint.SoapServer.SoapServerException e)
{
                                        System.Diagnostics.EventLog.WriteEntry("SharePoint Foundation", "soap exception" + e.Detail + e.Message + e.Source + e.Node);
}
catch (Exception ex)
{
                                        System.Diagnostics.EventLog.WriteEntry("SharePoint Foundation", "Site Created");
                                        System.Diagnostics.EventLog.WriteEntry("SharePoint Foundation", ex.Message + ex.Source + ex.StackTrace);
 }

Tuesday, September 20, 2011

Create Site collection using Sharepoint Webtemplate object model

Create Sites and Site colletion using Custom Web template using object model and shrepoint web services in sharepoint 2010.


Web templates are new introduction in sharepoint 2010. But in a nutshell they are same as site template in 2007 except for the fact that Microsoft listened to all the developer community and made this change. The change is good and bad. The change that is brought into site template is now when you save the site as template it now saved into the solution gallery under site settings page as a WSP. WSP is a deployment package in sharepoint world. This solution gallery is a repository for sanboxed solutions, which implies the template that you created has now become sanboxed solution and can be used with the site collection.


Now let us talk about the good thing. The wsp can be downloaded and using the Sharepoint 2010 project template in visual studio 2010 you can import the wsp as a solution. Viola, now you can see all the information present in the template. You have access to onet.xml and element file that goes with it. There is also a feature created for you that acts as feature stapler or more like a feature that adds all the required thing to the site created out of this template.


Another very important and thoughtful idea that microsoft incorporated in web templates is you can deploy these web templates globally instead of having this as sanboxed solution. How do you do that? It is simple and straight forward. Once you download the template from solution gallery and import the wsp you can see a Site level feature is built in, you can change this feature to Farm scoped and then repackage the solution and deploy it in central admin either using Power shell or stsadm commands. If you go to create site page in central admin to create new site collection you will be able to see the newly deployed template. Now you can create site collection using this template. See how simple it is for admin or site owner to maintain the look and feel across all sites by using web templates.


How easy it is and how good the life is for creating from UI. But for the developers the life is not always smooth sailing. We updated to 2010 Sharepoint recently in our organization and we decided to use web templates. We built a site provision code that automatically provisions the site when some one submits request. There are lot of site templates that we built over years on MOSS 2007. We converted those site templates to web templates as first step. Now is the bad part of web template showed up. In our 2007 code we used to pass the name of the site template directly to create site, it worked because we were only subsites. But now since we made these web templates a Farm feature and deploy it globally the provisioning code needs to change. The problem sprang up when we provisioning the site automatically.


Code:


site.WebApplication.Sites.Add("/project/testsite", testsite,testsite 1033,"NewWebTempalte", usr.LoginName, usr.Name, usr.Email));


This code is expected to work. Here comes the bouncer. The site got created and the templates never got applied. Then changed the code to create the site with null and apply the template in object model.


Code:


using(spsite newsite = site.WebApplication.Sites.Add("/project/testsite", testsite,testsite 1033,null, usr.LoginName, usr.Name, usr.Email))
{
newsite.RootWeb.ApplyWebTemplate("NewWebTemplate");
}

This failed too. After doing some research and doing some search that takes me to no where i decided to see how the templates are stored. I found the templates are stored in the same as other WSPs are stored in database. Since I deployed globally I decided to get all the templates available in the site. To my surprise i noted that the template is available but the name of the template is not same as I thought. The name is preceded by the feature GUID.

Code:

{a0006016-915d-4008-b0f1-c25d1665ec9b}#NewWebTemplate;

This is how the name is stored. This not the name with which the template was created. After reading through some of MSDN documents i found that in 2010 since the templates are created to use in different places the name that we enter is always appended with the feature guid. so when you save it sharepoint creates a feature and appends it with the name that is entered in "Save Site as Template" page in site settings. This is what I am talking about. It is hard for a regular user to know this and when some one else creates the template and sends you then they are not going to give you the entire name including the guid. No wonder my first code and second one failed. 


Then what is the right way to get the templates and apply it. Luckily that is not a daunting tasks. You have to get all the templates and then get your template out of it. Here is snippet of code that will come handy.


Code:



using(spsite newsite = site.WebApplication.Sites.Add("/project/testsite", testsite,testsite 1033,null, usr.LoginName, usr.Name, usr.Email))
{
        SPWebTemplateCollection tempaltes = newsite.RootWeb.GetAvailableWebTemplates(1033);
       SPWebTemplate temp = (from SPWebTemplate t
                               in tempaltes
                                                                  where t.Title == "NewWebTemplate"
                                                                  select t).FirstOrDefault();

                                            newsite.RootWeb.ApplyWebTemplate(temp.Name);
    }



I am using LINQ because it is better than enumerating . Also I am using "Title" because title is what is going to contains the name that I entered in the test box.  Remember that you can enter different name and title for your templates. 

In the same way you can also use the web services to get the templates in remote servers. In case of webservices you will get an array and sent in out object.


Code:


   SharepointSiteService.Template[] templates;
                                                        siteWS.GetSiteTemplates(1033, out templates);
                                                        SharepointSiteService.Template template = (from SharepointSiteService.Template t
                                                        in templates
                                                                                                   where t.Title == FeatureConstants.Project_Template
                                                                                                   select t).FirstOrDefault();





I decided to write this down here because it may be useful to some one else as sharepoint is growing in leaps and bounds.

Monday, September 19, 2011

Sharepoint Webservices and Special Characters

I recently had to use List.asmx to update metadata properties in sharepoint. I have used it many times before and felt comfortable using it too. But this time there was an error been thrown as "An error occurred while parsing EntityName". After looking into the XML i found that the Title field had special character "&" This was causing the whole problem. The solution was to parse the special character. I wanted to share one of the easiest way to parse the XML.

string s = System.Security.SecurityElement.Escape(str);

This is an easier way to encode the special characters. In a regular .NET application you can parse the entire XML, but donot parse the whole XML that is passed into List.asmx updatelistitems method. This will give you no error but the list will not updated because System.Security.SecurityElement.Escape method will encode all the characters and this will cause issues with your field name, at least it did cause issues for me.

Code Snippet:

XmlDocument xDoc = new XmlDocument();
                        XmlElement batch = xDoc.CreateElement("Batch");
                        batch.SetAttribute("OnError", "Continue");


                        string strBatch = "<Method ID='1' Cmd='New'>" +
                           "<Field Name='ID'>New</Field>" +
                            "<Field Name='Title'>" + System.Security.SecurityElement.Escape("A.M. Pappas & Associates") + "</Field>" +
                            "<Field Name='Test_x0020_Check'>1</Field>" +
                           "<Field Name='Test_x0020_URL'>http://www.google.com</Field>" +
                           "<Field Name='Test_x0020_Choice'>InActive</Field>" +
                           "<Field Name='Test_x0020_User'>" + SPContext.Current.Web.CurrentUser.ID + ";#" +"</Field>" +
                             "</Method>";
                        batch.InnerXml = strBatch;

                        XmlNode node = listws.UpdateListItems("Error List", batch);



There are other ways that you can parse the XML either by stripping out the special characters or replacing with space or using XMLwriter. But I felt this is an easier way and you can never go wrong with this.

Friday, September 16, 2011

One or More fields not installed Properly Sharepoint

I decided to pen down this error for the reason that I tend to forget what i learned over a period working on sharepoint. Recently it so happened that one of my colleague faced this error developing on sharepoint and he is relatively new to sharepoint. There are millions of blogs and article taking about "one or more fields not installed propertly" error in sharepoint. In his case he was using sharepoint List.asmx web services to update the list. After looking through his code he was using display name and that was causing this error. This would have worked perfectly in object model to update the list item, but in webservices call the xml created is used as CAML and hence it was looking for internal name.


So I decided to list some of the reasons why "One or more fields not installed properly" would happen in sharepoint.

Sharepoint column is not added to the list

Display name of the column is used in the CAML (Object Model)

Display Name is used in Sharepoint Web Services XML (This XML will be converted to CAML, so similar to 2nd Point)

If the Column Type is different than the one referenced in code.

I am adding a code snippet. This is used to create new or update existing item in SharePoint using web services.

"<Method ID='1' Cmd='New'>" +
                                         "<Field Name='ID'>New</Field>" +
                                         "<Field Name='"Property_x0020_Name "'>1</Field>" +
                                        
                                          "<Field Name='"Property_x0020_Status"'>active</Field>" +


                                          "<Field Name='" Site_x0020_Type "'>Entity</Field>" +


                                          + "<Field Name='Title'>" + foundEntityWeb.Title + "</Field>" +
  "</Method>";


"<Method ID='1' Cmd='Update'>" +
                                         "<Field Name='ID'><ID of the item to update></Field>" +
                                         "<Field Name='"Property_x0020_Name "'>1</Field>" +
                                        
                                          "<Field Name='"Property_x0020_Status"'>active</Field>" +


                                          "<Field Name='" Site_x0020_Type "'>Entity</Field>" +


                                          + "<Field Name='Title'>" + foundEntityWeb.Title + "</Field>" +
  "</Method>";


you can refer to MSDN article for creating XML for sharepoint List.asmx.