Pages

Thursday, December 15, 2011

User Information List

This past week we are were getting ourselves ready for the christmas party and holidays. We are done with one of our big project and wanted to chill out during this holiday. Ironically this happened that one of our developer brought up an interesting question about sharepoint. In our project we had to see whetehr user exists and since we had sites and subsite present in the site structure we were using 


     Web.Users["username"]  and web.SiteUser["username"]

The question was

  is there a nice way to get the user information than using users?

The reason he wanted to know was these objects were uses interchangeably and some time the web.users throw an exception and then had to go through siteusers. I set to investigate further and I also remembered that there is list in sharepoint where users are stored. But I totally forgot about it. It is the userinformation List. Here you have information about the user as soon as the user is created and Sharepoint is using this list for its operation like when you have a document or item created in sharepoint CreatedBy and ModifiedBy is all getting information from this List. This List is what used to by sharepoint to track the changes and user who performs it (Audit).

Here is a code to get information from usre information list.
Remember, this list is hidden and you need to be an administrator to access this list.

Here is how you can access the list from UI

URL : [SiteURL]/_catalogs/users/detail.aspx 


I am not using the Name in my CAML rather email field to run the query. Also getting the user like this will be more useful if you are performing other operation with the user information.

Code:

SPSecurity.RunWithElevatedPrivileges(delegate()
            {

                using (SPSite site = new SPSite(SPContext.Current.Web.Url))
                {
                    using (SPWeb web = site.OpenWeb())
                    {


                        int userId = SPContext.Current.Web.CurrentUser.ID;
                        string userName = SPContext.Current.Web.CurrentUser.Email;

                        SPList userInformationList = SPContext.Current.Web.SiteUserInfoList;


                       SPListItem userItem = userInformationList.Items.GetItemById(userId);

                        SPQuery query = new SPQuery();

                         string queryString =  string.Format("<Where><Eq><FieldRef Name='EMail' /><Value Type='Text'>{0}</Value></Eq></Where>",userName);
                        query.Query = queryString;
                        SPListItemCollection userItems = userInformationList.GetItems(query);

                        if (userItems != null && userItems.Count > 0)
                        {
                            console.Writeline("User Found");
                        }
}
}
});

Wednesday, November 23, 2011

The backup set holds a backup of a database other than the existing database

Wish you all a Happy Thanks Giving. Thanksgiving was real blessing this time because i got the needed rest from a tiring project. It was titring in many front because we were dealing with an accounting firm and we ought to get the project done before the end of November so they can sign off and proceed to go live. Now finally the the week of thanks giving we are done and they are merrily testing the solution. I wanted to blog this information here because it might be useful for many who are using custom database in there application solution.


We were buiilding a sharepoint solution and had a custom database for some of our custom operations. One of our developer who was new had to restore database from a backup and he got the error which he had no clue off. "System.Data.SqlClient.SqlError: The backup set holds a backup of a database other than the existing database". The error had nothing to do with him. He was trying to restore the database from the backup using SQL Server Management studio and using the restore option. There are couple of reasons why this error could come up

1. if restoring from a different version of SQL Server.
2. If  logical Name of the Database is different from the one that is backed up.

In our case it was the first option because we backed up long time ago and the developer was trying to restore it on SQL Server R2.

Following T-SQL query can be handy in fixing this. Make sure you run this query on the master and not on the database itself.


RESTORE DATABASE TestDatabase
FROM DISK = 'C:\BackupTestDatabase.bak'
WITH REPLACE

Happy Thanks Giving

http://g.co/doodle/ab23hc

Tuesday, October 18, 2011

CAML to Query User field

Sharepoint as a database is more of a Flat structure database. Querying is often times the most time consuming operation in especially when running against millions of List data. Microsoft has done a lot to increase the query time, still there are some limitations in sharepoint. Hence it is necessary to optimize the CAML as much as possible when querying against large Lists or document Libraries.

Often times I get asked by team members about writing CAML against Lookup Field and User Field. I decided to write it down here as a reference for everybody who wants to use CAML to query Sharepoint user field for me as well because every time some one asks me I tend to forget and needs to go back to code and give them the query. So I thought this is a right form so every body can be benefited.


Code:

SPQuery query = new SPQuery();
query.Query = string.Format("<Where><Eq><FieldRef Name='Author' LookupId='TRUE' /><Value Type='Int'>{0}</Value></Eq></Where>", SPContext.Current.Web.CurrentUser.ID);
SPListItemCollection itemCollection = oList.GetItems(query);



I am using the sharepoint user field as sharepoint lookup field and performing the query based on user id. I prefer this method because there is no way this could go wrong as no 2 users can have same ID. This struck me when my team was implementing FBA and we created test user with same name. Interestingly the same query can be used for sharepoint Lookup field as well. If you notice the way Sharepoint stores the Look up field you can the format as

1;#lookupvalue

This same format is used for SPUser field as well. This set up is actually a blessing for us  "Developers"

Monday, October 10, 2011

Sharepoint Web Events and Branding

Sharepoint Branding is one of the important thing in Sharepoint development. Often times there is a requirement to create branding features and feature stapler to achieve required branding. I think feature stapler is definetly a great idea, but in sharepoint 2010 there a new concept that is introduced in solution deployment. In sharepoint 2007 we did not had any sandbox solution. In a nut shell Sharepoint Sandbox solution is a way to deploy solution that can be used only in site collection that is deployed. These sandbox solution doesnot have access to file system. Here comes the problem because it cannot access the file system feature stapler cannot be used to add new features. Another change or improvement in sharepoint 2010 is web templates. Web templates replaces site templates in sharpoint 2007. These web templates are again deployed as Sandbox solution.hence feature stapler cannot be used to attach any branding as most often web templates are used for creating sites with similar look and feel and branding.

After researching quite a bit I felt that there is less documentation on how to achieve branding or change certain functionality in sandbox solution using feature stapler. Having used feature stapler heavily in MOSS 2007 I felt hard to get away with it. I did experiment with some of the events and see other ways to achieve this. I found the Web Events that are introduced in Sharepoint 2010 is a better way to achieve this. In sharepoint 2010 we can use "Site was provisioned" which is an Asynchronous event to achieve some of the branding stuff. I recently created this to set master pages for the sites created using Sandbox Web templates.

Code 

public class SetMasterPageEvent : SPWebEventReceiver
{
       /// <summary>
       /// A site was provisioned.
       /// </summary>
       public override void WebProvisioned(SPWebEventProperties properties)
       {
           base.WebProvisioned(properties);

           using (SPSite site = new SPSite(properties.FullUrl))
           {
               using (SPWeb web = site.OpenWeb())
               {
                   web.MasterUrl = web.Site.RootWeb.MasterUrl;
                   web.CustomMasterUrl = web.Site.RootWeb.CustomMasterUrl;
                   web.AlternateCssUrl = web.Site.RootWeb.AlternateCssUrl;
                   web.SiteLogoUrl = web.Site.RootWeb.SiteLogoUrl;
                   web.Update();
               }
           }
       }


    }


In the example I am setting the master page of the newly created site to the master page of root site. You can register this event by creating a site collection feature if you want the operation to be performed on all the sites that are created under the site collection or a web feature if an operation needs to performed on a specific site.


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.