Wednesday, November 16, 2011

Deploying a Titanium app: Part 1



I'm going to make some assumptions here that 1) you already are a registered Apple developer, 2) you've registered your device on the developer portal, and 3) you have both Titanium and XCode properly setup.  Part 1 of this 2 part blog series will focus on what you'll need to do in the Developer Portal on Apple's website.

Login to iOS Dev Center at http://developer.apple.com/devcenter/ios/index.action.

Go to the iOS Provisioning Portal


















Go to the App IDs subtab and click the New App ID button


Setup your app and make sure the package name exactly matches what you specified in Titanium


Go to the Provisioning Profile subtab and click the New Profile button


Check a Certificate, select the appropriate App ID, and click the devices that you are going to deploy to.


On the next screen you'll have to wait for the profile to become Active (should take less than 30 seconds).  Then click download to save the .mobileprovision file to your machine.


This is all you'll need to do on the iOS Dev Center.


Saturday, October 22, 2011

The Mighty In'N'Out 5x5

During one of my many trips to Cali last year, I paid homage to In'N'Out burger to take down a 4x4 burger. First off, in case you're unaware, In'N'Out is practically a religion for many people on the west coast. You can start a holy war by stating In'N'Out burger is NOT the best burger you've had in the state. Their burgers actually are very tasty, but it's the extra stuff that you can add to it that makes it stand out.

I usually order a double double, animal style, extra toast, with a whole grilled onion. Quite a tall order for a single sandwich (you can customize your fries as well if you know how). Sadly we'll probably never get to see one here in the midwest.

A 4x4 means that there are 4 meat patties and 4 slices of cheese.  During that time I happily scarfed it down and still had room to tuck away an order of fries.  This year I had to 1up myself by tackling a 5x5.

My quest started by pulling in behind a sea of cars in the drive-thru of the only In'N'Out in Salinas (and yes it's always this packed).  Once I get to the ordering guy and tell him I want a 5x5 he stops and tells me that they can't allow me to order it.  WTF????  "This sandwich is 80% of the reason I flew here from Chicago" I tell him.  Why can't I order one?  He tries to make some excuse about how some people are going nuts with it by ordering 20x20's.  And the problem with that is ????

I finally talk him into selling it to me, they rang it up as a 4x4 and put an extra patty on there that I actually had to put into the burger myself.


After a mixup of who I was meeting up and where we were eating, I finally got to sit inside with a bunch of my cousins and start eating the burger (almost 15 minutes after it was handed to me). After the first few bites I knew that I was biting off more than I could chew (womp womp womp womp). Some of the patties were undercooked and were pink, not a good sign for such thin patties.


Some of my cousins were taking pictures of the effort while others were explaining to other patrons that so happened to be watching what was going on, wondering what it was that I was holding in my hands.  One of the younger cousins was staring in disbelief with her mouth open.

The burger stopped tasting good a while ago.  The amount of cold, undercooked meat and somehow still sweaty cheese really started playing tricks on my mind. I literally started gagging as I was eating.  It became a pride thing at that point as I tried to man up mentally and power through it.  The last 5 bites made my legs go numb and I can truly say that now I know what despair tastes like.  Alas, I had let my ancestors down and was not able to slay the mighty beast, leaving off somewhere between 1/3 and 1/4 of the burger.



Was it a valiant effort?  Maybe, maybe not.  I do know that I will be just fine if I never have to eat In'N'Out burger again.... at least not until my next trip out west ;)

Getting started with Jasmine in Visual Studio

You've probably heard good things about the Javascript testing framework known as Jasmine. Hopefully you've given it a test run over at http://try-jasmine.heroku.com. It is a quick way to unit test a small class or set of functions and see the red-light/green-light statuses.

Start by downloading the standalone Jasmine at https://github.com/pivotal/jasmine/wiki. Copy the jasmine folder to your web project. As of version 1.1.0 the contents are jasmine.css, jasmine.js, and jasmine-html.js (and a .png icon). For some reason there was no specrunner.htm file as indicated by the instructions.

The next step is to create the specrunner.htm file mentioned above. This will be the single file used to run a suite of all tests for the project. I created a file named **specrunner.htm** at the root of the project.

