Assemblies, friends, and general code organization

S

Scott Roberts

We're just getting started on our new .NET project. When I started, I was
just throwing everything into one DLL (assembly) and there were few
problems. I then decided that multiple assemblies would be a good idea for
several (rather typical, I believe) reasons including versioning, security,
deployment options, and general code organization. The model I have come up
with is as follows:


GUI assemblies (windows forms, asp.net, etc.)

Application assemblies (non-visual classes specific to a particular
"application"). Our customers may purchase any combination of applications.
We only deploy the one(s) they purchase.

Framework assembly. There is only one framework assembly. It contains base
classes that most (all?) of the classes in the application assemblies are
derived from. Most importantly, it implements functionality for persisting
objects to a database.

Database assemblies. There would conceivably be an assembly for each
database we support (there is only one assembly for SQL Server at this
time).


I think this is a fairly typical design. I can deploy one framework DLL
along with whatever application, GUI, and database DLLs are appropriate for
a particular customer. Sounds peachy.

However, there is a problem.

The "database" assemblies and the "application" assemblies both access the
"framework" assembly, but they need very different types of access. Namely,
the "database" assemblies need to be able to read private data of the
classes defined in the framework assembly in order to persist them into the
database. So, some properties (or classes) in the framework DLL should be
visible to the database DLLs, but not to the application DLLs.

I read up on the "friend" functionality ("internal" in c-sharp), but if I
understand correctly it requires that "friend" classes be in the same
assembly. I like the idea of having the database assemblies seperate so that
I can:

1. Deploy only the database DLLs necessary for a particular customer. Why
include code for accessing an Oracle database to a customer that is using
SQL Server?

2. I can write a new assembly to access a new database without touching the
framework assembly. If we get a new customer that wants to use MySQL, I can
just write an assembly for MySQL and deploy the rest of the application as
usual.

So, what to do? Allow public access to all properties on the framework
classes so that the database assembly can read them? Roll the database
access classes into the framework assembly? Are there some other features
that I've missed? I haven't looked into reflection all that much, but it
seems overly complicated for my simple plan. And, I would assume that the
same "public/friend" access permissions exist for reflection that they do
for "normal" coding practice.

I guess what I would really like is to make two assemblies "friends", so
that they work closely together but can be deployed seperately.

Any insights, links, corrections, comments, or questions are welcome.
 
J

John Saunders

Scott Roberts said:
We're just getting started on our new .NET project. When I started, I was
just throwing everything into one DLL (assembly) and there were few
problems. I then decided that multiple assemblies would be a good idea for
several (rather typical, I believe) reasons including versioning, security,
deployment options, and general code organization. The model I have come up
with is as follows:


GUI assemblies (windows forms, asp.net, etc.)

Application assemblies (non-visual classes specific to a particular
"application"). Our customers may purchase any combination of applications.
We only deploy the one(s) they purchase.

Framework assembly. There is only one framework assembly. It contains base
classes that most (all?) of the classes in the application assemblies are
derived from. Most importantly, it implements functionality for persisting
objects to a database.

Database assemblies. There would conceivably be an assembly for each
database we support (there is only one assembly for SQL Server at this
time).


I think this is a fairly typical design. I can deploy one framework DLL
along with whatever application, GUI, and database DLLs are appropriate for
a particular customer. Sounds peachy.

However, there is a problem.

The "database" assemblies and the "application" assemblies both access the
"framework" assembly, but they need very different types of access. Namely,
the "database" assemblies need to be able to read private data of the
classes defined in the framework assembly in order to persist them into the
database.

This is a questionable design. "Private" means PRIVATE. No other class
should ever need to look at such data. Rather than having the database know
about the innards of these classes, why not have the classes implement
serialization? Then the classes will know what to serialize, and won't care
_how_ it gets serialized.
 
S

Scott Roberts

This is a questionable design. "Private" means PRIVATE. No other class
should ever need to look at such data. Rather than having the database know
about the innards of these classes, why not have the classes implement
serialization? Then the classes will know what to serialize, and won't care
_how_ it gets serialized.

John, thanks for the reply.

Using serialization would offer some advantages, but it also brings in some
extra baggage and I'm not certain it really solves my problem anyway. Here
are my thoughts.

Advantages: By serializing objects (let's say using XML), I can
theoretically write one serialization routine and pass the XML to the data
adaptor(s) who then parse the XML into SQL commands (or whatever the
database uses to retrieve/update/delete data). If I'm careful, I may even be
able to use some of the XML utilities built into the .NET framework or SQL
Server itself.

Disadvantages: By serializing objects, I've added another layer of
indirection/abstraction between the object and the database. More code =
more opportunity for bugs. More code also = slower performance.

Still, at this point I think the advantages would outweigh the
disadvantages. But I'm not sure my problem is solved. For example, the
framework objects have properties that track object state. The object state
changes when the object is saved to the database (all of the fields are
marked as "not modified", the object is marked as "not new", etc.). To
accomplish this currently, the data adaptor class calls "AfterSave" on the
object. The object then resets itself to a "saved" state. So, the data
adaptor needs to be able to call "AfterSave" on the framework objects, but
obviously I don't want GUI classes calling this method.

So you see, it's not really a matter of accessing "private" data, per se.
It's more of "this class needs to be able to access some methods of the
framework classes, but these other classes should not".

What I've done in the mean time is create one class in the framework
assembly to be a base class for all data adaptors. This class can access the
necessary "protected internal" methods of framework classes and expose them
to derived data adaptor classes. This also shields the data adaptor classes
from changes to the "private" or "protected" areas of framework classes by
placing all of the dependancies into one base class that is part of the
framework assembly. Any compiler errors due to the interdependancy of these
objects will be caught when the framework is compiled, not at some later
date when I attempt to recompile the data adaptor assemblies.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top