Category: SharePoint Development

SharePoint Development

Create custom verbs for SharePoint 2010 web parts

The web part verbs are the menus items (like Minimize, Close etc) appears when we click the Edit option in web parts. The SharePoint web part framework exposes one of the propery called WebPartVerbCollection. This is very flexible which allows us to add our own items (custom web part verbs) to the web part collection.

The whole idea is to override the getter of WebPartVerbCollection property, add custom verb items and return it back to web part framework. The following code snippet covers the same.

using System;
using System.ComponentModel;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;

namespace WP_Verb_Sample.VisualWebPart1
{
    [ToolboxItemAttribute(false)]
    public class VisualWebPart1 : WebPart
    {
        // Visual Studio might automatically update this path when you change the Visual Web Part project item.
        private const string _ascxPath = @"~/_CONTROLTEMPLATES/WP_Verb_Sample/VisualWebPart1/WPVerbSample.ascx";

        protected override void CreateChildControls()
        {
            Control control = Page.LoadControl(_ascxPath);
            Controls.Add(control);
        }

        public override WebPartVerbCollection Verbs
        {
            get
            {
                //return base.Verbs;

                WebPartVerb Verb1 = new WebPartVerb("Verb Inovking Server Handler", 
                                              new WebPartEventHandler(CustomVerbEventHandler));
                Verb1.Text = "Verb Inovking Server";
                Verb1.Description = "This verb is used to demonstrate the server-side WP verb operation";


                WebPartVerb Verb2 = new WebPartVerb("Verb Inovking Client Script", 
                                              "Javascript:alert("Hi from Client");");
                Verb2.Text = "Verb Inovking client script";
                Verb2.Description = "This verb is used to demonstrate the client-side WP verb operation";


                WebPartVerb[] addedVerbs = new WebPartVerb[] { Verb1, Verb2 };

                return new WebPartVerbCollection(base.Verbs, addedVerbs);


            }
        }




        protected void CustomVerbEventHandler(object sender, WebPartEventArgs args)
        {
            // any arbitrary operation can be performed here
           
            
        }
    }
}

The web part verbs can invoke both a client-side action and a server-side handler as well. The above sample covers both the scenarios. Once you compile and deploy this code, you’d see your custom webpart verb.

clip_image002

 Subscribe to my blog

Consuming a WCF Service from SharePoint 2010 web part

In this article I’d cover the steps to be followed to consume a IIS 7.5 hosted WCF service from SharePoint 2010 visual web part.

Step1.

Make sure that web part project has references to the following assemblies

System.ServiceModel.dll

System.ServiceModel.Web.dll

System.ServiceModel.dll

System.Runtime.Serialization.dll
Step2
 Import the following namespace in the code-behind of the web part
using System.ServiceModel;
using System.Runtime.Serialization;
Step3
The next step is to generate the client proxy for the WCF service. You can use ‘Add Service Reference’ option in Visual Studio 2008/10 or leverage 
the command line utility svcutil.exe. Personally I’d prefer the svcutil.exe tool for many reasons.

svcutil /config:output.config   /out:CreditCardService.cs /tcv:Version35 /n:*,SandboxVisualWP.VisualWebPart1 http://localhost:1414/CreditCardService/ValidationService.svc

/config – specifies the name of the client configuration file to be generated

/output – specifies the name of the client proxy file (.cs file)

/tcv – specifies the .net framework version for the client proxy

/n:* – specifies the namespace for the client proxy. This is a significant factor that needs to be considered. Please make sure that the namespace of the proxy file matches with the namespace of visual web part project.

Step4

The generated client configuration file looks like the following

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_IVadlidationService" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                    maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
                    allowCookies="false">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <reliableSession ordered="true" inactivityTimeout="00:10:00"
                        enabled="false" />
                    <security mode="Message">
                        <transport clientCredentialType="Windows" proxyCredentialType="None"
                            realm="" />
                        <message clientCredentialType="Windows" negotiateServiceCredential="true"
                            algorithmSuite="Default" />
                    </security>
                </binding>
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://lt012464.abc.com:1414/CreditCardService/ValidationService.svc"
                binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IVadlidationService"
                contract="SandboxVisualWP.VisualWebPart1.IVadlidationService"
                name="WSHttpBinding_IVadlidationService">
                <identity>
                    <dns value="localhost" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