In the HEAD section you'll want to link the main jasmine javascript and css files. After that you'll want to link your javascript code that will be tested. The third thing to link will be your javascript test files or spec files as jasmine refers to them as. The final step needed for you page is to put script tags in the BODY section to execute the test runner. Below is a sample completed html page with all needed elements that tests one javascript file and has one spec file.
<!DOCTYPE html>
<html>
<head>
    <title>Jasmine Tests</title>
    
    <!-- Files required for Jasmine -->
    <link href="Content/scripts/jasmine-1.1.0/jasmine.css" rel="stylesheet"/>
    <script type="text/javascript" src="Content/scripts/jasmine-1.1.0/jasmine.js"></script>
    <script type="text/javascript" src="Content/scripts/jasmine-1.1.0/jasmine-html.js"></script>
    
    <!-- Javascript files to be tested -->
    <script type="text/javascript" src="Content/scripts/numberConverter.js"></script>

    <!-- Spec files holding the tests -->
    <script type="text/javascript" src="Content/scripts/tests/numberConverterSpecs.js"></script>

</head>
<body>

    <!-- Code to run the tests and show results -->
    <script type="text/javascript">
        jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
        jasmine.getEnv().execute();
    </script>

</body>
</html>
Hopefully you're using classes in your javascript, if not then WTF are you thinking? Here is a simple js class that we'll write tests against:
var hero = (function() {
  var shieldMaterial = 'iron';
  
  return {
    blockFlames: function() {
      if (shieldMaterial != 'iron')
        return 'dead';
      else
        return 'safe';
    },
    
    dropShield: function() {
      shieldMaterial = '';
    }
  };
}());
So what does code inside a spec file look like?
describe('hero',function(){
  beforeEach(function() {
    this.addMatchers({
      toBeSafe: function() {
        return this.actual === 'safe';
      },
      toBeDead: function() {
        return this.actual === 'dead';
      }
    });
  });
  it('can fight dragon',function(){
    expect(hero.blockFlames()).toBeSafe();
  });
  it('dies after dropping shield',function(){
    expect(hero.blockFlames()).toBeSafe();
    hero.dropShield();
    expect(hero.blockFlames()).toBeDead();
  });
});
Lines 2 - 10 of the spec files are used to define two new comparison functions: toBeSafe and toBeDead in relation to our hero. Defining those two methods at the beginning allows them to be used throughout the rest of the spec file and can make our tests have more meaning within the context of our domain.

If we launch our htm page in a browser we should see something like this:

If we change our hero's shield material to 'wood' in Line 2 and refresh the page, the results will turn into this:


This is a quick way to start using Jasmine in your projects. If you want to really integrate your javascript testing into Visual Studio such that you can view the results in a test runner window, take a look at JsTestDriver and the Jasmine adapter for it.

Copying MongoDB data from your machine to the cloud


For this example I’ll be using MongoHQ as the cloud host. I prefer MongoHQ over MongoLab because the web interface actually lets you edit and manage your data, which is great for making quick small tweaks.

Step 1 - Create a new database in MongoHQ

I start with a Free 16 MB collection. The next page you’re taken to shows you the address for the database and will look something like staff.mongohq.com:10023/DbName

Step 2 - Create a Database User

Click on the Database Users tab and add a user. Leave the Read Only boxed unchecked.

Step 3 - Prep your local data for transfer

On your machine open a command prompt and navigate to your Mongo bin directory or wherever the mongo.exe file is located.
Type mongodump -d DatabaseName where DatabaseName is the actual name of your database 
There will be a new folder in the directory named dump and in there another folder named after your database.

Step 4 - Transfer the data to the cloud

Type mongorestore -h staff.mongohq.com:10023 -d DatabaseName -u admin -p password C:\Mongo\dump\DatabaseName (Make sure to substitute the appropriate values).
Verify on MongoHQ’s collections tab that the data was transferred successfully.

Preparing for my first Lunch and Learn


This was an earlier post from September when I was still posting to Tumblr.

This Thursday I present my first lunch and learn at Geneca.  It's titled "Getting your web microservice onto the cloud."  I initially wanted to title it "Creating a web microservice for practically free" but the focus was intended to be more around the cloud aspect of it rather than the entrepreneurial side of it.  Nonetheless the spirit of the talk is very much so fitted towards the entrepreneur.

