Saturday, January 31, 2015

Visual Studio Add-Ins

On my current project we have an n-tier solution that combines Angular JS, MVC for ASP.NET, and Web API.  When you want to create a "full stack" (all the way from the Angular files to the data access layer) you have to create 10 separate files.  Because of the naming conventions we use, we end up naming the files very similarly (e.g. SomeController, SomeBusiness, SomeDataAcess).  My boss tasked me with coming up with a way for the development team to create a full stack with as few steps as possible.  I ended up creating an add-in for Visual Studio that accepts a namespace and a root name ("Some" in the previous example) along with a few boolean options.  When you press the button, 10 custom templates are imported and modified to match the naming conventions.

This process will significantly decrease development time and coding errors.  Since we use Unity for IoC and DI, the add-in also registers each interface created with its respective concrete class.  We've effectively been able to eliminate the "class does not have a default constructor" error, which was a huge bonus.

It turns out creating an add-in is pretty easy, but getting it to do anything complex is a bit trickier.  Below are some pointers on creating an add-in so hopefully I don't make the same mistakes next time.


   1:  (Solution2)_applicationObject.Solution 

That little guy right there will get you the Solution (which seems a bit obvious now).


   1:  private IEnumerable<Project> GetProjects(List<string> projectNames)
   2:          {
   3:              var projects = new List<Project>();
   4:   
   5:              // get the projects from the root (solution) object
   6:              var solutionProjects = _applicationObject.Solution.Projects;
   7:   
   8:              // get the enumerator from the projects from the root (solution) object
   9:              var enumerator = solutionProjects.GetEnumerator();
  10:              // iterate the projects
  11:              while (enumerator.MoveNext())
  12:              {
  13:                  var project = (Project)enumerator.Current;
  14:   
  15:                  if (project == null)
  16:                  {
  17:                      continue;
  18:                  }
  19:   
  20:                  // check whether the project is a solution folder
  21:                  if (project.Kind == ProjectKinds.vsProjectKindSolutionFolder)
  22:                  {
  23:                      // if the project is a solution folder, get the projects from the solution folder
  24:                      projects.AddRange(GetSolutionFolderProjects(project, projectNames));
  25:                  }
  26:                  else if (projectNames.Contains(project.Name))
  27:                  {
  28:                      // if the project isn't a solution folder, add it to the results
  29:                      projects.Add(project);
  30:                  }
  31:              }
  32:   
  33:              return projects;
  34:          }

That beauty will get the projects at the root of the solution.  You'll notice on line 24 I'm calling another method named GetSolutionFolderProjects.  That's used in case your solution uses solution folder for easier visible navigation (like ours does).  Here's that method:


   1:  private IEnumerable<Project> GetSolutionFolderProjects(Project solutionFolder, List<string> projectNames)
   2:          {
   3:              var list = new List<Project>();
   4:   
   5:              // iterate the project items in the solution folder (each project item should either be another solution folder or a project
   6:              for (var i = 1; i <= solutionFolder.ProjectItems.Count; i++)
   7:              {
   8:                  var subProject = solutionFolder.ProjectItems.Item(i).SubProject;
   9:                  if (subProject == null)
  10:                  {
  11:                      continue;
  12:                  }
  13:   
  14:                  // check whether the project is a solution folder
  15:                  if (subProject.Kind == ProjectKinds.vsProjectKindSolutionFolder)
  16:                  {
  17:                      // if the project is a solution folder, get the projects from the solution folder
  18:                      list.AddRange(GetSolutionFolderProjects(subProject, projectNames));
  19:                  }
  20:                  else if (projectNames.Contains(subProject.Name))
  21:                  {
  22:                      // if the project isn't a solution folder, add it to the results
  23:                      list.Add(subProject);
  24:                  }
  25:              }
  26:   
  27:              return list;
  28:          }

You'll notice on line 18 I'm calling another method named GetSolutionFolderProjects... that's a little recursion joke.  If you didn't get it, remember this: in order to understand recursion, you must first understand recursion.

I'm going to post more about this later, but I've been meaning to write this post for over a month and just haven't made the time.  This is a start.

Friday, January 30, 2015

C# Reference Value

I often run into situations in C# where my variables don't behave as I expect them to.  For example, I pass an instance of a custom object into another method and the attributes of that instance are changed even though I didn't specify the ref keyword.  That's because C# has value and reference types and which one you get depends on what you're declaring.  This also affects where the memory is stored (the two concepts are tied together to a degree).

In short, when you're using an instance of a custom object, your resulting variable will be a reference type.  Every time.  I know this article is a bit outdated, but it explained it very clearly to me (for the first time) so I'm passing it along (and remember, this blog is all about keeping track of my own answers).

