Sunday, December 11, 2011

Delete Orphaned Event Handler Using Code

During preupgradecheck, I found many orphaned event handlers listed out. This need to be deleted from almost every site. I googled a lot but not able to find any solution to delete this using code. So I decided to create my own solution.


My Solution is Loop over all web applications, then loop over all lists inside all webs. Look for event receivers attached with list. And then try to look for the assembly associated with event receiver is valid or not. If assembly is invalid delete the event receiver.


Download working project EventReceiverHelper


Check my code below:


//get local farm
            SPFarm localFarm = SPFarm.Local;


            //loop Services
            foreach (SPService spService in localFarm.Services)
            {
                //if service is WebService
                if (spService is SPWebService)
                {
                    SPWebService webService = (SPWebService)spService;


                    //loop over web applications
                    foreach (SPWebApplication webApp in webService.WebApplications)
                    {
                        //Loop Site Collections
                        foreach (SPSite site in webApp.Sites)
                        {
                            //Loop Sites
                            foreach (SPWeb web in site.AllWebs)
                            {
                                try
                                {
                                    //Loop Lists
                                    foreach (SPList list in web.Lists)
                                    {
                                        SPEventReceiverDefinitionCollection spEDC = list.EventReceivers;


                                        if (spEDC.Count > 0)
                                        {
                                            List<Guid> orphandIDs = new List<Guid>();
                                            for (int i = 0; i < spEDC.Count; i++)
                                            {
                                                SPEventReceiverDefinition spED = spEDC[i];
                                                string assembly = spED.Assembly;
                                                string className = spED.Class;


                                                System.Reflection.Assembly eventReceiverAssembly = System.Reflection.Assembly.LoadWithPartialName(assembly);


                                                if (eventReceiverAssembly == null)
                                                    orphandIDs.Add(spEDC[i].Id);
                                            }


                                            for (int i = orphandIDs.Count - 1; i >= 0; i--)
                                            {
                                                list.EventReceivers[i].Delete();
                                            }
                                        }
                                    }
                                }
                                catch (Exception ex)
                                {
                                    
                                }
                                web.Dispose();
                            }
                            site.Dispose();
                        }
                    }


                }
            }
        }

Saturday, December 10, 2011

SharePoint Directly Query Database

Query Documents:

dbo.AllDocs is a table that holds information about all the documents in all document libraries for all sites and sub sites. Here is simple query to retrieve documents from "Shared Documents" library from all sites. 




SELECT *
FROM AllDocs 
JOIN AllLists 
ON AllLists.tp_Id=AllDocs.ListId
JOIN Webs
ON Webs.Id=AllLists.tp_WebId
 where 
 AllLists.tp_Title = 'Shared Documents'
 ORDER BY webs.title


The above query will return all documents including System Forms like "EditForm.aspx". In order to exclude these documents executue query below:



SELECT *
FROM AllDocs 
JOIN AllLists 
ON AllLists.tp_Id=AllDocs.ListId
JOIN Webs
ON Webs.Id=AllLists.tp_WebId
 where 
 AllLists.tp_Title = 'Shared Documents' and
 AllDOcs.Dirname not like '%/Forms%' and
 AllDocs.LeafName !='Forms'
 ORDER BY webs.title


To execute query on particular web add another condition in where clause "webs.Title='title of web'" as below:

SELECT *
FROM AllDocs 
JOIN AllLists 
ON AllLists.tp_Id=AllDocs.ListId
JOIN Webs
ON Webs.Id=AllLists.tp_WebId
 where 
 AllLists.tp_Title = 'Shared Documents' and
 AllDOcs.Dirname not like '%/Forms%' and
 AllDocs.LeafName !='Forms' and
 webs.title = 'Development'


To get detail about user contribution we can use query:




SELECT  count(*) as 'Number Of Documents & Items', UserInfo.tp_Title
FROM AllDocs, AllLists, Webs,UserInfo
where AllLists.tp_Id=AllDocs.ListId and
Webs.Id=AllLists.tp_WebId and
UserInfo.tp_SiteID = Webs.SiteId and
UserInfo.tp_ID = tp_Author and
webs.title = 'Development'
Group by UserInfo.tp_Title






