Showing posts with label .net. Show all posts
Showing posts with label .net. Show all posts

Sunday, September 29, 2013

How to Add Barcode Scanning to your Web App using Xamarin

Recently I had a client who wanted to add barcode scanning capabilities to their web app. Their web app was already responsive thanks to Bootstrap but there isn't a convenient way to scan a bar code from mobile Safari or Chrome.

This turned out to be fairly trivial thanks to Xamarin and two components in their Component Store:
JsBridge - eases Native to Javascript communication
ZXing.Net.Mobile - handles the barcode scanning

Here are some screenshots of what the web app looks like when accessed via the iOS app:



One of the requirements of the bar code scanning was to not show the Scan button if the user is not using the native app. To do this I customize the UserAgent of the UIWebView and then do UserAgent sniffing on the server side to hide or show the Scan button.

You'll notice if you view the web app in a browser the Scan button is not displayed:
http://xamarinbarcodesample.apphb.com/
To enable this functionality in the iOS app we append a XamarinBarcodeSampleApp string to the default UserAgent of the UIWebView:

Then in the web app we do UserAgent sniffing for this string.

To wire up the Scan button we take advantage of JsBridge. The first thing we do is register the mt.js library. Secondly we listen for the scanComplete event which is triggered on the iOS app side. Thirdly we handle the Scan button click event and let the iOS side know about it by firing the scanBarcode event.

On the iOS side we need to enable JsBridge, then listen for the scanBarcode event. When scanBarcode is fired we display the ZXing.Net.Mobile scanner. If the user successfully scans a barcode we fire the scanComplete event and pass the barcode string as an event parameter.

The native / hybrid iOS app source code can be downloaded here: 
https://github.com/crdeutsch/Xamarin.iOS.BarcodeSample

The web app source code is here:
https://github.com/crdeutsch/Xamarin.Web.BarcodeSample

Final thoughts:

Xamarin tools are flexible enough to handle the requirements of the Web Application developer dipping their toes into native development. 

In fact the Xamarin tools work so nicely with UIWebView based web apps that I'd urge any developer looking at PhoneGap or Titanium to add Xamarin to your review list and avoid the limitations you may run into. 

For instance, I built a series of HTML5 based game for a client that play audio via Flash in a desktop browser. To make them work on an iPad I used Titanium to martial the audio playback to native code. At the time I figured Titanium was the best solution since the bulk of the code was already Javascript. I eventually ran into limitations with Titanium when I wanted to detect custom gestures and realized they don't have a 1 to 1 mapping with the iOS API like Xamarin does. I plan on porting this app to Xamarin in the near future to take advantage of more advanced native iOS functionality.

In a future blog post I will demonstrate how to use JsBridge and another library I wrote to martial audio calls to the native side like I did for those HTML5 games.

DISCLAIMER: I've been work full time for Xamarin for about 3 weeks as a web developer. The following experiences and opinions were developed during my 3 years as a freelance consultant.

Tuesday, August 28, 2012

Force Content Types to Json in .NET WebApi

I ran into a situation where I couldn't set the Content-Type header in the http request client I was using. (Crossrider's appAPI.request.post)

The client was either not setting a Content-Type or defaulting to application/x-www-form-urlencoded

If you put the code below in Application_Start you should be able to force form-urlencoded data to the JsonFormatter and by removing the XmlFormatter, Json will also be the default.

HttpConfiguration config = GlobalConfiguration.Configuration;
foreach (var mediaType in config.Formatters.FormUrlEncodedFormatter.SupportedMediaTypes)
{
    config.Formatters.JsonFormatter.SupportedMediaTypes.Add(mediaType);
}
config.Formatters.Remove(config.Formatters.FormUrlEncodedFormatter);
config.Formatters.Remove(config.Formatters.XmlFormatter);

Saturday, August 18, 2012

Using Less and Twitter Bootstrap in ASP.NET MVC4

UPDATE 05/02/2013:

Changed ScriptBundle and StyleBundle to just Bundle, per Andrey Taritsyn:
Bundle Transformer it is not recommended to use together with the StyleBundle and ScriptBundle classes, because these classes already contain transformations (instances of the built-in minifiers: CssMinify and JsMinify). Use a Bundle class.