If the web part is of type farm-solution copy the contents of this configuration file and place it inside the System.ServiceModel section of the web.config file

Step5

My generated proxy file looks like the following. If you are using visual studio 2010 to create a proxy, it will always create a client proxy .cs file targetted to .NET Framework 4.0

//——————————————————————————

// <auto-generated>

//     This code was generated by a tool.

//     Runtime Version:4.0.30319.269

//

//     Changes to this file may cause incorrect behavior and will be lost if

//     the code is regenerated.

// </auto-generated>

//——————————————————————————

namespace SandboxVisualWP.VisualWebPart1

{

   
   
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]

    [System.ServiceModel.ServiceContractAttribute(ConfigurationName="SandboxVisualWP.VisualWebPart1.IVadlidationService")]

    public interface IVadlidationService

    {

       
        [System.ServiceModel.OperationContractAttribute(Action=http://tempuri.org/IVadlidationService/GetCountry,

          ReplyAction="http://tempuri.org/IVadlidationService/GetCountryResponse")]
        string GetCountry(int value);
    }
    
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
    public interface IVadlidationServiceChannel : SandboxVisualWP.VisualWebPart1.IVadlidationService, System.ServiceModel.IClientChannel
    {
    }
    
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
    public partial class VadlidationServiceClient : System.ServiceModel.ClientBase<SandboxVisualWP.VisualWebPart1.IVadlidationService>, 
     SandboxVisualWP.VisualWebPart1.IVadlidationService
    {
        
        public VadlidationServiceClient()
        {
        }
        
        public VadlidationServiceClient(string endpointConfigurationName) : 
                base(endpointConfigurationName)
        {
        }
        
        public VadlidationServiceClient(string endpointConfigurationName, string remoteAddress) : 
                base(endpointConfigurationName, remoteAddress)
        {
        }
        
        public VadlidationServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : 
                base(endpointConfigurationName, remoteAddress)
        {
        }
        
        public VadlidationServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : 
                base(binding, remoteAddress)
        {
        }
        
        public string GetCountry(int value)
        {
            return base.Channel.GetCountry(value);
        }
    }
}
6. Now add the proxy class ‘CreditCardService.cs’  to the visual web part project. 
pic1
If you try to access the client proxy on the code-behind of the Visual Web Part, the intellisense will show that class now.
pic2

For the intellisense to recognize this proxy class, the namespace of the generated proxy class has to match with the namespace of the visual web part project. If there is a mismatch in the namespace, the intellisense will not recognize this proxy class. It is always recommended to explicitly specify the namespace during the generation of client proxy using svcutil (mentioned in step 3).

Now you are all set to invoke the various service operations on the WCF service.

 Subscribe to my blog

How to implement logging in SharePoint 2010–Part 3

In this post, I’d be focusing on how to create custom log entries using the SharePoint Logger (ILogger) component.

The LogToOperations methods and its overload can be used to create the custom log entries to Windows event log and the SharePoint 2010 ULS log.

  • It is recommended that enough information is provided to IT professionals to remediate the problem, when an event is logged using SharePoint Logger component

  • The default implementation of the LogToOperations method will write the event to the Windows event log and the ULS log.

  • Do not log the events to the  event source with limited information, like only the event message below :-

IServiceLocator oServiceLocator = SharePointServiceLocator.GetCurrent();
ILogger oLogger = oServiceLocator.GetInstance<ILogger>();

// Log an event with a message.
string message = "The current user does not have enough permissions for this operation";
oLogger.LogToOperations(message);
  • It is recommended to provide  comprehensive information like Event Id, Error Message and Event Severity while logging.

// Log an event with a message and a severity level.
oLogger.LogToOperations(message, EventSeverity.Error);

// Log an event with a message, an event ID, and a severity level.
oLogger.LogToOperations(message, (int) EventLogEventId.MissingID,
 EventSeverity.Error);