The first 5 minutes gives a quick look at what "cloud" computing means to me, what the 3 different setups are (IaaS, PaaS, and SaaS), and then a little bit about EC2 and Azure.  What I'm really trying to do in the part is give definition to some cloud terms and maybe talk a little about what EC2 and Azure look like physically.

From there the talk will shift into the tools I used to get a website up and running using all free tools starting with an IDE, a DVCS, a hosting account, and a db host.  I'll be highlighting the site wizard in WebMatrix for a basic shell site.  Then I'll save the code to BitBucket for source control using TortoiseHg in windows explorer and Mercurial (it helps having learned Git first to understand the process flow as they are practically identical).  Then I'll be pushing the site to AppHarbor and talk about continuous deployment.  I'm still thinking of an easy way to highlight linking MongoHQ but I'd have to switch to one of my existing web apps to show this in a meaningful capacity.

My second Titanium app: a movie soundboard app

My goal with this next app is to build something that I would actually use, a soundboard app with a few of my favorite movie quotes. I wanted to learn how to play media and also to start getting HTML 5 in the phone working as well so I used a tab grouping with two tabs.
Ti.UI.setBackgroundColor('#000');

// Windows
var win1 = Ti.UI.createWindow({ 
    title:'Anchorman',
    backgroundColor:'#fff',
    url: "/windows/anchorman.js"
});
var win2 = Ti.UI.createWindow({ 
    title:'Other',
    backgroundColor:'#fff'
});

var webview = Titanium.UI.createWebView({url:'/web/other.htm'});
win2.add(webview);

// Tabs
var tabAnchorman = Titanium.UI.createTab({
 id:'tabAnchorman',
 icon: 'KS_nav_ui.png',
 window:win1,
 title: 'Anchorman Quotes'
});
var tabOther = Titanium.UI.createTab({
 id:'tabOther',
 icon: 'KS_nav_views.png',
 window:win2,
 title: 'Other Quotes'
});
var tabGroup = Titanium.UI.createTabGroup({id:'tabGroup1'});
tabGroup.addTab(tabAnchorman);
tabGroup.addTab(tabOther);

tabGroup.open();
The first tab is a normal tableview with entries for Anchorman quotes.

Here is the anchorman list page:
var win = Ti.UI.currentWindow;

// Table view for showing the list of data
var tableview = Ti.UI.createTableView({ top: 0, backgroundColor: 'white' });
tableview.addEventListener('click', function(e)
{
    var sound = Ti.Media.createSound();
 sound.url = '../mp3/' + e.rowData.className + '.mp3';
 sound.play();
});

win.add(tableview);
refreshData();

function refreshData() {
 var data = [];
 data[data.length] = Ti.UI.createTableViewRow({title:'Cannonball',className:'a_cannonball'});
 data[data.length] = Ti.UI.createTableViewRow({title:'Having Fun',className:'a_havingfun'});
 data[data.length] = Ti.UI.createTableViewRow({title:'Real Panther',className:'a_realpanther'});
 data[data.length] = Ti.UI.createTableViewRow({title:'Stings Nostrils',className:'a_stingsnostrils'});
 data[data.length] = Ti.UI.createTableViewRow({title:'Very Important',className:'a_veryimportant'});
 data[data.length] = Ti.UI.createTableViewRow({title:'Every Time',className:'a_everytime'});
 data[data.length] = Ti.UI.createTableViewRow({title:'I Wanna Be On You',className:'a_iwannabeonyou'});
 data[data.length] = Ti.UI.createTableViewRow({title:'No Pants Dance',className:'a_nopantsdance'});
 data[data.length] = Ti.UI.createTableViewRow({title:'Pirate Hooker',className:'a_piratehooker'});
 data[data.length] = Ti.UI.createTableViewRow({title:'Storming Your Castle',className:'a_stormingyour'});
 data[data.length] = Ti.UI.createTableViewRow({title:'Whammy',className:'a_whammy'});
 data[data.length] = Ti.UI.createTableViewRow({title:'Yelling About',className:'a_yellingabout'});
 
 tableview.data = data;
}
Clicking an entry will create a sound object which takes a url and plays the sound.

Here is the html page for the second tab which has links for other movie quotes: I don't consider this app finished by any stretch but it addresses the two goals I had set out with playing media and incorporating an HTML 5 page in the app. And this app was completed in a half hour after work meetup.

