Saturday, July 30, 2011

OSX Crashes More Then Windows

There! I said it!

For the record, all my computer hardware, phones, and tablets have been Apple for years; but I primarily do programming in .NET which means I still need to use Windows.

I'm on my 3rd Macbook Pro since Sept of 2007 and over that time OSX has consistently crashed more then Windows XP and Windows 7. Up until April of this year, I was primarily booting directly into Windows using Bootcamp and only using OSX 5% of the time and even with 5% use it had more complete lock ups!

Since April I've started running OSX 100% of the time and run Windows 7 off the Bootcamp partition using Parallels.

Since making the switch to 100% of the time I'd estimate OSX does a Black Screen of Death on average 3-4 times per month. I had one waiting for me this morning after leaving the computer on over night.

People think I'm making this up, so I plan to start tweeting every time it crashes for a historical record.

Granted I have a ton of software loaded on OSX, I'm running Parallels, and I use a Diamond BVU195 USB Display Adapter for a second monitor, BUT other then Parallels these are all things I did on Windows as well so I feel it's a fair comparison.

I've had Windows get slow, or weird, or need a reboot. But I can't remember the last Blue Screen of Death I've had, I can usually kill enough process where I can shut down the OS gracefully. I can't say the same for OSX.

I don't plan on switching away from my current setup and I'll be installing Lion soon. I just want people to STFU about how stable OSX is versus Windows, because it's simply not true.

Crash Log
  • 7/30/2011
  • 8/17/2011 (Milestone: first crash of OSX Lion)
  • 9/8/2011
  • 9/19/2011
  • 9/25/2011
  • 9/30/2011
  • 10/14/2011
  • 11/3/2011
  • 5/25/2012
  • 6/22/2012
  • 8/3/2012 (Milestone: first crash of OSX Mountain Lion)
  • 8/9/2012
  • 8/16/2012
  • 8/17/2012
  • 8/17/2012 (second time in one day, grrr)
  • 8/20/2012
  • 8/22/2012
  • 10/14/2012
  • 10/17/2012

Friday, July 15, 2011

ASP.NET MVC3 App Using plupload to Upload Directly to Amazon S3

UPDATE 8/15/2011:
I can't recommend using this for large files (video files). It's very unreliable. Web size image files and normal email attachment sized files would probably do fine. What I ended up doing to get around it was creating a web app on AppHarbor (which runs on EC2) that I upload the files to and it saves them to S3. Since the AppHarbor app is on a different domain you are still limited to Flash and Silverlight support but you do gain file chunking which brings back some reliability. Alternatively to AppHarbor you could setup your own server on Amazon as well.

I created a working example of using plupload to upload files directly to Amazon S3 and threw it on github, since the .NET examples I found on the web we're incomplete or broken.
https://github.com/crdeutsch/MVC3PluploadToAmazonS3

The files that are being uploaded do not even touch your web server. They are posted directly to Amazon. At the moment plupload only supports the Flash and Silverlight plugins as far as I can tell.

The AmazonS3Helper.cs library originated from Cary Abramoff off of this plupload forum thread.

I've made some changed based on iwasrobbed's excellent Ruby on Rails example.

Usage

Upload the crossdomain.xml found in the root of the site to your Amazon S3 Bucket.

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-access-from domain="*" secure="false" />
</cross-domain-policy>

Modify the settings in HomeController.cs to use your Amazan credentials and set your S3 bucket.

public ActionResult Index()
{
 string acl = "private";
 string bucket = "YOUR S3 BUCKET NAME";
 string accessKeyId = "YOUR AMAZON ACCESS KEY ID";
 string secret = "YOUR AMAZON SECRET ACCESS KEY";
 string policy = AmazonS3Helper.ConstructPolicy(bucket, DateTime.UtcNow.Add(new TimeSpan(0, 10, 0, 0)), acl, accessKeyId);
 string signature = AmazonS3Helper.CreateSignature(policy, secret);

 var model = new PluploadAmazonS3Model()
 {
  AWSAccessKeyId = accessKeyId,
  Policy = policy,
  Signature = signature,
  Bucket = bucket,
  Acl = acl
 };

 return View(model);
}

On the View side you could just use Razor to dump the Model variables directly into your javascript, but I decided to use hidden form variables instead in case you want to move the javascript to its own file where embedding Razor syntax won't work.

Hope this saves somebody else some time!

Friday, July 1, 2011

ASP.NET & IIS7 Error: Could not load file or assembly 'System.Data.SQLite'

This was annoying. I setup an ASP.NET MVC3 web application on a fresh install of Windows 2008 R2 and got the following error:
Could not load file or assembly 'System.Data.SQLite' or one of its dependencies. An attempt was made to load a program with an incorrect format.

I wasn't even using SQLite in my project; at least that's what I thought. Turns out ELMAH was trying to load it.

