Category: Tools

  • Why can’t I collapse HTML in a master page? Oh, wait, I can! (Sort of.)

    I’m going to file this one under Stupid Visual Studio tricks.

    When editing a master page file in an ASP.NET project (or in my particular case, a SharePoint solution), it came clear that the normal display of the HTML source was missing the very useful expand/collapse option.

    Exhibit 1.  Master page with no collapse

    no collapse when viewing Master Page

    With a hat tip to this Stackoverflow post, it appears re-opening the file and explicitly selecting the editor to use fixes this behavior, as shown below. (Note, I’m basing this on VS2010 SP1.  YMMV.)

    First, right-click on the File, and select Open With…
    open-file-with

    Then select Master Page Editor (which is probably already marked as default) and click OK.

    select editor

    Then watch your cursor spin while some Visual Studio voodoo magic happens. When the file opens, you should see the expand/collapse boxes and lines.

    master with collapse

     

    The epic fail part comes when Visual Studio makes you do this every time you open the file.  

    It is worth noting, however, that .aspx and .ascx pages are exempted from this bug feature.

     

  • 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 https://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.

  • 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: 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
  • In Praise of Balsamiq

    I have a lot of reasons to like Balsamiq.

    1. They make a great product that is easy to use, provides real value, and does exactly what it says it is going to do.
    2. They are a small business, started by people who, according to their website are ” a small group of passionate individuals who believe work should be fun and that life is too short for bad software.”
    3. They use a lightweight company model I can appreciate, with most of their employees working from home and meeting via online tools.

    For those who don’t know, Balsamiq’s flagship product is called Mockups, and it allows you to readily build User Interface design mockups and prototypes.  If you are active in any sort of product or system design effort, Mockups is well worth the purchase price.

    Doing one thing well is a lesson so many companies can still learn.  My kudos to the Balsamiq team for staying focused.