The Raiser’s Edge API: VB.NET versus C#

I am sure that there are a many people out there who still use VB6 when working with The Raiser’s Edge API but it is more and more common that you need to write .NET code and indeed want to write .NET code. There are several reasons for this but for me it is simply that the Visual Studio 2008 is a thousand time better than the VB6 development environment. I cringe every time I have to go back to a piece of old code or to the VBA environment. What really interests me is the choice of VB.NET or C# for development.

I started my working career developing CAD CAM software on UNIX and later Windows with C++. I then moved on to using Java in the telecoms industry and then with the RE API I used VB6 and VBA. It therefore seemed a natural progression to work with VB.NET. Recently I have been using C#. The client I am working with also develops code and they have been using C#. I thought it would be good to get my teeth into something a bit different (although at its inception C# was almost a clone of Java so the learning curve was not that steep).

There are a number of similarities between VB.NET and C# but they reside almost exclusively around the fact that they both share The .NET Framework. This makes translating code between the two relatively simple. It is the differences that make it obvious that RE API was built with VB in mind.

1. In C# you cannot use Fields like properties with implicit get and set. Instead you have to use the newly inferred get_Field and set_Field methods for each collection

2. You cannot implicitly convert the value of the field output into a string so for example the following is possible in VB.NET:

Dim name = constit.Fields(ERECORDSFields.RECORDS_fld_FIRST_NAME)

In C# you have to write:

string name = constit.get_Fields(ERECORDSFields.RECORDS_fld_FIRST_NAME).ToString();

and even that may fail. If there is no value i.e. it is null then the ToString method will fails. So you have to convert it instead.

string name = (string)constit.get_Fields(ERECORDSFields.RECORDS_fld_FIRST_NAME);

or my preference using the null coalescing operator

string name = (constit.get_Fields(ERECORDSFields.RECORDS_fld_FIRST_NAME) ?? "").ToString();

3. There is the added confusion that there are several forms of objects you can work with in C#: e.g. CRecord, CRecordClass and _CRecord. This is to do with the way COM works and when I did a project a while back with C++ and the API I was thoroughly haunted by it at first. I now realise that COM always abstracts the actual implementation with interfaces. As Blackbaud are doing the same thing with their classes you always get these multiple possibilities. Here CRecord is the interface, CRecordClass is the implementation (where you can also find all the other interfaces implemented too e.g. IBBMetaField, IBBTopObject, etc) and _CRecord is the COM interface to CRecord. In general I use the CRecord interface for a constituent but you have to instantiate it using the CRecordClass object. There is nothing to say that you cannot simply use the CRecordClass throughout (at least I don’t think that there is) but the CRecord interface mimics the functionality as it was originally intended.

4. I discovered today that there appear to be some gaping holes in the C# interpretation of the API. I am not sure why this is the case but the CFund interface does not implement the set_Fields and get_Fields methods so you are forced to use the CFundClass.

5. There are very many areas where you have to pass parameters by reference even though there seems no reason to do so. It is quite common for me at least to forget that ref keyword before the parameter and when it says that there is no matching overloaded method I regularly miss that issue.

Don’t get me wrong I really like using C#. There are some really good features. The client that I am working with now for example had built up a framework where they have objects that inherit from common RE top level objects. In order to instantiate them you have to supply the IBBSessionContext object. (nothing that VB.net could not do of course). They also implement the IDisposable interface and call the Closedown method and all cleanup methods there. This means that you can put these objects into a using clause. After this clause the objects will closedown without the need for extra code in the methods – Very neat.

All in all though VB.NET unsurprisingly so, just gels nicer with the REAPI although as always I would love to hear your comments otherwise. Have you found any issues with C# or any benefits to using it?