The error is due to trying to load the 32bit SQLite.dll on a 64 bit server.

To fix the error set Enable 32-Bit Applications to True for your Application Pool under Advanced Settings.





Sunday, May 1, 2011

Introducing Nodeler

After over a month of work I'm ready to subject my latest work, Nodeler, to the criticisms of the first 50 people who sign up using the Invite Code MakeRocketGoNow. ;)

Here's a video introduction to Nodeler. Otherwise read on...



What is it?
At it's heart I kind of think of it as a higher level, zero configuration service (Apple calls theirs Bonjour).

What good does that do me?
If you're a developer, it will allow you to register your application or game as a "node" that can request to be paired with other "nodes". A node can be anything from a game node requesting to be paired with a controller node to a video web site node requesting a remote control node.

You're not a developer?
Today, there are three Chrome extensions plus a Pacman game you can try.
  1. Nodeler Keyboard: allows you to accept keyboard input on any web page from a remote device.
  2. Nodeler Rdio Remote: allows you to remotely control the Rdio player. Play, pause, mute, and skip forward and back are currently supported.
  3. Nodeler Amazon Video Remote: allows you to remotely control the Amazon Video On Demand player. Play, pause, skip forward and back are currently supported.
  4. Pacman: I've modified Dale Harvey's excellent HTML5 Pacman app to be controllable via a Nodetroller (what I like to call the applications used to provide input to the above Chrome extensions).
You are a developer?
Send me an email if you're interested in using the Nodeler API. Once your Nodes are registered and authenticated via OAuth there are currently just two API calls. Node A submits a PairRequest and then Node B calls GetPairRequests.  The protocol used to communicate between nodes is up to you. If you need a central communication server I hope to offer the Nodeler Central's Node.js server in the near future. This is what the current nodes use. I'm still working out how I want to charge for usage of the Nodeler Central communication server but I do plan to have a free plan.

You're still reading and want to know what technologies this was built with?
Just C# and Javascript. ;)

The Nodeler web site and API are hosted at AppHarbor and were built with:
The server the Nodes communicate through is built using:
The Chrome Extensions use:
The iPhone app that I'm just finishing up was built using:
How can I find out more?
Follow me or Nodeler on Twitter for updates.

