Thursday, December 10, 2015

SharePoint Custom ULS Logging

Here is a working code snippet (C# class) to write custom errors or logs to ULS log.

using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using System.Collections.Generic;

namespace CustomLogging
{
    class LoggingService : SPDiagnosticsServiceBase
    {
        public static string diagnostcAreaName = "CustomLogging";
        public static string errorPrefix = "CustomLogging: ";

        private LoggingService()
            : base("CustomLogging Logging Service", SPFarm.Local)
        {
        }

        protected override IEnumerable<SPDiagnosticsArea> ProvideAreas()
        {
            List<SPDiagnosticsArea> areas = new List<SPDiagnosticsArea>
            {
                new SPDiagnosticsArea(diagnostcAreaName, new List<SPDiagnosticsCategory>
                {
                    new SPDiagnosticsCategory("CustomLogging", TraceSeverity.Unexpected, EventSeverity.Error)
                })
            };

            return areas;
        }

        public static void LogError(string message, EventSeverity eventSeverity)
        {
            SPSecurity.RunWithElevatedPrivileges(delegate ()
            {
                SPDiagnosticsService diagnosticService = SPDiagnosticsService.Local;
                diagnosticService.WriteTrace(0, new SPDiagnosticsCategory(diagnostcAreaName, TraceSeverity.Monitorable, eventSeverity),
                   TraceSeverity.Monitorable, errorPrefix + "{0}", new object[] { message });
            });

        }
    }
}

An entry to ULS logs can be written using the below snippet with make use of the above class.
try
{
    //Business logic
}
catch (Exception ex)
{
    LoggingService.LogError(ex.Message + " " + ex.StackTrace + "\r" + ex.Source, (EventSeverity)EventSeverity.Information);
}

Monday, August 3, 2015

SharePoint Cross Site Lookup Field

Can we create a cross site lookup field?
Yes of course, it can be. Thought it is not possible OTB, a simple trick will do this.

Scenario: Creating a cross site lookup field between the two peer web sites or sub web sites under a same site collection.
Example: Create a lookup field between two sites http:/sitecollection/webA & http://sitecollection/webB

The trick is just to set the lookup field webId with the target list webId.
Code snippet to create cross site lookup field programatically:
private bool CreateCrossSiteLookupField(SPWeb sourceWeb, SPWeb targetWeb, string sourceListTitle, string targetListtitle, string lookUpFieldName, string lookupValueColumn, bool isRequiredField)
{
    ////Get the source and target lists 
    SPList sourceList = sourceWeb.Lists.TryGetList(sourceListTitle);
    SPList targetList = targetWeb.Lists.TryGetList(targetListtitle);

    if (null != sourceList && null != targetList)
    {
        ////Add a lookup field to source list with target list as lookup list
        sourceList.Fields.AddLookup(lookUpFieldName, targetList.ID, isRequiredField);

        ////Get the created lookup field from source list 
        SPFieldLookup lookupField = (SPFieldLookup)sourceList.Fields[lookUpFieldName];

        ////Set the lookup field's webID with target list webId
        lookupField.LookupWebId = targetList.ParentWeb.ID;

        ////Set the lookup field's display field 
        lookupField.LookupField = targetList.Fields[lookupValueColumn].InternalName;

        ////Finally update the lookup field
        lookupField.Update();
    }
    return true;
}
Code snippet to create cross site lookup field with PowerShell:
Add-PSSnapIn "Microsoft.SharePoint.Powershell"

#Get the webs and lists
$webA = Get-SPWeb http://siteurl/webA/
$webB = Get-SPWeb http://siteurl/webB/
$sourceList = $webA.Lists.item("SourceList")
$targetList = $webB.Lists.item("TargetList")

#Add a lookup field to source list with target list as lookup list
$sourceList.fields.AddLookup("LookupFieldName", $targetList.id, "true")

#Get the created lookup field from source list
$lookupField = $sourceList.Fields["LookupFieldName"]

#Set the lookup field's webID with target list webId
$lookupField.LookupWebId = $targetList.ParentWeb.ID

#Set the lookup field's display field
$lookupField.LookupField = $targetList.Fields["Title"].InternalName
$lookupField.Update();

Saturday, August 1, 2015

JQuery Set Checkbox checked vs RadioButton checked

It is a common mistake or confusion on how to set value of Checkbox vs. RadioButton to checked using JQuery. Devs often use .attr method to set the value for both checkbox and radiobutton controls. Note: Using .attr on checkbox is deprecated.

However the right way to set checkbox checked is by using .prop method and radiobutton checked is by using .attr method respectively.

CHECKBOX:
$("#checkBoxCtrlId").prop("checked", true);
$("#checkBoxCtrlId").prop("checked", false);
RADIOBUTTON:
$("#radioButtonCtrlId").attr("checked", true);
$("#radioButtonCtrlId").attr("checked", false);
However same attribute will be used to check either checkbox or radiobutton is checked.
$('.checkBoxCtrlId').is(':checked');
$('.radioButtonCtrlId').is(':checked');

How to View SharePoint App Web Site Contents

I know most of the SharePoint App developers or users would definitely look for site contents of an App Web and List Settings in an App Web. But it turns out that there is no direct way to access the App Web Contents similar to a regular site's Site Contents.

However I have a trick to see the app web site contents by typing in the below URL as a suffix to your app web URL.
/_layouts/15/mcontent.aspx

Example: http://app-web-url/_layouts/15/mcontent.aspx

It lists all the available lists/libraries in the app web. But you will notice that the way the contents are listed is different from the regular Site Contents and by clicking on the list/library will redirects to list/library settings instead actual list. On the settings page you see the List Name which redirects to the actual list content.

Hope this post is helpful...

Thursday, July 16, 2015

How to Get Outgoing E-Mail Settings Programatically

Sometimes it might be needed to get the Web Application outgoing emails settings programatically.
The below code snippet gives all the settings including Outbound SMTP server, From address, Reply-to address and Character set information.
using (SPSite site = new SPSite("http://siteurl"))
{
    SPWebApplication webApp = site.WebApplication;
    string outboundSMTPServer = webApp.OutboundMailServiceInstance.Parent.Name;
    string fromAddress = webApp.OutboundMailSenderAddress;
    string replyToAddress = webApp.OutboundMailReplyToAddress;
    int characterSet = webApp.OutboundMailCodePage;
}
Web application outgoing email settings can also be updated programatically as below.
using (SPSite site = new SPSite("http://siteurl"))
{
    string outboundSMTPServer = "Outbound SMTP server";
    string fromAddress = "From address";
    string replyToAddress = "Reply-to address";
    int characterSet = 65001; //Character set code

    SPWebApplication webApp = site.WebApplication;
    webApp.UpdateMailSettings(outboundSMTPServer,fromAddress,replyToAddress,characterSet);
}
Similarly we can get & set the Global outgoing email settings as below.
GET:
var globalAdmin = SPAdministrationWebApplication.Local;
var outboundSMTPServer = globalAdmin.OutboundMailServiceInstance.Parent.Name;
var fromAddress = globalAdmin.OutboundMailSenderAddress;
var replyToAddress = globalAdmin.OutboundMailReplyToAddress;
var characterSet = globalAdmin.OutboundMailCodePage;
SET:
string outboundSMTPServer = "Outbound SMTP server";
string fromAddress = "From address";
string replyToAddress = "Reply-to address";
int characterSet = 65001; //Character set code
var globalAdmin = SPAdministrationWebApplication.Local;
globalAdmin.UpdateMailSettings(outboundSMTPServer, fromAddress, replyToAddress, characterSet); 

Wednesday, July 15, 2015

SharePoint AutoComplete Lookup Field with JQuery

Created a Custom SharePoint Lookup field that offers new functionalities to default SharePoint lookup field by allowing Auto Complete or Type Ahead search functionality with Contains CAML query.
Below is a few of the features offered by AutoComplete Lookup field over standard SharePoint Lookup field:
  • Auto Complete or Type Ahead lookup search (queries after each typing)
  • OTB SharePoint Lookup Dropdown look and feel for the results 
  • Proper validations
  • Searches the lookup keyword with Contains CAML query
  • Configurable for No.of results to be displayed
  • Configurable for No.of characters to start the auto complete search
Limitations:
  • It cannot be multi-valuated
  • Only one AutoComplete Lookup field is allowed per list
  • The target lookup field is frozen and always the Title field
The project is packaged as a Windows installer using the SharePoint Solution installer; to install, simply run setup.exe. The software is available on CodePlex here.
AutoComplete Lookup - Create Column
AutoComplete Lookup - Configure Column
AutoComplete Lookup - Results Display

Please do let me know if you find any issues or bugs or useful enhancement that could be added.

Tuesday, July 14, 2015

Create Folder in SharePoint using REST

Here is the quick code snippet to create a folder in a Library or List using SharePoint REST.
var docLibraryName = "DocLibrary";
var folderName = "FolderTest";
var appWebUrl = "http://weburl";

var folderRelativePath = ''; //Populate with the path after folder creation to add files to folder
var folder = CreateFolder(appWebUrl, docLibraryName, folderName);
if (folder && folder.statusText && folder.statusText == 'Created') {
    if (folder.responseJSON && folder.responseJSON.d) {
        folderRelativePath = folder.responseJSON.d.ServerRelativeUrl;
    }
}

////Method to create a folder and returns folder object with metadata
CreateFolder = function (url, libraryname, foldername) {
    var folderRelPath = libraryname + '/' + foldername;
    var requestUri = url + "/_api/web/folders";
    var data = $.ajax({
        url: requestUri,
        type: "POST",
        async: false,
        data: JSON.stringify({ '__metadata': { 'type': 'SP.Folder' }, 'ServerRelativeUrl': folderRelPath }),
        headers: {
            "accept": "application/json; odata=verbose",
            "content-type": "application/json; odata=verbose",
            "X-RequestDigest": $("#__REQUESTDIGEST").val()
        },
        success: function (data) {
            alert('Folder created successfully.');
            return data;
        },
        error: function (error) {
            alert('Folder creation failed!');
            //alert(JSON.stringify(error));
            return data;
        }
    });
    return data;
}
Reference:
SharePoint REST Create Folder in Library
Creating Folder in Library using REST
REST Create Folder in SharePoint Library

Monday, July 13, 2015

SharePoint ListItem Update vs SystemUpdate vs UpdateOverwriteVersion

Here is a simple table format to explain the differences among Update vs SystemUpdate vs UpdateOverwriteVersion vs SystemUpdate(true). 

This information is pretty much useful to look at the differences between the following SPListItem methods when working with event receivers or workflows.


Update()
SystemUpdate()
SystemUpdate(true)
UpdateOverwriteVersion()
Updates the item in the database
ü  
ü  
ü  
ü  
Creates a new version
ü  
û   
ü  
û   
Updates the Modified and Modified By values
ü  
û   
û   
ü  

How to update Modified By field in a SharePoint list item programatically

While adding/updating a list item using SPSecurity.RunWithElevatedPrivileges with administrator privileges, Created By / Modified By fields are set to System Account as the piece of code is executed with Application Pool account context.

But in an ideal case Created By / Modified By fields should have the original user who actually did the modification. In order to achieve this Created By / Modified By fields needs to be updated at the time of inserting / updating list item.

The catchy point here is to get the Current User out of the SPSecurity.RunWithElevatedPrivileges scope because within the scope it is always System Account as mentioned.

The below code snippet works as as explained above:
////Get the current user out of the SPSecurity.RunWithElevatedPrivileges scope
SPUser currentUser = SPContext.Current.Web.CurrentUser;

SPSecurity.RunWithElevatedPrivileges(delegate()
{
    using (SPSite newSite = new SPSite("http://siteurl"))
    {
        using (SPWeb newWeb = newSite.OpenWeb())
        {
            SPList list = newWeb.Lists.TryGetList("List Title");
            if (null != list)
            {
                bool isNewItem = true; //Adding or Updating item
                SPListItem item = list.GetItemById(1);
                if (isNewItem)
                {
                    item["Author"] = currentUser;
                }
                item["Editor"] = currentUser;

                item.Update();
            }
        }
    }
});

Reference:
How to update Modified By field programatically
How to update Created By field programatically
SharePoint List Item update Modified By field programatically
SharePoint List Item update Created By field programatically

Monday, March 2, 2015

How to Check Whether Service Application is Running using PowerShell

For one of my requirements, I wanted to Start/Stop the Search Service Application through PowerShell.
Before executing Start/Stop operations, I wanted to check if Search Service Application is running or not. Based on the state i would start or stop the service accordingly.

I have used the below PowerShell script to check whether a Search Service Application is running or not. Then Start/Stop the service accordingly.
$ServiceName = "state service"
$serviceApp = Get-SPStateServiceApplication -Identity $ServiceName
Write-Host -ForegroundColor DarkGray "Checking if "  $ServiceName  " instance is Online"
if($serviceApp.Status -ne "Online")
{
   Write-Host -ForegroundColor Yellow "Starting " $ServiceName " instance"
   Start-SPStateServiceApplication -Identity $stateServiceName
   While ($serviceApp.Status -ne "Online")
   {
       Start-Sleep -s 5
   }
   Write-Host -ForegroundColor Yellow $ServiceName " instance is started"
}
else
{
   Write-Host -ForegroundColor Green $ServiceName " instance is already running"
   Stop-SPStateServiceApplication -Identity $ServiceName
}
The same script can be used to check if any of the service applications is running by providing the service application name against the variable $ServiceName. The scripts executes against the provided service application and checks if it is running or not.

Friday, February 27, 2015

Unable to Create a Search Managed Property

While i was trying to create a new Search Managed Property against a crawled property using either PowerShell or UI I am gettin an error "There was an internal problem connecting to or querying the database".

I spent enough time in figuring out the problem. At last I have identified that the Search Service Application doesn't have a valid Administrator who has access to SSA database.
Note: The mappings will be created in DB MSSManagedProperties table.

Administrator can be added by going to Central Administration --> Manage Service Applications --> Select Search Service Application --> Click on Administrators (Ribbon) --> Add an user with Full control (who has proper privileges to DB).

This process will provide the needful privileges to SSA to add the new search managed properties.

Why Office 365 APIs

What is Office 365 APIs:
Office 365 APIs are collections of tools that simplify building Office’s cloud services into your apps.

The Office 365 APIs are REST services that provide access office 365 services like mail, calendars, and contacts from Exchange Online; files and folders from SharePoint Online and OneDrive for Business; users and groups from Azure AD.

Why Office 365 APIs & Advantages of Office 365 APIs:
·    Extend Office everywhere.
·    General availability of new Office 365 APIs for mail, files, calendar and contacts.
·    Build on an Open Platform - Apps for mobile, web, and desktop.
·    Visibility for developers’ apps through the new Office 365 app launcher.
·    Office 365 and Azure Active Directory as hubs where apps store files and users build collaborative relationships with others.
·    Building the Office 365 platform on open standards such as HTML5, REST web services, and OAuth.
·    Microsoft is providing SDKs for common platforms to access o365 REST APIs includes mobile SDKs for native app development.
·    Microsoft is exposing O365 to apps by making call against REST APIs.
·    REST and OData are used to transfer data, JSON for data abstraction.
·    Authenticate users using single sign-on with Azure Active Directory (Azure AD) to access all office 365 services.
·    OAuth version 2.0 for authentication that means application does not have to handle or store user credentials and makes it possible to request tightly scoped permissions to user data.
·    Automatically determine URL of O365 services using discovery capability.
·    Office 365 App also supports multi tenants.
·    Support rich query filters.


Tuesday, January 6, 2015

How to Check Group Exists in SharePoint Programatically

I was trying to check if specific group exists in SharePoint web. I couldn't find any OTB API method to achieve this.
Hence I am using the below LINQ statement to check whether group exists in a web.
string groupName = "MyGroupName";
SPWeb web = SPContext.Current.Web;
 //Check if group exists in the web
 if (web.Groups.OfType<SPGroup>().Count(g=>g.Name.Equals(groupName, StringComparison.InvariantCultureIgnoreCase))>0)
 {
     //Get the SPGroup by group name if exists
     SPGroup group = web.Groups[groupName];
 }