Themes and ASP.NET MVC

I wanted to easily add theme support to yonkly, so that others can install it and modify its look and feel as they please.  I also wanted it to be as easy as installing a theme in wordpress.

I created a themes folder under the content folder

image

Then I referenced my css file in the master page using a helper method

<%= ThemeHelper.GetCss() %>

I also use a helper method for images

<img src='<%=ThemeHelper.GetImageUrl("reply.png")%>’ alt="reply" class="icon" />

But most of my images are set in the stylesheet, which makes it easier to manipulate different skins

The helper methods above look at the defined theme in the config file (or database or wherever you store your settings) and then return the path to the correct resource.

Take a look at these live samples:

They are all using the same codebase but have a different theme defined.  The trick is in making your HTML css-friendly by naming elements and assigning them classes as well as using Divs and avoiding tables.  This allows you to create a stylesheet that radically changes the look of the site.  Think of the element ids and classes as an API to your view, that the css can manipulate.

I also added a feature that lets you upload a folder theme as a zip file and have the application unzip it into the themes folder.

image

It would be cool if we can define a "virtual folder" in our application, so I wouldn’t have to use helper methods.  Imagine if you could just say /content/theme/logo.gif and it would just work.  The theme folder doesn’t really exist but instead it would route to the correct folder based on a setting.  I wonder if I can do that with current routing mechanism in asp.net mvc!!!  Anyone?

Database Schema Compare & Upgrade

I spent a few days playing with Ruby on Rails a while back.  During the learning experience, there was one particular feature that I really liked.  It was the database migration scripts that get automatically generated for you.  I always wished I had something like this in the windows (asp.net) world.  It turns out there is something out there and it is right there within Visual Studio.

When upgrading my production applications, I have always struggled with trying to update my production database schema to match the latest schema.  This has always been a manual, error-prone and time consuming task.  One that I always dreaded and postponed to the last minute.  It usually involved crossing my figures, praying to the SQL Gods and running a hand-made migration script against the production database.  I am not a DB guy, so you can imagine how much un-fun this was.

Long story short, you can do this with a few clicks in Visual Studio 2008. 

Start a new schema comparison

clip_image001

Select your source database (e.g. development database) and your target database (e.g. production database)

clip_image001[4]

Click Ok.  Visual studio will compare the two schemas and display the results in a grid, showing you what objects (tables, views, procs, etc…) have changed and the action you want to take.

clip_image001[6]

Select any item that has changed and you will see the differences between source and target.

clip_image001[8]

The last pane at the bottom contains the update (migration) script that will run against the target to make it identical to the source.  You can quickly scan it to make sure you are not wiping out your entire production database (not recommended).

clip_image001[12]

You can also customize the update by clicking the drop downs in the grid to customize the script

clip_image001[14]

Once everything looks good to go, just hit the button "Write Updates" and you are done.

clip_image001[16]

This has been a sore in my side for a long time and I am glad I discovered this.  I am actually kind of pissed off because I have always seen that menu and never really tried to click it.  Oh well!!!

Hmm…  What to do with all the time I just freed up???

NOTE: According to msdn this feature is only available in the Database Edition and Team Suite versions.  I am running Team Suite (click Help > About Microsoft Visual Studio to find out your version)

image

Unit Test Private Methods in Visual Studio

I am working on a feature that will let me import twitter messages to yonkly and wanted to write a test for it.  The method is private and I couldn’t get the unit test to see it.  I also didn’t want to use the private accessor class generate by Visual Studio because I was mocking some functionality in the actual class and didn’t really fell like re-mocking it on the private accessor.

So, after several minutes of googling, I found several solutions that I didn’t like.  John Hann uses reflection to test private methods.  Tim Stall has a similar solution at the code project.  Andrew Stopford suggested that I don’t test private methods and use code coverage to make sure that they are being exercised.  I was about to use the methods suggested by John Hann and Tim Stall to test my private methods, but then I accidentally (thanks to IntelliSense) discovered PrivateObject.

The PrivateObject class is part of the Team Test API.

Allows test code to call methods and properties on the code under test that would be inaccessible because they are not public.
from msdn

It turned out to be pretty easy to test private methods and the code looked like this:

var myController = new TwitterController();
var po = new PrivateObject(myController);
var page = 1;
var count = 25;
po.Invoke("ImportTweets", new object[] { page, count });

 

The code above will call the private method ImportTweets and pass it two integer parameters.  This is the equivalent of calling

myController.ImportTweets( page, count);

 

Note that this is essentially what John Hann and Tim Stall suggested but why use extra code when PrivateObject is already available for you.

Shortening URLs Using TinyUrl API in .net

Here is a quick method to shorten URLs using the TinyUrl API in .net – C# and VB

C#

