Category: Tips and Tricks

  • Add root certificate as trusted source in SharePoint 2010

    Following a recent SharePoint 2007 to 2010 upgrade, we got a report of an RSS Viewer that was not displaying any content.

    The message shown was “The requested RSS feed could not be displayed. Please verify the settings and url for this feed. If this problem persists, please contact your administrator.”

    After confirming for myself, I checked the feed that the RSS Viewer was pulling, and found it was from the Cisco support forums at https://supportforums.cisco.com/community/feeds/video?community=2004.

    Next we checked the SharePoint Logs to find the following entry:

    04/02/2012 10:17:05.24         w3wp.exe (0x4610)                               0x3D3C        SharePoint Portal Server              Web Parts                             8imh        High            RssWebPart: Exception handed to HandleRuntimeException.HandleException System.Net.WebException: The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. —> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure. at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, Exception exception)     at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)     at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)     at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRe…        193b14f8-f282-438d-bf91-36bb7c640d03

    A corresponding entry in the Event log was also a clue.

    An operation failed because the following certificate has validation errors:\n\nSubject Name: CN=supportforums.cisco.com, OU=Communications and Collaboration Team, O=Cisco Systems, L=San Jose, S=CALIFORNIA, C=US\nIssuer Name: CN=VeriSign Class 3 Secure Server CA – G3, OU=Terms of use at https://www.verisign.com/rpa (c)10, OU=VeriSign Trust Network, O=”VeriSign, Inc.”, C=US\nThumbprint: CAF5027FDDE630D4AC3FFB1000FC2E09B18249A3\n\nErrors:\n\n The root of the certificate chain is not a trusted root authority..

    What was going on?

    The Cisco site had a chain of SSL certificates that was 3 layers deep.

    1. A root certificate
    2. An intermediate or secondary certificate
    3. A site certificate

    As the RSS Viewer attempted to connect to this location, it connects as the SharePoint service, not as a browser.  SharePoint then tried to travel up the certificate chain to confirm the authenticity of each layer. When it got to the intermediate certificate, it choked, not able to validate it as a legitimately trusted source.

    How do we fix it?

    In order for SharePoint to recognize the Verisign certificates chained together and used by the Cisco site, we need to explicitly tell SharePoint they are trustworthy.  Thankfully, there is a simple to use UI as part of Central Administration where we can do just that.

    First, log in to Central Administration, then click on the ‘Security’ menu item.

    Then, select ‘Manage Trust’ from the ‘General Security’ section.

    Before we can add the Verisign certificates as trusted relationships, we have to retrieve them from the Verisign website.  All of Verisigns root and secondary certificates can be found at http://www.verisign.com/support/roots.html

    By examining the certificate details in the Browser, we can determine which root certificate to download and add to SharePoint.  In our case, there needed root was:

    Root 3
    VeriSign Class 3 Primary CA – G5
    Description:
    This root CA is the root used for VeriSign Extended validation Certificates and should be included in root stores. During Q4 2010 this root will also be the primary root used for all VeriSign SSL and Code Signing certificates.

    Download the Root Certificate file.

    Now, add the Trust Relationship to SharePoint

    After that certificate is in place, you can return to the page with the RSS Viewer and confirm it is able to retrieve the results.

    If not, then there may be additional certificates in the chain that you would need to retrieve and add to SharePoint.

    The Trust Relationships in SharePoint are also used when calling out to an external web service from a web part.

    Thanks to http://blog.mattsampson.net/index.php/calling-a-webservice-over-ssl-in-sharepoint-ssl?blog=1 for helping guide the way.

  • Override ASP.NET Membership Password Generation rules

    I am a real fan of the ASP.NET Membership system as a way to deliver a basic account management and log in mechanism to a web application.  I have used it in both ASP.NET and ASP.NET MVC applications, using both SQL and Active Directory as the backing identity store.

    One nuance of the Membership provider when using SQL is how it generates new passwords when the user requests their password be reset.  By default, the generated password is a whopping 14 characters in length, with no clear way to adjust the format.  (The MSDN page for SqlMembershipProvider.ResetPassword describes this behavior.)

    Thankfully, it is fairly easy to create a new MembershipProvider and override the GeneratePassword method with your own rules.

    First, we’ll create a new class that inherits SqlMembershipProvider.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    
    namespace MyNamespace
    {
    public class MyMembershipProvider:System.Web.Security.SqlMembershipProvider
    {
    
    public MyMembershipProvider()
    : base()
    { }
    
    }

    Then we’ll override the GeneratePassword() method to use our own rules for creating a new password value.  In this case we assemble an 8 character string of upper and lower case letters, numbers, and a few symbols.

    public override string GeneratePassword()
    {
        string newRandomPassword = string.Empty;
        int passwordLength = 8;
        Random random = new Random();
    
        while (newRandomPassword.Length != passwordLength )
        {
            int randomNumber = random.Next(48, 122);
            if (randomNumber != 95 && randomNumber != 96)
                newRandomPassword += Convert.ToChar(randomNumber);
        }
    
        return newRandomPassword;
    }

    Next, we need to update the web.config file to define our new class as a provider for the Membership system.

    <membership defaultProvider="MySqlProvider">
    <providers>
    <add name="MySqlProvider" type="MyNamespace.MyMembershipProvider" connectionStringName="MyConnectionString" applicationName="My Application" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" maxInvalidPasswordAttempts="1000" passwordAttemptWindow="5" minRequiredPasswordLength="4" minRequiredNonalphanumericCharacters="0" />
    
    </providers>
    
    </membership>

    Finally, we tell the included PasswordRecovery control to use our provider class, using the name specified in the web.config entry.

    <asp:PasswordRecovery ID="PasswordRecoveryControl" runat="server" Width="385px" UserNameLabelText="" OnSendingMail="PasswordRecoveryControl_SendingMail" MembershipProvider="MySqlProvider"
    OnUserLookupError="ShowPasswordRecoveryError" UserNameInstructionText="Enter your Email Address to receive your password">
    </asp:PasswordRecovery>

    This is a great testimony to the Provider pattern as a way to quickly reconfigure a system.

  • Unable to start debugging on the web server.

    This morning I got the following error when trying to run a project in Visual Studio 2010.

    After a bit of digging, I found that IIS was not running on my PC.  I tried using iisreset but it did not start up.

    A system reboot was all it took to get IIS cleared up and started without any exceptions.  I will note that a Windows Update had just occurred the night before.

  • Incoming Tabular Data Stream Incorrect

    This morning my team fielded an error we had not seen before in a production site.  When performing a lookup, the following exception bubbled up:

    The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect.  Too many parameters were provided in this RPC request.  The maximum is 2100.

    Upon investigation, we found that a Linq query using the .Contains() clause was the culprit.

    It appears that Entity Framework was translating the .Contains() clause to a WHERE x IN () when setting up the SQL SELECT statement to run.  In our case, we had done a retrieval of records first, then passed that list into the Contains.  It worked fine until the list exceeded 2100 entries.

    We were able to just refactor our lookup to eliminate the .Contains() clause.

    Part of what made this an unusual case was that even in production, this system had run for 2 years without any issues.  But as the number of records grew through the system’s use, it was only a matter of time before we exceeded that boundary imposed by SQL Server.

  • SSMS Tools Pack Works for Me

    Today a co-worker of mine introduced me to a great add on to Microsoft’s SQL Server Management Studio (SSMS).  It’s simply called the SSMS Tools Pack and is a free download from http://www.ssmstoolspack.com/

    The product is a collection of ‘a few upgrades to the SSMS IDE that I thought were missing” according to the author.  These features include:

    • SQL Snippets
    • Window Connection Coloring
    • Window Content History, Query Execution History and Current Window History
    • Format SQL
    • Search Table, View or Database Data
    • Run one script on multiple databases
    • Copy execution plan bitmaps to clipboard or file
    • Search Results in Grid Mode
    • Generate Insert statements from resultsets, tables or databases
    • Regions and Debug sections
    • Running custom scripts from Object Explorer
    • CRUD (Create, Read, Update, Delete) stored procedure generation
    • New query template
    • General Options

    The particular feature I needed was to Generate Insert statements from an existing table – particularly when dealing with partial synchronizing between two copies of the same database, such as a Dev and Staging or Production environment.

    I’ve added SSMS Tools Pack to all of my systems now, and is definitely one product I want to promote.

  • My Favorite Extension Methods: IsGuid

    In this third installment of my Favorite Extension methods series, I will show how to quickly evaluate a string to determine if it is the string representation of a Guid.

    I came upon the need for this method because I am using ASP.NET MVC for an application that uses a Guid to identify a record. In a case where my controller method is to retrieve a record, the controller’s parameter is a string.

    <Extension()> _
    Public Function IsGuid(ByVal value as String) As Boolean
      If String.IsNullOrEmpty(value) Then
        Return False
      Else
        Try
          Dim guid As New Guid(value)
          Return True
        Catch Ex As Exception
          Return False
        End Try
    End Function

    Using this extension method, I can ensure that a string represents a Guid and I won’t encounter any errors when trying to Cast that value into a Guid.

    If Not recordGuid.IsGuid Then Throw New ArgumentException("RecordGuid must contain a Guid string.")
  • My favorite extension methods: HtmlEncode shortcut

    This is the second installment in my series highlighting my personal favorite .NET extension methods.  We’ve already talked about a String.Format shortcut.  Now we’re on to making the HtmlEncode function readily accessible.
    Any time you are showing user-entered content as text on a web page, it is important to HtmlEncode the string so as to prevent execution of any rogue scripts.  The following is a two part implementation of the .NET HtmlEncode that makes this useful function much more accessible.
    Part 1 is a wrapper around the base .NET function with an overload to pass in your own value to display if the value to encode is empty.
    Public Shared Function HtmlEncode(ByVal value As String) As String
            Dim context As HttpContext = System.Web.HttpContext.Current
            If Not context Is Nothing Then
                Dim Server As HttpServerUtility = context.Server
                If value Is Nothing OrElse Trim(value) = "" Then
                    Return "{none}"
                Else
                    Dim sText As String = Server.HtmlEncode(value)
                    Dim sCRLF As String = vbCrLf
                    sText = Replace(sText, sCRLF, "<br>")
                    Return sText
                End If
            Else
                Throw New Exception("This function must be called from an ASP.Net application.")
            End If
        End Function
    
        Public Shared Function HtmlEncode(ByVal value As String, ByVal mapEmptyTo As String) As String
            Dim context As HttpContext = System.Web.HttpContext.Current
            If Not context Is Nothing Then
                Dim Server As HttpServerUtility = context.Server
                If value Is Nothing OrElse Trim(value) = "" Then
                    Return mapEmptyTo
                Else
                    Dim sText As String = Server.HtmlEncode(value)
                    Dim sCRLF As String = vbCrLf
                    sText = Replace(sText, sCRLF, "<br>")
                    Return sText
                End If
            Else
                Throw New Exception("This function must be called from an ASP.Net application.")
            End If
        End Function
    The second part is an extension method to let you call the HtmlEncode function from any string, again with an overload to let you pass in your own empty value text.
       <Extension()> _
       Public Function HtmlEncode(ByVal value As String) As String
           Return Functions.HtmlEncode(value, "{none}")
       End Function
       <Extension()> _
       Public Function HtmlEncode(ByVal value As String, ByVal mapEmptyTo As String) As String
           Return Functions.HtmlEncode(value, mapEmptyTo)
       End Function
  • My favorite Extension methods: String.Format shortcut

    This is the first entry in a short series highlighting some of my favorite extension methods.

    It’s a generally accepted best practice to use the String.Format() method to assemble string values that merge text and variables.

    Using an Extension Method (.NET 3.5 or greater) makes accessing the String.Format function even easier.

    Now, for any string value, you can simply use the following

    "The quick brown fox {0}".Fmt("jumped over the lazy dog.")

    Here’s the code for the extension method and various overloads:

    <Extension()>_
    Public Function Fmt(ByVal format As String, ByVal arg0 As Object) As String
      Return String.Format(format, arg0)
    End Function
    
    <Extension()>_
    Public Function Fmt(ByVal format As String, ByVal arg0 As Object, ByVal arg1 As Object) As String
      Return String.Format(format, arg0, arg1)
    End Function
    
    <Extension()>_
    Public Function Fmt(ByVal format As String, ByVal arg0 As Object, ByVal arg1 As Object, ByVal arg2 As Object) As String
      Return String.Format(format, arg0, arg1, arg2)
    End Function
    
    <Extension()>_
    Public Function Fmt(ByVal format As String, ByVal ParamArray args() As Object) As String
      Return String.Format(format, args)
    End Function