Note:

  1. All these queries are completed unsupported.
  2. Direct SELECT statements against the database take shared read locks at the default transaction level so your custom queries might cause deadlocks and stability issues. 
To overcome stability issue
To overcome stability issue when we directly query database we can use With (NoLock).  

Select * From dbo.AllDocs With (NoLock)

Thursday, November 10, 2011

SharePoint 2010 Document ID in Word

What is required?
  • A content type in your content type hub
    the document id feature must be enabled in the CT hub
  • A site collection where the document if feature is enabled (original library).
  • A site collection where the document if feature is NOT enabled (will be used to create template)
  • Both site collections must be subscribing to the content type hub, so they inherit the content type.

Prepare your content type:
  • Make sure the “Document Id Service” feature is enabled in the content type hub.
  • In the content type hub, go to Site settings > site content types.Create a content type if you haven’t already done so.
  • Edit your content type, select “Information management policy settings”.
  • Click “Enable Labels”.
  • In the Label format input field, write {Document ID Value} and click OK.
  • Republish your content type (”Manage publishing for this content type”).
  • Run the following timer jobs from central Administration:
    • “Content Type hub”
    • “Content Type Subscriber – <your web application name>”.
Prepare your Microsoft Word Document Template

  • Create a document library in the site collection where there is no document id.Note: It is crucial that the “Document Id Service” feature is disabled. If your document template gets a document id here, it will be stuck in the template, and all documents based on that template will get the same document id as the template, which is obviously not what you want!
  • Go to library settings >> advanced settings, and enable content types.
  • Click “add from existing site content types” and add your content type.
  • Upload your Document template to this library.
  • Make sure that it is given the correct content type.
  • Open the Document template in MS Word from the library.
  • Place the cursor in the correct location.
  • Click Insert – Quick Parts – Document Properties – Label.
  • This will add label as shown below.
  • Add a Word macro to the template: Open the template in Word, click the Developer tab Macros – call it Reload and hit Create.
    Add following code inside “Reload”
Sub Reload()     ActiveDocument.ReloadEnd Sub
Add another macro “FileSave” and call Reload directly after save. This will make the Document ID show in the document.

    Sub FileSave()  
          Dialogs(wdDialogFileSaveAs).Show
          Reload
    End Sub

Add another macro “FileSaveAs” and call Reload directly after save. This will make the Document ID show in the document.

    Sub FileSaveAs()  
          Dialogs(wdDialogFileSaveAs).Show
          Reload
    End Sub

  • Save and close word.
  • Upload the template to the content type. In the content type hub, go to site settings – site content types, edit your content type, click advanced settings, add upload your template there.
 

Wednesday, October 19, 2011

Client Object Model Use Nesting Include To Improve Performance

In Client Object Model if we want to call LoadQuery method, we can specify multiple levels of properties to load. This will help in reducing the number of round trips to the server to retrieve the required Data. Now below example retrieve all lists and associated fields. This will print on console if list or field is hidden.


Download Working Example



 static void Main(string[] args)
        {
            ClientContext _context = new ClientContext("http://anmol-pc");
            
            IEnumerable<List> allLists = _context.LoadQuery(
                _context.Web.Lists.Include(
                    myList => myList.Title,
                    myList => myList.Hidden,
                    myList => myList.Fields.Include(
                        myField => myField.Title,
                        myField => myField.Hidden)));


            _context.ExecuteQuery();


            foreach (List myList in allLists)
            {
                Console.WriteLine("{0}List: {1}",
                    myList.Hidden ? "Hidden " : "", myList.Title);
                foreach (Field myField in myList.Fields)
                    Console.WriteLine("  {0}Field: {1}",
                        myField.Hidden ? "Hidden " : "",
                        myField.Title);
            }


            Console.ReadLine();
        }

Tuesday, October 18, 2011

Client Object Model Access Large Lists

If you want retrieve large list using Client Object Model. You can use the ListItemCollectionPosition class to implement paging list item retrieval according to the position of items relative to their collection. Use the RowLimit element to specify the number of items to return per page.