public static string MakeTinyUrl(string Url)
{
try
{
if (Url.Length <= 30)
{
return Url;
}
if (!Url.ToLower().StartsWith("http") && !Url.ToLower().StartsWith("ftp"))
{
Url = "http://" + Url;
}
var request = WebRequest.Create("http://tinyurl.com/api-create.php?url=" + Url);
var res = request.GetResponse();
string text;
using (var reader = new StreamReader(res.GetResponseStream()))
{
text = reader.ReadToEnd();
}
return text;
}
catch (Exception)
{
return Url;
}
}

VB

Public Shared Function MakeTinyUrl(ByVal Url As String) As String
Try
If Url.Length <= 30 Then
Return Url
End If
If Not Url.ToLower().StartsWith("http") AndAlso Not Url.ToLower().StartsWith("ftp") Then
Url = "http://" + Url
End If
Dim request As var = WebRequest.Create("http://tinyurl.com/api-create.php?url=" + Url)
Dim res As var = request.GetResponse()
Dim text As String
Using reader As var = New StreamReader(res.GetResponseStream())
text = reader.ReadToEnd()
End Using
Return text
Catch Exception ex
Return Url
End Try
End Function

Tricky Asp.net MVC URL Rewriting

I am working on an asp.net mvc application and I wanted to make the user’s main page (profile) be http://www.domain.com/username.&nbsp; This is a problem because the routing engine in MVC treats the first item after the domain as a controller.  Ofcourse I could do a {*catchall} and do my own parsing but why re-invent the wheel – plus I suck at regular expression.  What I ended up doing is registering all the routes manually.  So if I wanted to go to /message/create, I would register a route like this:

routes.Add(
    new Route("Message/Create", new MvcRouteHandler())
        {
            Defaults = new RouteValueDictionary(new
                                                    {
                                                        controller = "Message",
                                                        action = "Create"
                                                    })
        }
    );

So far so good, nothing earth shattering.  So I basically did this for all my routes and the last route, I added was:

routes.Add(
    new Route("{*username}", new MvcRouteHandler())
       {
           Constraints = new RouteValueDictionary(new {username = "^(?!content/).*"}),
           Defaults = new RouteValueDictionary(new {Controller = "User", action = "View"})
       });

This basically will catch any route that has not been defined before it and will treat it as a username so /eibrahim would go to the view action on the user’s controller.  Also, note that I added a constraint to prevent the catch-all route from catching any url in the content subfolder.  Important: All your scripts, images, css files and so on have to be in the content folder otherwise they will be handled by the catch-all route and not be accessible to your application.

The signature for the view action look like this:

public void View(string username, int? page)
{

}

Now the tricky part is that you want to make sure that your users don’t signup with a username matching the controller.  So if a user decided to register with the username “message”, he will never be able to go to his profile at /message because it will be handled by the generic message route “message/{action}”.  A quick workaround is to prevent the user from registering with those names.  In my signup process I call a method to check if the selected username is valid.  The validation process loops through all the routes and makes sure the username doesn’t match any controller or action.  It works out pretty well so far.

foreach (Route route in RouteTable.Routes)
{
    if (username == route.Defaults["controller"].ToString().ToLower())
        return false;
    if (username == route.Defaults["action"].ToString().ToLower())
        return false;
}

I don’t know if this is the best solution, so if you know of a better way to do it, let me know.

My Elevator Pitch

I found this cool site that has a free wizard which helps you build your elevator (15 second) pitch. Here are some of my pitches:

Consultant

My name is Emad Ibrahim and I am a consultant specializing in .net development. I architect, design and create software. I can do it faster and better than the competition. Unlike other consultants, I don’t want to milk a contract to make more money. I want to finish on time and under budget, so I can have a happy customer and repeat business. Call or email me for a free consultation – I would love to help you even if you get someone else to do the job.

Entrepreneur

My name is Emad Ibrahim and I am an entrepreneur specializing in web development and new media.. I create software applications and web services using the latest technologies and embracing new web and social trends. I understand the online landscape and stay up to date on what is hot and what is not and how to tap new technologies to improve your business and your life. Contact me for partnership opportunities. I have learned that I can’t do it all alone.

Superhero

My name is Super-E and I am a super hero. I can read and write computer languages incomprehensible to humans. I also have the ability to create self-healing programs and an expert bug exterminator. I like to guide people and business on how to use computers to improve their work and personal life. If you have any questions that only a superhero can answer, then call on Super-E.


Creative Commons License photo credit: zukker

Create your own 15-second pitch for free at http://www.15secondpitch.com

Cross Domain Error Fix for Silverlight

The easiest/quickest way to fix a cross domain error is to create a test website to host your Silverlight application.

image

When you hit F5 to debug the application, it will run the development server and the address bar will say http://localhost:xxx/blahblah.  This will prevent a cross-domain error.

If you try to run it using an test html page from the file system i.e. browser address would say something like c:projectssilverlighttest.html then it will throw the cross-domain error.

If you already have your Silverlight application created then just create an empty website or web application project and then right-click on it and click "Add Silverlight Link…"

image

Then follow the instructions on the screen

image