Wednesday, December 22, 2010

How We're Surprising The Kids with a Disney World Trip

We booked a trip to Disney World for my fiance's 8 year old daughter and 10 year old son as their Christmas present. Which means we needed a good way to surprise them. I did some Googling and liked a couple ideas:
  • Wrapping up a mylar helium balloon with tickets attached so when the gift is opened the balloon floats out.
  • Putting a "gold ticket" inside a chocolate bar
  • Scavenger hunt
Since I'm not that good at "arts and crafts" I decided to go with what I knew and make a website. 
(best viewed using the Google Chrome web browser)

We plan to surprise the kids Christmas night, so if you know us keep it a secret for a few more days.  ;)

For any "non-programmers" reading this you can probably stop now. ;)

For the geeks, I used StaticMatic and TextMate to do the coding. The site is a single page of HTML5 and jQuery (and jQuery UI). You can get the source code here on GitHub.

The snow was Seb Lee-Delisle's work. It's a bit CPU intensive so if the application feels slow it's mostly due to the snow. The computer we'll be using to surprise the kids is fast enough to not be an issue.

I modified the jQuery TickerType plugin to type out the "You're going to Disney World" message at the end. 

If you've never used StaticMatic it's pretty cool. It allows you to use Haml and Sass to do your markup which is a fun quick way to code HTML. Great for a quick static website.

Since I use pieces of Paul Irish's HTML5 Boilerplate in just about every site I do now (I'm even updating old sites to use it as I work on them) I went looking for a StaticMatic plugin for it and thankfully found staticmatic-boilerplate by Aaron Cruz on GitHub.

Overall it was a fun break to use StaticMatic and TextMate (and OS X for that matter) versus the Visual Studio 10 environment I currently spend most of my time in.

But there are two things I'd love to see improved with StaticMatic and/or the Boilerplate plugin:
1) Make it easier to add jQuery UI to your site.
2) Make it easier to switch between uncompressed Javascript while developing and the production minified and combined javascript.


Friday, December 3, 2010

Fixed: PowerPoint 2010 Crashes When Typing

I ran into an issue where I'd open Power Point and as soon as I'd type a key into a slide it would lock up and crash.

The issue seems to be with Boot Camp drivers 3.1 and up which affects Apple hardware running Windows via BootCamp.