Download Working Example



 static void Main(string[] args)
        {
            ClientContext clientContext = new ClientContext("http://anmol-pc");


            List list = clientContext.Web.Lists.GetByTitle("Tasks");


            ListItemCollectionPosition itemPosition = null;
            while (true)
            {
                CamlQuery camlQuery = new CamlQuery();
                camlQuery.ListItemCollectionPosition = itemPosition;
                camlQuery.ViewXml = @"<View>
                                        <ViewFields>
                                          <FieldRef Name='Title'/>
                                        </ViewFields>
                                        <RowLimit>1</RowLimit>
                                      </View>";


                ListItemCollection listItems = list.GetItems(camlQuery);
                clientContext.Load(listItems);
                clientContext.ExecuteQuery();
                
                itemPosition = listItems.ListItemCollectionPosition;
                
                foreach (ListItem listItem in listItems)
                    Console.WriteLine("Item Title: {0}", listItem["Title"]);
                
                if (itemPosition == null)
                    break;
                
                Console.WriteLine(itemPosition.PagingInfo);
                Console.WriteLine();
            }


            Console.ReadLine();
        }

Monday, October 10, 2011

Safe Control Entries in Web Config File

There may come a situation where we want to add a custom new safe control entry in web.config file. 


Create New Empty SharePoint Project.


Add new "Empty Element" in project.


Select the newly created element and press F4 to open properties window.


Click ellipse button against the "Safe Control Entries" property as shown in below image.




The safe control entry dialog opens as shown below.




Click "Add" This will add a new safe control entry. Set properties 
Name: name of safe control entry
Assembly: A strong assembly name, such as: MyFirstProject.MyFirstAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=11e9bce111e9418c.
NameSpace: The fully-qualified namespace for the class/control
Safe: True



Add as many entries as you like.

SharePoint Using Custom Page with visual web part as Default View

Download Sample Project


We may encounter a situation where we want a custom view to show list and another web part on same page.  To achieve this on custom list definition created using visual studio, we need to follow the instructions listed below.

Create new "Empty SharePoint Project". Use trust level as "Deploy as Farm Solution".

Add new "List Definition" named "CustomListDefinition". Choose type of List Definition as "Custom List" or whatever you require.

Add new mapped folder "Template\Layouts"

Add new folder in Layouts folder named "CustomDefaultView". Add new Application page named "CustomListForm.aspx" inside this folder.

Add new Visual web part named "MyVisualWebpart". Design your visual web part as required.

Now edit "CustomListForm.aspx". Remove "AutoEventWireup" and "CodeBehind" attributes from Page directive. In code behind file inherit your page from "WebPartPage" instead of LayoupPageBase. 

Register "Microsoft.SharePoint.WebPartPages" namespace as 


<%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>


Register your visual part inside webpage as 

<%@ Register Tagprefix="MyWebParts" Namespace="CustomDefaultView.MyVisualWebpart" Assembly="$SharePoint.Project.AssemblyFullName$" %>

Inside PlaceHolderMain add this code


<MyWebParts:MyVisualWebpart runat="server" ID="SearchIndividualsWebPart" >

        </MyWebParts:MyVisualWebpart>

Add web part zone below the above line

 <WebPartPages:WebPartZone runat="server" FrameType="None" ID="Main" Title="loc:Main" />

Open "Schema.xml" file under "CustomListDefinition". Find View Element  as highlighted in below image

now replace SetupPath="pages\viewpage.aspx"  with 
SetupPath= "layouts\CustomDefaultView\CustomDefaultView.aspx".

We replaced "pages\viewpage.aspx" this with our custom layout page. So now the when list default view is created SharePoint will use our custom layout page.

Now we need to register our custom aspx page in web.config as safe control. For this create "Empty Element". Select empty element and press F4 to open properties window. In Safe Control Entries property dialog create your safe entry. For more information on this visit Safe Control Entries in Confog File.

Build your project and deploy. Now create new List from your custom definition. You will see visual web part over the list. 

Thursday, October 6, 2011

How to create Terms and Term Set programmatically (using code)?

How to create Terms and Term Set programmatically?

