Blog of Sundar Narasiman

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

Content Type text/xml charset=utf-8 was not supported by service

I was trying to consume a WCF service from SharePoint web part. Basically I got this error “Content Type text/xml charset=utf-8 was not supported by service. The client and server bindings may be mismatched”. After a bit of analysis, I’ve realized that the three was mismatch in the Binding type specified in the service and client configuration.  At the service-level, I had configured WSHttpBinding and at the client it was configured as BasicHttpBinding. I’ve fixed this issue by making sure that the bindings match at both the client and server.

 

WCF error: could not find default end point element that references contract

I was trying to consume an IIS hosted WCF service, got this error “could not find default end point element that references contract in the ServiceModel client configuration. This might be because no endpoint element matching this contract could be found in the client element”.

I fixed it by performing the following steps:-

1. Included the following namespace in the WCF client component

using System.ServiceModel;
using System.Runtime.Serialization;

If the WCF client project is of type .NET 3.5 or higher, it will have references to System.ServiceModel.dll and System.Runtime.Serialization.dll. It will not have references to those namespaces in the code, this needs to be added.

2. Changed the name of the client configuration file from ‘output.config’ to ‘app.config’. When I generated client proxy using svcutil.exe, I set the default name of output.config and this needs to be changed to ‘app.config’.If your client is a web application, you can copy the contents inside System.ServiceModel to the web.config

After doing the above 2 steps, my WCF client worked like a charm.

 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

Publish Access Web Database to SharePoint 2010 Access Services

Here are the pre-requisite for publishing the access web database to access services.

1. Install Microsoft SQL Server 2008 R2 Reporting Services add-in for SharePoint Technologies 2010 and configure it.

image_thumb

2. Create a service account (in Active Directory) to run the application pool of Access Services

3. Register the service account as the managed account in the central administration

4. Start the Access Service application

 

In order to make the access database publishable to SharePoint 2010 Access Services, create the access database using ‘web database’ template in access 2010.

image

Now we can create the required set of tables within Access Web Database. The next step is to publish the access web database to SharePoint 2010 Access Services

1. File –> Save & Publish

2. Click ‘Publish to Access Services’

3. Enter Server Url and Site Name

accesswebdb1

 Subscribe to my blog

List of performance counters for SharePoint web parts/application

While troubleshooting one of the SharePoint application performance issues, one of my colleague asked me a question “What are the list of performance counters  to be considered for SharePoint application performance Diagnostics ?”. Here is the the indicative list of performance counters that can be considered for SharePoint webpart / application performance diagnostics.

Basic system related performance counters

No Counter Frequency of measurement
1 CPU Usage Longer intervals, once in 2-3 hours
2 Virtual Bytes Longer intervals, once in 2-3 hours
3 Private Bytes Longer intervals, once in 2-3 hours
4 Pool Paged Bytes Longer intervals, once in 2-3 hours
5 Pool nonpaged Bytes Longer intervals, once in 2-3 hours
6 Working set Longer intervals, once in 2-3 hours
7 Thread Count Longer intervals, once in 2-3 hours
8 Average CPU usage Shorter intervals, once in 2-5 minutes
9 Average Virtual Bytes Shorter intervals, once in 2-5 minutes
10 Average Private Bytes Shorter intervals, once in 2-5 minutes
11 Average Pool Paged Bytes Shorter intervals, once in 2-5 minutes
12 Average Pool nonpaged Bytes Shorter intervals, once in 2-5 minutes
13 Average Working set Shorter intervals, once in 2-5 minutes
14 Average pages/sec Shorter intervals, once in 2-5 minutes
15 Average interrupts/sec Shorter intervals, once in 2-5 minutes

Counters for ASP.NET and ASP.NET application

No Counter Frequency of measurement
1 Average request Shorter intervals, once in 2-5 minutes
2 Average request execution time Shorter intervals, once in 2-5 minutes
3 Average request wait time Shorter intervals, once in 2-5 minutes
4 Average request executing Shorter intervals, once in 2-5 minutes
5 Request total Longer intervals, once in 2-3 hours
6 Output cache hits Longer intervals, once in 2-3 hours
7 Output cache misses Longer intervals, once in 2-3 hours
8 Average output cache entires Shorter intervals, once in 2-5 minutes

Counters for W3WP (worker process)

No Counter Frequency of measurement
1 Average aggregated CPU usage process information Shorter intervals, once in 2-5 minutes
2 Average virtual bytes Shorter intervals, once in 2-5 minutes
3 Average private bytes Shorter intervals, once in 2-5 minutes
4 Average pool paged bytes Shorter intervals, once in 2-5 minutes
5 Average pool nonpaged bytes Shorter intervals, once in 2-5 minutes
6 Average working set Shorter intervals, once in 2-5 minutes
7 Average thread count Longer intervals, once in 2-3 hours
8 Average handle count Longer intervals, once in 2-3 hours
9 Average number deployed Longer intervals, once in 2-3 hours

 Subscribe to my blog

WCF error: The service cannot be activated because it does not support ASP.NET compatibility

I got the following error when I was trying to host my WCF service in IIS 7.5 using WsHttpBinding

The service cannot be activated because it does not support ASP.NET compatibility. ASP.NET compatibility is enabled for this application. Turn off ASP.NET compatibility mode in the web.config or add the AspNetCompatibilityRequirements attribute to the service type with RequirementsMode setting as ‘Allowed’ or ‘Required’.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: The service cannot be activated because it does not support ASP.NET compatibility. ASP.NET compatibility is enabled for this application. Turn off ASP.NET compatibility mode in the web.config or add the AspNetCompatibilityRequirements attribute to the service type with RequirementsMode setting as ‘Allowed’ or ‘Required’.

Solution:

One of the  solution is to turn-off ASPNet compatibility in service configuration file

<serviceHostingEnvironment aspNetCompatibilityEnabled="false"/>. It worked for me.

WCF error: SOAP security negotiation failed for target

I got this error when I tried to host the WCF service in the IIS 7.5 using WSHttpBinding.

Exception
[System.ServiceModel.Security.SecurityNegotiationException] {"SOAP security negotiation with ‘http://localhost/Migraton/MigrationService.svc’ for target ‘http://localhost/OrderService/OrderService.svc’ failed. See inner exception for more details."}

Inner Exception
[System.ComponentModel.Win32Exception] {"The Security Support Provider Interface (SSPI) negotiation failed."}

Solution

The solution was to change the following userPrincipalName in the <userPrincipalName value="MACHINENAMEASPNET" /> to <servicePrincipalName value="host/localhost" /> . This did the trick and solved the issue.