Pages

Saturday, June 21, 2014

SharePoint - Get Properties with OOB Tags

Recently, in my project a need arises to show the site description in header part of the custom master page. Sharepoint provides a tag named “ProjectProperty” to use site properties inside custom master page for user display.
<asp:Content ContentPlaceHolderId=”PlaceHolderPageTitle” runat=”server”>
SharePoint Tags
</asp:Content>

Site Title: <SharePoint:ProjectProperty Property=”Title” runat=”server”/>
Site Description : <SharePoint:ProjectProperty Property=”Description” runat=”server”/>

Other SharePoint Properties are listed below which avoids the customization.
<SharePoint:ListProperty Property=”Title” runat=”server”/>
<SharePoint:ListItemProperty Property=”Title” runat=”server”/>
<SharePoint:ListFormPageTitle runat=”server”/>

Place this tag inside the master page or in page layouts and see the changes. 

Monday, June 16, 2014

Create HTTPModule Step Wise - Explained with CustomAccessDenied Page in SharePoint 2013

This post guides not only how to create a HTTPModule but also helps for further steps for my post on Custom Access Denied Page in SharePoint 2013.

For this you need to do three steps,

Step 1:- Add a new class file and extend that one from IHTTPModule. Then copy below code to your .cs file.

public class CustomAccessDenied : IHttpModule
    {
        public void Init(HttpApplication app)
        {
            app.PreRequestHandlerExecute += new EventHandler(app_PreRequestHandlerExecute);
        }
        void app_PreRequestHandlerExecute(object sender, EventArgs e)
        {
            HttpContext context = HttpContext.Current;
            string str = Path.GetFileName(new Uri(context.Request.Url.AbsoluteUri).LocalPath);

            if (str.ToLower().Equals("accessdenied.aspx"))
            {
                string strSourceURL = context.Request.RawUrl.ToString();
                strSourceURL = strSourceURL.ToLower().Replace("accessdenied", "customaccessdenied");
                context.Response.Redirect(strSourceURL , true);
            }
        }

        public void Dispose()
        {
        }
    }

Step 2:- Now you need to enter in the Modules section in your web.config file. I would recommend to go with IIS UI. For this, select your website and find the Modules Section as below.




Step 3:- Click on this Modules, and in the right section you will find Add Managed Module Option. Click on that and add Name and Type as below.

For Eg:- Name as CustomAccessDenied
Type as {Your_NAMESPACE}.CustomAccessDenied, {Your_NAMESPACE} ,Version=1.0.0.0, Culture=neutral, PublicKeyToken={Value}

Click Ok.




If this .cs file is not in your existing solution and created separate C# Library Project, need to make sure that you have entry in SafeControls of your web.config file. I would recommend here also not to enter value manually but through VS. Go to Package in your VS Solution and Add the Assembly. Select as YES under safe controls  column. This way the value get enters in your web.config file.






Saturday, June 14, 2014

SharePoint 2013 June 2014 Cumulative Updates


     Issues that this cumulative update package fixes

  • When a SharePoint 2013 workflow sends an email message, the workflow context Current Item URL does not have the complete URL.
  • Assume that you publish an InfoPath form that contains an enhanced rich text column that immediately follows a multiple-selection choice column to a SharePoint list. When you browse to this SharePoint list by using a web browser other than Internet Explorer, the rich text column is always empty.

Thursday, June 12, 2014

SharePoint - Create and Delete Alerts on List Programatically

Generally when we require any action need to happen if we do any operation on List Items, we go with List Item Event Receivers. But if you have a requirement where just a notification need to go to some user with items added/changed, you can go with ALERTS in SharePoint which is OOB Feature.



In order to setup this on List, we dont have any way of declarative syntax[XML through Schema.xml]. We need to set this either Manually or through Programatically.

Let me explain you how to create and delete alerts on SharePoint List Programatically. In Google, you will able to get easily about how to Create alerts but I think I didn't find much info on Delete alerts. For this I will explain you both in below:-

Create Alerts:-

 private static void CreateAlert(SPUser user, SPList list)
        {
            SPAlert newAlert = user.Alerts.Add();
            //Here kept Alert Name same as List Name, but can give any Name
            newAlert.Title = list.Title;
            newAlert.AlertType = SPAlertType.List;
            newAlert.List = list;
            newAlert.DeliveryChannels = SPAlertDeliveryChannels.Email;
            newAlert.EventType = SPEventType.Add;
            newAlert.AlertFrequency = SPAlertFrequency.Immediate;
           //If we do False in below line, it will not send email notification to user when Alert has been sent.
            newAlert.Update(false);

        }