Unit testing .aspx pages


One of the inherent problems with unit testing .aspx web pages in Visual Studio is dealing with the missing HttpContext object in a Test project. There are ways that this can be mocked but this is not very intuitive nor easy to find documentation on (at least from my searching). The good news is that there is a way around this without much effort.

First off let's talk about a rudimentary solution provided by Visual Studio Test Edition that falls short of our goal of effectively unit testing an .aspx page. With this version of VS you'll see a special kind of test called a "web unit test". Oooh, sounds promising... until you actually try to use it. You launch a running web app and the test captures the all POST data from a postback. Then you can edit these POST action variables and substitute whatever values you want for them. As for your assertions you do a pattern match on the resulting html to see if a keyword you're expecting got rendered on the screen. Yeah, clunky at best.

So onward to a legitimate solution! Let's say you're writing a search screen that has several ASP server controls such as textboxes, dropdowns, radio buttons, etc. on it and below that you have a GridView to show the search results. The ideal test scenario would allow us to reference our server controls explicitly and with minimal effort. This means that in our test we'd get to set any control attribute like we normally would in code behind, we can raise control events, and lastly we can run our assertions by looking at our controls' properties.

Setting up your test project

There are two methods that you'll want in a separate class in your test project. Your test methods will make several references to these. Let's create a class called WebTestHelper and place these static methods in it.

The first method (actually one method with an override to make two methds) allows you to find a control on a page by referencing it's control ID, the code is as follows:
private Control FindControl(string id)
{
    return FindControl(TestContext.RequestedPage, id);
}
private Control FindControl(Control container, string id)
{
    // See if current control contain's the control we're looking for
    if (container.ID == id) return container;
    Control output = null;
 
    // Loop through child controls and call recursively until found or until end
    if (container.HasControls())
    {
     foreach (Control ctrl in container.Controls)
     {
         output = FindControl(ctrl, id);
         if (output != null) break;
        }
    }
 
    return output;
}
The second method lets you raise events on your controls:
private void RaiseEvent(string eventName, object targetObject, EventArgs args)
{
 var privateObject = new PrivateObject(TestContext.RequestedPage)
 privateObj.Invoke(eventName, targetObject, args);
}
PrivateObject is a class that is part of the Microsoft.VisualStudio.TestTools.UnitTesting namespace. The TestContext object is a private variable that's included in every unit test class generated by Visual Studio.

Dressing up your Test Method(s)

With the above two methods in place you're almost ready to write your first test. You'll need a few attributes above your unit test to get this to work properly.
[TestMethod]
[HostType("ASP.NET")]
[UrlToTest("http://localhost:80/PathToPage.aspx")]
[AspNetDevelopmentServerHost("C:\\Projects\\MyWebProject")]
private void WebPageTest() ...
Fill in the appropriate URL for your .aspx page and the path to your web project.

Writing test code for your .aspx page

We want to test filling in search criteria on the page, clicking search, and then analyze our gridview for data:
// Load controls
var txtCompany = FindControl("txtCompany") as TextBox;
var btnSearch = FindControl("btnSearch") as Button;
var grdCompanies = FindControl("grdCompanies") as GridView; 

// Trigger the search
txtCompany.Text = "Acme";
RaiseEvent("btnSearch_Click", btnSearch, EventArgs.Empty); 

// Run assertions
Assert.IsTrue(grdCompanies.Rows.Count > 0, "No results in search grid");
The result is that our test looks fairly simple and we're referencing our controls explicitly allowing us to run fine-grained tests on them.

Skip and Take the SQL way

In Asp.Net most databound controls having paging built-in to automatically segment long data sets. There are even jQuery grids that have been built to allow paging. The downside to automatic paging is that you’re still querying and returning the entire set of rows even if you’re showing a subset (in most cases).

If you want to truly limit the bandwidth from your database you can implement Skip and Take within your SQL code.
DECLARE @Skip int
DECLARE @Take int

SET @Skip = 0   -- The number of records to skip
SET @Take = 10  -- The number of records to return

SELECT * FROM (
   SELECT ROW_NUMBER() OVER (ORDER BY [t0].[ID], [t0].[Name],
     [t0].[Address]) AS [ROW_NUMBER], [t0].ID, [t0].Name, [t0].Address
   FROM [Company] AS [t0] ) AS [t1]