The solution that worked from me was found in this thread on the Apple Discussion forum posted by nallex:
Open "Control Panel" from the Start Menu
Select "Clock, Language, and Region"
Select "Change keyboards or other input methods" 
Click "Change keyboards..." button
Click "Add..." button
Roll down "English (United States)" (if it's not already expanded)
Select "US"
Click "OK"
Click "OK"
Click "OK"


Hopefully Apple comes out with BootCamp drivers to fix this issue.

Monday, November 29, 2010

.NET WebClient 403 Forbidden Error

Wasted 2 hours trying to track down the following error when making a simple WebClient DownloadFile request to an Amazon S3 url:
The remote server returned an error: (403) Forbidden.

Offending code and Url:
Uri uu = new Uri("https://zencoder-live.s3.amazonaws.com:443/add9d5d739193c13fcde60d3d7ff5ba7%2Ffe33f4d52e1cff0ef06592ed4041a7dc.mp4?Signature=b%2FXw9ylREb4up4QDw6Tyv9GyQhU%3D&Expires=1291150754&AWSAccessKeyId=AKIAIIEXNN2J4YDTRUVQ");
using (WebClient wClient = new WebClient())
{
    wClient.DownloadFile(uu, @"C:\output.mp4");
}

I was able to use Fiddler to compare Firefox's request versus my .NET application's request.

Firefox:GET /add9d5d739193c13fcde60d3d7ff5ba7%2Ffe33f4d52e1cff0ef06592ed4041a7dc.mp4?Signature=b%2FXw9ylREb4up4QDw6Tyv9GyQhU%3D&Expires=1291150754&AWSAccessKeyId=AKIAIIEXNN2J4YDTRUVQ HTTP/1.1


.NET WebClient:GET /add9d5d739193c13fcde60d3d7ff5ba7/fe33f4d52e1cff0ef06592ed4041a7dc.mp4?Signature%3Db%2FXw9ylREb4up4QDw6Tyv9GyQhU%3D%26Expires%3D1291150754%26AWSAccessKeyId%3DAKIAIIEXNN2J4YDTRUVQ HTTP/1.1

Notice that .NET is escaping my Url. Particularly the forward slash (%2F). You used to be able to pass a dontEscape parameter to the new Uri constructor but now that parameter is deprecated and is always false.

Luckily I came across a workaround on StackOverflow by Rasmus Faber:
Uri uu = new Uri("https://zencoder-live.s3.amazonaws.com:443/add9d5d739193c13fcde60d3d7ff5ba7%2Ffe33f4d52e1cff0ef06592ed4041a7dc.mp4?Signature=b%2FXw9ylREb4up4QDw6Tyv9GyQhU%3D&Expires=1291150754&AWSAccessKeyId=AKIAIIEXNN2J4YDTRUVQ");
ForceCanonicalPathAndQuery(uu);
using (WebClient wClient = new WebClient())
{
    wClient.DownloadFile(uu, @"C:\output.mp4");
}

void ForceCanonicalPathAndQuery(Uri uri){
  string paq = uri.PathAndQuery; // need to access PathAndQuery
  FieldInfo flagsFieldInfo = typeof(Uri).GetField("m_Flags", BindingFlags.Instance | BindingFlags.NonPublic);
  ulong flags = (ulong) flagsFieldInfo.GetValue(uri);
  flags &= ~((ulong) 0x30); // Flags.PathNotCanonical|Flags.QueryNotCanonical
  flagsFieldInfo.SetValue(uri, flags);
}

Now the code downloads the file like without the error!

Saturday, November 27, 2010

.NET Zencoder API Wrapper

I've been working with automated video encoding systems for over 10 years. I'd like to say there have been lots of improvements in the tools available but the only tools that have made life easier are the hosted solutions like Zencoder.

Zencoder has a really nice API builder on their website and tools like John Sheehan's RestSharp make calling web services from .NET easier then ever. But why not take it a step further and get it down to one line of code to submit an encoding job? That's what I've done over my Thanksgiving weekend and the results are on GitHub in my ZencoderWrapper repository.

One liner transcode:
JobResponse job = new ZencoderClient(API_KEY).SubmitJob("http://cdeutsch.com/input.avi", "ftp://ftpuser:[email protected]/videos/", "output.mp4");

You'll need to create an account on Zencoder to use the service. And if you want to encode more then 5 seconds of video you'll need to pick a payment option. You can alternatively use the ZencoderWrapper to create your account:
CreateAccountRequest account = new CreateAccountRequest("[email protected]", "password123");

Here's a more advanced example of creating an Ogg Vorbis file with thumbnails and notifications:
ZencoderClient client = new ZencoderClient(API_KEY);
JobRequest jobRequest = new JobRequest("http://cdeutsch.com/input.avi", new OutputSetting("ftp://ftpuser:[email protected]/videos/", "output.ogg"));
//configure output settings.
jobRequest.outputs[0].audio_codec = AudioCodecSetting.Vorbis;
jobRequest.outputs[0].video_codec = VideoCodecSetting.Theora;
//add a notification.
jobRequest.outputs[0].NotificationSettings = new List<NotificationSetting>();
jobRequest.outputs[0].NotificationSettings.Add(new NotificationSetting(NotificationType.Email, "[email protected]"));
//create thumbnails
jobRequest.outputs[0].thumbnails = new ThumbnailSetting();
jobRequest.outputs[0].thumbnails.base_url = "ftp://ftpuser:[email protected]/thumbs/";
jobRequest.outputs[0].thumbnails.format = ThumbnailFormatSetting.PNG;
jobRequest.outputs[0].thumbnails.interval = 5;
jobRequest.outputs[0].thumbnails.number = 3;
jobRequest.outputs[0].thumbnails.prefix = "thumb_";
jobRequest.outputs[0].thumbnails.size = "120x80";
jobRequest.outputs[0].thumbnails.start_at_first_frame = true;
//submit the job
JobResponse job = client.SubmitJob(jobRequest);

Here's how to check the status of the job we just created:
//get job details.
JobListingResponse job = client.GetJob(job.id);

Here's how to check to the status of the job's output file (there can be multiple outputs):
//get progress of first (in this case only) output file.
JobOutputProgressResponse progress = client.GetJobOutputProgress(job.outputs[0].id);

And finally here's how to get a list of all of your jobs:
//get list of jobs
List<JobListingResponse> jobList = client.ListJobs();

If I can convince Implex (the company I work for) to outsource their encoding to Zencoder I'll be using this wrapper for their QwikCast product. I also have another personal project I plan to use the wrapper in.

If you end up using it shoot me a message I'd love the feedback!

UPDATE 11/28/2010:
Not sure how I overlooked this earlier (either missed the Zencoder "Libraries" link or just got carried away with the idea of trying something new I guess) but Chad Burggraf has already created an excellent C# Zencoder client. I may end up using his library over my own for the asynchronous support. Part of it will depend on if Chad's library can compile with Mono since the personal project I want to build will ultimately be running on OSX. I'm not sure if my library will compile in Mono "as-is", but I believe RestSharp will and I don't think I used anything special beyond what's contained in RestSharp.

Tuesday, November 9, 2010

WatchedIt - An MVC3, Razor, EF4 Code First Production

One of the features I love about applications like Boxee is it treats the content you're watching like email. Instead of "read" and "unread" it's "watched" and "unwatched". This is great if you don't have a significant other who tends to watch all of your shows before you. ;)

So I decided to make an application I call WatchedIt to track where I left off watching shows. What a perfect opportunity to try out some new technologies! For this project I used the following fairly new technologies:

So what did I think of the experience? MVC3 is a promising improvement over MVC2 and Web Forms. Outside of a radical paradigm change (like being more dynamic like Ruby) I'd pick MVC3 for my next project without hesitating. It integrated nicely with jQuery by offering ways to produce and consume JSON.

HTML5 gets a big thumbs up! I've already begun using as many features as I can that are backward compatible with older browsers. If you want to know what you can and can't use now, I recommend HTML5 and CSS3 by Brian Hogan.

I really liked Razor! But the lack of intellisense (auto completion, etc) in Visual Studio was a bit painful. Hopefully this will get added soon and it will be my preferred View Engine hands down. It was a little hard to figure out when you don't have to use the @ symbol to prefix code but the error messages were very helpful.
UPDATE 11/9/2010: And 3 hours after posting this, Intellisense has been added in MVC 3 RC!

EF4 Code First didn't go nearly as smooth as the other new features even though I love the concept. The parts that worked are great but it still has a few too many limitations for me to pick it again without hesitation over other options. Some of the limitations:
  • I couldn't find a simple, elegant way to do a cascading delete of all child objects when you delete a parent.
  • You can't have more then one DbContext share the same database (not a major issue)
  • Deploying to production didn't go very smoothly. I had to configure the connection string to use the "sa" account to get the DB created.
Keep in mind these .NET offerings are all fairly new and I think Microsoft is on the right track with all of them.

I've decided to give back to the community and put the source code on GitHub. I'm sure there are some things I could have done better or that didn't follow best practice so if you find something that would have been much easier to do another way let me know. I'd love to hear it.

Some 3rd party libraries that made this application possible:
Elmah - my favorite error logging library
tvdblib - they did an awesome job of wrapping the TVDB API!
TheTVDB - without this DB this application wouldn't be possible. Please consider contributing info and artwork.

Saturday, October 30, 2010

Custom iPhone 4 Mount For Car

Cutting to the chase. Here are the pics of my new custom iPhone mount!


Previously I had customized my car to mount my iPhone 3G using a Griffin iPhone 3G Windshield Mount.

A couple months later the iPhone4 came out and it does not work with the Griffin mount I was using. I took a gamble and order a Griffin WindowSeat AUX.

I got very lucky and was able to put the cradle from the new Griffin mount onto the existing arm from the 3G mount. It's an extremely tight fit but it works. It doesn't swivel as easily as I'd like but I'm very happy I didn't have to do anymore cutting.

The next customization I wanted to do was to add steering wheel controls for music. I found this Kensington LiquidAUX Bluetooth Car Kit and it was on sale so I got overly excited and bought 2!

After it arrived I was disappointed to find out that my Alpine CDA117 car stereo does not have a regular "line in" that would work with the Kensington Bluetooth kit. :(

In addition the AD2P audio takes over the wired line out so it was looking like I'd have to not use the Bluetooth kit or buy a new stereo. After some googling I found the solution to my problem. If you jailbreak your iPhone and install Bluetooth Profile Selector (BTPS) you can disable the AD2P out and the audio will play out the wired connection, BUT the wireless steering wheel controls still work!

The Kensington Bluetooth kit allows me to play/pause, and skip songs forward and backward and also has a button that will bring up Voice Control. Voice Control seems to work Ok for dialing numbers. So far I haven't found the trick to get it to play songs/artists while connected to the car stereo.

The final mod I did was to disable the "Accessory Connected" splash screen that replaces the iPod apps UI when connected to my head unit. There is another app on Cydia for jailbroken phones called No Accessory Splash. Install this and you can use the iPod app like normal in addition to having the head unit controls work.

The combination of a nice touch screen and steering wheel controls should make my commutes much more pleasant! Especially considering every other feature in my Mitsubishi Evo IX RS is manual (locks, windows, mirrors, seats, etc). For those curious the RS is a stripped down model primarily marketed to be raced. This saves weight and allows the car to be sold at a lower price.

Thursday, October 14, 2010

How Not to Implement Unsubscribe

UPDATE 10/14/2010 11:55 AM CST: SpeakerRate may not have done the unsubscribe correctly. But they know customer service. Thanks guys!
http://twitter.com/#!/speakerrate/status/27356776561

This is just plain unacceptable. I rated one speaker and used my email address to do so. I get a newsletter from SpeakerRate the next day which is fine because I planned to just click the Unsubscribe link at the bottom. Here's what I was presented with:



Do you really think I want to create an account?

Friday, October 8, 2010

Count the Number of Network Connections in Windows

If you need to count the number of network connections to a certain port start by entering this command into a command prompt:
netstat -a -n

Then find the IP:Port combo you want to count and modify the following command to get the count:
netstat -a -n | find /c "<ip:port>"

Example:
netstat -a -n | find /c "127.0.0.1:1935"




Thursday, October 7, 2010

Upgrade ASP.NET MVC 3 Preview to MVC Beta

I previously blogged about upgrading the TekPub ASP.NET 2 Starter Site from MVC2 to MVC3 Preview:
http://blog.cdeutsch.com/2010/08/upgrade-mvc2-to-mvc3.html

Today I upgrade that project to MVC3 Beta.

It was pretty easy. Biggest change was with Dependency Injection. IMvcServiceLocator no longer exits and has been replaced with IDependencyResolver.

My NinjectServiceLocator file has been replaced with NinjectResolver (thanks Jedidja from StackOverflow!) and looks like this:

namespace Mvc3Ninject.Utility
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web.Mvc;
    using Ninject;

    [System.Diagnostics.DebuggerStepThrough]
    public class NinjectResolver : IDependencyResolver
    {
        private static IKernel kernel;

        public NinjectResolver()
        {
            kernel = new StandardKernel();
            RegisterServices(kernel);
        }

        public NinjectResolver(IKernel myKernel)
        {
            kernel = myKernel;
            RegisterServices(kernel);
        }

        public static void RegisterServices(IKernel kernel)
        {
            //kernel.Bind<IThingRepository>().To<SqlThingRepository>();
        }

        public object GetService(Type serviceType)
        {
            return kernel.TryGet(serviceType);
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            return kernel.GetAll(serviceType);
        }
    }

}

And then in the Global.asax.cs file I changed this line....

//// Tell ASP.NET MVC 3 to use our Ninject DI Container 
MvcServiceLocator.SetCurrent(new NinjectServiceLocator(_container));

...to...

//// Tell ASP.NET MVC 3 to use our Ninject DI Container 
DependencyResolver.SetResolver(new NinjectResolver(_container));

And that's that! Have fun coding!

Here's a complete working sample project based on my Code-First Entity Framework upgrade of the TekPub Starter Site.

Sunday, September 5, 2010

Save Web Page as PDF on iPad then Annotate

I was viewing the schedule for Twin Cities Code Camp on my iPad this morning and wanted to circle the talks I was interested in. I quickly realized I wasn't going to be able to do this without some help. After some research here's what I came up with.
  1. Configure your iPad to sync Bookmarks with one of your browsers (I picked Safari)


  2. Add this Bookmarklet for converting web pages to PDF from PDF Download to Safari (originally found this tip on "The Heat Web")

  3. Sync your iPad with iTunes to get the Bookmarklet onto your iPad.
  4. Install one of the iPad PDF Annotation apps. I picked Noterize by Robert Stretch. I also looked at iAnnotate which I'll try next if I don't like Noterize.
  5. Browse to the web page you want to annotate, open your Bookmarks, and select Save Page As PDF
  6. Unfortuantely I had to hit stop and then "refresh" in Safari to get PDF Download to work (your results may vary)
  7. PDF Download will eventually open the page as a PDF. (it can take a while)
  8. Copy the URL of the PDF.
  9. Open Noterize, go to the root of your Notes and click Import PDF/PPT. Select the Web Browser option and paste in the copied URL.
  10. The PDF is now available to annotate.
I also highly recommend using Dropbox so you can easily save your annotations and view them on your computer or in other apps that support Dropbox. You can use Dropbox to easily get PDFs into Noterize from your computer as well.

Noterize does not automatically save your PDF's to Dropbox. You'll need to Share the PDF within Noterize after it has been annotated and then upload to Dropbox.

I'd love to hear from you! Leave a comment or reply to @cdeutsch on Twitter if you find something useful.



Saturday, August 21, 2010

Code-First Entity Framework ISession for Tekpub MVC Starter Site

I've been using a lot of the ideas/code in Tekpub's MVC Starter Site for a personal project of mine. For better or worse the features of .NET 4.0 and MVC keep rapidly changing. I wanted to use both MVC 3 Preview 1 and Code-First Development with Entity Framework 4 so I've taken the time to upgrade the MVC Starter Site to support both of these features. You can download my working project here. See this post for more info on the headache to upgrade to MVC 3.

IMO it took way too much time to do this but a lot of it is probably due to my inexperience with MVC and in particular Dependency Injection.

Below is the class I added in order to use Code-First in the MVC Starter Site. The class inherits ISession. At first I tried to get access to the underlying ObjectContext so I could just use the already written EFSession class. I couldn't get this to work and then luckily I took a step back and realized I didn't need it to. I still haven't figure out how to do a working IReadOnlySession.cs but for my needs it won't be an issue at this time.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
using System.Data.Metadata.Edm;
using System.Data.Entity;

namespace Web.Infrastructure.Storage
{
    public class EFCFSession : ISession
    {
        DbContext _context;
        public EFCFSession(DbContext context)
        {
            _context = context;
        }

        
        public void CommitChanges() {
            _context.SaveChanges();
        }

        public void Delete<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression) where T: class, new() {

            var query = All<T>().Where(expression);
            foreach (var item in query) {
                Delete(item);
            }
        }

        public void Delete<T>(T item) where T: class, new() {
            _context.Set<T>().Remove(item);
        }

        public void DeleteAll<T>() where T: class, new() {
            var query = All<T>();
            foreach (var item in query) {
                Delete(item);
            }
        }

        public void Dispose() {
            _context.Dispose();
        }

        public T Single<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression) where T: class, new() {
            return All<T>().FirstOrDefault(expression);
        }

        public IQueryable<T> All<T>() where T: class, new() {
            return _context.Set<T>().AsQueryable<T>();
        }

        public void Add<T>(T item) where T: class, new() {
            _context.Set<T>().Add(item);
        }
        public void Add<T>(IEnumerable<T> items) where T: class, new() {
            foreach (var item in items) {
                Add(item);
            }
        }
        public void Update<T>(T item) where T: class, new() {
            //nothing needed here
        }
    }
}