Delete Alerts:-

  private static void DeleteExistingAlert(SPWeb web, SPUser User, string strListTitle)
        {
            //Using this As we cant Delete in the Loop of Web.Alerts
            var col = new List<string>();
            foreach (SPAlert alert in web.Alerts)
            {
               // If You want to remove particular Alert, if not remove this If Condition
                if (alert.List.Title.Equals(strListTitle) 
                    && alert.Title.ToLower().Equals(strListTitle.ToLower()))
                {
                    col.Add(alert.ID.ToString());
                }
            }
            // If we use Delete Alert in above If Condition only, will get an error as Collection Cant be Modified
            foreach (var item in col)
            {
                web.Alerts.Delete(new Guid(item));
            }
        }

Once it gets Created, in order to verify you cant check in the same place of List All Items page. For this you need to go to Site Settings --> Click On User Alerts





Happy Programming..!

Tuesday, June 10, 2014

SharePoint Programming - Dont set or use AllowUnsafeUpdates Instead Use ValidateFormDigest

Generally in your daily SharePoint Programming, you may come across issue of 

The security validation for this page is invalid. Click Back in your Web browser, refresh the page, and try your operation again

To Fix this issue, if you googled many places it will be suggested as to set AllowUnsafeUpdates = true or false.

If you do above, it will not throw error and resolve the issue but it is not the right way. By setting AllowUnsafeUpdates you are allowing for security threats.

The best way is to use SPUtility.ValidateFormDigest()
  • In your Master Page or in your aspx page, place below tag
         <sharepoint:formdigest id=”FormDigest1″ runat=”server” />
  • Now in your .cs file, in your init method or before you use the SPSecurity.RunWithElevatedPrivileges, place below code line.
protected override void OnInit(EventArgs e)
{
if (Page.IsPostBack)
{
SPUtility.ValidateFormDigest();
base.OnInit(e);
}
}

                                          [OR]