Add reference of "Microsoft.SharePoint.Taxonomy" assembly to your project. Include namespace "Microsoft.SharePoint.Taxonomy". And use the code as listed below.


 using (SPSite site = new SPSite("http://anmol-pc"))
            {
                TaxonomySession _TaxonomySession = new TaxonomySession(site);

                //Get instance of the Term Store 
                TermStore _TermStore = _TaxonomySession.TermStores["My Term Store"];

                //Now create a new Term Group
                Group _Group = _TermStore.CreateGroup("My New Group");

                //Create a new Term Set in the new Group
                TermSet _TermSet = _Group.CreateTermSet("My New Termset");

                //Add terms to the term set
                Term _term1 = _TermSet.CreateTerm("First Term", 1033);
                Term _term2 = _TermSet.CreateTerm("Second Term", 1033);
                Term _term3 = _TermSet.CreateTerm("Third Term", 1033);
                Term _term4 = _TermSet.CreateTerm("Last Term", 1033);

                //commit changes
                _TermStore.CommitAll();

            }

Tuesday, October 4, 2011

How to create SharePoint Views (SPView) Programmatically?

How to create SharePoint Views (SPView) Programmatically?

Please see below code:

SPWeb web = SPContext.Current.Web;
SPList list = web.Lists["My List"];

SPViewCollection allListViews = list.Views;
string viewName = "My New View";

StringCollection newviewFields = new StringCollection();
viewAllContactFields.Add("Edit");
viewAllContactFields.Add("LinkTitleNoMenu");
viewAllContactFields.Add("Field1");
viewAllContactFields.Add("Field2");
viewAllContactFields.Add("Field3");


string myquery = "<OrderBy><FieldRef Name='LinkTitle' Ascending='TRUE' /><FieldRef Name='EffectiveDate' Ascending='TRUE' /></OrderBy>";

allListViews.Add(viewName, newviewFields, myquery, 30, true, false);

Monday, October 3, 2011

Using People Picker control in edit web part Properties

How to use People Picker control in edit web part Properties?

First Create a "Empty SharePoint Project". Add New "Web Part" named "TestWebpart". Create a new webpart property in this, as shown below.

private string _ImpersonateUser = null;

[Personalizable(PersonalizationScope.Shared)]
[WebBrowsable(false)]
[System.ComponentModel.Category("Custom Properties")]
[WebDisplayName("Impersonate User")]
[WebDescription("User for impersonation")]
        public string ImpersonateUser
        {
            get
            {
                return _ImpersonateUser;
            }
            set
            {
                _ImpersonateUser = value;
            }
        }


Leave this as it is, we will come back to this again.


Add new class named "PeoplePickerEditor.cs" to this project. Your class should look like:

namespace SP.Anmol.Customization
{
    public class PeoplePickerEditor: EditorPart
    {
        private PeopleEditor _peoplePicker;

        public PeoplePickerEditor(string webPartID)
        {
            this.ID = "PeoplePickerEditor" + webPartID;
            this.Title = "Impersonate User";
        }


        protected override void CreateChildControls()
        {
            _peoplePicker = new PeopleEditor();
            _peoplePicker.ID = "pe1";
            _peoplePicker.AllowTypeIn = true;
            _peoplePicker.AllowEmpty = false;
            _peoplePicker.MultiSelect = false;
            _peoplePicker.Width = Unit.Pixel(250);
            _peoplePicker.SelectionSet = PeopleEditor.AccountType.User.ToString();

            Controls.Add(_peoplePicker);
        }


        public override bool ApplyChanges()
        {
            EnsureChildControls();
            TestWebpart.TestWebpart webPart = WebPartToEdit as TestWebpart.TestWebpart;
            if (webPart != null)
            {

                //set value of web part property
                webPart.ImpersonateUser = _peoplePicker.CommaSeparatedAccounts;
            }
            return true;
        }


        public override void SyncChanges()
        {
            EnsureChildControls();
            TestWebpart.TestWebpart webPart = WebPartToEdit as TestWebpart.TestWebpart;
            if (webPart != null)
            {

                //set value back to people picker control
                _peoplePicker.CommaSeparatedAccounts = webPart.ImpersonateUser;
            }
        }


    }
}