Another interesting thing I found when doing this is that I couldn't use the same DB for the ReportingDB DbContext and the SiteDB DbContext without Code-First wiping the other out. Not a huge deal at the moment but could become an issue down the road.

So far I'm loving the idea of using POCO model classes and can't wait to try combine them with the MVC 3 Model Validation improvements!



Sunday, August 15, 2010

Upgrade MVC2 to MVC3

Today I upgrade a fairly new MVC2 app to MVC3. My original MVC2 app was based off of The Tekpub ASP.NET MVC 2.0 Starter Site

The first step is to update your projects references. This blog post by Rick Schott worked great to handle that task.

After doing that I was faced with the error:
No parameterless constructor defined for this object.

My original global.asax.cs looked like this:
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Ninject.Web.Mvc;
using Ninject;
using Ninject.Modules;
using Site.Infrastructure.Logging;
using Web.Infrastructure.Authentication;
using Web.Infrastructure.Reporting;
using Web.Infrastructure.Storage;
using Web.Model;

namespace Web
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : NinjectHttpApplication
    {
        public static ISession Session
        {
            get
            {
                return _container.Get<ISession>();
            }
        }

        public static void RegisterRoutes(RouteCollection routes)
        {
            
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.IgnoreRoute("favicon.ico");
            routes.MapRoute(
                "Login", // Route name
                "login", // URL with parameters
                new { controller = "Session", action = "Create" } // Parameter defaults
            );
            routes.MapRoute(
                "Logout", // Route name
                "logout", // URL with parameters
                new { controller = "Session", action = "Delete" } // Parameter defaults
            );

            routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );

        }

        protected override void OnApplicationStarted()
        {
            Logger.Info("App is starting");

            //Database.SetInitializer<SiteDB>(new AlwaysRecreateDatabase<SiteDB>());

            AreaRegistration.RegisterAllAreas();
            RegisterRoutes(RouteTable.Routes);

            //ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory(Container));
        }

        protected void Application_End()
        {
            Logger.Info("App is shutting down");
        }

        protected void Application_Error()
        {
            Exception lastException = Server.GetLastError();
            Logger.Fatal(lastException);
        }

        /// <summary>
        /// IoC stuff below
        /// </summary>
        /// <returns></returns>
        protected override IKernel CreateKernel()
        {
            return Container;
        }

        internal class SiteModule : NinjectModule
        {
            public override void Load()
            {
                //a typical binding
                Bind<ILogger>().To<NLogLogger>().InSingletonScope();
                //Bind<INoSqlServer>().To<DB4OServer>().InSingletonScope();
                //Bind<ISession>().To<Db4oSession>().InRequestScope();

                //You can use the SimpleRepository to build out your database
                //it runs "Auto Migrations" - changing your schema on the fly for you
                //should you change your model. You can switch it out as you need.
                //http://subsonicproject.com/docs/Using_SimpleRepository
                Bind<ISession>().To<SiteEFSession>();
                Bind<IReporting>().To<ReportingSession>();
                Bind<IAuthenticationService>().To<UserAuthenticationService>();
            }
        }

        public ILogger Logger
        {
            get
            {
                return Container.Get<ILogger>();
            }
        }

        static IKernel _container;
        public static IKernel Container
        {
            get
            {
                if (_container == null)
                {
                    _container = new StandardKernel(new SiteModule());
                }
                return _container;
            }
        }
    }
}