SPUtility.ValidateFormDigest();
SPSecurity.RunWithElevatedPrivileges(delegate()
{....

Thursday, June 5, 2014

SharePoint List - Re Order Items with OOB Feature


This is a very common request from client when we do create them custom SharePoint lists. “How can I re-order the list?” In fact, you could create an extra column in your custom list via SharePoint Designer (SPD) or via your internet browser. Add a new column and have it as a “Number” field, name it “Display Order” and start identifying the order of each list item. Well, but we are going to use another way. The little trick I am going to show works perfectly in MOSS 2007, SharePoint 2010 and 2013.

For this, we can go with One of the SharePoint hidden pages which resides in Layouts Folder.  reorder.aspx page which will allows to re-order your list items. 

Specify {SiteUrl}/_layouts/Reorder.aspx?List={ListId}

Now you will see the List Items Displaying with its Only Title and a dropdown Column like below.

In SP 2013,

In SP 2010,


Once you the Order, it will get effected the List. But when you see in UI, you might still see the Items not displayed in order what you did in earlier step. For this, as by default in All Items Page, items are ordered by ID it will consider that one. Here I want to point that there is one Field named as ORDER which will be available as OOB field in any List and this will be in Hidden State.

Make this Hidden Field as Visible, using Powershell or if custom list adding in your schema.xml itself.

Using Powershell,

# Change List Schema to unhide order field.
$siteUrl = "yourSiteUrl;
$listTitle = "yourListTitle";
$site = Get-SPSite -Identity $siteUrl;
$web = $site.OpenWeb();
$list = $web.Lists[$listTitle];
$field=$list.Fields["Order"];
$field.SchemaXml=
$field.SchemaXml.Replace("Hidden=""TRUE""","Hidden=""FALSE""");
Write-Host "-------------------------------------"
Write-Host "Order field is set to visible in
list :  " $list.Title -foregroundcolor Green -nonewline
Write-Host " in the site  : " $site.Url -foregroundcolor Green
Write-Host "-------------------------------------"
$web.Dispose();
$site.Dispose();



If you are having your list in the visual studio solution you can add
<Field ID="{ca4addac-796f-4b23-b093-d2a3f65c0774}" ColName="tp_ItemOrder" RowOrdinal="0" Name="Order"
DisplayName="Order" Type="Number" Hidden="FALSE" SourceID="http://schemas.microsoft.com/sharepoint/v3"
StaticName="Order" FromBaseType="TRUE" /> 

to the <Fields> collection of the Schema.xml

Now go to your respective view settings and change the Sort by ORDER Column


Now go to your list and view the Items, you will observe all Items are in ORDER wise which you specified in ReOrder Page.

This way we can understood, where lot of things we can do able without coding/logic in SharePoint if we are in the SharePoint OCEAN...!

Wednesday, June 4, 2014

SharePoint Object Model Best Practices - Working with Lists and Folders

1.      Use SPList.GetItems instead of SPList.Items

Apply Filters, specify only fields needed to make the query more efficient. Apply pagination in increments of no more than 2000 items.
SPQuery query = new SPQuery();
SPListItemCollection spListItems ;
string lastItemIdOnPage = null; // Page position.
int itemCount = 2000

while (itemCount == 2000)
{
    // Include only the fields you will use.
    query.ViewFields = "<FieldRef Name=\"ID\"/><FieldRef Name=\"ContentTypeId\"/>";  
    query.RowLimit = 2000; // Only select the top 2000.
    // Include items in a subfolder (if necessary).
    query.ViewAttributes = "Scope=\"Recursive\"";
    StringBuilder sb = new StringBuilder();
    // To make the query order by ID and stop scanning the table, specify the OrderBy override attribute.
    sb.Append("<OrderBy Override=\"TRUE\"><FieldRef Name=\"ID\"/></OrderBy>");
    //.. Append more text as necessary ..
    query.Query = sb.ToString();
    // Get 2,000 more items.

    SPListItemCollectionPosition pos = new SPListItemCollectionPosition(lastItemIdOnPage);
    query.ListItemCollectionPosition = pos; //Page info.
    spListItems = spList.GetItems(query);
    lastItemIdOnPage = spListItems.ListItemCollectionPosition.PagingInfo;
    // Code to enumerate the spListItems.
    // If itemCount <2000, finish the enumeration.
    itemCount = spListItems.Count;
}

2.      Instead of using SPList.Items.GetItemById, use SPList.GetItemById(int id, string field1, params string[] fields). Specify the item identifier and the field that you want.

3.      Use SPList.ItemCount instead of SPList.Items.Count.

4.      Use SPList.GetItemByUniqueId(System.Guid) instead of SPList.Items[System.Guid]

5.      Use SPList.GetItemById(System.Int32) instead of SPList.Items[System.Int32]

6.      Use SPList.GetItemById(System.Int32) instead of SPList.Items.GetItemById(System.Int32)

7.      Use SPWeb.Lists[GUID] or SPWeb.GetList(strURL) is preferable to using SPWeb.Lists[strDisplayName].

·         Using the GUID is preferable because it is unique, permanent, and requires only a single database lookup.

·         The display name indexer retrieves the names of all the lists in the site and then does a string comparison with them.


8.      Use DeleteByID method instead of Delete()

SPSite site = new SPSite("site url");
SPWeb web = site.OpenWeb();
SPList list = web.Lists["custom list name"];
SPListItem item = list.GetItemById(1);
SPFile file = web.GetFile(item.Url);
SPFileVersionCollection collection = file.Versions;
ArrayList idList = new ArrayList();
foreach (SPFileVersion ver in collection)
{
  idList.Add(ver.ID);
}
foreach (int verID in idList)
{
try
{
  collection.DeleteByID(verID);
}
catch (Exception ex)
{
  MessageBox.Show(ex.Message); 
}

}

Monday, June 2, 2014

Bug in SharePoint 2013 for Public Facing Sites - Popup message to Run ActiveX Controls

Recently in one of my SharePoint 2013 project which is Public Facing Site faced an issue of "The Web site wants to run the following add-on: 'Name ActiveX Control".


The SharePoint plugin that those web sites try to load is only useful for collaboration but not for public facing web sites.



Issue in Default SharePoint Javascript Files:-
The actual code will look like this in init.js file, which can be found inTemplates\Layouts\15\1033


function ProcessImn() {
if (EnsureIMNControl() && IMNControlObj.PresenceEnabled) { imnElems=document.getElementsByName("imnmark"); imnElemsCount=imnElems.length; ProcessImnMarkers(); }
}

function ProcessImnMarkers() {
for (i=0;i<imnMarkerBatchSize;++i) { if (imnCount==imnElemsCount) return; IMNRC(imnElems[imnCount].sip,imnElems[imnCount]); imnCount++; } setTimeout("ProcessImnMarkers()",imnMarkerBatchDelay);
}

Work Around Solution:-
Two ways you can go, one is

Comment all the above lines.Search for the function ProcessDefaultOnLoad() in the init.js file. Comment the ProcessImn() function. Now execute. Warning will no more display.


The other way and Preferred method will be,
Add below two Javascript Lines in your master Page,


function ProcessImn() {}
function ProcessImnMarkers() {}


Now for end user will not popup the The Web site wants to run the following add-on: 'Name ActiveX Control"





for more info:- http://support.microsoft.com/kb/931509