Brothers In Code

...a serious misallocation of .net resources

I Love Visual Studio's Build Events!

I've been using Visual Studio for more than 10 years, yet I've only discovered build events in the last year.  I really don't know how I survived with out them.

The big push for me was SharePoint.  There's a lot of things to do after you build a project: register a dll, run some stsadm.exe commands, copy some files to the 12 hive, etc.  Doing all this manually started to drive me nuts. 

But build events saved me.  Basically if you can execute your task from the command line, then it can be a build event.

A simpler example involves config files.  In a multi-project solution, I often need to keep multiple copies of a config file - say a dll is used by both a web app and a unit test project.  Keeping these in sync can be frustrating - all of a sudden your unit tests start blowing up because you only changed an expired connection string in the web app and not in the unit test.  I wrote a simple build event to copy the config files from the main project.  I even appended a little note that it was copied by the build event so I remember to edit the main file and not the copy.

There's pre and post-build events and there's lots of "macro" variables that'll keep your build events friendly over multiple developers or PCs.  You'll find the build events tab by right clicking a project file and selecting properties.

B

SQL Plus vs. PL/SQL and binding variables between the two.

I had a lightbulb moment yesterday.  My new employer is mostly an oracle shop so I end up spending a lot of time translating what I know about sql server into oracle terms.  But one thing I've struggled with is SQL Plus vs. PL/SQL.  That is until yesterday.   Maybe I never took the time before but a sequence of searches forced me in the right direction.

I'm using very few stored proceedures lately (reasons for which will come in a different post).  Consequently I was looking for ways to execute a batch of statements .net code with the Oracle Data Provider and found my answer here on OTN.  But then i looked at how he was getting variable data out of the command.  He was basically doing what I've always wanted to do with Oracle's SQL Developer.  When using the Sql Server query tools (query analyzer, SSMS), I'd often write myself maintenance procedures that I just kept in a file.  It's no problem to create variables and run sql statements in the exact same way you would from inside of a stored procedure.  Sometimes I could copy nearly the same code into a SqlCommand and it would run just fine.  Oracle isn't like that.  Variables (pl/sql variables at least) must be declared within the 'declare' section of a begin/end block.  These blocks can be 'anonymous' (not in a stored procedure) but once you enter the block things change.  You can't simply do a 'select column from table' for example or you get an 'INTO clause expected' error.  Oracle assumes that you're now in a programming block and not connected to some user interface so it wants you to store the data in some variable.  But how was this .net code getting this v_maxnum variable out?  On some sort of protocol level there must be a way for a human to do the exact same thing.

Finally thanks to Wikipedia, I got it.  SQL Plus is very similar to the combination of cmd.exe and SqlCmd/isql?  The big difference is that line between sqlcmd and t-sql is blurred a little more blurred than it is with SQL Plus and pl/sql.  But once I dug in to sqlcmd a little I realized that other than begin/end blocks it's really not that different.  I guess I really never used sqlcmd for anything but a single statement from the command line.

The big realization came now when I understood the variable types in SQL Plus.  It has both substitution variables (&var and &&var) and regular variables (var myvar varchar2).  But unlike sqlcmd's variables being t-sql variables, SQL Plus's variables are different than PL/SQL variables.  However, PL/SQL can 'bind' SQL Plus variables.  Take the following example.

var myDate varchar2;
begin
  select sysdate into :myDate from dual;
end;
/
print myDate

Now I finally understood what the data provider was doing and consequently I understood SQL Plus a lot better too.

Simple Custom Configuration

A lot of these posts are merely for my own quick reference.  The upside of that is that you'll get a taste for the way I actually do something rather than just a rehash of a reference page.

For simpler projects I just create a class with some static properties that just pull from AppConfig variables.  At least from there I have intellisense to help me remember all of my configuration variables.  But the appSettings section app.config or web.config can get messy pretty fast so creating a custom section isn't that much work to clean it up.

First I'll create a ConfigurationSections folder (which creates an automatic namespace) and an AppConfig class:

 

The GeneralConfigurationSectionClass looks like this:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration;

namespace MyCust.MyProj.ConfigurationSections
{
  public class GeneralConfigurationSection : ConfigurationSection
  {
    [ConfigurationProperty("TestKey")]
    public String TestKey
    {
      get { return (String)this["TestKey"]; }
      set { this["TestKey"] = value; }
    }

    [ConfigurationProperty("ConnectionString")]
    public String ConnectionString
    {
      get { return (String)this["ConnectionString"]; }
      set { this["ConnectionString"] = value; }
    }
  }
}

 

Then I'll create a property that pulls the config data and returns this class in the AppConfig.cs

  public class AppConfig
  {
    public static GeneralConfigurationSection General
    {
      get
      {
        return (GeneralConfigurationSection)ConfigurationManager.GetSection("MyCust.MyProj/General");
      }
    }

  }

And last add the new section to the app/web.config.  First add the section group:

<configSections>
  <sectionGroup name="MyCust.MyProj.WebServices">
    <section name="General" type="MyCust.MyProj.WebServices.ConfigurationSections.GeneralConfigurationSection, MyCust.MyProj.WebServices" allowLocation="true" allowDefinition="Everywhere"/>
  </sectionGroup>
</configSections>

And then add the section itself into the configuration element:

<MyCust.MyProj.WebServices>
  <General
    TestKey="32AAAC4-8DB2-4059-852A-73BBBBBB9698"
    ConnectionString="Data Source=SqlServer;User Id=sa_app;Password=pwd;"
  />
</MyCust.MyProj.WebServices>

Usage is then a nice and clean line:

AppConfig.General.ConnectionString

B