I then tried to add the NinjectServiceLocator.cs class and update my global.asax.cs to use Ninject like this sample from Scott Gu.

It looked something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Ninject;
using Ninject.Modules;
using Site.Infrastructure.Logging;
using Web.Infrastructure.Authentication;
using Web.Infrastructure.Reporting;
using Web.Infrastructure.Storage;
using Web.Model;
using Mvc3Ninject.Utility;

namespace Web
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : HttpApplication
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
        }

        public static void RegisterRoutes(RouteCollection routes)
        {
            
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.IgnoreRoute("favicon.ico");
            routes.MapRoute(
                "Login", // Route name
                "login", // URL with parameters
                new { controller = "Session", action = "Create" } // Parameter defaults
            );
            routes.MapRoute(
                "Logout", // Route name
                "logout", // URL with parameters
                new { controller = "Session", action = "Delete" } // Parameter defaults
            );

            routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );

        }

        public static void RegisterServices(IKernel kernel)
        {
            //a typical binding
            kernel.Bind<ILogger>().To<NLogLogger>().InSingletonScope();
            //Bind<INoSqlServer>().To<DB4OServer>().InSingletonScope();
            //Bind<ISession>().To<Db4oSession>().InRequestScope();

            //You can use the SimpleRepository to build out your database
            //it runs "Auto Migrations" - changing your schema on the fly for you
            //should you change your model. You can switch it out as you need.
            //http://subsonicproject.com/docs/Using_SimpleRepository
            kernel.Bind<ISession>().To<SiteEFSession>();
            kernel.Bind<IReporting>().To<ReportingSession>();
            kernel.Bind<IAuthenticationService>().To<UserAuthenticationService>();
        }

        public void SetupDependencyInjection()
        {
            // Create Ninject DI Kernel 
            _container = new StandardKernel();

            //// Register services with our Ninject DI Container
            RegisterServices(_container);

            //// Tell ASP.NET MVC 3 to use our Ninject DI Container 
            MvcServiceLocator.SetCurrent(new NinjectServiceLocator(_container));
        }

        void Application_Start()
        {
            SetupDependencyInjection();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);

            Logger.Info("App is starting");
        }

        protected void Application_End()
        {
            Logger.Info("App is shutting down");
        }

        protected void Application_Error()
        {
            Exception lastException = Server.GetLastError();
            Logger.Fatal(lastException);
        }

        public ILogger Logger
        {
            get
            {
                return Container.Get<ILogger>();
            }
        }

        static IKernel _container;
        public static IKernel Container
        {
            get
            {
                return _container;
            }
        }
    }
}

This caused the following error to constantly trigger the debugger although the site seems to still be working:
Error activating IControllerFactory
No matching bindings are available, and the type is not self-bindable.

I then added the following line to the RegisterServices function based on this Stackoverflow tip:
kernel.Bind<IControllerFactory>().To<Ninject.Web.Mvc.NinjectControllerFactory>();