Would love to hear feedback on how I can improve the product!


    Tuesday, April 19, 2011

    Using RazorJS with MVC3

    I've been working on a project where I've managed to accumulate 1200+ lines of javascript in my View file. There are two reasons for this:
    1. Since the application is still in development I don't have to worry about the browser caching JS files if the code is in the View.
    2. I often have Url.Action and other snippets of Razor mixed in with my javascript. 
    I was just getting to the point where I was ready to move this code to its own .js file but I was worried about how to deal with the Razor that was mixed in. Thanks to John Katsiotis's (aka djsolid) RazorJS project I now have a solution!

    Installation is easy, just use Nuget to add RazorJS to your solution in Visual Studio. The command line to do is:

    Install-Package RazorJS

    By default @Url.Action will not work and you'll get the error:
    error CS0103: The name 'Url' does not exist in the current context

    To get it to work add the following at the top of your javascript file.
    @{
        var Url = new System.Web.Mvc.UrlHelper(System.Web.HttpContext.Current.Request.RequestContext);
    }
    

    If you run into other errors you should be able to use similar workarounds. If you do use other workarounds, let me know and I can add them to this post.

    UPDATE: In version 0.4.2 you no longer need this work around for the UrlHelper. Thanks to John for adding this so fast!

    Wednesday, April 6, 2011

    Sort Table Rows By Drag and Drop Using jQuery

    jQuery UI allows you to make a list of elements sortable, but if you want to use it to sort table rows you have to do a few workarounds. This is the code I started with.

    $(document).ready(function () {
    
        //make table rows sortable
        $('#myTable tbody').sortable({    
            helper: function (e, ui) {
                ui.children().each(function () {
                    $(this).width($(this).width());
                });
                return ui;
            },
            scroll: true,
            stop: function (event, ui) {
                //SAVE YOUR SORT ORDER                    
            }
        }).disableSelection();
    
    });
    
    


    The helper function (courtesy of The Foliotek Dev Blog) fixes the width of the row which collapses as soon as you remove it from the table.

    This should work for most scenarios, but I've found a bug in Firefox where the row will jump up and float above the cursor when there are scrollbars present on the web page. It seems to be a position issue caused by parent elements of the table. I still haven't figured out exactly what the magic combination is that causes this but I can replicate it with HTML5 Boilerplate when using the default style sheet and table below.

    I've replicated the bug on jsFiddle here:
    http://jsfiddle.net/cdeutsch/2Yxw2/

    <div id="container">
    <header>
    
    </header>
    <div id="main" role="main">
        <div style="position: relative;">
        <table id="myTable">
            <tbody>
            <tr>
                <td>1</td>
                <td>Blah Blah Blah Blah</td>
            </tr>
            <tr>
                <td>2</td>
                <td>2222 22222 22222 2222 22222</td>
            </tr>
            <tr>
                <td>3</td>
                <td>Test Test Test Test Test</td>
            </tr>
            <tr>
                <td>4</td>
                <td>4444 4444 4444 4444 4444</td>
            </tr>
            <tr>
                <td>5</td>
                <td>Hi Hi Hi Hi Hi Hi</td>
            </tr>
            <tr>
                <td>6</td>
                <td>Bye Bye Bye Bye Bye Bye Bye</td>
            </tr>
            </tbody>
        </table>
        </div>
    </div>
    <footer>
    
    </footer>
    </div> <!--! end of #container -->
    
    

    If this happens use the code below (inspired by this Stackoverflow question with some tweaks) to fix the issue.

    Try it in jsFiddle here:
    http://jsfiddle.net/cdeutsch/WysJL/

    $(document).ready(function () {
        //make table rows sortable
        $('#myTable tbody').sortable({
            start: function (event, ui) {
                //fix firefox position issue when dragging.
                if (navigator.userAgent.toLowerCase().match(/firefox/) && ui.helper !== undefined) {
                    ui.helper.css('position', 'absolute').css('margin-top', $(window).scrollTop());
                    //wire up event that changes the margin whenever the window scrolls.
                    $(window).bind('scroll.sortableplaylist', function () {
                        ui.helper.css('position', 'absolute').css('margin-top', $(window).scrollTop());
                    });
                }
            },
            beforeStop: function (event, ui) {
                //undo the firefox fix.
                if (navigator.userAgent.toLowerCase().match(/firefox/) && ui.offset !== undefined) {
                    $(window).unbind('scroll.sortableplaylist');
                    ui.helper.css('margin-top', 0);
                }
            },
            helper: function (e, ui) {
                ui.children().each(function () {
                    $(this).width($(this).width());
                });
                return ui;
            },
            scroll: true,
            stop: function (event, ui) {
                //SAVE YOUR SORT ORDER                    
            }
        }).disableSelection();
    });
    
    

    Hope this helps someone. Took me about 1/2 a day to fix the Firefox issue.

    Saturday, March 26, 2011

    Sensitive Web.config Settings + GitHub + AppHarbor

    So I learned some lessons with having an open source project (WatchedIt.net) on GitHub that is also being deployed to AppHarbor using the same Git repository.

    Number one tip. Do NOT save any sensitive information in any source file that you check into the repository. Even if you make a single commit locally with the sensitive info and then undo it with another commit, do NOT push it to GitHub without removing the history because your history will be sent to GitHub with a normal push. This page on GitHub can help you with that.

    Once we make sure our application does not have any sensitive info we need a way for AppHarbor to know our settings. The easy settings to handle are the Application Settings. AppHarbor has a Configuration Variables page where you define Key/Value pairs in your Web.Config you want AppHarbor to replace. For instance for WatchedIt I store my Twitter Key and Secret tokens like this in the Web.Config that is checked into Git and pushed to GitHub.

    <appSettings>
        <!--Site Settings-->
        <add key="ApplicationName" value="WatchedIt" />
        <add key="Twitter_Consumer_Key" value="YOUR_KEY" />
        <add key="Twitter_Consumer_Secret" value="YOUR_KEY" />
    </appSettings>
    

    Then I configure AppHarbor to replace Twitter_Consumer_Key and Twitter_Consumer_Secret with the real values and everything just works. This is pretty straight forward and covered by AppHarbor here.

    The setting that challenged me though was the connection string. I use Entity Framework Code First running on SQL CE to develop WatchedIt locally. My connection string in the Web.Config I check into Git looks like this:

    <connectionStrings>
        <add name="SiteDB" connectionString="Data Source=|DataDirectory|SiteDB.sdf" providerName="System.Data.SqlServerCe.4.0" />
    </connectionStrings>
    
    

    If you use an AppHarbor SQL or MySQL DB, AppHarbor says it will replace your connection string based on the name property. For some reason this didn't work for me and I think it's because it doesn't change the providerName property. So since AppHarbor also supports Web.Config transformations and Thomas Ardal has created a nice little webconfig transformation tester, I decided to combine the two features and see what would happen. To my delight it worked! Here is the code I placed in Web.Release.config to make it work:

    <connectionStrings>
        <add name="SiteDB" connectionString="" providerName="System.Data.SqlClient" xdt:Transform="Replace" />
    </connectionStrings>
    

    Now I don't have to worry about accidentally pushing my database connection string to GitHub for the world to see and while developing locally Visual Studio will use my SQL CE DB.

    This is just another example of why I love AppHarbor! I strongly recommend trying them out if you haven't yet!

    ....And one more thing. A big thanks to Michael Friis of AppHarbor for changing by DB password after "the incident". These guys rock at customer service!