UPDATE 11/08/2012:
  1. Create a new MVC4 Internet Application
  2. Add the following Nuget Packages
  3. Rename /Content/site.css to /Content/site.less 
    • Edit BundleConfig.cs in the App_Start folder and update the css file name to site.less like so:
      bundles.Add(new var cssTransformer = new CssTransformer();
      var jsTransformer = new JsTransformer();
      var nullOrderer = new NullOrderer();
      
      var defaultScriptsBundle = new Bundle("~/bundles/default.js").Include(
                  "~/Scripts/jquery-{version}.js",
                   "~/Scripts/jquery-ui-{version}.js",
                  "~/Scripts/site.js");
      defaultScriptsBundle.Transforms.Add(jsTransformer);
      defaultScriptsBundle.Orderer = nullOrderer;
      bundles.Add(defaultScriptsBundle);
      
      var defaultStylesBundle = new Bundle("~/Content/default.css").Include("~/Content/site.less");
      defaultStylesBundle.Transforms.Add(cssTransformer);
      defaultStylesBundle.Orderer = nullOrderer;
      bundles.Add(defaultStylesBundle);
      
    • Add the following to the top of /Content/site.less in order to have access to all of the Bootstrap mixins:
      @import "less/bootstrap.less"; 
      body {
            padding-top: 60px;
            padding-bottom: 40px;
      }
      @import "less/responsive.less"; 
      

    =================== THE REST OF THIS POST IS OUT OF DATE ==========

    UPDATE 8/20/2012: I've created a Nuget package that performs the steps below. I'd suggest reviewing what the package does below and then running:
    Install-Package Twitter.Bootstrap.Less.MVC4

    ASP.NET MVC4 has a great new feature that can bundle and minify your CSS and Javascript files.

    But in order to get Twitter Bootstrap to work it takes a bit more work. Here are the steps that worked for me.

    1. Create a new MVC4 Internet Application
    2. Add the following Nuget Packages
    3. Create an Infrastructure folder and add the following two files: (hat tip to this Stackoverflow question)
    4. Rename /Content/site.css to /Content/site.less 
    5. Edit BundleConfig.cs in the App_Start folder and replace the default Content/css bundle with the following:
      var css = new Bundle("~/Content/css").Include("~/Content/site.less");
      css.Transforms.Add(new LessMinify());
      bundles.Add(css);
      

    6. Add the following to the top of /Content/site.less in order to have access to all of the Bootstrap mixins:
      @import "less/bootstrap.less";
      

    If you have "shared" .less files from other projects I found importing them in site.less right after boostrap.less to work pretty well. They'll have access to all the mixins.
    @import "less/bootstrap.less";
    @import "less/shared.less";
    

    The completed solution is available on Github here

    If there is a better/easier way to do this please let me know in the comments!




    Tuesday, May 1, 2012

    MonoTouch JsBridge - Communicate with the UIWebView

    Today I'm open sourcing JsBridge for MonoTouch which allows for bidirectional communication between the javascript in your UIWebViews and your native C# code in your MonoTouch app. Go directly to GitHub for the documentation on how to use it.

    This project was inspired by doing a project using Appcelerator's Titanium. In fact the javascript used in JsBridge was taken directly from that project, so if you're used to using Titanium you should be right at home using JsBridge.

    At this time it requires MonoTouch 5.3.3, which as of 5/1/2012 is in Alpha, because JsBridge needs to register a custom url protocol using NSUrlProtocol.

    I'm not 100% satisfied with the implementation of the event listeners on the native side, so I'm open to suggestions on how to make it better. Ideally some day the Xamarin team will implement something like this in a future version. ;)

    I've already submitted my first app to use it the iOS AppStore and it relies heavily on bidirectional communication between javascript and native. The app is a remote control for Rdio's new UI. A nicely executed feature by Rdio (even if it came way after the chrome extension remote I made for their first UI ;) ), but unfortunately it doesn't work on iOS partially due to the Rdio servers not supporting the Websockets protocol that the UIWebView has. Using JsBridge I was able to implement the WebSocket connection on the native side and override the Rdio javascript calls that use WebSockets and pass them to the native side and vice versa. I'm quite pleased with the results so far. ;)

    Wednesday, February 29, 2012

    MonoTouch.Dialog UIPicker

    In iOS a UIPicker looks like this:

    I'm working on an iPhone application that's built using MonoTouch.Dialog and after a full day of trying to get the MonoTouch.Dialog compatible Picker in ClanceyLib to work, I've decided to package up my work and release it on GitHub.

    The main issues with ClanceyLib is that it requires a heavily modified and out of date version of MonoTouch.Dialog. If you try to compile it with the built-in version of MonoTouch.Dialog you'll get the following two errors:

    /Users/guivho/Mono/ClanceyLib/ClanceysLib/MT.D/ButtonElement.cs(49,49):
    Error CS0115: `ClanceysLib.ButtonElement.GetCell(MonoTouch.Dialog.DialogViewController,
    MonoTouch.UIKit.UITableView)' is marked as an override but no suitable
    method found to override (CS0115) (ClanceysLib)


    /Users/guivho/Mono/ClanceyLib/ClanceysLib/MT.D/ComboBoxElement.cs(49,49):
    Error CS0115: `ClanceysLib.ComboBoxElement.GetCell(MonoTouch.Dialog.DialogViewController,
    MonoTouch.UIKit.UITableView)' is marked as an override but no suitable
    method found to override (CS0115) (ClanceysLib)


    Ripping out the elements you need from ClanceyLib wasn't as easy as I hoped on the first try but I now have it working along with some other improvements:
    • Updated it to hide the keyboard or picker when selecting different cells to edit.
    • Changed so the Items in the Picker list are UIView's for greater customization.
    • Actually has a sample of how to use it. ;)
    UPDATE 3/1/2012: It works out of the box with the version of MonoTouch.Dialog that is now packaged with MonoTouch. But, it will not dismiss the picker when selecting a different cell. To enable that feature it requires a custom version of MonoTouch.Dialog and you'll need to comment in 3 lines of code in PickerElement.cs.

    I sent a pull request to get my minor change to MonoTouch.Dialog included in the core. If/when it's pulled I will update PickerElement.cs to take advantage of it and the dependency on the custom version of MonoTouch.Dialog will be no more. ;)

    Tuesday, September 6, 2011

    Entity Framework Code First Error: Could not create constraint

    While using Entity Framework Code First you will run into an error similar to the one below if you create objects that have a circular reference.

    Introducing FOREIGN KEY constraint 'File_Folder' on table 'Filess' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
    Could not create constraint. See previous errors.


    The fix is pretty simple but not very intuitive.

    Add the following line to your OnModelCreating override of your DbContext:

    modelBuilder.Entity<File>().HasRequired(oo => oo.Folder).WithMany(oo => oo.Files).WillCascadeOnDelete(false);
    

    So it looks something like this:

    public class FilesystemDB : DbContext
    {
     public DbSet<File> Files { get; set; }
     public DbSet<Folder> Folders { get; set; }
     
     protected override void OnModelCreating(DbModelBuilder modelBuilder)
     {
      modelBuilder.Entity<File>().HasRequired(oo => oo.Folder).WithMany(oo => oo.Files).WillCascadeOnDelete(false);
     }
    
    }
    

    For the best information on Entity Framework Code First read Morteza Manavi's blog.

    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.





    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!

    Sunday, January 16, 2011

    MVC3 Boilerplate

    Every time I create a new ASP.NET MVC3 project there are certain libraries and code I re-use regularly. One of them being HTML5 Boilerplate which I love. I did some googling for "MVC3 Boilerplate" and didn't find anything, so I decided to start my own and placed it here on GitHub.


    With every release MVC3 included more awesome out of the box (finally has jQuery AND jQuery UI!), but I'd like to see the option to go further. One of the things I love about Ruby on Rails is it includes more of what you need to get you straight to coding like a de facto ORM (ActiveRecord). I also don't like how complicated AspNetSqlMembershipProvider is and the fact it doesn't store data in cleanly named "Users" table so I decided to add my own simple User class that can be modified and extended.


    I'd love to see someone with more experience then me clean up, take over, re-do or otherwise improve on this idea. So feel free to fork my project or make suggestions. I'm not always the best and keeping projects up to date but I'll see what I can do.


    Some of the features I've included are:
    • HTML5 Boilerplate
    • Elmah (error logging)
    • JSON Parser (comes in handy when making JSON based ajax calls)
    • Modernizr (part of HTML5 Boilerplate, but awesome enough to warrant its own mention)
    • AntiXSS Library (Most of the places this is used was based on the Tekpub MVC2 Starter Site, I'm probably doing it wrong and/or not using it enough)
    • Ninject (dependency injection)
    • SquishIt (used to compress and minimize javascript and CSS)
    • Sql Server CE (included so you don't need full MS SQL or SQL Express)
    • EF Code First (used as the ORM)
    • Bits from Tekpub MVC 2 Starter Site
    • Basic User Signup using simple POCO User object

    I really don't know how much I'll keep this project up to date but even if it helps one person that's enough for me. ;)

      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.

      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.

      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

      Friday, April 16, 2010

      Visa Fail with Authorize.NETs CIM

      Just heard from a client that their "Save Credit Card" feature stopped working. They use Authorize.NET's Customer Information Manager (CIM) to securely save the credit cards.

      Suddenly the application was just returning:
      3,1,290,There is one or more missing or invalid required fields.
      Why two, large, successful companies like VISA and Authorize.NET can't tell you which fields they want is beyond comprehension.

      According to this message thread:
      Visa has a mandate in place that allows us to do $0.00 authorizations to test the validity of a card, but in order to do it they require that an address be passed also. Since VISA is the only company that has this policy, the other card types will be unaffected and not experience the same error.
      Up until recently they only required Card Number, Expiration, and Security Code. I tried using a dummy address like the message thread suggested. This would only work if the Authorize.NET Address Verification Service settings were configured to ignore the address, so in my case we'll likely be updating the code to pass the billing address in since we have it anyway.

      Thanks for the notice on this VISA and Authorize.NET! You have to wonder how much time and money changes like this cost all the organizations affected?

      Sunday, February 28, 2010

      .NET LINQ Bug - Specified cast is not valid.

      I ran into this nasty little bug last week. It didn't show up on my local work station running Windows 7 but it showed up once published to our development server running Windows 2003 Server. It would happen when inserting a record to the database after calling "db.SubmitChanges()"

      The root cause was having a "non-integer" key which I rarely use, but this instance was special. I was able to fix it immediately by deleting the association in the LINQ designer. I was lucky because so far I don't need this relationship defined in LINQ.

      After the immediate fix I noticed our development server was missing some patches, so I put in a request to have those installed. I haven't yet tested if that fixes the problem but I suspect it will. Also there is this hotfix that may work:
      https://connect.microsoft.com/VisualStudio/feedback/details/351358/invalidcastexception-on-linq-db-submit-with-non-integer-key

      Hope this saves someone else some time!