WHERE [t1].[ROW_NUMBER] BETWEEN @Skip + 1 AND @Skip + @Take
ORDER BY [t1].[ROW_NUMBER] 

Creating my first Titanium mobile app

This is a post I published back in July when I was still posting to Tumblr.

As part of our Gendroid mobile initiative, I’ve created a Todo application using Appcelerator’s Titanium studio. The goal of the exercise was to build a simple “breakable toy” application in order to get comfortable with the basics of building a mobile app. Many people in the group decided to build their app as a native Android application using Java and Eclipse.

I decided to build my app using Titanium to take advantage of a single code base that creates apps for multiple mobile platforms. Secondly, the fact that the language used in Titanium is javascript really appealed to me. Javascript is probably the second-most import language that a developer should know (aside from whatever primary language you already know). Lastly, apps are converted to native Objective-C code for iOS if you use the built-in Titanium libraries.

Start by creating a new Titanium mobile project and selecting the mobile devices you want to target (in my case I chose iPhone and Android). After the project files are generated look for the app.js file in the Resources folder. This is the “Main” function that gets called to start your app. In here you setup the starting interface for your app such as a single window or a tab group if your app will involve several pages. For my app I didn’t really have multiple tabs to switch between because it only dealt with managing a task list. Basically my vision was to build a list page and a details page. In order to get page navigation working the way native iPhone apps do it was necessary to create a tab group that had a single tab. Doing this provided the app with a title bar that would automatically incorporate navigation buttons at the top whenever I switched from my list view to my details view.

So app.js defined the tab group. The tab group itself housed a “window” object. The window object represents a new view (or page if you’re more comfortable with the web world). To best separate this I created a new .js file for each window, in this case I created a list.js page and a details.js page. Inside the list.js page is a table view object that you bind to a data array. By default the table view object will fill all available screen space unless you manually set it’s width or height properties. I bound a click event to the table, the code looks very similar to binding a click event to an element in jQuery. In the click event I have it open a new window whose url is set to the detail.js page while setting some page-level variables of this new page so it knows the Id of the row I clicked.

On the details page there are 3 main elements: 1 textbox for Name, 1 textarea for Description, and a Save button. In order to get these on the screen I explicitly set each element’s height, width, and top properties.

Yes this is dreaded absolute positioning and I’m not a big fan of it. I honestly haven’t tried setting up elements any other way yet and am hoping that there’s more of a natural flow layout that happens instead somehow. Once Save is clicked I persist all data and then close the current window. The built-in windows navigation nows to jump back to the previous open window so that the list page comes back up. Of course, if I just close the details window the list page will have stale data and will need to be refreshed. The way that I solved this was by creating a page-level function in the list page that just refreshes the table view data. I pass this function the details page so that when Save is called, the details page can call the Refresh function before it closes its window.

So that’s the general gist of how my first app went. I didn’t really follow any video or web tutorials, what I did do was look at some code from Appcelerator’s KitchenSink demo app. For me it’s just fun to try and figure out how to make something work on your own than to follow a cookie-cutter tutorial on getting something done. It’s probably not the right way but I was happy with the progress that was made and for the short amount of time it took to finish the app (I use the word ‘finish’ very loosely).

Thursday, October 6, 2011

Mocking a web context for .Net MVC using Moq

To effectively unit test MVC Controllers you'll need to supply a web context or an HttpContext object. This is a quick and dirty way to mock out a web context that can access the Request, Response, Form, and Cookies objects. They essentially become Dictionary objects for which you can stuff values in the same way normally would for a Dictionary. Those values will be there when you run your unit tests.
public class ContextMocks {
 public Moq.Mock<HttpContextBase> HttpContext { get; private set; }
 public Moq.Mock<HttpRequestBase> Request { get; private set; }
 public Moq.Mock<HttpResponseBase> Response { get; private set; }
 public RouteData RouteData { get; private set; }