This will help the administrator to filter the log entries based on security level.
  • For Sandbox solutions the event severity enumeration of SandboxEventSecurity should be used.

  • Do not use EventSeverity enumeration for Sandbox solutions, it will throw an error

  • It is also good to have the Event Category logged to the event source

// Log an event with a message, an event ID, a severity level, and a category.
string oArea = "New Custom Area"
string oCategory = "Operations";
string oAreaCategory = string.Format("{0}/{1}", oArea, oCategory);
logger.LogToOperations(msg, (int) EventLogEventId.MissingID,
                       EventSeverity.Error, oAreaCategory);
  • Do not leave the DiagnosticsArea and DiagnosticsCategory as unspecified.

  • Because the SharePointLogger will assign a default value of ‘Patterns and Practices’ to the area value and the default value of ‘SharePoint Guidance’ to the Category.

  • The exception messages can also be directly passed as the parameter to the LogToOperations method. This should be avoided as much as possible

  •  

 Subscribe to my blog

How to implement logging in SharePoint 2010–part 2

This post would focus on  how to create & manage custom log areas and custom log categories.

It is always recommended to create custom logging areas and categories using SharePoint Logger. The custom logging areas and categories makes life easier for system administrators. So that the system administrator can apply throttling rules to the applications in the same way that they configure logging and reporting from the other SharePoint applications.

  • The AddAreas and RemoveAreas methods of DiagnosticsAreaCollection can be used to add/remove areas of the diagnostic logging. The AddCategory and RemoveCategory methods of DiagnosticsCategoryCollection can be used to add/remove categories of the diagnostics logging.
  • The following snippet illustrates how to add DiganosticsArea and DiagnosticCategory to the SharePoint Logger.
       //Creates a new Diagnostic Area
        DiagnosticsArea oDiagnosticsArea = new DiagnosticsArea("Any Area1");

        //Add 1’st Diagnostics Category   
        oDiagnosticsArea.DiagnosticsCategories.Add(new DiagnosticsCategory(
            UI", EventSeverity.Error, and TraceSeverity.Medium));

        //Add 2’nd Diagnostics Category
        oDiagnosticsArea.DiagnosticsCategories.Add(new DiagnosticsCategory(
           "DataAccess", EventSeverity.Warning, and TraceSeverity.Medium));
  • It is always recommended to assign the application name to the Diagnostics Areas, which is easier for troubleshooting.

  • To save the Diagnostics area and category to the SharePoint environment, pass the instance of IConfigManager to the DiagnosticsAreaCollection.

  • Then, invoke the SaveConfiguration method of DiagnosticArea class to save all the custom areas and categories (of your application) to the SharePoint environment.

  • Do not use the default constructor of DiagnosticsAreaCollection and invoke the SaveConfiguration method together, this will cause an InvalidOperationException.

  • It is always recommended to use the overloaded constructor of DiagnosticsAreaCollection and invoke the SaveConfiguration method together

  • Do not add an area that already exists on the DiagnosticsAreaCollection, this will throw an InvalidOperationException.

  • Leverage the Remove method of DiagnosticsAreaCollection to remove the individual areas

IConfigManager oIConfigurationManager =
    SharePointServiceLocator.GetCurrent().GetInstance<IConfigManager>();
DiagnosticsAreaCollection oDiagnosticsAreaCollection = new
    DiagnosticsAreaCollection(oIConfigurationManager);

foreach (DiagnosticsArea oDiagnosticsArea in MyAreas)
{
  DiagnosticsArea oAreaToRemove = oDiagnosticsAreaCollection[oDiagnosticsArea.Name];

  if (oAreaToRemove != null)
  {  
    oDiagnosticsAreaCollection.Remove(oAreaToRemove);
  }
}
oDiagnosticsAreaCollection.SaveConfiguration();
  • Leverage the Remove method of DiagnosticsCategoryCollection to remove the individual categories

foreach (DiagnosticsArea area in oMyAreas)
{
  DiagnosticsArea oAreaToRemove = oConfiguredAreas[area.Name];

  if (oAreaToRemove != null)
  {
    foreach (DiagnosticsCategory c in area.DiagnosticsCategories)
    {
      var oExistingCategory = oAreaToRemove.DiagnosticsCategories[c.Name];
      if (oExistingCategory != null)
        {
          oAreaToRemove.DiagnosticsCategories.Remove(oExistingCategory);
        }
      }
      if (oAreaToRemove.DiagnosticsCategories.Count == 0)
      {
        oConfiguredAreas.Remove(oAreaToRemove);
      }
    }
  }
}

 Subscribe to my blog

How to implement logging in SharePoint 2010–part1

Nowadays I’m doing lot of code review for SharePoint 2010 projects. One of the thing I’ve noticed is that the developers don’t understand the best practices for implementing logging with SharePoint 2010. This has compelled me to collate the guidance on SharePoint 2010 logging. I’ll be writing series of articles about SharePoint 2010 logging. In this article I’d be providing an overview of SharePoint Logger component and how to create an instance of ILogger object.

It is recommended to leverage the re-usable component SharePoint Logger(Logger) shipped with MSDN Patterns and Practices guidance for implementing logging capablities for SharePoint 2010 development. It provides the capability to write messages to the Windows event logs and ULS trace log. The interface ILogger exposes the following methods:-

ILogger method

Description

LogToOperations

This method can be used to write the Windows event logs and ULS trace logs. The overloaded parameters like identifiers, categories, severities and exception details can be provided

TraceToDeveloper

This method can be used to write to the ULS Trace log. The overloaded parameters like identifiers, categories, severities and exception details can be provided

The following code-snippet illustrates how to

ILogger oLogger = SharePointServiceLocator.GetCurrent ().Get Instance<ILogger> ();

oLogger.TraceToDeveloper ("Unexpected condition");

Creating a Logger object

The first step in logging message to the Windows event log or the ULS trace log is to create an object that implements ILogger interface. The SharePoint Logger provides a default implementation of this interface in a class named SharePointLogger. The SharePointLogger can be instantiated directly or it can be instantiated through the SharePoint Service Locator. It is recommended to leverage the SharePoint Service Locator pattern for getting the instance of SharePoint Logger, considering separation of concerns and test driven development in mind.

The next logical step is to add the reference to the required assemblies (Microsoft.Practices.SharePoint.Common.dll and Microsoft.Practices.ServiceLocation.dll).

Using Microsoft.Practices.ServiceLocation;

using Microsoft.Practices.SharePoint.Common.ServiceLocation;

using Microsoft.Practices.SharePoint.Common.Logging;

//Get the instance of Service Locator

IServiceLocator oServiceLocator = SharePointServiceLocator.GetCurrent();

//Get the instance of ILogger

ILogger oLogger = oServiceLocator.GetInstance<ILogger>();
In the next post, I’d be focusing on how to create and manage custom log areas and custom log categories.

 Subscribe to my blog

Upload large documents to SharePoint site using WebClient class

One of the best way to programmatically upload large documents to SharePoint site is by leveraging the UploadAsync method of WebClient class. The WebClient class internally uses the WebDav protocol. This approach can be used for uploading documents to SharePoint Online (Office 365) as well. The only limitation with this approach is that we’ll not able to set the meta-data of the documents using WebClient class. Here is the code-snippet for the same:-

 WebClient oWebClient = new WebClient();

oWebClient.UseDefaultCredentials = true;
byte[] bFile = System.IO.File.ReadAllBytes(@"C:SundarWEB315.wmv");
string ulr = @"http://lt010593/Shared Documents/WEB315.wmv";
System.Uri oUri = new System.Uri(ulr);

oWebClient.UploadDataAsync(oUri, "PUT", bFile);
oWebClient.UploadDataCompleted += new UploadDataCompletedEventHandler(oWebClient_UploadDataCompleted);

 Subscribe to my blog

SPWebService.ContentService returning System.NullReferenceException

When I tried to access SPWebService.ContentService in the following code-snippet (executed inside a console application), I was getting Null value.

 SPWebService contentService = SPWebService.ContentService;
            contentService.ClientRequestServiceSettings.MaxReceivedMessageSize = -1;

            SPWcfServiceSettings csomWcfSettings = new SPWcfServiceSettings();
            csomWcfSettings.MaxReceivedMessageSize = 104857600; // 100MB
            contentService.WcfServiceSettings["client.svc"] = csomWcfSettings;
            contentService.Update();

 

The resolution is to change the target CPU type in the Build properties from X86 to X64 or AnyCPu Type. That fixed my issue.

Programmatically add attachments to custom list using SharePoint 2010 Client Object Model

One of the important capability of SharePoint 2010 Managed Client Object model it its ability to add attachments to custom list. This capability is provided by the Microsoft.SharePoint.Client.File class in the client side APIs. The whole idea is to directly invoke the SaveBinaryDirect method of the Microsoft.SharePoint.Client.File class and pass the parameters like ClientContext, attachment path, filestream object and a boolean flag to set the overwrite status.

  using (ClientContext clientContext = new ClientContext("http://yoursitecollection"))
            {

                Web oWeb = clientContext.Web;
                List oList = oWeb.Lists.GetByTitle("NewCustomList");               
                FileStream oFileStream = new FileStream(@"C:SundarTestFile.txt",FileMode.Open);
                string attachmentpath = "/Lists/NewCustomList/Attachments/2/TestFile.txt";
                clientContext.Load(oList);
                clientContext.ExecuteQuery();
                Microsoft.SharePoint.Client.File.SaveBinaryDirect(clientContext, attachmentpath, oFileStream, true);             
                


            }

The important point to consider here is how to frame the attachment path url for adding attachment. The attachment url needs to be in the following format :-

“/Lists/NameoftheList/Attachments/ItemNumber/AttachmentFile.extension

NameoftheList – is the name of the custom list where you want you add attachments

ItemNumber – is the id of the custom list item

AttachmentFile.extension – is the file to be attached

 Subscribe to my blog

Programmatically upload documents using SharePoint 2010 Client Object Model

The following code snippet helps us to programmatically upload documents to document library, using Client Object Model.

 using (ClientContext clientContext = new ClientContext("http://yoursitecollection"))
            {

                Web oWeb = clientContext.Web;
                List oList = oWeb.Lists.GetByTitle("Shared Documents");               

                FileCreationInformation oFileCreationInformation = new FileCreationInformation();                  
                
                byte[] filecontent=System.IO.File.ReadAllBytes(@"C:SundarTestFile.txt");
                oFileCreationInformation.Content = filecontent;
                oFileCreationInformation.Url = @"http://yoursitecollection/Shared Documents/TestFile.txt";              


                oList.RootFolder.Files.Add(oFileCreationInformation);
                

                clientContext.Load(oList);
                clientContext.ExecuteQuery();        
                
                
            }

 Subscribe to my blog

Common symptoms of non-performing SharePoint code

The following are the common symptoms of a non-performing SharePoint code.

1. Frequent IIS Application Pool Recycling during the peak usage of the portal

The general practice is to allocate the IIS Application Pool Memory between 800MB – 1.5GB, assuming that at least 4GB RAM is available on the machine. The IIS App Pool recycle setting limit plays an important part in the recycling of app pool memory. The idea is that app pool re-cycle settings should not be too high or too low. The recommended app pool reset limit is 1 GB. Even after all this, the IIS App Pool resets frequently, then it has to be with SharePoint code. Make sure that the native SharePoint objects are disposed explicitly.

2. Poor Application Performance

Another symptom of a non-performing SharePoint code is the Poor Application performance. Meaning, during the peak load (when the memory usage increases), system would struggle to do paging and memory fragmentation, to compensate the load.

3. High Memory Usage for IIS Worker Process Memory

When the memory usage increases, the application would struggle to handle memory allocation. In many cases, this leads to “Out of Memory” exception, which leads to application crash, when unhandled in the code.

4. High Memory Usage for SQL

The common symptom of a non-performing SharePoint application is the high memory usage for SQL Process, when the system usage is not high. If the above symptoms persist, even after proper memory management in the code, then the Capacity Planning needs & sizing needs to be re-visited again.

 Subscribe to my blog