Creating a .net API advice?

I searched a lot but could not find a good explanation or tutorial on creating a dotnet API from scratch. I only found tutorials about Web APIs and Java Apis, things I am not interested in.

I wish to learn by creating my own simple API but don’t know where to start.

What advice could you give me?

e.g.

  • Nested classes, how many levels is too much?
  • multiple dlls or single dll?
  • should each new API start with a class derived from System.Object? Why is that?
  • what is the best practice?
  • any hints, tips & tricks?

Thank you all in advance.

Most of these questions are covered in the
“Framework Design Guidelines” by Microsoft.

There is a lot to read at:
https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/

1 Like

First of all what do you mean with API? A collection of dll for Rhino? A COM Api etc?

Always 1 (more are possible). In DotNet, namespaces are used to structure your code. A project namespace should be a well structured project tree. Use folders for each subnamespace. Or do you mean derivation depth?

It depends on the project size. You already have two, if one is a test project. But don’t create too many if not necessary. 3-4 binaries for medium sized projects plus 3-4 Testprojects, plus Installer etc. making 6 to 10 solutions to be quite common. If you deal with more then 1 repository, a common repository might be benefical as well. But keep your sub repro count low, source control (Git) becomes quite cumberstone then. For a GH Addin 1-3 dlls/gha exposed to the user are probaly realistic.

I don’t understand, each class in dotnet derivies from System.Object

Follow and understand SOLID.

Use Ioc/Di Container -> Its a central place for constructing and retreiving object instances. There are many great plugins for this. Microsoft recently integrated their own “ServiceLocator”. This way you don’t need to pass other objects from object to object and so forth. And it works well when Unittesting. You can easily replace with mocks, for instance a Database - object with a DataBaseMock - object
.
Write Unittest and force yourself to comment. Comment at least every public member. Give a rough explanation what it does and why

Sketch a software architecture and add it to the project documentation. It really helps others and an older yourself to understand what it does and how.

Hi @TomTom,
Thanks for your reply.

Since I want to create an api to learn a bit more about .net and how things are organized. I want to start from scratch before I am able to create something more complex related to Rhino or COM.

My initial idea is e.g.:

DLL

  • class Vehicle(System.Object)
  • class LKW (System.Collection) #Funny that I know the German abbreviation word for this classification but not the English one :smiley:
  • class PKW (System.Collection)
  • class Car (Vehicle)
  • class Truck (Vehicle)
  • class Buss (Vehicle)
  • class SUV (Car)
  • class Hatchback (Car)
  • class Estate (Car)
  • class Sedane (Car)
  • etc. etc.

I assume an API should be organized like this going deeper and deeper to actual parts of the vehicles.

I think this is too advanced, and too much automation. The more automation the less you learn about the basis. My main goal creating this API is to learn. Perhaps later on I can mix the classes I create with RhinoCommon deriving from both my test api and RhinoCommon and thus providing geometry to my vehicles. At least this is what I understand now about how APIs work. It is possible I am totally wrong about this and the approach should not be this at all

I saw you are recently promoting this unittesting a lot, and read a little about it. I believe this is for when I get a little bit more fluent. There are still a lot of things about C# that I do not understand.

Are you fluent enough to run your code and check whether it is running properly? Unit testing on small elements of code and integration testing on whole sections is simply doing this in a structured, repeatable manner.

1 Like

Though they are not new, you cannot go wrong watching the talks linked here, by Brad Abrams.

The downloads themselves are a bit of a pain, but the .exe for each talk will extract a bunch of stuff to a directory, and somewhere in there you will find a .wmv of the talk.

1 Like

I guess not enough when it comes to c# :smiley:
I can translate 70-80% of c# code to Python. But if I have to create csharp code from scratch no so much.

1 Like

There are also Unittesting frameworks for CPython!

All you need to to do is to create a test project, and test your functionality method by method. Testing frameworks usually give you the ability to assert.

def answer_to_life_test():
  #Arrange 
  expected_result = "I don't know"
  my_name = 'Ivelin'
  #Act
  returned_result = my_awesome_lib.answer_to_life(my_name) #returns 42
  #Assert
  assert.are_equal(expected_result,returned_result ) # will fail -> test will not pass

=> now a unittest framework usually gives you visual feedback.
The reason -> you can test multiple input cases and validate your functionality. This way you can easily test extreme input. The main advantage however is if you change your code later on, you know if it breaked something somewhere else. So when you move on with your code, you don’t need to repeat your tests manually again and again. You eliminate many bugs beforehand.

2 Likes

Just as a side note. The use of ioc container esp. the ServiceLocator Pattern may not be well suited for Apis, since it hides Dependencies. I completely missed that out. But within a closed application or not publicly exposed library functionality, I really like the pattern. Its also criticized by some people, but it is one of the most simple ways in structuring code!

I have no idea what that means.

Currently, I have the dilemma what are the differences between Interface and Abstract Class. Do I start the api by creating just Interfaces and then create Abstract Classes that derive from multiple interfaces. Or start by creating just Abstract Classes? How do one make a choice? Say you have a clear idea of an object with all the methods it has to have how do you decide if it has to be an interface or abstract class?