Tuesday, January 13, 2015

RDP With Multiple Monitors

I love working from home, but I hate that I lose my dual monitors when I have to remotely access my work computer.  Apparently, you can totally do that with Windows 7 and I just gave up after being unable to do it with Windows XP.  If you need to remotely access another computer and you want that RDP session to span multiple monitors (I only have two, so I'm not sure whether this works with more than two) you can launch the RDP application with the /span switch, like this: mstsc /span.

Thursday, January 8, 2015

Code Comments

I came across an old email from a coworker wherein he described his preference for commenting code.  To paraphrase: "Comments should explain why you did something, not how you did it.  If they want to know how you did it, they'll just look at your code."

That sums it up nicely.  If you're one of the many, many, many, many, many, many developers who thinks commenting code is pointless, consider that nugget next time and see if it helps.

Thursday, December 11, 2014

Entity-ORM Hybrid

Sometimes you end up working on a project that shifts away from Entity Framework in favor of something else, ADO.NET, Linq to Sql, an available ORM, or maybe even a homegrown ORM.  That's what happened at one client I've worked with.  There were a few reasons to move away from EF, mostly based on misunderstandings, database design, and lack of knowledge of the product.  But there are still some things EF does better than some other methods.  Instead of writing a new stored procedure in SQL Server every time we need to update one field, we set out to use the features of EF to make that happen a little more easily.  After all, isn't it better when you can pass two variables to your repository and just wait for the true/false response?  That's right, it is better.

Here's the code:

   1:  public bool Save<T>(T domainModel, string idFieldName) where T : class
   2:          {
   3:              var type = typeof(T);
   4:              var idProperty = type.GetProperty(idFieldName);
   5:              var domainModelIdValue = (int)idProperty.GetValue(domainModel, null);
   6:   
   7:              var match =
   8:                  Context.Set<T>().Where(PropertyEquals<T, int>(idProperty, domainModelIdValue)).ToList();
   9:   
  10:              // if there's more than one record with a matching ID field (which shouldn't be possible as long as our field is specified correctly) we can't do this update
  11:              // also, if there's no match from the database on the ID field, we can't do this update
  12:              if (!match.Any() || match.Count() > 1)
  13:              {
  14:                  return false;
  15:              }
  16:   
  17:              var firstMatch = match.First();
  18:   
  19:              // set all properties from the domain model passed to the match found in the database
  20:              Context.Entry(firstMatch).CurrentValues.SetValues(domainModel);
  21:   
  22:              var numberOfObjectsWrittenToUnderlyingDatabase = Context.SaveChanges();
  23:   
  24:              return numberOfObjectsWrittenToUnderlyingDatabase == 1;
  25:          }
  26:   
  27:          public Expression<Func<TItem, bool>> PropertyEquals<TItem, TValue>(PropertyInfo property, TValue value)
  28:          {
  29:              var param = Expression.Parameter(typeof(TItem));
  30:              var expressionProperty = Expression.Property(param, property);
  31:   
  32:              BinaryExpression body;
  33:              if (Nullable.GetUnderlyingType(expressionProperty.Type) != null)
  34:              {
  35:                  var comparisonValue = Expression.Convert(Expression.Constant(value), typeof(int?));
  36:                  body = Expression.Equal(expressionProperty, comparisonValue);
  37:              }
  38:              else
  39:              {
  40:                  body = Expression.Equal(Expression.Property(param, property), Expression.Constant(value));
  41:              }
  42:   
  43:              return Expression.Lambda<Func<TItem, bool>>(body, param);
  44:          }

Tuesday, December 2, 2014

Angular ng-include

If you need to bring one HTML file into another using Angular, you may want to take advantage of the ng-include directive (documentation can be found here).  Using ng-include will bring in the specified HTML file.

<div ng-include="'/Pages/SomeApp/Ordering.html'">

Be careful, though!  I ran into a problem with this directive that was driving me crazy.  I had used ng-include in a file that also had an ng-include in it and it caused me no small headache.  Others have done the nested ng-include so it may have just been my specific usage that was causing problems, but it's worth noting.

In case you're seeing something similar, I was forced to use IE 8 (you can peruse my hatred of that browser in other posts) and whenever the ng-hide class was applied, the entire screen went blank.  The DOM was technically still there, but you couldn't see anything.  Good times.  Or not.

Plain HTML as a Partial View

Sometimes you just need to include a plain HTML file in another MVC view.  It's easy enough.  Just use the code below and you should be all set.

@Html.Raw(File.ReadAllText(Server.MapPath("~/Pages/SomeApp/Ordering.html")))