Thursday, April 23, 2015

C# Tuples

Tuples in C# provide a way for "one" object to have multiple types and values.  I use this a lot when I'm returning results from one method to another so I can check whether the call was successful (with a bool) and also return a value (like an error message) to the caller.

You use Tuples by specifying - through the use of generic type parameters - what the data types will be of each "item" in the tuple.  Each tuple can have seven items, and an eighth item that is another tuple.

In our home-grown ORM solution I've implemented tuples as the return type of the methods that map data from the database to the objects:



   1:  Tuple<TParent, TChild1, TChild2, TChild3, TChild4, TChild5, TChild6> Get
   2:              <TParent, TChild1, TChild2, TChild3, TChild4, TChild5, TChild6>(string sprocName,
   3:                                                                              List<SqlParameter> parameters = null,
   4:                                                                              string schema = "dbo",
   5:                                                                              CommandType commandType =
   6:                                                                                  CommandType.StoredProcedure)
   7:              where TParent : class
   8:              where TChild1 : class
   9:              where TChild2 : class
  10:              where TChild3 : class
  11:              where TChild4 : class
  12:              where TChild5 : class
  13:              where TChild6 : class;

This method will return a single object with a total of 7 items where there is one parent object that has six properties that are each a complex object.  When I invoke this method, I do so like this:



   1:  var data = Get<Person, List<Pet>, List<Car>, Person, List<Person>, House, Employer>("Person_GetDetails", new List<SqlParameter> {new SqlParameter("@ID", 12345)});
   2:   
   3:  var person = data.Item1;
   4:  person.Pets = data.Item2;
   5:  person.Cars = data.Item3;
   6:  person.Spouse = data.Item4;
   7:  person.House = data.Item5;
   8:  person.Employer = data.Item6;

This way I can pass back a single Person object from my repository method.  There are, of course, other uses, but this is a quick example of how to use tuples.

JavaScript Object.keys

JavaScript has a useful little function called Object.keys(object) where you pass an object and get the "keys" (properties) of that object.  Once you have those, you can enumerate the values of those keys on the object you want.  Check it out:

function ListKeyValues(input) {
    var keys = Object.keys(input);
    
    for(var i = keys.length; --i >= 0;){
        console.log(input[keys[i]]);
    }
}

This is obviously a contrived example, but here's the usage:


ListKeyValues({Name: "John Doe", Age: 32});

Generic Type Parameters in C#

Generic type parameters are used all over the place in built-in constructs in C#, such as
   1:  IEnumerable<T>
and
   1:  List<T>
which you've probably used before.

But you can create your own methods to use generic type parameters, too.  You may be asking why you'd want to do this.  Well, the short answer is compile-time support for methods that return an instance of an object only known at runtime.  That's one reason anyway, and it's the reason I'll demonstrate here.

Let's say you have two classes:

   1:  public class ClassOne
   2:  {
   3:      public string FirstName { get; set; }
   4:  }
   5:   
   6:  public class ClassTwo
   7:  {
   8:      public int Id { get; set; }
   9:  }

And a method that can return an instance of either class:

   1:  public ClassOne | ClassTwo BuildAnObject()
   2:  {
   3:  }