 public ContextMocks(Controller onController) {
  // Define all the common context objects, plus relationships between them
  HttpContext = new Moq.Mock<HttpContextBase>();
  Request = new Moq.Mock<HttpRequestBase>();
  Response = new Moq.Mock<HttpResponseBase>();
  
  HttpContext.Setup(x => x.Request).Returns(Request.Object);
  HttpContext.Setup(x => x.Response).Returns(Response.Object);
  HttpContext.Setup(x => x.Session).Returns(new FakeSessionState());
  Request.Setup(x => x.Cookies).Returns(new HttpCookieCollection());
  Response.Setup(x => x.Cookies).Returns(new HttpCookieCollection());
  Request.Setup(x => x.QueryString).Returns(new NameValueCollection());
  Request.Setup(x => x.Form).Returns(new NameValueCollection());
  
  // Apply the mock context to the supplied controller instance
  RequestContext rc = new RequestContext(HttpContext.Object, new RouteData());
  onController.ControllerContext = new ControllerContext(rc, onController);
 }
 
 // Use a fake HttpSessionStateBase, because it's hard to mock it with Moq
 private class FakeSessionState : HttpSessionStateBase {
  Dictionary<string, object> items = new Dictionary<string, object>();
  public override object this[string name] {
   get { return items.ContainsKey(name) ? items[name] : null; }
   set { items[name] = value; }
  }
 }
}

Tuesday, October 4, 2011

Dynamic expression for LINQ

Here is a class I wrote a while ago for building dynamic lambda expression to be used against a LINQ to SQL data context. Yes, it's a giant beast that shows I didn't have any refactoring skills at some point in time, but the intent of the class is good and will hopefully help out someone.
using System;
using System.Linq.Expressions;

namespace DataAccess.DomainModel.Entities.BaseEntities
{
    public abstract class BaseSearchClass<T>
    {
        #region Variables

        private SearchClauseSeparator _clauseSeparator = SearchClauseSeparator.Or;

        #endregion

        #region Properties

        public SearchClauseSeparator ClauseSeparator
        {
            get { return _clauseSeparator; }
            set { _clauseSeparator = value; }
        }

        #endregion

        #region Expression Building Methods

        public virtual Expression<Func<T, bool>> BuildExpression()
        {
            // Create return object
            var param = Expression.Parameter(typeof(T), "x");
            Expression workingExpression = null;

            // Loop through all properties
            foreach (var property in this.GetType().GetProperties())
            {
                // Skip if missing SearchProperty attribute
                var attrs = property.GetCustomAttributes(typeof(SearchableProperty), false);
                if (attrs == null || attrs.Length == 0) continue;

                // Get the attribute properties
                var attr = attrs[0] as SearchableProperty;
                var searchOperation = attr.SearchOperation;
                var dataFieldName = attr.DataFieldName;
                if (string.IsNullOrEmpty(dataFieldName)) dataFieldName = property.Name;
                var prependOperator = attr.PrependOperator;
                var expressionBuildingDelegate = attr.ExpressionBuildingDelegate;

                // Get the value
                var value = property.GetValue(this, null);
                if (value == null) continue;

                // Build the expression
                var exp = GenerateExpressionForProperty(param, searchOperation, dataFieldName, value, expressionBuildingDelegate);
                if (exp == null) continue;

                // Combine expressions accordingly
                if ((_clauseSeparator == SearchClauseSeparator.Or && prependOperator == SearchClauseSeparator.None) || prependOperator == SearchClauseSeparator.Or)
                {
                    workingExpression = OrCombineExpressions(workingExpression, exp);
                }
                else
                {
                    workingExpression = AndCombineExpressions(workingExpression, exp);
                }
            }

            // See if expression is null
            if (workingExpression == null)
            {
                workingExpression = CreateDefaultExpression(param);
            }

            // Return the lambda of the expression
            return Expression.Lambda<Func<T, bool>>(workingExpression, param);
        }