Another thing is what criteria to use when creating the folder structure of my project? How to arrange my class.cs files?

These kind of questions I was looking for when I started this thread.

I started reading the article from the link from @piac, but there aren’t any guides regarding this.

You use Abstract classes if you want to derive multiple objects from one base. GeometryBase -> Curve, or Surface or Mesh. GeometryBase holds variables and methods which all 3 childs share.
An interface allows you to “connect” objects quite loose (by Contract). You don’t care about the implementation but instead you say, whatever you are and whatever you do, if you implement this interface you guarantee that all functionality exposed in the Interface is callable. Interface can be used similar to an Abstract Base class, but you shouldn’t. You rather create interfaces based on features. Any object implementing the IDisposable interface owns a Dispose method which cares about cleaning up the object because the garbage collection can’t do for those objects. Another famous interface is the IEnumerable, which (if implemented) say this object contains multiple members which are iterable. For instance a collection like a List and Array share this. Another more CAD related Interface could be a fictive IExportable, which describes an object which can be exported and therefore contains an Export method. Since any object can implement more Interfaces, it could also implement an IImportable which guarantees this object contains a Import method for instance. There are more advantages to interfaces esp. regarding software patterns, but this will extend that reply by far. But interfaces are no objects, they are blueprints of functionality. Abstract classes in comparison can be instanciated but the abstract keyword say that this won’t make any sense. I mean, what would an GeometryBase instance do?

2 Likes

Thanks @TomTom,

If I understand correctly interfaces simply add some methods if a class is derived from them. But is the Abstract Class derived from multiple interfaces or a class that derives from an abstract class also derived from an interface?

A few more questions:

  1. In the above example about vehicles. I assume the abstract class will be e.g. Abstract Class Vehicle. Then are the Class Trucks and Class Cars supposed to be Abstract again?
  2. I see Interfaces are set a name of an ability: IEnumerable, IDisposable,IExportable, etc. So I guess the Abstract Class Vehicle should derive from a number of interfaces: IMovable, ILoadable (for fuel), IUnloadable(for fuel), IFuelConsuming, ISteerable, etc. Is that meaningful?

Fluent Pythonis pretty good on ABCs and interfaces.

Is this applicable for csharp?

No idea :open_mouth:

I guess the concepts are the same so if that is the part that s confusing you…?

I’ve never created python package/module either.

I’ll definitely take a look, thanks. I think I have a digital copy of this book.

Sure you can derive an abstract class from an abstract class and so forth. Derivation depth is not bound

But any object can only derive from one (abstract) class. So polymorphism is not allowed in C#

Abstract just means its an class which does not makes sense to initiate. You don‘t need to use the abstract keyword, but someone using your code immediately knows that (I mean its actually obvious) a car, truck or vehicle are not classes to initiate, whereas as Bugatti Chiron for instance is.

You don‘t need to create interfaces which follow no purpose later on, but dividing into multiple smaller interfaces follows the SOLID principles. The advantages, lets say you implement some concrete subclasses Vehicle-Car-Sportscar-BugattiChiron and a Vehicle-Car-Pickup-DogdeRam1500 which both implement the Interface IGasolineEngine and you also have third Class Vehicle-Car-Sportscar-BMWi8 which implements the IElectricEngine . Now at the other end of your application you create a „GasStation“ class which refuels only IGasolineEngine objects. If you later create complete different objects such as totally vehicle unrelated object like EmergencyPowerGenerator which also implements the IGasolineEngine you can take this object and „refuel“ it at your gasstation.

2 Likes

Hi @TomTom,

Might this example not be a little confusing to a newbie? I can’t immediately think of a commonplace situation where I would create a class specific to a vehicle model. I would create, say, Vehicle-Car-Sportscar and instantiate an object, BugattiChiron, of that class. I could then easily instantiate an MGB and whatever other sportscars I wanted. I don’t see that there would be sufficient differences between sportscars’ attributes and methods to warrant further subdivision. What do you think?

Regards
Jeremy

Maybe the Dodge is an interface.

DodgeRam is the abstract class derived from the interface and from the PickUp abstract class.

Then the object (instance) is the 1500?

Hi Ivelin,

That’s a design decision. I doubt you would do that, but it depends on what your system is intended to do.

The workflow is to start by eliciting requirements (“As a garage owner I need to find a pickup with V8 power”), then analyse what a system has to do to meet (at least some of) the requirements (“We need to classify vehicles by use”, “we need to distinguish power sources”), then design a software model that delivers the functionality (“We need an abstract vehicle class”, “we need a utility vehicle sub-class”, “the vehicle class will have an attribute Engine of type EngineClass”, the utility vehicle class will have an attribute LoadCapacity"), finishing up with coding.
In designing our classes we look to include the attributes and methods that are common to the class (vehicle.wheelCount, vehicle.topSpeed, vehicle.startEngine()). We create a sub-class only where the information content or activity of a vehicle is specialised to that sub-class only (utility.loadCapacity). Ideally we want our classes to be as general as possible, because too many classes make program maintenance harder.

The important thing is to follow the workflow so you have a rationale for your design decisions. That workflow, incidentally is cyclical, you keep going round to refine, extend and improve.

Regards
Jeremy

2 Likes