(Hint: that won't compile)

So if you know that your method will return one or the other, you could write two separate methods, taking the exact same parameters, but returning a different type.  That would technically work (if you named the methods differently anyway), but it's kind of a pain in the butt.  Instead, you can change your method signature to use generic type parameters to specify the return type when you call the method:


   1:  public T BuildAnObject<T>()
   2:  {
   3:      return default(T);
   4:  }

At this point, "T" represents whatever you want it to represent.  This way, if you created a third class you could use the exact same method by specifying ClassThree as T when you make the call:

   1:  public void BuildIt()
   2:  {
   3:      var result = BuildAnObject<ClassOne>();
   4:   
   5:      var firstName = result.FirstName;
   6:  }

Right there you can see we have compile-time support for result.

Friday, April 17, 2015

Web API UrlHelper (DefaultApi)

I wrote a helper to get the location to return in the Location header of an Add/Create request.  At first I wrote this (because I found it on the Internet so it has to be true, right?):

   1:  var urlHelper = new UrlHelper(request);
   2:  var uri = urlHelper.Route("DefaultApi", new { id });
   3:  return uri != null ? new Uri(uri, UriKind.Relative) : null;

The problem with that was that my Location header was being returned with the Add endpoint, which is obviously not right:

Location: /api/grade/add/1

To fix this, I created a new route in the WebApiConfig and then switched one line of code to use the new route:


   1:  config.Routes.MapHttpRoute(
   2:      name: "GetApi",
   3:      routeTemplate: "api/{controller}/get/{id}",
   4:      defaults: new { action = "Get", id = RouteParameter.Optional }
   5:  );


   1:  var urlHelper = new UrlHelper(request);
   2:  var uri = urlHelper.Route("GetApi", new { id });
   3:  return uri != null ? new Uri(uri, UriKind.Relative) : null;

That does it.  Now my header is right:

Location: /api/grade/get/1

Monday, April 6, 2015

ng-if or ng-show

I just came across something that I figured out quickly enough, but really threw me off for a few minutes.

In Angular, I know that ng-if and ng-show aren't interchangeable, but in most situations they seem to be pretty interchangeable and I don't know the differences between them - other than ng-if doesn't render things if the "if" condition isn't met.

I have a table that shows/hides a <th> and a corresponding <td> based on an ng-if.  That was all working fine until I needed to change the <tr> inside of which the <td> exists to also rely on (a differnet) ng-if.  Once I added that, I found that the condition on which the <td> relied wasn't updating when the underlying model value was being changed, but only in the header evaluation.  That meant the <th> was staying put while the <td> was toggling, which caused me a bit of confusion.

A coworker just stopped by to tell me it has to do with the fact that ng-if creates a new scope and ng-show doesn't, but we both agree that this still seems like a weird scenario.  An example is below.


This doesn't work:
<table>
    <tr>
        <th ng-show="OptionA == true">Column 1 Header</th>
        <th ng-show="OptionA == false">Column 2 Header</th>
        <th>Column 3 Header</th>
    </tr>
    <tr ng-if="OptionB == true">
        <td ng-show="OptionA == true">Column 1 Row 1 Data</td>
        <td ng-show="OptionA == false">Column 2 Row 1 Data</td>
        <td>Column 3 Row 1 Data</td>
    </tr>
    <tr ng-if="OptionB == false">
        <td colspan="3">Row 2 Merged Data</td>
    </tr>
</table>


But this does:
<table>
    <tr>
        <th ng-show="OptionA == true">Column 1 Header</th>
        <th ng-show="OptionA == false">Column 2 Header</th>
        <th>Column 3 Header</th>
    </tr>
    <tr ng-show="OptionB == true">
        <td ng-show="OptionA == true">Column 1 Row 1 Data</td>
        <td ng-show="OptionA == false">Column 2 Row 1 Data</td>
        <td>Column 3 Row 1 Data</td>
    </tr>
    <tr ng-show="OptionB == false">
        <td colspan="3">Row 2 Merged Data</td>
    </tr>
</table>


Friday, March 27, 2015

Angular Scopes and Factories

If you checked out my last post you know I needed to open a jQuery UI dialog from Angular.  This ultimately led me down a long and winding path to Angular factories and creating my own scope.

First the problem, in full detail.  I needed a link that would open a jQuery UI dialog to a form that needed rich controls (show/hide based on data and whatnot).  We'll call that dialog Details.  The Details dialog has a button that opens a History Summary dialog, which also needed rich controls.  One of the rich controls was a link that would open a History Details dialog.  The History Details dialog would look and behave exactly the same as the Details dialog except that the History Details dialog would not have the button that opens a History Summary.  So.  Link A opens Dialog 1, which opens Dialog 2, which has Link B, which opens Dialog 3, which is exactly like Dialog 1.

All of that convolutedness (yes, it's a word, or it is now anyway) had me really scratching my head over how to deal with all the scopes I was creating, not to mention all the new DOM elements I was creating.  I ended up writing a Directive (for the link), a Controller (for the rich controls on the Details and History Summary dialogs), a Service (to retrieve the markup to render, and the data to populate), and a Factory (to handle the scopes and actually opening the dialogs).  Yup, I'm pretty awesome.

First, the Directive:
myApp.directive('dialogLink', ['dialogFactory',
        function (dialogFactory) {
            return {
                // restrict this directive to be used as an element only
                restrict: 'E',
                require: '?ngModel',
                scope: {
                    "ngModel": "="
                },
                link: function (scope, element, attr) {
                    // watch the attribute so that once it populates, we render the value to the screen
                    scope.$watch(function () { return attr.displayValue; }, function (value) {
                        // only render the value if it's an actual value
                        if (value != undefined) {
                            scope.DisplayValue = value;
                        }
                    });
                    // bind the click event to open the dialog
                    element.bind("click", function (e) {
                        dialogFactory.open(attr);
                        
                        e.preventDefault();
                        e.stopPropagation();
                    });
                },
                template: "<a href='#'>{{DisplayValue}}</a>"
            };
        }
  ]
);

Use it like this:
<dialog-link display-value="{{SomeProperty}}"></dialog-link>

Now the Controller:
myApp.controller('dialogController', ['$scope', '$compile', 'dialogService', 'dialogFactory',
        function ($scope, $compile, dialogService, dialogFactory) {
            var historySummaryDialog;

            $scope.CloseHistorySummaryDialog = function() {
                historySummaryDialog.dialog('close');
            };

            $scope.CloseDialog = function () {
                dialogFactory.close($scope);
            };
            
            $scope.Initialize = function () {
                // get the detail data
                dialogService.getDetailData().then(function (data) {
                    $scope.Data = data;
                });
            };
            
            $scope.ShowHistorySummary = function () {
                var historyTitle = "History Summary Dialog";                
                dialogService.getHistorySummaryMarkup().then(function (markup) {
                    // compiles the current scope into the history summary dialog so the current scope ($scope) is used for the history summary dialog as well as the current dialog
                    historySummaryDialog = $compile(markup)($scope);
                    historySummaryDialog.dialog({
                        open: function() {
                            $(this).css({ 'max-height': dialogService.MaxDialogHeight, 'overflow-y': 'auto' });
                        },
                        width: dialogService.DialogWidth,
                        maxWidth: 1000,
                        height: 'auto',
                        fluid: true,
                        title: historyTitle,
                        modal: true,
                        closeOnEscape: true
                    });
                });
            };

            if (!$scope.PreventInit) {
                $scope.Initialize();
            }
        }
    ]
);

And the Service:
myApp.service('dialogService', ['$http', '$q', '$rootScope',
        function ($http, $q, $rootScope) {
            this.DialogWidth = $(window).width() * .8;
            this.MaxDialogHeight = $(window).height() * .8;
            
            this.getDetailData = function () {
                var deferred = $q.defer();

                $http({
                    url: "/GetDetailData",
                    method: "GET"
                })
                    .success(deferred.resolve)
                    .error(deferred.reject);

                return deferred.promise;
            };
            
            this.getDetailMarkup = function () {
                var deferred = $q.defer();

                $http({
                    url: "/Pages/Dialog/Detail.html",
                    method: "GET",
                    cache: true
                })
                    .success(deferred.resolve)
                    .error(deferred.reject);

                return deferred.promise;
            };
            
            this.getHistoricDetailData = function () {
                var deferred = $q.defer();

                $http({
                    url: "/GetHistoricDetailsData",
                    method: "GET"
                })
                    .success(deferred.resolve)
                    .error(deferred.reject);

                return deferred.promise;
            };
            
            this.getHistorySummaryMarkup = function () {
                var deferred = $q.defer();

                $http({
                    url: "/Pages/Dialog/HistorySummary.html",
                    method: "GET",
                    cache: true
                })
                    .success(deferred.resolve)
                    .error(deferred.reject);

                return deferred.promise;
            };
        }
    ]
);

And finally, the pièce de résistance, the Factory:
myApp.factory('dialogFactory', ['dialogService', '$compile', '$rootScope', '$controller', 
        function (dialogService, $compile, $rootScope, $controller) {
            return {
                open: function (attr) {
                    dialogService.getDetailMarkup().then(function (markup) {
                        var title;
                        // create a new scope manually (instead of allowing the ng-controller directive in the markup do it
                        var scope = $rootScope.$new();
                        // prevent the data from being retrieved twice
                        scope.PreventInit = true;

                        var dataPromise;
                        
                        if (attr.getHistory == undefined) {
                            dataPromise = dialogService.getDetailData();
                            title = "Details";
                        } else {
                            dataPromise = dialogService.getHistoricDetailData();
                            title = "History Details";
                        }
                        
                        dataPromise.then(function (data) {
                            scope.Data = data;

                            // instantiate a new instance of the controller
                            var controller = $controller('dialogController', { $scope: scope });
                            // bind the controller to the markup
                            $(markup).children().data('$ngControllerController', controller);
                            // compile the new scope against the markup
                            scope.Dialog = $compile(markup)(scope);
              
                            scope.Dialog.dialog({
                              width: dialogService.DialogWidth,
                              maxWidth: 1000,
                              height: 'auto',
                              fluid: true,
                              title: title,
                              modal: true,
                              closeOnEscape: true
                            });                            
                        });
                    });
                },
                close: function (scope) {
                    // destroy the jQuery UI dialog
                    scope.Dialog.dialog('destroy');
                    // remove the dynamically injected DOM element
                    $('[ng-controller="dialogController"]').each(function (index) {
                        var element = $('[ng-controller="dialogController"]')[index];
                        if (element != null && angular.element(element) != null && angular.element(element).scope().$id == scope.$id) {
                            element.remove();
                        }
                    });
                    // destroy the scope
                    scope.$destroy();
                }
            };
        }
    ]
);

There's so much fun going on here that I'm probably going to explain it all in another (or several) posts. I also forgot to mention earlier that the contents of the Details Dialog (aka Dialog 1) also have to be available outside of a dialog. That's where the Initialize function and PreventInit property come in to play. By specifying PreventInit when I create the scope myself in the factory, I can stop the data from being loaded during the Initialize function. But when the markup includes the ng-controller directive to create a new scope (for the standalone implementation of the Details Dialog) that property isn't set so the Initialize function gets called and data is retrieved. I'm very pleased with myself for figuring this one out. And it only took me a full day!

Debug Test

I upgraded to Visual Studio 2012 Ultimate a few weeks ago so I could generate a couple of UML diagrams from the code I had already written (yes, I know that's a backward process, leave me alone).  Anyway, after I upgraded I found that I couldn't build my solution anymore because of the test projects I had.  Everything worked fine before I upgrade, then didn't work fine after I upgraded.

It turns out the fix was pretty simple.  I found it here, and reproduced the answer in my blog in case for some reason Stack loses the answer.

"I was getting the same output after upgrading a test project from VS 2010 to VS 2012 Ultimate Update 3. The message was displayed in Test Output window after using MSTest command to Debug Selected Tests.
I tried to debug tests using Resharper 8 Unit Test Session window. The message in the result window was "Test wasn't run".
The solution that helped me was to modify the test project settings to enable native code debugging as instructed at this link: Uncaught exception thrown by method called through reflection
In case the link does not work:
  1. Go to the project right click and select properties.
  2. Select 'Debug' tab on the left.
  3. Go to ‘Enable Debuggers’ on the bottom
  4. Check ‘Enable Native code debugging’ (or 'Enable unmanaged code debugging', depends on version) check box
Thanks to GalDude33 for posting the solution."
And the answer I just copy/pasted was posted by Branko on October 3, 2013.