        private Expression GenerateExpressionForProperty(Expression parameter, SearchOperation searchOperation,
            string propertyName, object value, ExpressionDelegate expressionDelegate)
        {
            // Stop if value is null
            if (value == null) return null;

            // See if field is nullable
            var propertyType = typeof(T).GetProperty(propertyName).PropertyType;
            var isNullable = propertyType.Name.StartsWith("Nullable");

            // See which operation to perform
            var operation = expressionDelegate;
            if (expressionDelegate == null) operation = DetermineOperator(searchOperation);

            // See if value is an array
            if (value.GetType().IsArray)
            {
                Expression returnExpression = null;
                var theArray = value as Array;
                foreach (var item in theArray)
                {
                    returnExpression =
                        OrCombineExpressions(returnExpression,
                                             BuildSingleExpression(parameter, propertyName, propertyType,
                                                                   item, operation, isNullable));
                }
                return returnExpression;
            }
            
            // See if value is a DualValuedObject (for performing BETWEEN operations)
            if (value is DualValuedObject)
            {
                // Stop if either value is null
                var dvo = value as DualValuedObject;
                if (dvo.Value1 == null || dvo.Value2 == null) return null;

                // Build left side
                var left = BuildSingleExpression(parameter, propertyName, propertyType,
                    dvo.Value1, Expression.GreaterThanOrEqual, isNullable);

                // Build right side
                var right = BuildSingleExpression(parameter, propertyName, propertyType,
                    dvo.Value2, Expression.LessThanOrEqual, isNullable);
                
                // Combine them using AND
                return AndCombineExpressions(left, right);
            }

            // Return a single expression
            return BuildSingleExpression(parameter, propertyName, propertyType, value, operation, isNullable);
        }

        private Expression BuildSingleExpression(Expression parameter, string propertyName, Type propertyType,
            object value, ExpressionDelegate delegateFunction, bool isNullable)
        {
            // Throw exception if property and value or not of the same type
            if (!propertyType.ToString().Contains(value.GetType().ToString()))
            {
                throw new Exception(propertyName + " is a " + propertyType.ToString() +
                    ", invalid attempt to compare to a " + value.GetType().ToString());
            }

            // Create the left and right hands of the expression
            var left = Expression.Property(parameter, propertyName);
            if (isNullable) left = Expression.Property(left, "Value");
            var right = Expression.Constant(value);

            // Combine using the specified operation
            return delegateFunction(left, right);
        }

        private Expression OrCombineExpressions(Expression left, Expression right)
        {
            return (left == null) ? right : Expression.Or(left, right);
        }

        private Expression AndCombineExpressions(Expression left, Expression right)
        {
            return (left == null) ? right : Expression.And(left, right);
        }

        private Expression CreateDefaultExpression(Expression parameter)
        {
            return BuildSingleExpression(parameter, "ID", typeof(int), 0, Expression.GreaterThan, false);
        }

        #endregion

        #region SearchOperation Methods

        private ExpressionDelegate DetermineOperator(SearchOperation type)
        {
            switch (type)
            {
                case SearchOperation.GreaterThanOrEqualTo :
                    return Expression.GreaterThanOrEqual;
                case SearchOperation.GreaterThan :
                    return Expression.GreaterThan;
                case SearchOperation.LessThanOrEqualTo :
                    return Expression.LessThanOrEqual;
                case SearchOperation.LessThan :
                    return Expression.LessThan;
                case SearchOperation.Contains :
                    return Contains;
                case SearchOperation.StartsWith :
                    return StartsWith;
                case SearchOperation.EndsWith :
                    return EndsWith;
                case SearchOperation.Equal :
                default:
                    return Expression.Equal;
            }
        }

        private static Expression CustomStringEvaluator(string stringEvaluator, Expression property, ConstantExpression value)
        {
            var method = typeof(string).GetMethod(stringEvaluator, new[] { typeof(string) });
            return Expression.Call(property, method, value);
        }

        private static Expression Contains(Expression property, ConstantExpression value)
        {
            return CustomStringEvaluator("Contains", property, value);
        }

        private static Expression StartsWith(Expression property, ConstantExpression value)
        {
            return CustomStringEvaluator("StartsWith", property, value);
        }

        private static Expression EndsWith(Expression property, ConstantExpression value)
        {
            return CustomStringEvaluator("EndsWith", property, value);
        }

        #endregion
    }
}

BitBucket now supports Git

Just found out this great piece of news. Now, I only need to master Git. I must say though that in the limited time I used Mercurial, it seemed very natural and similar to using Git. Hopefully I can find something similar to TortoiseHg for Git.

Saturday, October 1, 2011

Autofac and the Generic Repository Pattern

The Generic repository pattern is useful when you want to quickly get a site persisting its data elements without a lot of customization. Here is how I use the Generic Repository pattern (using MongoDB) with Dependency Injection (via Autofac).
builder.RegisterGeneric(typeof(MongoRepository<>))
    .WithParameter(new NamedParameter("connectionString", connectionString))
    .As(typeof(IRepository<>));