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.