Category: General

  • Building QuickBooks: How Intuit Manages 10 Million Lines of Code

    This was a great article about a large scale commercial product and the tools and techniques used to manage it.

    https://www.drdobbs.com/tools/building-quickbooks-how-intuit-manages-1/

  • System.TypeLoadException: Method does not have an exception

    Sometimes you hit smack in to a runtime exception that requires a weekend off to get your head straight again to tackle come Monday morning.  That was my experience today, as I wrangled with an unexpected exception when doing something I’d done plenty of times before.

    Our app has the following structure:

    • Interfaces assembly
    • Business Logic assembly (where interfaces are implemented)
    • Web Application (where Interface and Business Logic are married using the Unity Framework)

    We have a build script that copies the latest version of the Business Logic assembly in to the /bin directory of the Web Application, since that app does not reference the assembly directly.

    It has been fairly routine for us, when adding or extending functionality, to add methods to our Interfaces library, implement the corresponding method in the Business Logic library, then use that method in our Web app.  But this time around, even after clean builds, we’d get a runtime error when the Unity framework would try to initialize.

    A bit of searching online revealed that this error occurs often when you’re not looking at the most recent version of an assembly that is implementing the Interface, and so to the Framework, it appears that the implementation is missing, even though your compiler will run clean.

    As a step to make sure that there were no residual versions of previously built assemblies, I went through Windows Explorer to purge the /bin directories.  Something caught my eye as I was looking at the /bin directory for the Business Logic library – an extra subdirectory names ‘x86’.  In this directory were the Debug and Release subdirectories, and then the new build of the assembly.

    So, it appeared the problem was that our build script was not in fact getting the latest version of our assembly since it was in a different (unexpected) location.

    The x86 name was a clue to look at the Configuration Manager in Visual Studio.  Sure enough, somehow the Business Logic project got set explicitly to x86 rather than ‘Any CPU’.

    I changed the target platform for that project, did a new clean and rebuild, and this time through, the app loaded up without error.

    Thankfully I didn’t spend an unrecoverable amount of time trying to sort this out, but I still thought it may be helpful to record for others who run in to that error and, as I did, mistakenly believe that nothing has changed to trigger the new runtime exception.

  • Filtering the SharePoint 2010 Blog Posts web part

    Sometimes it’s the little things that drive you mad.

    We got a report from a customer following a SharePoint 2007 to 2010 upgrade that their Blog site was showing too many posts, and they wanted to filter it by category.  That’s a simple enough request, right?

    In 2007, the user explained, she’d Edit the Page, Edit Web Part, then click on the ‘Edit the current view’ to get the ability to set the filter criteria.  However, in 2010, the ‘Edit the current view’ link never appeared.

    I set off to confirm what she was seeing.

    In my 2010 development lab, I created a new site using the Blog site template.

    As advertised, the default view of the site showed the ‘Posts’ web part showing all the approved posts from the blog.  I added a few other posts, and set one of the categories to be called ‘Announcements’.

    So, as the user did, I went to Edit the web part.

    Sure enough, the ‘Edit the current view’ was notably absent.

    I was able to get the link to s how up, by changing the Selected View, clicking ‘Apply’, then re-selecting ‘<Summary View>’ and clicking ‘Apply’ again.

    However, when I clicked on the link, I got a whole lot of nothing.

    So, on to plan B as it was evident this was not to be done through the Browser UI.  I launched SharePoint Designer and loaded up the Blog site.

    Then clicked on ‘Edit site home page’ to load up the web part page.  There was my Posts web part.

    By selecting the Web Part, I got a ‘List View Tools’ ribbon with a nice big ‘Filter’ button on it.

    Clicking the Filter button brings up the ‘Filter Criteria’ dialog, where I could add my category filters.

    After adding the additional criteria, the Posts web part showed the filtered list of entries.

    Save the page in SharePoint Designer, which will automatically publish the changes to the server.

    Now, when I go back to the Blog site, I see the filtered list of entries.

  • 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 https://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 https://blog.mattsampson.net/index.php/calling-a-webservice-over-ssl-in-sharepoint-ssl?blog=1 for helping guide the way.

  • Rejected but encouraged

    A few weeks ago I applied for a grant offered by a local Venture Capital firm.  The grant application is essentially an abbreviated business plan, and finalists compete for several awards.

    Today I received my rejection letter.  Complete with the classic “we regret to inform you” clause.

    However, they attached a remarkably polished PDF analysis of my application compared to the 183 other submissions.

    The analysis gave me a unique insight to my own idea-making.  Here was an objective evaluation of my idea (related to offering HomeSpot in a unique way to home improvement companies) and some direct feedback from people who look at entrepreneurial ideas for a living.

    Across the seven scoring categories, our application performed above average in all seven.  This is more clearly seen in graphical form.

    I assume, but do not know for sure, that the selected finalists exceeded some established threshold for their total score.  So, while our application was 30 points off of the maximum score, it may have only be 10 points off of the threshold.  I’ll never know.

    Here is some of the feedback from the reviewers:

    This is an interesting service, but it feels like an ultra specialized solution. It is addressing a real need, but it is another website that consumers need to log into. It is not unique and it is very difficult to differentiate. Ultimately the success will obviously depend on execution.

    What I take from this is the validation that we are addressing a real need.  Finding a solution for a existing problem is key to success as an entrepreneur.  I agree fully with the reviewer here that execution will be the determining factor on our success.

    Great platform with promising customer feedback. I am wondering, however, what the long term competetive response and market growth will be. How are you planning to grow your platform outside of local handymans? What is your growth strategy serving as an anonymous service provider?

    Again, affirmation on the product idea itself and the feedback we have received already.  But the challenge is put forth – how do we grow, scale and sustain ourselves beyond our initial markets? The third review also shared this concern:

    The problem, market, and technology are all very clearly presented. It is difficult to see how this really scales to a company with significant revenue…

    In the eyes of a Venture Capitalist, “significant revenue” has lots of zeroes following it.  For me as the entrepreneur, my standards of significance are no doubt different.  My definition for success may well come in being able to first hit “insignificant revenue” having started with “zero revenue”.  But for the reviewer, and the investor alike, the criteria for growth and scale are well understood.

    The last reviewer was the most critical.

    I think it’s good that there’s a competitor, but I’m slightly concerned that your product (as described) appears to be very similar, yet you describe your product as “revolutionary”. Honestly, this hurt the credibility a bit, at least in my eyes. If successful, there are likely to be other revenue stream opportunities. I’m not sure if you considered any, as they’re not included in the proposal. You indicated that the product is already on the market, but that you have no sales and don’t expect any for 12 months. Why? Also, pricing was not indicated.

    This reveals much to me about how we presented ourselves in the application.  We obviously (at least in this reviewer’s eyes) lacked differentiation and clarity on our current status and future growth.  Our exclusion of other revenue streams was not because we are not keenly aware of them, but had to choose carefully our statements in the limited format of the application.  Questions about our sales efforts and pricing are also in our minds constantly, but we chose not to put them forth in the application.

    What is important is that these things that I deem to be secondary or even trivial are clearly not thought of the same way by the reviewer.

    All told, I am encouraged by this feedback.  It was a solid helping of affirmation, with some key calls to address the perceived challenges in a product we have yet to fully bring to market.  I am motivated to prove these skeptics wrong, execute, achieve significant revenue, and capture all the opportunity before me.

  • Picking a Mobile Web Strategy

    In the ongoing development roadmap for HomeSpot HQ is a simple item: Create a Mobile Optimized Site.  By itself, it is a pretty straightforward task.  We designed the HomeSpot HQ site for a 1024×768 browser window.  And while most of the modern mobile devices will render this site satisfactorily, there is definitely something about a truly optimized browsing experience when using the scaled down browser on an iPhone or (in my case ) Droid Incredible.

    Web or Native

    Our first strategic decision has been to focus first on an optimized website in lieu of a native mobile app.  There are plenty of reasons for leading with this approach:

    • the ability to leverage our existing code base vs. managing multiple code lines per device
    • broader device audience vs. per device versioning
    • avoiding deployment channels (and cost) via AppStore or Android Market

    As HomeSpot is an ASP.NET MVC application, I was able to use some guidance from Scott Hanselman about having a parallel set of Views for the mobile browser set that run alongside the default set of Views for the traditional browser set.  This approach allowed me to use my existing Controllers and (with a few exceptions) reuse the Models without modification.  Compared to rewriting in Java or learning Objective C to target their respective device platforms, this approach represented the fastest path to mobile coverage.

    Split or Common Site

    The other choice I made was to keep the mobile version and desktop version of the site under the same Url.  There are several pros and cons to this approach, and there may in fact be some ramifications I will have to deal with down the road.  So, the user experience will be such that if you view the site on a recognized mobile device, you’ll be served the mobile optimized Views, otherwise you’ll get the normal desktop Views.  The Url won’t change between the two versions.

    The advantages of this approach, so far as I have thought about them, include

    • easier deployment process with only one site to manage
    • unified Google Analytics

    However, there are some trade-offs:

    • lack of distinct Url such as “m.homespothq.com”
    • inability to easily deploy code fixes just to mobile site independent of main site
    • trickier to allow mobile users to view the non-mobile site if they so choose.

    Mobile Web Framework

    The final decision I chose to make was picking a mobile optimization framework.  I looked at iui and jquery mobile primarily, and decided to go with jquery Mobile.  While it is still emerging from an alpha stage, it appears to be meeting my expectations so far.  I’ll create additional posts with more specific commentary on this platform.

    The Mobile Optimized HomeSpot site is still under development and initial testing.  Given the limited time afforded to me to contribute to my own side-hustle, I hesitate to even offer a ship date.  Still, it has been a good exercise to weigh out the various options for reaching a mobilized audience.

  • Creating or Consuming

    Creating or Consuming

    On this 3-day weekend, I found myself with a few spare cycles I don’t normally have.

    But by default, it seemed, I used those cycles reading and consuming content from the web.

    It occurred to me, that I could have been using those moments to create.  To add a feature to HomeSpotHQ.com.  To rework one of the broken reports from work.  To make a smoothie even.

    Does Creation always require more energy than Consumption?  Why is the inertia to get towards Creation so high, but the path to Consumption so well paved?

    And more critically, how do I maintain a mindset of Creation, while keeping idle Consumption at bay?

  • Integrating with Amazon Simple Email Service (SES)

    Amazon recently announced the release of their Simple Email Service for use by developers.  In doing so, Amazon opens up a pay-as-you-go email sending mechanism that is tailored for application developers.

    Sending system generated email messages has always proven to be a challenge for developers.  It’s not for lack of means to do so, it’s dealing with a multitude of anti-spam safeguards imposed by ISPs and hosting providers.  Some block outbound sending altogether, and many throttle the number of messages that can be send per day/hour/minute.

    Amazon’s SES provides a great deal of infrastructure, and uses a variety of proven methods to help ensure deliverability of your message.  Their quota system is dynamic, so the more you prove your messages are legitimate, the more you can send.

    Setting up your SES account.

    If you already have an Amazon Web Services account, adding on the Simple Email Service is pretty straightforward.  You’ll get a confirmation email from Amazon to click through and activate the service.  Initially, you’ll be set up in a Sandbox, and there is a process for requesting Production Access.

    Getting your Access Keys

    After you have enabled the service, you’ll need a set of credentials to use it.  Again, if you already have an AWS account, you’ve probably got your Access Keys set up already.  Like any credentials, keep them safe and secure.  If someone were to gain access to your AWS keys, they could send email through SES without your knowledge.

    Verifying an email address.

    Before you can send outbound messages through SES, you have to verify the source email address.  Amazon provides a small collection of scripts used to communicate via command line to the SES services.  Follow the Getting Started guide’s instruction to prepare a file containing your AWS Access Keys and verify a sending address.  SES will generate a response email to the address you are verifying, within which is a link you’ll have to click in order to complete the verification.

    Downloading the Amazon Web Services API.

    Amazon offers a couple of methods for leveraging the SES API.  You can use the scripts downloaded to verify your source address to also send messages.  I chose, however, to use their packaged .NET SDK library.  It contains wrappers for all of Amazon’s Web Services, including the SES.

    After downloading and unpacking the SDK, you can add a reference to the AWSSDK.dll assembly to your project.

    Using the SES API methods.

    Creating and sending email via the SDK then becomes a matter of setting up the outbound SES message object and sending it through the API.  The following method takes a standard .NET MailMessage object and translates it to a SES message, then sends it along.

    Public Function SendMessage(ByVal message As System.Net.Mail.MailMessage) As String Implements Core.DataInterfaces.IMailServer.SendMessage
    
                If String.IsNullOrEmpty(_accessKey) Or String.IsNullOrEmpty(_secretKey) Then Throw New Exception("API Credentials are required to use this provider.")
    
                Dim ses As New AmazonSimpleEmailServiceClient(_accessKey, _secretKey)
    
                Dim messageToSend As New Amazon.SimpleEmail.Model.SendEmailRequest
    
                'set up addresses
                messageToSend.Destination = New Amazon.SimpleEmail.Model.Destination
    
                For Each toAddress In message.To
                    messageToSend.Destination.ToAddresses.Add(toAddress.Address)
                Next
    
                For Each ccAddress In message.CC
                    messageToSend.Destination.CcAddresses.Add(ccAddress.Address)
                Next
    
                For Each bcAddress In message.Bcc
                    messageToSend.Destination.BccAddresses.Add(bcAddress.Address)
                Next
    
                'set reply to
                If message.ReplyTo IsNot Nothing Then
                    messageToSend.ReplyToAddresses.Add(message.ReplyTo.Address)
                End If
    
                'set subject line
                messageToSend.Message = New Amazon.SimpleEmail.Model.Message
                messageToSend.Message.Subject = New Amazon.SimpleEmail.Model.Content().WithData(message.Subject)
    
                'set message body
                If message.AlternateViews.Count > 0 Then
                    Dim messageBody As New Amazon.SimpleEmail.Model.Body()
    
                    For Each view In message.AlternateViews
                        Dim viewStream = view.ContentStream
                        Dim viewData(viewStream.Length) As Byte
                        Dim viewContent As String = System.Text.Encoding.ASCII.GetString(viewData, 0, viewStream.Read(viewData, 0, viewData.Length))
    
                        If view.ContentType.MediaType.Equals("text/html") Then
                            messageBody.Html = New Amazon.SimpleEmail.Model.Content(viewContent)
                        Else
                            messageBody.Text = New Amazon.SimpleEmail.Model.Content(viewContent)
    
                        End If
                    Next
    
                    messageToSend.Message.Body = messageBody
                Else
                    messageToSend.Message.Body = New Amazon.SimpleEmail.Model.Body(New Amazon.SimpleEmail.Model.Content(message.Body))
                End If
    
                'set from address
                messageToSend.Source = message.From.Address.ToString
    
                'send message
                Dim sendResponse As Amazon.SimpleEmail.Model.SendEmailResponse
    
                sendResponse = ses.SendEmail(messageToSend)
    
                Return sendResponse.SendEmailResult.MessageId
    
            End Function
        End Class

    Lessons Learned

    A few things I learned to keep in mind:

    1. The reply-to address also has to be verified, just like the sending address.
    2. As a new account with Production Access, you’ll have a 1,000 message per day quota.
    3. There is a Send Rate limiter for the number of messages per second.  You’ll have to account for this limit in your code to ensure that it doesn’t fail mid-way through your batch of messages.

    Amazon’s service is easy to use, economical, and capable.  I probably won’t replace every outbound message instance with SES, but definitely for cases where I need to generate larger batches (such as monthly newletters or maintenance reminders) I will leverage SES.

  • 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