Sunday, 1 November 2015

September and October Update

Here’s a quick roundup of what I’ve been writing about in the last two months.

F#

NAudio

LINQ / Functional Programming

Misc

Sunday, 20 September 2015

July and August Update

My big news from the last two months is that I’ve released a new Pluralsight course – Creating and Selling a Digital Product. I’ve also managed to progress a bit towards the next release of NAudio. Here’s links to the new posts I’ve done in the last few months over at my new blog.

NAudio

Miscellaneous

Saturday, 4 July 2015

June Update

June has been a busy month for me. I’m working on a new course for Pluralsight, and you might be able to guess what it’s going to be about from what I’ve been blogging about. As usual, my articles are now hosted over at my new site, so do head over there to keep up with my latest content.

Creating and Selling Digital Product Series

Azure

Miscellaneous

NAudio

Thursday, 4 June 2015

May Update

Last month saw the release of my new Pluralsight course on MahApps.Metro. You can read a couple of articles I wrote to introduce it and help you get started with MahApps.Metro below, along with a couple of other articles I wrote last month:

Saturday, 16 May 2015

April Update

I’ve already mentioned that I’m no longer blogging here at blogger, and if you’re subscribed you should head over to markheath.net to be kept up to date. Here’s what you’ve missed over the past few weeks. If you want to keep updated with a weekly newsletter of new posts, do sign up for my mailing list.

Thursday, 7 May 2015

Creating Modern WPF Applications with MahApps.Metro

I’m pleased to announce that my latest Pluralsight course, Creating Modern WPF Applications with MahApps.Metro has been released. MahApps.Metro is one of my favourite open source projects, and if you’re a WPF developer you should definitely check it out. What it offers is a ridiculously quick and easy way to update a plain old WPF application and give it a “modern” metro look and feel. And of course, being open source, it’s completely free.

Not only does it provide updated styles for the vast majority of standard WPF controls, but it ships with a variety of useful additional controls, as well as giving you the choice of several light and dark colour schemes, and access to a great library of useful icons.

image

I’ve used MahApps.Metro myself on a number of projects, and can’t speak too highly of it. I hope my new course will be of use to the community and help people get up to speed with it quickly. Basically, in the course I take a plain looking WPF application and update it to use the various features of MahApps.Metro. I also show how you can add charts from the Modern UI Charts open source project.

So do head over to Pluralsight and check it out if you’re interested in how to give your WPF applications a fresh lick of paint. If you’re not a subscriber yet, then why not take advantage of their 10 day free trial? There is an amazing library of fantastic content there and I think it’s the best way of quickly getting up to speed on any new technology.

Finally, let me give a big shoutout to Jan Karger and the rest of the MahApps.Metro team, who have just announced version 1.1.2. Thanks for your tireless work creating and maintaining this library.

Thursday, 2 April 2015

March Update

I’ve already mentioned that I’m no longer blogging here at blogger, and if you’re subscribed you should head over to markheath.net to be kept up to date. Here’s what you’ve missed over the past few weeks. If you want to keep updated with a weekly newsletter of new posts, do sign up for my mailing list.

NAudio

Skype Voice Changer

Misc

Sunday, 22 February 2015

Moving to markheath.net

I announced a while back that I was moving my blog to http://markheath.net. Well I’ve been double posting on both blogs for a while, but the transition is now complete, and no new posts will be added here.

If you’re subscribed with feedburner, then you should already be getting content via the new blog. But otherwise, please check at markheath.net for all future content.

To see what you’ve missed since I’ve moved, check out my archives page.

Sunday, 8 February 2015

Week Two - Bugs and Sales

Last week I told the story of how the "entreprogrammers" podcast inspired me to turn one of my ideas for an application into an actual product and make it available for sale. Of course I had no idea how it would actually do, and in the first week I only made one sale. That was pleasing in the sense that I knew that one or two sales a month would effectively cover my costs for web hosting, and also proved that that my shopping cart and license generator both worked. But I was hoping I could improve things. So in this (rather long) post, I'll tell you what happened in my second week.

Attracting Visitors