Now get back to web part code file. Implement the interface IWebEditable. Your web part code looks like:

namespace SP.Anmol.TestWebpart
{


    [Guid("84B6AF3B-9BA4-440A-AA4A-9657A5D67798")]
    public class TestWebpart : Microsoft.SharePoint.WebPartPages.WebPart, IWebEditable
    {
        public AnonymousUpload()
        {
            this.ExportMode = WebPartExportMode.All;
        }

      
        private string _ImpersonateUser = null;

      
        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(false)]
        [System.ComponentModel.Category("Custom Properties")]
        [WebDisplayName("Impersonate User")]
        [WebDescription("User for impersonation")]
        public string ImpersonateUser
        {
            get
            {
                return _ImpersonateUser;
            }
            set
            {
                _ImpersonateUser = value;
            }
        }

      
        protected override void CreateChildControls()
        {
                 //Place your logic here
        }


 

        //Methods to be implement for interface IWebEditable        EditorPartCollection IWebEditable.CreateEditorParts()
        {
            List<EditorPart> editors = new List<EditorPart>();
            editors.Add(new PeoplePickerEditor(this.ID));

            return new EditorPartCollection(editors); 
        }

        object IWebEditable.WebBrowsableObject
        {
            get { return this; }
        }


    }
}

Sunday, October 2, 2011

Client Object Model Exception Handling Scope

When we perform the operations on client side, we need to make a require to execute some operations that depend on the presence of an exception or not. We all have used try and catch blocks so far.
Lets take an example to understand: if you want to access a specific list in the SharePoint 2010 site in order to modify its property to allow Folder creation and versioning.