This caused the following error:
Method Ninject.Syntax.IBindingToSyntax`1[System.Web.Mvc.IControllerFactory].To: type argument 'Ninject.Web.Mvc.NinjectControllerFactory' violates the constraint of type parameter 'TImplementation'.

I then tried using DefaultControllerFactory instead of the line above and finally success!
kernel.Bind<IControllerFactory>().To<DefaultControllerFactory>();

This is my final working global.asax.cs file:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Ninject;
using Ninject.Modules;
using Site.Infrastructure.Logging;
using Web.Infrastructure.Authentication;
using Web.Infrastructure.Reporting;
using Web.Infrastructure.Storage;
using Web.Model;
using Mvc3Ninject.Utility;

namespace Web
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : HttpApplication
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
        }

        public static void RegisterRoutes(RouteCollection routes)
        {
            
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.IgnoreRoute("favicon.ico");
            routes.MapRoute(
                "Login", // Route name
                "login", // URL with parameters
                new { controller = "Session", action = "Create" } // Parameter defaults
            );
            routes.MapRoute(
                "Logout", // Route name
                "logout", // URL with parameters
                new { controller = "Session", action = "Delete" } // Parameter defaults
            );

            routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );

        }

        public static void RegisterServices(IKernel kernel)
        {
            kernel.Bind<IControllerFactory>().To<DefaultControllerFactory>();

            //a typical binding
            kernel.Bind<ILogger>().To<NLogLogger>().InSingletonScope();
            //Bind<INoSqlServer>().To<DB4OServer>().InSingletonScope();
            //Bind<ISession>().To<Db4oSession>().InRequestScope();

            //You can use the SimpleRepository to build out your database
            //it runs "Auto Migrations" - changing your schema on the fly for you
            //should you change your model. You can switch it out as you need.
            //http://subsonicproject.com/docs/Using_SimpleRepository
            kernel.Bind<ISession>().To<SiteEFSession>();
            kernel.Bind<IReporting>().To<ReportingSession>();
            kernel.Bind<IAuthenticationService>().To<UserAuthenticationService>();
        }

        public void SetupDependencyInjection()
        {
            // Create Ninject DI Kernel 
            _container = new StandardKernel();

            //// Register services with our Ninject DI Container
            RegisterServices(_container);

            //// Tell ASP.NET MVC 3 to use our Ninject DI Container 
            MvcServiceLocator.SetCurrent(new NinjectServiceLocator(_container));
        }

        void Application_Start()
        {
            SetupDependencyInjection();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);

            Logger.Info("App is starting");
        }

        protected void Application_End()
        {
            Logger.Info("App is shutting down");
        }

        protected void Application_Error()
        {
            Exception lastException = Server.GetLastError();
            Logger.Fatal(lastException);
        }

        public ILogger Logger
        {
            get
            {
                return Container.Get<ILogger>();
            }
        }

        static IKernel _container;
        public static IKernel Container
        {
            get
            {
                return _container;
            }
        }
    }
}

Alternatively in going through this headache I found downloading the source for both Ninject and Ninject.Web.Mvc and updating it to use .NET Framework 4.0 and Mvc 3 fixed most of the errors above and allows you to NOT change the global.asax.cs at all. You can just use it as it was originally.

To get Ninject.Web.Mvc updated you must:
  • Change the Target Framework to .NET 4.0.
  • Update the reference to System.Web.Mvc to use 3.0.0.0 instead of 2.0.0.0
  • Remove the following references:
    • System.Web.Routing
    • System.Web.Abstractions
In closing, I really wish the MVC team would include a default Dependency Injection with MVC. I've lost way too many hours at this point trying to get DI working between all the different options and all the outdated tutorials. If I'm struggling with it I have to imagine there are many others out there as well. This is making it harder for people to adopt MVC and should be eliminated by the MVC team picking a default to include when installing MVC and generating the default global.asax.



Friday, August 13, 2010

How was the Picture Quality Bitches? - Netflix

Just received this in my inbox:



Maybe Dave Chappelle works at Netflix nowadays? Or at least somebody who loves this bit as much as I do!


Thursday, July 15, 2010

The New Digg Rocks!

If you haven't heard yet Digg.com has done a major upgrade to their site. Currently it's invite only but you can go to new.digg.com to request an invite. 

My username is crdeutsch (cdeutsch was taken) if you want to follow me. 

One of the new features is you can add RSS Feeds of your content to automatically publish to Digg which I've just taken advantage of.  

The new site is way faster, cleaner, and easier to follow people that are relevant to you. Can't wait until more people I know start using the service!

Tuesday, July 13, 2010

Comcast EcoBill Eco Sucks

If you're a Comcast Business customer make sure you write down your account number before signing up for EcoBill otherwise Comcast won't help you. I tried to add Basic TV to my Internet service and first the customer service rep says I can't have business TV since my business is a "residence" so she transfers me to Residential Service where I wait on hold for 10-15 minutes before being told they can't do anything for me since I'm a business customer and they transfer me back to the SAME WOMAN! This time I say the business service is at a "business" so I get to the "next level" in their little game. Now she needs my account number or she can't help me. I ask where to find it and she says on the statement. I get electronic EcoBill statements and guess what? No account number. I searched for Comcast emails and every time I found my account number the beginning is "starred out". So tell me again A) how EcoBill saves me time and money? B) why the hell do I do business with this company? It's rumored you can save time and money by figuring out where the notch filter is for your service and removing it yourself.

UPDATE: Received a call back from my original Sales Rep after shooting him an email about my experience. This is what customer service is supposed to be. He took the time to explain there are some licensing issues with Business Class TV in a residence, etc. So I do indeed need to setup Residential TV Service but the rate should be the same as the one packaged with Business Internet.
2 Tips:
  1. Basic Analog Cable does exist even though I can't find it on their web page
  2. Call after 10pm to avoid commissioned sales reps


Sunday, June 27, 2010

Ultimate Windows Mac - Part 2

This is Part 2 in a series on configure a MacBook for Windows power users.

When I left off in Part 1 I was debating on which SSD to use. I decided on a OCZ Vertex 2 after reading about some issues the RealSSD's were having. I also purchased an MCE ObtiBay. So let's get to installing these parts. UPDATE: I'm having issues getting full performance from the Vertex 2 using Windows (seems to be limited to SATA I speeds). You may be better offer getting a lower ended SSD if your hardware/software combo is the bottle neck. More info will come as I work my way through the issue.


I'm not going to go into great detail on installing the hardware since others have already done it way better then I could. I left the OEM drive where it is and just installed the new SSD using the ObtiBay. The instructions from MCE where excellent. If you still need help with installation Other World Computing is a great resource.


Now that the drive is installed it's time to install Windows. I'll be installing Windows 7 Enterprise N 64bit edition. Since I'm not installing Windows to the same hard drive as OS X, I didn't run Boot Camp to prepare the drive. Instead I just booted from the Windows 7 DVD and installed Windows to the second hard drive (in my case the SSD one since I'll primarily being using Windows). Be careful which drive you install to. If you're paranoid then remove the OEM disk with OS X installed on it before beginning the Windows install.

Once Windows is installed you need to install the Boot Camp software. Put in your OS X installation disc and run setup. If you get the following error "Boot Camp x64 is unsupported on this computer model" which may happen if you use a retail disk of OS X, open a Command Prompt in Windows as Administrator and type the following:
cd /d D:
cd "Boot Camp\Drivers\Apple"
BootCamp64.msi

Run through the installer and most if not all your MacBook hardware should have the correct drivers installed. In my case the Light Sensor gives me a "This device cannot start" error but considering I'll have my laptop hooked up to an external monitor and keyboard 90% of the time I didn't bother fixing it. I'll make an update if I ever spend time looking for a solution.

The next step I do is to configure the keyboard so it's uses a PC style keyboard layout. There are a couple solutions but Sharp Keys is my favorite.

Map the keys as follows. Older MacBooks have an "Enter" to the left of the directional errors. New MacBooks have a "Right Alt/Option" key. The screen shot and direction handle both versions.
Num: Enter (E0_1C)             = Special: Right Ctrl (E0_1D
Special: Left Alt (00_38)      = Special: Left Windows (E0_5B)
Special: Left Windows (E0_5B)  = Special: Left Alt (00_38)
Special: Right Alt (E0_38)     = Special: Right Ctrl (E0_1D)
Special: Right Windows (E0_5C) = Special: Right Alt (E0_38)

This works great if you don't plan to use an external PC style keyboard. I use a Microsoft Natural Ergonic Keyboard 4000 at home and at work. These key mappings will cause the external keyboard to work different so I need to be able to toggle back and forth. Unfortunately Windows needs to be restarted (or at least logged off) for keyboard mapping changes to take effect. The best solution I came up with is to script this. Our custom keyboard mapping is stored in the registry so I've created two registry export files and 2 batch files to either Enable or Disable the custom mapping. As soon as I log into Windows I run the batch file I need and it will immediately log me off and then I'll log back in and the keyboard will be in the configuration I need. I also add 3 registry settings for the mouse. I like the MacBook Pro's trackpad to be "slower" then my external mouse and I also find scrolling 1 line at a time is better with the trackpad versus 3 lines for the external mouse.

You can create the 6 files you need as follows or download them from here.

MacKeyboard-Enable.reg :
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
"Scancode Map"=hex:00,00,00,00,00,00,00,00,06,00,00,00,1d,e0,1c,e0,5b,e0,38,00,\
  38,00,5b,e0,1d,e0,38,e0,38,e0,5c,e0,00,00,00,00

MacKeyboard-Disable.reg :
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
"Scancode Map"=-

MacMouse-Enable.reg :
Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Control Panel\Desktop]
"WheelScrollChars"="1"
"WheelScrollLines"="1"

[HKEY_CURRENT_USER\Control Panel\Mouse]
"MouseSensitivity"="6"

MacMouse-Disable.reg :
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Control Panel\Desktop]
"WheelScrollChars"="3"
"WheelScrollLines"="3"

[HKEY_CURRENT_USER\Control Panel\Mouse]
"MouseSensitivity"="10"

~MacHardware-Enable.bat (I use the tilde to force the file to the top in the list)
REGEDIT.EXE  /S  "MacKeyboard-Enable.reg"
REGEDIT.EXE  /S  "MacMouse-Enable.reg"
shutdown -l

~MacHardware-Disable.bat
REGEDIT.EXE  /S  "MacKeyboard-Disable.reg"
REGEDIT.EXE  /S  "MacMouse-Disable.reg"
shutdown -l

The next part is specific to my dual hard drive configuration and it's your call if you want to do it. Since I didn't buy a monster sized SSD I want to store any data that is large and relatively static on the regular hard drive we're running OS X off of. The first step is to boot into OS X and use BootCamp assistant to partition your hard drive. Of the 320GB on the hard drive my MacBook came with I gave OS X 60GB and I'll use the other 260GB as a "data" partition. After partitioning with BootCamp choose to "not install windows" at this time and then boot back into Windows to format the drive using NTFS. The drive should now be available as drive D: (drive letter may vary but I'll assume it's D for the rest of this article). You could choose to move the entire "User" folder to the new drive. Since this would include various application temp and setting folders that may be altered often and may benefit from being on an SSD I opted to just move the individual "Documents", "Downloads", "Music", "Pictures", and "Videos" folders.

You could do it the "easy way" built into Windows 7 but I chose a more transparent way since some Windows programs don't seem to default to the correct folder when using the "easy way". I'm going to use the command line program MKLINK to create a "symlink" similar to what Unix has had for ever.

First I create individual "Documents", "Downloads", "Music", "Pictures", and "Videos" folders on the D drive. If you have a lot of data already in these folders on the C drive then use this guide to move the data. My folders are still pretty much empty so I just deleted the folders on the C drive and then opened a command prompt and typed the following from your User Profile directory (ex. C:\Users\CDEUTSCH):
MKLINK /J Downloads D:\Downloads
MKLINK /J Documents D:\Documents
MKLINK /J Music D:\Music
MKLINK /J Pictures D:\Pictures
MKLINK /J Videos D:\Videos

Another optional step is to purchase and install MacDrive if you want the ability to write to the partition with OS X on it.

On my first MacBook Pro I tired to "share iTunes" between OS X and Windows. I stored the files in the default Music folder in OS X, then used MacDrive on Windows to read and write to this location. You can have iTunes open an alternative iTunes library by holding the "Shift" key while opening iTunes. This worked Ok, except iTunes always update the file paths every time you switched from Windows to OS X. This process took way too long sometimes, so after Windows 7 came out I moved iTunes to my Windows partition and now only use iTunes under Windows. I currently mostly use OS X for MonoTouch iPhone development and for casual web browsing. If you're into hooking up your laptop to your TV I highly recommend Boxee, Remote Buddy, and Hulu Desktop (I use a dedicated MacMini for this instead of my laptop). Another thing OS X is great at is backing up your Windows partition. Winclone is excellent but I believe it only works for GPT formated drives. So unless you're running Windows on the same drive as OS X I would find another program for doing a bare metal backup. I may explore this more in a future blog post.

Saturday, June 19, 2010

Ultimate Windows Mac - Part 1

This is my first post in a series on configure a MacBook for Windows power users.

First a little history (skip next 2 paragraphs if you're in a hurry). I grew up with PC's. My dad's business Agvise used computers for data acquisition in addition to regular office use and they tended to build their own computers most of the time. Therefore the first PC he purchased for me before college in 1996 was one I got to build. It was a Cyrix 6x86 which was the budget way to get a faster chip at a lower price then what Intel had to offer. In addition to PC hardware I grew up using DOS and spent plenty of time using Windows 3.1 before Windows 95 came along. I built every desktop I ever owned and then in December of 2000 the company I had just started at, MediaDVX, bought me a laptop and then a year or so later upgraded it to a business class Compaq M500. That thing was so rock solid I never had any desire to go back to tinkering with building my own computers and continued using HP/Compaq up until fall of 2007 when my trusty beaten up NC6000 finally died. So it's September 2007 and I have never owned ANY Apple product so far (I miss you RIO MP3 players!) and for the most part I'm really not an Apple fan but a couple of co-workers began showing off their personal MacBook Pros and introduced me to Bootcamp. I thought the hardware had interesting features, I was open to exploring OS X, and being able to boot into Windows or run the same instance of Windows in VMWare sold me on purchasing a 15" MacBook Pro and it's been downhill from there. Since late 2007 I've purchased the following: iPod Touch, iPod Classic, iPhone 3G (waited in line), Apple TV, MacMini, iPhone 3GS (for Fiance), and an iPad (waited in line). The one thing about my MacBook Pro I couldn't get over is the keyboard and the lack of some features Apple is/was behind on adding like eSata, HDMI, and a swappable media bay like HP, Lenovo, and others have. Once Windows 7 came out I had pretty much stopped using OS X all together on my MacBook Pro so I was ready to switch back to a PC.

I picked out an awesome combo of power and portability in the Lenovo T410S. I had it custom built, waited a few weeks for it to show up, and began using it. It took me many hours spanned across a week or two to get all the software I need to do development installed and configured on it. Then the big day came, it was time to start using it as my primary machine. Boy was I in for disappointment. The wired NIC lost connectivity every hour. The Display Port connection seemed to have interference issues and on top of that would "black out" the screen for a second every couple minutes. I found other people on the internet who had experienced both of these issues and I decided I didn't have time to work through these bugs. (Sidebar: The T410s has a multi-touch trackpad. I hoped it was as good as Apple's. With a ton of tweaking I got it to work "better", but even then it is not even close to as polished as Apple's, contrary to what some reviewers said) This was a $1700 laptop and it shouldn't have these issues so the laptop has been RMA'd much to my disappointment. Now I needed a replacement and since Apple had stood behind their products for me in the past (my MBP died and they replaced the screen, logic board, hard drive, and some fans, all for FREE! since the root issue was a manufacturing defect) and considering I'd just started getting into doing iPhone development using MonoTouch I decided I'd once again go back to Apple and I'm now typing this on my new 13" MacBook Pro!!! Thanks to Mitch Coopet for convining me I didn't need the i5 in the 15" since I really wanted a smaller notebook.


On to the good stuff.

Here is the list of System Preferences I tweak out of the box:
  1. Add right click if your MacBook trackpad supports it:
    • Trackpad -> One Finger -> check "Secondary Click" -> Bottom Right Corner
  2. Configure Expose (probably my favorite OS X feature)
    • Expose & Spaces -> Expose -> Active Screen Corners
    • Set Bottom Left corner to "All Windows"
    • Set Bottom Right corder to "Desktop"
  3. Shrink size of dock since I won't be using the laptop from 500ft away.
    • Dock -> Size -> adjust to your comfort level
  4. While you're at it remove Dock Items you probably won't use. I remove:
    • Mail
    • iCal
    • Address Book
    • Photo Booth
    • GarageBand
    • Time Machine (I'll be using CrashPlan thank you)
  5. Configure OS X so you can tab to checkboxes and drop downs in web browser.
    • Keyboard -> Full Keyboard Access -> All controls


Here is the list of software I immediately load onto my MacBook (first two will help OS X behave more like Windows):


Configure Double Command - I check the following to make the Mac keyboard more like a PC:
  • Command Key acts as Option Key
  • Option Key acts as Command Key
  • Control Key acts as Command Key (you won't have a Control key, but as far as I can tell the Control Key is only there because Steve Jobs doesn't like mouse buttons)
  • PC style Home and End Keys


Configure Quicksilver - since we don't have a control key we need to change the hot key. I use "Option Key - Space bar". Note if you configured Double Command like above my "Option Key" is actually the "Command Key" on the physical keyboard. If you want to use the physical "Control Key" then you'll need to configure Spotlight to not use that Hot Key first under "System Preferences -> Keyboard -> Keyboard Shortcuts -> Spotlight"


This should get you by until we install Windows using Bootcamp in Part 2. In preparation for Part 2 I've decided to immediately void my warranty and do the following:
  1. Add a SSD drive. Currently debating between Intel X25-M and Crucial's RealSSD C300 due to the recommendation by The Tech Report
  2. Add the SSD drive in place of the DVD drive using a MCE OptiBay

I opted not to use Apple's SSD offering and instead save money by adding it myself. Since I'll be using 2 hard drives I plan to purchase a smaller SSD and then store most of my data (music, movies, etc) on the regular hard drive which will save even more money since SSDs are still relatively expensive.

Note, I'll be updating the software list above as I continue my build.

Thursday, June 3, 2010

Move Google Apps Domain To DiscountASP.NET

Tonight I signed up for web site hosting plan with DiscountASP.NET. Partially forced to because Google was indexing by blog at blog.cdeutsch.com as cdeutsch.com (due to the way I had Google Apps configured, D'oh!), but I also want to do some experimenting with ASP.NET MVC 2 and play around with some custom iPhone web services.

DiscountASP.NET wants you to point your domain at their nameservers for their hosting to work. This is kind of a bummer since I was happy with Google Apps handling that. The good news though is this CAN be done! I figured out how to do the CNAMES myself and had been smart enough to write down the info I needed before switching nameservers. Unfortunately I didn't write down the MX Records but with help from Steve Trefethen's blog I was able to fix them. My settings are below:

CNAME Record Manager
Canonical Name Record: Creates an alias from one hostname to another.
Use of CNAME is generally not recommended.
Domain NameDestination TTL

blog.cdeutsch.com


ghs.google.com

3600

calendar.cdeutsch.com

ghs.google.com


3600

docs.cdeutsch.com

ghs.google.com

3600

mail.cdeutsch.com

ghs.google.com

3600

sites.cdeutsch.com

ghs.google.com

3600


start.cdeutsch.com

ghs.google.com

3600






MX Record Manager 
Mail Exchanger Record: Identifies the email server that handles email for a domain.
Domain NameDestination DistanceTTL

cdeutsch.com

ASPMX.L.GOOGLE.COM

10

3600

cdeutsch.com

ALT1.ASPMX.L.GOOGLE.COM

15

3600

cdeutsch.com

ALT2.ASPMX.L.GOOGLE.COM

15

3600

cdeutsch.com

ASPMX2.GOOGLEMAIL.COM

20

3600

cdeutsch.com

ASPMX3.GOOGLEMAIL.COM

20

3600

cdeutsch.com

ASPMX4.GOOGLEMAIL.COM

20

3600

cdeutsch.com

ASPMX5.GOOGLEMAIL.COM

20

3600







The second part of my mission was to redirect www.cdeutsch.com to just cdeutsch.com. Due to DiscountASP.NET's awesomeness they support II7 and the IIS Rewrite extension so this is super easy. Just update your web.config with the following:

<system.webServer>
 <rewrite>
  <rules>
   <rule name="Canonical Host Name" stopProcessing="true">
    <match url="(.*)" />
    <conditions>
     <add input="{HTTP_HOST}" negate="true" pattern="^cdeutsch\.com$" />
    </conditions>
    <action type="Redirect" url="http://cdeutsch.com/{R:1}" redirectType="Permanent" />
   </rule>
  </rules>
 </rewrite>
</system.webServer>


Or if you want to do the reverse (cdeutsch.com to www.cdeutsch.com) :

<system.webServer>
 <rewrite>
  <rules>
   <rule name="Redirect to WWW" stopProcessing="true">
    <match url=".*" />
    <conditions>
     <add input="{HTTP_HOST}" pattern="^cdeutsch.com$" />
    </conditions>
    <action type="Redirect" url="http://www.cdeutsch.com/{R:0}" redirectType="Permanent" />
   </rule>
  </rules>
 </rewrite>
</system.webServer>

Now that I had that working I needed some content. What better way to start then with a fresh ASP.NET MVC 2 website. I started with the basic template built-in to Visual Studio 2010. You'll need to go to your project's References and click "Properties" on the "System.Web.Mvc.dll" and change "Copy Local" to "True" to get MVC to work on DiscoutASP.NET's servers. More info here. You'll also want to make sure you configured your web application to run using the .NET Framework 4.0. Framework 3.5 will work for MVC 2, but in my control panel it defaulted to Framework 2.0 and was throwing errors. When I went to fix it the only other option I saw was 4.0, it's possible there is a 3.5 settings somewhere, if there is feel free to try that too:  UPDATE: after talking to Michael Maddox I realized the errors I got were probably because I had my solution/project targeting 4.0. So you can either do the steps below if your project is for 4.0, or change your project to target 3.5 and then you can skip this step.
  • In your Control Panel go to "IIS Tools"
  • Under the "ASP.NET Version" tab set the version to "4.0".
  • Make sure after you hit "Update" you read the warning and click "Update" (or whatever it says) again.
If you found this helpful and you're going to sign up for DiscountASP.NET, please use my referral code: CDEUTSCH

Saturday, May 29, 2010

MonoTouch.Dialog: Improved List Documents!

After completing my last example on listing Documents using MonoTouch, Miguel de Icaza pointed out that MonoTouch.Dialog could make it easier. He was right and below are the results.

Two ways to start off, you can add an "IPhone Window-based Project" and then add a "UINavigationController" to the "MainWindow.xib", or do the route I took and create a "iPhone Navigation based Project" and just delete the extra "RootViewController.xib" we won't be needing.



If you haven't already, download MonoTouch.Dialog (use the "Download Source" link at the top) and then add a reference to it in your project and also be sure to add a "using MonoTouch.Dialog" at the top of "Main.cs"

Below is all the code I need to place in Main.cs to do exactly what my last blog post did which used a TON of extra auto generated code. The code I added starts under the "EDITED" comment.

public class Application
 {
  static void Main (string[] args)
  {
   UIApplication.Main (args);
  }
 }

 // The name AppDelegate is referenced in the MainWindow.xib file.
 public partial class AppDelegate : UIApplicationDelegate
 {
  // This method is invoked when the application has loaded its UI and its ready to run
  public override bool FinishedLaunching (UIApplication app, NSDictionary options)
  {
   
   window.AddSubview (navigationController.View);

   
   //EDITED: this is it!!! Takes care of generating the whole Table View!
   var menu = new RootElement ("Documents"){
    new Section("") {
     from ff in System.IO.Directory.GetFiles(Environment.GetFolderPath (Environment.SpecialFolder.Personal)).ToList()
      select (Element) new StringElement (new System.IO.FileInfo(ff).Name)
    }  
   };
   var dv = new DialogViewController (menu) {
    Autorotate = true
   };
   navigationController.PushViewController (dv, true);    
   dv.Style = UITableViewStyle.Plain;
   
   
   window.MakeKeyAndVisible ();
   
   return true;
  }

  // This method is required in iPhoneOS 3.0
  public override void OnActivated (UIApplication application)
  {
  }
  
 }

You'll need to read my last blog post if you need to add some files to the "Documents" directory (there aren't any by default).

Here are the results or those 12 lines of code (yes, the last sample only had 5 lines added but these extra 7 lines eliminated LOTS of auto generated code and is much simpler):



Amazing! Miguel de Icaza and the Mono/MonoTouch crew didn't stop at the awesome achievement of bringing C# and the .NET Framework to IPhone development; with MonoTouch.Dialog they've outright made Apple and their ancient Object-C language embarrassing. If you can't see the ROI on the $400 a MonoTouch license costs, then your time isn't worth money.

Be sure to visit the MonoTouch.Dialog page on Github and Miguel's blog post on it for more amazingness!

MonoTouch - List Documents

Use the following MonoTouch code to easily list all the files in your Applications Documents folder. First create a regular IPhone Navigation based Project.


Open "RootViewController.xib.cs" and add the following code. I only added five lines of code. I've put a "//EDITED:" comment in front of each line that I added. Make sure to add a "using System.Linq" to the top of the file as well.


partial class RootViewController : UITableViewController
 {
   //EDITED: list to hold file names.
  private System.Collections.Generic.List&lt;string> dataItems = null;

  public RootViewController (IntPtr handle) : base(handle)
  {
  }

  public override void ViewDidLoad ()
  {
   base.ViewDidLoad ();
   //Show an edit button
   //NavigationItem.RightBarButtonItem = EditButtonItem;
   
     //EDITED: build list of files.
   string path = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
     dataItems = System.IO.Directory.GetFiles(path).ToList();
   
   this.TableView.Source = new DataSource (this);
  }

  /*
  public override void ViewWillAppear (bool animated)
  {
   base.ViewWillAppear (animated);
  }
  */
  /*
  public override void ViewDidAppear (bool animated)
  {
   base.ViewDidAppear (animated);
  }
  */
  /*
  public override void ViewWillDisappear (bool animated)
  {
   base.ViewWillDisappear (animated);
  }
  */
  /*
  public override void ViewDidDisappear (bool animated)
  {
   base.ViewDidDisappear (animated);
  }
  */

  /*
  // Override to allow orientations other than the default portrait orientation
  public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
  {
   //return true for supported orientations
   return (InterfaceOrientation == UIInterfaceOrientation.Portrait);
  }
  */

  public override void DidReceiveMemoryWarning ()
  {
   // Releases the view if it doesn't have a superview.
   base.DidReceiveMemoryWarning ();
   
   // Release any cached data, images, etc that aren't in use.
  }

  public override void ViewDidUnload ()
  {
   // Release anything that can be recreated in viewDidLoad or on demand.
   // e.g. this.myOutlet = null;
   
   base.ViewDidUnload ();
  }

  class DataSource : UITableViewSource
  {
   RootViewController controller;

   public DataSource (RootViewController controller)
   {
    this.controller = controller;
   }

   public override int NumberOfSections (UITableView tableView)
   {
    return 1;
   }

   // Customize the number of rows in the table view
   public override int RowsInSection (UITableView tableview, int section)
   {
    //EDITED: return count of files.
    return controller.dataItems.Count();
   }

   // Customize the appearance of table view cells.
   public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
   {
    string cellIdentifier = "Cell";
    var cell = tableView.DequeueReusableCell (cellIdentifier);
    if (cell == null) {
     cell = new UITableViewCell (UITableViewCellStyle.Default, cellIdentifier);
    }
    
    // EDITED: Configure the cell.
       cell.TextLabel.Text = (new System.IO.FileInfo(controller.dataItems[indexPath.Row])).Name;
   
    return cell;
   }

   /*
   // Override to support conditional editing of the table view.
   public override bool CanEditRow (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
   {
    // Return false if you do not want the specified item to be editable.
    return true;
   }
   */
   /*
   // Override to support editing the table view.
   public override void CommitEditingStyle (UITableView tableView, UITableViewCellEditingStyle editingStyle, MonoTouch.Foundation.NSIndexPath indexPath)
   {
    if (editingStyle == UITableViewCellEditingStyle.Delete) {
     controller.TableView.DeleteRows (new NSIndexPath[] { indexPath }, UITableViewRowAnimation.Fade);
    } else if (editingStyle == UITableViewCellEditingStyle.Insert) {
     // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
    }
   }
   */
   /*
   // Override to support rearranging the table view.
   public override void MoveRow (UITableView tableView, NSIndexPath sourceIndexPath, NSIndexPath destinationIndexPath)
   {
   }
   */
   /*
   // Override to support conditional rearranging of the table view.
   public override bool CanMoveRow (UITableView tableView, NSIndexPath indexPath)
   {
    // Return false if you do not want the item to be re-orderable.
    return true;
   }
   */

   // Override to support row selection in the table view.
   public override void RowSelected (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
   {
    // Navigation logic may go here -- for example, create and push another view controller.
    // var anotherViewController = new AnotherViewController ("AnotherView", null);
    //controller.NavigationController.PushViewController (anotherViewController, true);
   }
  }
 }

By default your app won't have any files in the documents folder but you can manually add some. In you user accounts "~/Library/Application Support/IPhone Simulator/" directory there will be multiple folders for each version of IPhone OS you can test. Pick the one you'll be test and put some files in the "Documents" folder.


Once that is done you can run your application in the simulator and it should give you the list of files you added to the "Documents" folder. Pretty simple huh?



I'll be using this code in a prototype that uploads Cycorder recordings from my IPhone 3G (I have a separate app for 3GS to use the built-in video recording) to Qwikcast, my company's WebCast presentation software. I'll be using SSH to create a symbolic link so Cycorder saves it's recordings to my applications Documents folder. Then I'll be doing a HTTP Upload to the Qwikcast web server where the video will automatically be encoded, published to a streaming media server, and then available on a "catalog" page for viewing (iPad and iPhone compatible of course) !