9 thoughts on “The Raiser’s Edge API: VB.NET versus C#

  1. From trying a few things out I believe that that .NET classes are merely automatically generated using the tlbgen tool from the main BBREAPI7.tlb file, so if it’s not in that it won’t be in the .NET Interop.

  2. You may be right. I am not sure exactly how these things work. However CFund doesn’t seem to be any different from any other class. When you look at the tlb or look at the PIA assembly in object browser there are entries for the Fields in no way different from any of the other objects (as far as I can see that is) so I am not sure why it is missing when working with C#.

  3. I think the problem here is not C# as like you say, they both came out of .NET but the fact that C# is designed in such a way that it promotes a cleaner more standards compliant way of coding …

    For example the use of the keyword “with” has been left out of C# deliberately because it was deemed to promote poor readability in code however me being a C# programmer myself like the the idea as with any language feature i believe it may be that Microsoft decided that this was being abused thus came the reasoning for it’s being left out.

    With that said in C# 4.0 you can do this …

    Var someObject = constit.get_Fields(ERECORDSFields.RECORDS_fld_FIRST_NAME);

    Apparently the “implicit casting” is supposed to happen but this to me is muddying the nice type safe coding that C# programmers are used to and will encourage bad programming practices as it means u end up treating everyhting like some generic object but call the specific implementation methods on it … evil …

    I’ve also noticed how when you get an instance of the main API class that you can call it with “optional parameters” something that does not exist in C# so you have to figure out a way around it, it turns out you can do it with reflection but this is typical of many API providers, they only think of the language they are using and not the fact that by releasing this as a universal API others might want to use it too.

    The point is that I think VB has always been the language of choice for Blackbaud and thus everything will appear nice and fluffy in VB, the fact of the matter is that VB is just not a “clean, standards promoting language” by todays standards within the industry, C# is clearly a superior language.

    It’s a bit of a sweeping statement i know but think about the origins of VB … didn’t it used to be a “training language” back before .NET … most serious programmers moved in to the C style languages which is where I believe the profesional solutions of today should live.

    Points 4 and 5 are classic examples of this coupled with my point on simply initialising the API.

    Despite not even being thought of in the development of the API I as a C# developer have the knowledge to go round a few extra miles and get there, something that would never happen in the VB world, simply because the language allows too many short cuts.

    Or maybe i’m wrong?

  4. Something also worth noting is that the API does not typically work in a “clr compliant” fashion for example :

    // ok this seems reasonable
    CRecord aRecord = new CRecord();
    aRecord.Load(recId);
    // here we go … what the …
    aRecord.Attributes.Add();

    as a tried and tested programmer when i add something to a collection i give it the object I plan to add like this …

    aRecord.Attributes.Add(anAttribute);

    Turns out anything complex with attributes requires a whole separate server instance that you have to do everything on.

    Copying an object is another prime example …

    If i have 2 CRecord instances and i want to do something like this …

    // assume these are initialised
    CRecord rec1;
    CRecord rec2;
    // rec2 is a duplicate so i want to copy everything and delete
    rec1.Addresses += rec2.Addresses
    //BOOM !!! … no chance

    even though this object looks like and seemingly appears to be a collection it’s got literally nothing in common with a typical .NET collection object.

    The API just appears out dated to me … maybe i’m just being over critical … it is a huge lengthy code monster after all.

    But then i could ask …
    why ?
    does it need to be ?
    if it used some standards would it still be ?

    It’s interesting how technically “Blackbaud does not support anything done with the API just simply the API itself”.

    thats like saying …

    I’ll sell you this car but if you drive it you will no longer be able to get insurance on it.

    … Eh ?!?!?

  5. Thanks Paul for some really good points. I agree to an extent about C# but I would say that VB.NET was totally reworked after VB6 and while the syntax is similar in many cases the grounding of the language has changed. There is little that VB.NET can do that C# can’t and vice versa. It is much more about the .NET framework rather than specific languages.

    Specifically referring to the RE API however, I think that VB does have an easier time. RE was written in a different era. There was no such thing as .NET when probably 95% of the API was written and as such they could not have foreseen where the technology would take the industry. COM technology was the big thing of the time and as such as long as the API worked with a COM language that was fine.

    Given that, even though VB.NET was rewritten, much of the syntax remains, it is obvious that VB.NET is going to be better suited to what was primarily intended to be used with VB6. The optional parameters is a good example.

    The example of collections is an interesting case. You are right this is nothing like the .NET syntax but then why should it be. This was not written for .NET. It is closer to the VB6 Collections class but even then it is more “advanced”.

  6. David :
    I completely agree, VB does show it’s roots a little still … microsoft have made the effort to keep it VB like whilst bringing the language in to compliance with their CLR.

    It seems to me that the biggest issue with the RE API is that it is not really ready for the .NET framework as a whole whatever language you use, you have to jump through hoops to make it work the way you expect and even then it chews you up and spits you out for being a nice .NET developer simply because you talk C or some other .NET pre dated technology.

    Between you and me, the problem is that updating the API doesn’t make money, and that’s all that Blackbaud are interested in, if someone could “sell the monetary advantages of .NET” to Blackbaud they would likely jump on it in an instant !!!

    I guess the other way to look at it is that the sort of customer base they have know of no other strong competitor at the moment that can deliver this type of thing effectively for a reasonable price so they have their little market cornered so to speak, introduce some competition and this whole issue could simply go away as a gimmick sold to developers in order to keep the administration and maintenance teams on side.

    It’s likely just a matter of time as I see it, these things ultimately always are 😉

  7. I am not sure I agree. Blackbaud know very well the benefit of .NET. That is why their latest platform is built on it. The Raiser’s Edge was built using COM so that it is not the case that they are trying to force us into use an old language. It is just that it would be prohibitively expensive to port RE to .NET. It would also be foolish. RE’s architecture is dated and Blackbaud are well aware of that fact. That is by Blackbaud Enterprise CRM and indeed all of the Infinity platform applications are built using and ready to use .NET.

  8. Interesting conversation here! I’m looking at Raiser’s edge for the first time since a client has it and wants me to synch it with another CRM app.

    The Raiser’s Edge API is always going to be a bit rough and ready to use in .NET, since the whole product is Visual Basic 6 and COM. Things just won’t work how they should. The types are fundamentally different, and the design patterns are from a kinder, gentler time. And there’s no way Blackbaud can get around that other than a rewrite – which as you say David would be a pointless exercise. Build a whole new product and migrate people to it.

    Building up a .NET RE framework is the best way forward. It’d be nice if Blackbaud published one, or if someone who had done one already launched an open source initiative. Give us all a standard, clean, .NET API that hid all the COM nastiness away.

    Have Blackbaud given any indication of where RE is going? A VB6 product is by definition a legacy product. What happens next for RE customers?

    Oh, and in terms of VB.NET vs C#… I see them as pretty close now anyway. You can easily machine translate from one to the other – that says it all really. If you really want to, you can write terrible code in C#, and beautiful code in VB.NET.

  9. I have used a lot of APIs through the years and while the RE API is clearly better suited to be used from other COM objects (it is after all COM based), it works pretty well with VB.NET too. It helps with the Primary Interop Assembly that Blackbaud have put together.

    You are right about VB.NET and C# being close. However there are some nuances that I mentioned above that don’t seem to appear in VB.NET but do in C#. One big part of this was optional parameters which can now be used in the latest version C#. It will be interesting to see if this works nicely with the COM optional variables that have been a problem.

Comments are closed.