public void AllowFolderAndVersionCreation(string listName)
        {
            ClientContext context = new ClientContext("
http://anmol-pc");
            using (context)
            {
                List myList = null;
                try
                {
                    myList = context.Web.Lists.GetByTitle(listName);
                    context.Load(myList);
                    context.ExecuteQuery();

                }
                catch
                {
                    ListCreationInformation info = new ListCreationInformation();
                    info.Title = listName;
                    info.TemplateType = (int)ListTemplateType.GenericList;

                    myList = context.Web.Lists.Add(info);
                    context.ExecuteQuery();
                }
                finally
                {
                    myList.EnableVersioning = true;
                    myList.EnableFolderCreation = true;
                    myList.Update();
                    context.ExecuteQuery();
                }

            }
        }



Issue with Try and Catch Block
If you see the above i am first trying to get a list by Title in try block, and if list not found in catch block i tried to create a new list and Then in finally block i updated "EnableFolderCreation", "EnableVersioning" properties of list. To acheive this I require to send three commands to the server. So in SharePoint 2010 Client Object Model it is not convenient to use the try and catch blocks in the operations. The reason why is very easy to understand: we are in a client-side context and we have to pay attention to the number of queries to the server in order to execute our operations.

How ExceptionHandlingScope comes to rescue?
SharePoint 2010 Client object Model provides a class ExceptionHandlingScope for exception management. It exposes basic four methods StartScope(), StartTry(), StartCatch() and StartFinally().
Exception Handling scope begins with Startscope() and other three as three difrent sections inside

 public void AllowFolderAndVersionCreation(string listName)
        {
            var context = new ClientContext("
http://anmol-pc");
            var _ExceptionHandlingScope = new ExceptionHandlingScope(context);

            using (_ExceptionHandlingScope.StartScope())
            {
                using (_ExceptionHandlingScope.StartTry())
                {
                    // the code you want to try
                }
                using (_ExceptionHandlingScope.StartCatch())
                {
                    //code to run on error
                }
                using (_ExceptionHandlingScope.StartFinally())
                {
                    // the code that will execute finally
                }

           }
    }

lets place our example code inside this structure


public static void AllowFolderAndVersionCreation(string listName)
        {
            var context = new ClientContext("
http://anmol-pc");
            var _ExceptionHandlingScope = new ExceptionHandlingScope(context);
            List myList = null;

            using (_ExceptionHandlingScope.StartScope())
            {
                using (_ExceptionHandlingScope.StartTry())
                {
                    myList = context.Web.Lists.GetByTitle(listName);
                    context.Load(myList);
                    // context.ExecuteQuery() not required here
                }
                using (_ExceptionHandlingScope.StartCatch())
                {
                    ListCreationInformation info = new ListCreationInformation();
                    info.Title = listName;
                    info.TemplateType = (int)ListTemplateType.GenericList;
                    myList = context.Web.Lists.Add(info);
                    // context.ExecuteQuery() not required here
                }
                using (_ExceptionHandlingScope.StartFinally())
                {
                    myList.EnableVersioning = true;
                    myList.EnableFolderCreation = true;
                    myList.Update();
                    // context.ExecuteQuery() not required here
                }
            }
            context.ExecuteQuery();
        }


So you can notice that same thing can be acheived using ExceptionHandlingScope using less calls to the server.


Use of the "Try and catch" block:
  • Definetly more than 1 call
  • The debug operations are more complicated.
  • Easily understandable code as we are known to this type of code.
     
Use of the "ExceptionHandlingScope" class:
  • With one call to server we can acheive our goal.
  • The debug operations are much easier.
  • The code may not look that clear.

Client Object Model Add,Update and delete List Items

Creating, Updating, Deleting List items using Client Object Model, is almost similar to doing this using Server Object Model.

Create List Items
Create List item, set its properties and update the object.

string siteUrl = "http://anmol-pc";
ClientContext clientContext = new ClientContext(siteUrl);
SP.List oList = clientContext.Web.Lists.GetByTitle("Test");

ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation();
ListItem oListItem = oList.AddItem(itemCreateInfo);
oListItem["Title"] = "My First Item!";
oListItem["FirstName"] = "Anmol Rehan";

oListItem.Update();
clientContext.ExecuteQuery();
//-----------------------------------------------------------------------------------------------

Update List Items
To update List item, get the item by id using GetById() method. Then set the properties and update the object.

string siteUrl = "http://anmol-pc";
ClientContext = new ClientContext(siteUrl);
SP.List oList = clientContext.Web.Lists.GetByTitle("Test");

ListItem oListItem = oList.GetItemById(6);
oListItem["FirstName"] = "Anmol";
oListItem["LastName"] = "Rehan";
oListItem.Update();

clientContext.ExecuteQuery();

//-----------------------------------------------------------------------------------------------

Delete List Item
To update List item, get the item by id using GetById() method. Then call objects deletion method DeleteObject().

string siteUrl = "http://anmol-pc";
ClientContext = new ClientContext(siteUrl);
SP.List oList = clientContext.Web.Lists.GetByTitle("Test");

ListItem oListItem = oList.GetItemById(6);
oListItem.DeleteObject();
clientContext.ExecuteQuery();

Friday, September 30, 2011

Step By Step External Content Type and External List

Steps to create External Content Types using SQL Server Table.

Open Central Administration > Application Management > Manage Service Applications

Select Business Data Connectivity Sevice and click "Manage"

We first need to give permissions to the user. Click "Set Metadata Store Permission". This will open up a Modal Window. Add required user set all permisions and click "OK".


Open SharePoint Designer 2010.

Open your site in SharePoint Designer.

Click "External Content Type" under Left Navigation.Click "New External Content Type".




Enter "Name" and "Display name" of new content type.Select "Generic List" for "Office Item Type"


Under "External Content Type Operation" click on "Click here to discover external Data source and define operations".


Click Add Connection.


Select "SQL Server" for "Data Source Type" and Click Ok


Enter SQL Server and Database Detail and click "OK"


Under "Data Source Explorer" select Table


Right Click Table and click "Create All Operations". This will open up operation creation window. Click Next.


Under Properties check "Show in Picker" and click Next.


On this screen you can set "Filter" if so required. Click Finish. Save External Content Type.


Steps to create External List using External Content Types created above.

Right Click External Content Type and Click "External List".


This will open a window. Enter "Name" and "Description" of new external list name.

Thats all a new External List is created will all Operations.

Popular Posts