First, I needed to get some more traffic to my site and thankfully I had one quite good way of doing that. I had made a similar but limited open source application which continues to be extremely popular (still don't really know how!). I simply updated this application to suggest to users that if they wanted to record their calls they should check out the "pro" version, and directed them to my site. The traffic from this route is currently about 75% of my total traffic.

Secondly, I tried to generate a bit of buzz about the application on twitter. I don’t have a particularly big following (about 400 followers) and programmers aren't really my target market, but probably the best thing I did was to give a shout-out to the entreprogrammers. They seemed glad to re-tweet it to their many followers, and it resulted in me reaching the heady heights of about 6 concurrent visitors to the site! Takeaway: a bit of flattery can really pay off if you want people to spread awareness of your product!

clip_image001

The Mailing List

My third idea for getting some traffic was to leverage my mailing list. I had made a bit of a mistake in harvesting emails in the year preceding my launch. I didn't do a "double opt-in" (where you get people to verify their email by clicking a link). This meant I couldn't import the 1400 email addresses I had on the list into MailChimp.

So instead I wrote my own script in the awesome LinqPad application to send mails to this list using my own SMTP server. This revealed that just over 10% of the emails in the list were invalid, and I created a special script on my website to serve up an image in the email so I could track open rate. I was sending out in batches of 50 for fear of getting blocked as a spammer, and so I could try alternative ideas as I worked my way through the list. But 300 emails in, and I've not really seen much of a response so far.

I also emailed out to my MailChimp mailing list (the one with proper double opt in subscribers!), which is slowly growing, but currently only at 40 subscribers. Again the open rate wasn't exactly impressive, and I don't think it led to any sales, but at least this list I am allowed to keep emailing, so I have the chance to keep the product in their mind.

Tracking Errors

Another thing I did during the week, was to actually allow customers to submit the details of any unhandled exceptions they encountered during the running of the application. I needed to know if all the people who were downloading my app were actually having any success running it. The results were interesting (read about what I did here) and I discovered many problems my users were having that could be relatively easily resolved. In fact there are still several issues I need to get fixes out for next week. I suspect that users who see the app crash are much less likely to shell out for a license, so the sooner I can eliminate common causes of error the better.

A Customer Support Case

My heart sank when only my third customer since the site went live contacted the support email to say she couldn’t install the application. Turns out she was getting some kind of weird ClickOnce error (yes I know, I'm supposedly an expert in that now). Thankfully she was very patient while we tried a few troubleshooting steps and eventually we got it working for her. But I suspect I was close to having to issue my first refund.

Getting More Subscribers

One of the entreprogrammers, Derick Bailey kindly gave me some advice on my site. He particularly pointed out that visitors could simply download my application without giving their email address. He suggested I should change that, and only offer them the download if they subscribed to my list.

To do that required a bit of learning about the MailChimp API. Unfortunately because I am not on one of their paid tiers yet, I can't create an email that gets auto-sent to new subscribers. So I had to set up a webhook and send out the email with the download link myself when a subscriber was confirmed.

In fact, I currently allow users through to the download page even before they click the confirmation from MailChimp, so technically it is still possible for people to install the app without subscribing to my newsletter. I'm going to see what percentage of people do that, and if it is too high, I'll force everyone to complete the cycle and subscribe before they get the download link.

Website Redesign

The second thing I did was a complete website redesign. This was a painful process as HTML and CSS is not my strong suit. I had paid for a nice looking landing page called Ultima from Wrap Bootstrap. The challenge was working out what bits of the gigantic 3000 line CSS file and the dozen or so JavaScript libraries it came with I actually needed.

clip_image002

I suspect it has left my site a little bloated in terms of download size, and I'm really hoping it actually still works in all browsers, but I do feel that the site now looks a lot more professional and engaging and hopefully I'll still get a lot of people downloading and installing despite the need to enter your email address.

Social Media

I also decided that I needed to give Skype Voice Changer a presence on social media. So I created a facebook page, a Google plus page, and a YouTube channel (no videos yet). I've not yet got round to a twitter account. Of course, these are currently virtual ghost towns, but I've added some social media icons to my website, and maybe if I decide to spend some money on advertising at some point I can drive some traffic through facebook, youtube or twitter.

clip_image003

Pricing

With only one sale in the first week, I was concerned that I had overpriced my app. I was charging $50/£30 and asking for VAT on top. Other similar Skype utilities seemed to be priced at around $30. So I decided to make the quoted price inclusive of VAT, and run a month long "launch sale" at 40% off. I thought that this might allow me to create a sense of "urgency", particularly towards the end of the month, by encouraging people to buy before the sale ends. As it is, it is rather too easy for them just to try the app out and then forget about it. What difference did my new pricing strategy make to sales? Well nearly there, read on to find out.

The Numbers - Visitors

I've had Google Analytics running in the background for much of the last week. It's fascinating how much information this tool gathers. The number of "sessions" has been artificially bloated by the number of times I've visited the site myself during development, but according to Google Analytics, I have nearly 100 different people visiting the site a day, which I'm hoping isn’t too bad for a two week old product (not really sure what I'm supposed to be expecting at this stage).

clip_image004

The Numbers - Sales

Finally, we're onto the bit we've been waiting for. How many did I sell in my second week? Well, I did improve on the one sale from the first week. There was a moment of excitement early in the week when I made two sales in quick succession. But sales came in at a rate of just under one a day and by the end of the week I had sold six. This was a fairly encouraging rate, and if I can keep it up will mean I comfortably cover my costs. Interestingly, including VAT in the price has not impacted my earnings at all, since all my customers so far have been from outside the EU (mostly USA, with one sale each in Canada, Australia and Brazil).

clip_image005

What's Next

Well although one sale a day isn’t too shoddy, I don’t think it's quite time to put my feet up and abandon this project as a source of "passive income". First of all I need to fix more of the bugs that my users are reporting. This should mean more people have a smooth first experience with the product.

I know I also need to improve the nag screen within the app, so that people who keep using it get regularly promoted to purchase a license, rather than the current half-hearted attempt that is in there.

I'm fairly happy with the overall content on my website now, but I do think I need to create at least one video, to show off the application's features and teach how to use it.

And finally, I'm a little paranoid now that with all the extra JavaScript in the site from the template I bought, maybe some visitors are getting JavaScript errors that are preventing them from being able to use the paddle.com payment form. So I'd like to investigate a way of making that part of the site bullet-proof, so that whatever happens in the page load, the purchase link will always work.

Well done if you managed to read all that to the end! My goal for next week is to improve on the six sales I achieved last week. I'll let you know how I get on, and do let me know in the comments how you're getting on with your own personal entrepreneurial projects!

Tuesday, 3 February 2015

How to Encode MP3s with NAudio MediaFoundationEncoder

In this post I am going to explain how the NAudio MediaFoundationEncoder class can be used to convert WAV files into other formats such as WMA, AAC and MP3. And to do so, I'll walk you through a real-world example of some code I created recently that uses it.

The application is my new Skype Voice Changer utility, and I wanted to allow users to save their Skype conversations in a variety of different formats. The WavFormat that Skype uses is 16kHz 16 bit mono PCM, and I capture the audio directly in this format, before converting it to the target format when the call finishes.

The input to the MediaFoundationEncoder doesn't actually have to be a WAV file. It can be any IWaveProvider, so there is no need to create a temporary WAV file before the encoding takes place.

Initialising Media Foundation

The first step is to make sure Media Foundation is initialised. This requires a call to MediaFoundation.Startup(). You only need to do this once in your application, but it doesn’t matter if you call it more than once. Note that Media Foundation is only supported on Windows Vista and above. This means that if you need to support Windows XP, you will not be able to use Media Foundation.

Determining Codec Availability

Since I planned to make use of whatever encoders are available on the user’s machine, I don't need to ship any codecs with my application. However, not all codecs are present on all versions of Windows. The Windows Media Audio (and the Windows Media Voice) codec, are unsurprisingly present on all the desktop editions of Windows from Vista and above. Windows 7 introduced an AAC encoder, and it was only with Windows 8 that we finally got an MP3 encoder (although MP3 decoding has been present in Windows for a long time). There are rumours that a FLAC encoder will be present in Windows 10.

For server versions of Windows, the story is a bit more complicated. Basically, you may find you have to install the "Desktop Experience" before you have any codecs available.

But the best way to find out whether the codec you want is available is simply to ask the Media Foundation APIs whether there are any encoders that can target your desired format for the given input format.

MediaFoundationEncoder includes a useful helper function called SelectMediaType which can help you do this. You pass in the MediaSubtype (basically a GUID indicating whether you want AAC, WMA, MP3 etc), the input PCM format, and a desired bitrate. NAudio will return the "MediaType" that most closely matches your bitrate. This is because many of these codecs offer you a choice of bitrates so you can choose your own trade-off between file size and audio quality. For the lowest bitrate available, just pass in 0. For the highest bitrate, pass in a suitably large number.

So for example, if I wanted to see if I can encode to WMA, I would pass in an audio subtype of WMAudioV8 (this selects the right encoder), a WaveFormat that matches my input format (this is important as it includes what sample rate my input audio is at - encoders don't always support all sample rates), and my desired bitrate. I passed in 16kbps to get a nice compact file size.

var mediaType = MediaFoundationEncoder.SelectMediaType(
                    AudioSubtypes.MFAudioFormat_WMAudioV8, 
                    new WaveFormat(16000, 1), 
                    16000); 

if (mediaType != null) // we can encode… 

What about MP3 and AAC? Well you might think that the code would be the same. Just pass in MFAudioFormat_MP3 or MFAudioFormat_AAC as the first parameter. The trouble is, if we do this, we get no media type returned, even on Windows 8 which has both an MP3 encoder and an AAC encoder. Why is this? Well it's because the MP3 and AAC encoders supplied with Windows don't support 16kHz as an input sample rate. So we will need to upsample to 44.1kHz before passing it into the encoder. So now let's ask Windows if there is an MP3 encoder available that can encode mono 44.1kHz audio, and just request the lowest bitrate available:

mediaType = MediaFoundationEncoder.SelectMediaType(
            AudioSubtypes.MFAudioFormat_MP3, 
            new WaveFormat(44100,1), 
            0); 

Now (on Windows 8 at least) we do get back a media type, and it has a bitrate of 48kbps. The same applies to AAC - we need to upsample to 44.1kHz first, and the AAC encoder provided with Windows 7 and above has a minimum bitrate of 96kbps.

Performing the Encoding

So, assuming that we've successfully got a MediaType, how do we go about the encoding? Well thankfully, that's the easy bit. So for example, if we had selected a WMA media type, we could encode to a file like this:

using (var enc = new MediaFoundationEncoder(mediaType)) 
{ 
    enc.Encode("output.wma"), myWaveProvider) 
} 

In fact, to make things even simpler, MediaFoundationEncoder includes some helper methods for encoding to WMA, AAC and MP3 in a single line. You specify the wave provider, the output filename and the desired bitrate:

MediaFoundationEncoder.EncodeToMp3(myWaveProvider, 
                        "output.mp3", 48000); 

 

Creating your Pipeline

But of course the bit I haven't explained is how to set up the input stream to the encoder. This will need to be PCM (or IEEE float), and as we mentioned, it should be at a sample rate that the encoder supports. Here's an example of encoding a WAV file to MP3, but remember that the input WAV file will need to be 44.1kHz or 48kHz for this to work.

using (var reader = new WaveFileReader("input.wav")) 
{ 
    MediaFoundationEncoder.EncodeToMp3(reader, 
            "output.mp3", 48000); 
} 

But that was a trivial example. In a real world example, such as my Skype Voice Changer application, we have a more complicated setup. First, we open the inbound and outbound recording files with WaveFileReader. Then we mix them together using a MixingSampleProvider. Then, since I limit unregistered users to 30 seconds of recording, we optionally need to truncate the length of the file (I do this with the OffsetSampleProvider, and using the Take property). Then, if they selected MP3 or AAC we need to resample up to 44.1kHz. Since we’re already working with Media Foundation, we’ll use the MediaFoundationResampler for this. And finally, I go back down to 16 bit before encoding using a SampleToWaveProvider16 (although this is not strictly necessary for most Media Foundation encoders).

// open the separate recordings 
var incoming = new WaveFileReader("incoming.wav"); 
var outgoing = new WaveFileReader("outgoing.wav"); 

// create a mixer (for 16kHz mono) 
var mixer = new MixingSampleProvider(
                WaveFormat.CreateIeeeFloatWaveFormat(16000,1)); 

// add the inputs - they will automatically be turned into ISampleProviders 
mixer.AddMixerInput(incoming); 
mixer.AddMixerInput(outgoing); 

// optionally truncate to 30 second for unlicensed users 
var truncated = truncateAudio ? 
                new OffsetSampleProvider(mixer) 
                    { Take = TimeSpan.FromSeconds(30) } : 
                (ISampleProvider) mixer; 

// go back down to 16 bit PCM 
var converted16Bit = new SampleToWaveProvider16(truncated); 

// now for MP3, we need to upsample to 44.1kHz. Use MediaFoundationResampler 
using (var resampled = new MediaFoundationResampler(
            converted16Bit, new WaveFormat(44100, 1))) 
{ 
    var desiredBitRate = 0; // ask for lowest available bitrate 
    MediaFoundationEncoder.EncodeToMp3(resampled, 
                    "mixed.mp3", desiredBitRate); 
} 

Hopefully that gives you a feel for the power of chaining together IWaveProvider’s and ISampleProvider’s in NAudio to construct complex and interesting signal chains. You should now be able to encode your audio with any Media Foundation encoder present on the user’s system.

Footnote: Encoding to Streams

One question you may have is "can I encode to a stream"? Unfortunately, this is a little tricky to do, since NAudio takes advantage of various "sink writers" that Media Foundation provides, which know how to correctly create various audio container file formats such as WMA, MP3 and AAC. It means that the MediaFoundationEncoder class for simplicity only offers encoding to file. To encode to a stream, you'd need to work at a lower level with Media Foundation transforms directly, which is quite a complicated and involved process. Hopefully this is something we can add support for in a future NAudio.

Monday, 2 February 2015

Are you feeling your customers’ pain?

I blogged recently about finally getting the first version of my Skype Voice Changer application out the door. In order to get something into the hands of users, I had to take a few shortcuts and make a few compromises. One of those was error handling. Basically, for the first version, if something went wrong I would pop up an apologetic dialog, and suggested that they emailed my support address with details of the problem (I included the stack trace in the dialog).

Of course, I got no reported errors at all via email, which meant that no one was having any problems with my app, right?

Automated Error Reporting

Well I knew that probably there were some issues, and so in the next version I added a button on my error dialog to offer the user the chance to submit an error report to a web API. Then my web server could simply drop the error report into Azure blob storage as a text file. Nice and simple (and VS2013 makes it really easy to check a blob container for new entries and look inside them).

Well, within an hour of going live with the new version, I saw three errors reported. And they kept on coming at a rate of about one or two an hour. Some of these were clearly the same user submitting the same problem multiple times, but it revealed that people were using my app, and it wasn't going smoothly for all of them.

Analysing the Errors

By analysing the errors it became apparent that I had some recurring faults. Several users failed to start up with a SocketException - clearly something was blocking them from opening the necessary ports. One user's soundcard refused to open. Some users could connect to Skype, but not determine which version of Skype they were connected to. One user couldn't initialise Media Foundation. One user's installation was bizarrely missing some of the included data files. Without automating error reporting from my app, I would have had no idea that these problems were occurring.

Improving Error Logging

So with error reports now flooding in thanks to my automated submit, I set to work about addressing them. In fact the first thing I did was to improve the error messages I was submitting to myself. They only included the stack trace, and so I upgraded them to include details of what version of Windows and Skype the user was running, and what operation they had been attempting.

Handling Anticipated Exceptions

It also meant I had the opportunity to write some more "defensive code" to handle "anticipated exceptions". In other words there are now several places in my code where I know things might go wrong. Thanks to the stack traces, I know what lines can blow up and with what exceptions. This allows me to specifically write code that anticipates those problems and either works around them, or presents the user with a much more friendly and meaningful message, allowing them to continue if at all possible. However, I still let them report these errors if they wanted, since I don't want to mask an ongoing problem.

Quick Bugfix Turnaround

So I quickly released another version, and sat there refreshing my error blob container to see if my fixes had worked. This time things were a bit more encouraging. In the next 24 hours I had just three errors reported. The improvements I made to error logging also proved extremely useful in helping me diagnose the cause of these issues. This is another benefit of automated error reporting - it allows me to have an extremely quick bugfix turnaround - I can resolve an issue a user is seeing and get an updated version of the app released within hours of the original problem.

Obviously I still don't have any information on how many people are successfully using my application - I'll need to ask my users permission to submit usage statistics in order to do that. But automated submitting of errors with good diagnostic information is an excellent starting point. What about your users? Are they suffering in silence, or are you feeling their pain?

Saturday, 31 January 2015

Buying a Code Signing Certificate

Towards the end of last year, I decided to buy a code signing certificate. Why would I want to do that? Well, I've been working on publishing a new Skype call recording utility, and if you leave your applications unsigned, then Windows SmartScreen can block users from installing and running it. There is a way to ignore the warning messages, but many users will not know how to do this, and I wanted to remove as many barriers to installation as possible.

clip_image001

Having a signed application doesn't automatically make these warnings go away. After all, what's to stop a malicious hacker from signing their own code? But once Windows decides that they trust my application, the theory is that any updates or new applications signed with the same certificate will also be trusted.

Step 1 was to find a code signing certificate that wasn't horrendously expensive. Code signing certificates are a lot more expensive than SSL certificates (I recently picked up an SSL certificate for $25 for five years), and can be several hundred dollars a year. This is of course no big deal if you are Microsoft or Adobe, but for an independent developer, this is a significant investment, particularly if you don't have a high volume of sales, or are producing freeware.

I eventually settled on using K Software, whose website seemed to contain relatively up to date information about code signing certificates. Their cheapest authenticode certificates were about $80 per year, and they promised a fast turnaround time. Apparently certificates could be issued as quickly as 15 minutes, or 1-2 days if identify verification was needed.

So I made the order, and my order was passed on to Comodo, who were the actual certificate authority who would be issuing me with my code signing certificate.

After a few days of silence I chased up to ask what was going on, and I got a reply back telling me I needed "face to face verification". In other words I needed to prove I was who I said I was. Fair enough, I was expecting to send some proof of identity to them, but I hadn't anticipated they would require me to visit a Notary Public.

They also told me they wanted my details on 192.com and scoot.co.uk. This was something I really didn't want to do, since these open you up to nuisance marketing phone calls. But I had no option if I wanted to, and registered my business on scoot.

Visiting a notary was a bit of a hassle as it required me to take a half-day off work. It cost me £40, and he took copies of my passports, bank statements and various other forms of identification, and faxed them through to Comodo. I was required to "overnight" the documents to Comodo, but that isn't an option the Royal Mail offer to America, so I went for their best service of tracked and signed, which supposedly delivers in five working days.

That proved to be a mistake, as my documents took 16 days to arrive. This was extremely frustrating as scoot were constantly pestering me with phone calls trying to upsell me to their paid offering. They kept explaining that their free option doesn't show your company website URL to visitors, and wondering why I didn't seem to care about this. I didn't want them to boot me off their listings, so I had to stall them for as long as possible, while I waited for the interminably slow overseas postal service to deliver my documents.

Very concerningly, after I got confirmation of delivery from Royal Mail, Comodo claimed not to have received my documents at all. But after several emails they eventually decided they had received them. Now they needed to contact my Notary Public and get him to verify that he really did send the documents. This took another a few days, and finally, well over a month after making the order, I got my signing certificate.

To actually download the certificate, I needed to use the same computer and browser as I had used to make the original order. This was a bit of a problem at first because I had actually forgotten which one I used now that a whole month had elapsed. But eventually I downloaded my certificate, and it downloaded into some mysterious location in Chrome, but fortunately allowed me to export it as a .pfx file, which is what I needed for signing ClickOnce applications.

So I did finally get my code signing certificate, and it certainly didn't take anything like the 1-2 days advertised. It meant I had to delay the launch of my product by a month. The good news is that as far as I can tell, signing my code has had the desired effect - the installs I've tried haven't been blocked by Windows SmartScreen.

So if you decide you want a code signing certificate, do give yourself plenty of time to get it sorted out and don’t leave it to the last minute. You may also want to check out this very thorough article from Eric Law in which he explains how he went about getting his code signing certificate and set up a hardware security token.

Thursday, 29 January 2015

Using Azure Application Diagnostics with ASP.NET Web Pages

Although I've built a couple of sites with ASP.NET MVC, I like the simplicity of ASP.NET Web Pages. It allows me to start with a completely empty project and only add code I've written and understand (interestingly this seems to be the philosophy behind the vNext version of ASP.NET). The downside is that every now and then I run into things that would be easy to do with ASP.NET MVC, but finding how to accomplish them with Web Pages is tricky.

Azure Diagnostics

Windows Azure WebSites offers a nice feature to turn on "application diagnostics". This allows you to write your own custom error logs using System.Diagnostics.Trace. It's super easy to configure - simply go to the control panel for your website in the Azure portal, and chose where you want these logs stored. You can choose any combination of file system, table storage and blob storage, and you can set different logging levels for each one.

clip_image001

Once you've done this, in theory you should just be able to write messages using the Trace class and see them appear in the places you’ve configured. If you choose blob storage, for example, you get a CSV file with the trace messages for a particular day.

@{
    System.Diagnostics.Trace.TraceInformation("INFORMATION");
    System.Diagnostics.Trace.TraceWarning("WARNING");
    System.Diagnostics.Trace.TraceError("ERROR");
}

 

Using it with ASP.NET Web Pages

However, if you try this with ASP.NET Web Pages, you simply won’t see anything at all in your logs. However, thanks to StackOverflow, I found out how to enable application tracing. Basically the TRACE flag needs to be set on the compiler this can in the web.config file. For a .NET 4.5 application, you need the following:

<system.codedom>
    <compilers>
        <compiler language="c#;cs;csharp" 
                  extension=".cs" 
                  type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" 
                  compilerOptions="/define:TRACE" 
                  warningLevel="1" /> 
    </compilers> 
</system.codedom>

Once you’ve done this, re-deploy your web.config and as if by magic all your trace statements will make it through to the configured destinations. This allows you to easily log anything from both within Razor views as well as from within any C# files you have in your App_Code folder.

Anyway, hope this post is useful to someone as it had me tearing my hair out for an evening trying to figure out why it wasn’t working.

Wednesday, 28 January 2015

Minimum Deliverable Product

Many years ago, I came up with an idea for a simple software application that I could sell online. Basically, an open source app I created for modifying your voice in Skype became incredibly popular and had millions of downloads, and it struck me that I could probably sell a "Pro" version with some additional features.

Of course what actually happened was that the code for the "Pro" version stagnated for years as my enthusiasm for this project came in fits and starts, and I couldn't make up my mind exactly how I wanted to build the thing, and wasn't even sure anyone would buy it. So the idea was going nowhere.

Getting Motivated

But about a year ago I started listening to the entreprogrammers podcast, and it inspired me to resurrect this idea. The only trouble was, would I be able to find the time to actually complete the thing, given that I was already spending a lot of my free time making courses for Pluralsight?

I soon realised that if I were to ever get something out the door I would need to pick a realistic and achievable feature set for the first version, and focus exclusively on completing that. In other words I needed to stop trying to make the perfect app, and create what's known as a "Minimum Viable Product".

Minimum Feature Set

For my application there were three main features I wanted to deliver:

  1. You can change your voice in a Skype conversation
  2. You can play back pre-recorded sounds for the other person to hear
  3. You can record your Skype conversations

For each of these features, I decided on what the bare minimum capabilities were that I would be happy launching with. For example, I wanted several cool voice effects, but I didn't really need the effects parameters to be adjustable. I wanted the ability to replay sounds, but I didn't really need looping and repositioning within those sounds for version 1. And I wanted to offer recording to MP3, but for version 1, recording to WAV would probably suffice.

By deciding on a minimum feature set for my application, I finally had an achievable goal and was able to focus on getting the job done.

Minimum Lovable Product

I've heard some criticism of the "minimum viable product" concept from people saying that what you really need to create is a "minimum lovable product". In other words, if your application is too stripped down and basic, you may find that no one is willing to buy it, and your potential customers go off in search of alternative solutions. So while I did go for a fairly basic feature set, I did attempt to ensure that I had just enough in each of my three key features to offer customers something genuinely fun and useful.

Minimum Deliverable Product

Unfortunately though, completing the minimum viable feature set of my application was the easy part. There is a whole host of additional stuff that needs to be done just to sell a single piece of software. I needed an installer, a logo, a website, a domain name, some help documentation and tutorials, an email address to handle sales and support enquiries, a way of selling the software that complies with the new and arcane EU VAT rules, a way of refunding people, a way of generating software licenses, and a way to handle errors gracefully within the application.

It turned out that it was these tasks rather than the core feature set that were preventing me from completing the project. So I decided I needed to take the "minimum viable product" approach with each of them too.

What's the "minimum viable website"? I created something very simple (and ugly) in bootstrap and ASP.NET web-pages. A few basic help pages, and the ability to install and buy were all that was really needed. It doesn't look pretty but I can improve it gradually or even hire a designer at a later date.

What's the "minimum viable installer"? I opted for ClickOnce, since it's quick to make an installer and easy to keep customers updated with new features. Even that turned into a bigger task than I wanted as the hassle I went through to purchase a code signing certificate was much greater than I anticipated.

What's the "minimum viable licensing mechanism"? Here I may have made a mistake. I opted for portable.licensing,which itself is great, but that meant I had to create an automated license creation and emailing system. Maybe I should have just decided not to worry about pirating, and save myself time by not using licenses.

What's the "minimum viable checkout"? Well a "buy now" PayPal button was my plan, but thanks to the new EU laws on VAT collection I needed a complicated system of verifying the locations of my customers and charging them the correct VAT. So I decided to find a company who would collect and report VAT for me. After a false start with Digital River's MyCommerce, who disabled my account and refused to respond to any emails, I found paddle.com whose customer support was much better, and offered straightforward integration for my own license generation code (turns out I could have used their built-in license generation capabilities but I was too far down the road with my own by this point).

Keeping Motivated

So actually going from a working prototype to a deliverable product is quite a journey. I realised that if I was ever going to complete the task, I'd need a way to motivate myself. So what I did was put an advert in my open source software for the "Pro" version. It would simply tell users that if they wanted to record their calls they could upgrade. The advert took them to a "coming soon" page hosted on my blog, where they could register their interest to be notified when the pro version was released, and they could purchase a pre-order license for a discounted price.

My email list grew quite rapidly - I collected 1400 email addresses in just over a year. And I had six people pre-order the product for $30 (actually seven pre-orders, but one wanted a refund when he realised it wasn't released yet). The very fact that I had some customers who had paid for the product helped motivate me to actually complete the task.

Going Live

So finally, years later than I should have done it, I went live with my site a couple of days ago. I've still got to email all the people who registered pre-order interest, and offer them a discount. I'm not sure what my "conversion rate" will be, but with 1,400 emails I'm hoping at least a few people will buy a license.

Obviously going live is only the beginning. There are lots of tweaks and enhancements to my app and website that I deliberately held off doing, just so I could get my first version out of the door. But that's the point of the minimum viable product. Just get something released, and then you can gauge how much further time and effort to invest, depending on whether there is actually any interest.

At the time of writing I'm still waiting for my first customer from the new site (it's early days yet, but I suspect my marketing and sales ineptitude isn't helping). But if you have a use for a Skype Voice Changer or a Skype call recorder, then why not try it out? And if you'd like to be my first customer, then I'm offering readers of my blog a 25% discount. Just use the SOUNDCODE coupon code when you purchase.

Tuesday, 6 January 2015

Porting WCF Service Contracts to F#

One of my goals this year is to get better at F#, by using it more, so I decided to port a simple WCF service over to F#. In this post, I will demonstrate how to port data and operation contracts over from C# to F#. Let’s start by looking at the service contract we will be porting (simplified for the purposes of this post):

[ServiceContract]
public interface IRetrieval
{
    [OperationContract]
    [FaultContract(typeof(RetrievalServiceFault))]
    ChunkResponse GetChunk(ChunkRequest request);

    [OperationContract]
    [FaultContract(typeof(RetrievalServiceFault))]
    VersionInfoResponse GetVersionInfo(VersionInfoRequest request);
}


[DataContract]
public class VersionInfoResponse
{
    [DataMember]
    public string Version { get; set; }
}

[DataContract]
public class VersionInfoRequest
{
}

[DataContract]
public class ChunkResponse
{
    [DataMember]
    public byte[] Data { get; set; }

    [DataMember]
    public bool IsEndOfFile { get; set; }
}

[DataContract]
public class ChunkRequest
{
    [DataMember]
    public string FileName { get; set; }

    [DataMember]
    public long Offset { get; set; }

    [DataMember]
    public int BytesRequested { get; set; }
}

[DataContract]
public class RetrievalServiceFault
{
    public RetrievalServiceFault(string message)
    {
        this.Message = message;
    }

    [DataMember]
    public string Message { get; private set; }
}

Attributes

First, we need to know how to put attributes on things in F#. The syntax is similar to C#, just with an extra set of angle brackets (one of the few cases where C# is more compact than F#):

[<OperationContract>]

That’s easy, but what about the FaultContract attribute we have on each operation? That takes a type as a parameter. Well F# also has a typeof function, and you put the type name in angle brackets like so:

[<FaultContract(typeof<RetrievalServiceFault>)>]

Interfaces

Now we need to know how to declare an interface in F#. There seems to be no special syntax other than to declare a type containing only abstract members. For each method, we need to provide the name, the annotated parameter list, and the type it returns. The syntax looks a little odd to C# developers at first as we are used to the return type coming at the beginning rather than the end of the method signature. It takes the form abstract MethodName : ParameterName : ParameterType –> MethodReturnType. Here’s our example

[<ServiceContract()>]
type IRetrieval =
    [<OperationContract>]
    [<FaultContract(typeof<RetrievalServiceFault>)>]
    abstract GetChunk : request : ChunkRequest -> ChunkResponse

    [<OperationContract>]
    [<FaultContract(typeof<RetrievalServiceFault>)>]
    abstract GetVersionInfo : request : VersionInfoRequest -> VersionInfoResponse

 

Data Contracts

The final piece of the puzzle is to implement the four objects that are passed as the input and output to the methods on our interface. One of the challenges is that the properties need public getters and setters, and F# likes to make properties immutable. There are a few ways of achieving this in F#, but the simplest one for this purpose seems to be to use an F# record with the mutable keyword like so:

[<DataContract>]
type VersionInfoResponse =
    { [<DataMember>] mutable Version : string }

Empty Classes

The VersionInfoRequest class had me stumped for a while, as it contains no members at all (probably a bad design choice in C#), but I eventually stumbled on a way to implement this in F#:

[<DataContract>]
type VersionInfoRequest() = 
    do()

Longs and Byte Arrays

The final challenge for me was learning how to declare the types of C# long and byte[] types. In F# these turn into int64 and array<byte> respectively. Other types, such as bool, int and string, are unchanged from C#:

[<DataContract>]
type ChunkResponse =
    {   [<DataMember>] mutable Data : array<byte>;
        [<DataMember>] mutable IsEndOfFile : bool;
     }

[<DataContract>]
type ChunkRequest =
    {   [<DataMember>] mutable FileName : string;
        [<DataMember>] mutable Offset : int64;
        [<DataMember>] mutable BytesRequested : int;
    }

 

I’ll hopefully find some time soon to do a follow-up post showing how to configure the WCF client and server in F#.