I’ve been doing a lot of reading lately regarding Inversion of Control (IoC), but more specifically, the Dependency Inversion Principle which essentially states that even though your object depends upon my object for help, it shouldn’t depend on my object directly, only the interface or abstraction of my class. This allows my object to be swapped out easily without your object either knowing or caring. The bottom line in all of this is to create loosely-coupled, easily-maintained software.
The crux of loose coupling is: How does your object get an instance of my object? As I see it, we’ve got 3 possible solutions.
What about static methods at all? It would appear that static methods, by their very nature at somewhat at odds with OOP. With loosely-coupled designs, as many interactions as possible become purely interface-based. Currently I abstract functionality shared by multiple classes to another class and often times I don’t have to make it an instance class to get the work done that I need, which introduces a nice, tightly-coupled dependency.
In the end, I’m having some difficulty reconciling some of these practices to a CSLA-centric view of the world. Any advice or experience you guys having implementing any dependency injection or even service locator functionality would be greatly appreciated.
Rocky – anything new on the DataPortal_XYZ factory methods as per this post: http://forums.lhotka.net/forums/post/13044.aspx
Thanks
Hi Bob,
Most IoC frameworks support constructing objects through calling
Factory Method, instead of calling a constructor ( which in csla case is generally
private).
Check David Hayde’s post where he gives examples for
Windsor and Spring. StructureMap also supports it as well as MS Unity (I
can get you examples for those frameworks as well):
From: Bob Matthew
[mailto:cslanet@lhotka.net]
Sent: Tuesday, March 18, 2008 4:02 PM
To: Nermin Dibek
Subject: [CSLA .NET] Dependency Injection vs. DataPortal and Service
Locators vs. Static Factory Methods
I???ve been
doing a lot of reading lately regarding Inversion of Control (IoC), but more
specifically, the Dependency Inversion Principle which essentially states that
even though your object depends upon my object for help, it shouldn???t depend
on my object directly, only the interface or abstraction of my class.
This allows my object to be swapped out easily without your object either knowing
or caring. The bottom line in all of this is to create loosely-coupled,
easily-maintained software.
The crux of
loose coupling is: How does your object get an instance of my object? As
I see it, we???ve got 3 possible solutions.
What about
static methods at all? It would appear that static methods, by their very
nature at somewhat at odds with OOP. With loosely-coupled designs, as
many interactions as possible become purely interface-based. Currently I
abstract functionality shared by multiple classes to another class and often
times I don???t have to make it an instance class to get the work done that I
need, which introduces a nice, tightly-coupled dependency.
In the end,
I???m having some difficulty reconciling some of these practices to a
CSLA-centric view of the world. Any advice or experience you guys having
implementing any dependency injection or even service locator functionality
would be greatly appreciated.
Rocky ???
anything new on the DataPortal_XYZ factory methods as per this post: http://forums.lhotka.net/forums/post/13044.aspx
Thanks
I would love to see any links you can get me for examples relating to StructureMap and Unity.
Thanks!
Bob Matthew:I would love to see any links you can get me for examples relating to StructureMap and Unity.
Thanks!
Sorry it took me a while to digg this out. From Jeremy himself, this is the Factory Method example for upcomming StructureMap 2.5. Lets say you have a csla object Project that has a static factory method Project.CreateProject(). Then to register it with the StructureMap you would do following:
StructureMapConfiguration.BuildInstancesOf<Project>.TheDefaultIs(
ConstructedBy<Project>( () => Project.CreateNew() )
);
Obviosly if you are not using .Net 3.5 you can simply replace the labmbda expression with an anonymous delegate that calls the factory method.
Since this is not officially released yet you would have to get the latest StructureMap code from subversion repository.
http://structuremap.sourceforge.net/Default.htm
Nermin
By the way Jeremy already has a blog post about this:
Things happen fast in Open Source world!
nermin:Sorry it took me a while to digg this out. From Jeremy himself, this is the Factory Method example for upcomming StructureMap 2.5. Lets say you have a csla object Project that has a static factory method Project.CreateProject(). Then to register it with the StructureMap you would do following:
StructureMapConfiguration.BuildInstancesOf<Project>.TheDefaultIs(
ConstructedBy<Project>( () => Project.CreateNew() ));
Obviosly if you are not using .Net 3.5 you can simply replace the labmbda expression with an anonymous delegate that calls the factory method.
Since this is not officially released yet you would have to get the latest StructureMap code from subversion repository.
http://structuremap.sourceforge.net/Default.htm
Nermin
Would you mind posting the code for the registration of the object being constructed by the StructurMap?
Nermin
No problem...
I. For a class with a default Ctor everything is kosher:
public class Patient {}
[TestMethod]
public void PatientTest()
{
// I don't
want to use the StructureMap.config file
StructureMapConfiguration.UseDefaultStructureMapConfigFile
= false;
StructureMapConfiguration.BuildInstancesOf<Patient>()
.TheDefaultIsConcreteType<Patient>();
Patient
patient = ObjectFactory.GetInstance<Patient>();
}
2. For a class with no default Ctor, (CSLA BO) all I’m getting is: “That CunstructorBy does not exist in the current context”
public class CslaPatient
{
// private ctor
private
CslaPatient() { }
public static CslaPatient NewCslaPatient()
{
return new CslaPatient();
}
}
[TestMethod]
public void CslaPatientTest()
{
StructureMapConfiguration.UseDefaultStructureMapConfigFile = false;
StructureMapConfiguration.BuildInstancesOf<CslaPatient>
.TheDefaultIs(ConstructedBy<CslaPatient>(() =>
CslaPatient.NewCslaPatient()));
}
I’ve tried specifying the PluginType and the PluggedType in the
StrucureMap.config and included that – didn’t help either…
Borris,
I have built a quick test around ProjectTracker's Project object. Following works:
[TestMethod]
public void TestMethod1()
{
StructureMapConfiguration.UseDefaultStructureMapConfigFile = false;
StructureMapConfiguration.BuildInstancesOf<Project>().TheDefaultIs(
new ConstructorExpression<Project>(delegate { return Project.NewProject();})
);
Project project = ObjectFactory.GetInstance<Project>();
Assert.IsNotNull(project);
}
You will notice I am not using ConstructBy, but rather just build the new ConstructorExpression. Little bit less fluent but works. I think that there is work in progress on this feature, and untill Jeremy stamps 2.5 for release, we will still have a little issue here and there.
I must say that my test above was originally failing:
Test method TestProjectTracker.UnitTest1.TestMethod1 threw exception: System.Security.SecurityException: User not authorized to add a project.
After commenting out the authorization rule in CanAddProject() and just setting it to return true test passed. (I can not set my domain account to a "ProjectManager" role, which is what the auth rule was about). Therefore it appears to me that DI in this case works.
Please let me know if you have any questions.
Nermin
Bob Matthew:Rocky – anything new on the DataPortal_XYZ factory methods as per this post: http://forums.lhotka.net/forums/post/13044.aspx
That turned out to be a lot harder than I'd hoped, and the result (to me) wasn't compelling - especially given the complexity introduced by the change.
The last thing I want is to have CSLA end up as complex as many pattern-happy frameworks seem to do. That flies in the face of my primary goal, which is to make it easier to write OO business layers. Patterns are great, but not if their negative consequences outweigh their positive consequences.
I may yet introduce some extra extensibility points in the data portal (on the server it is just a chain of responsibility after all). But my original thought of allowing wholesale replacement of parts of the process was just not a good idea. Mostly because I'd end up supporting cases where people didn't understand the various dependencies in the chain and thus created a mess. Not useful to anyone.
What is more interesting to me is the use of a separate DAL, and the use of a factory model (or locator or whatever you want) to load/invoke that DAL. And that works with the existing data portal model just fine.
I think it is important to only use a design pattern where the pattern provides more value than it does cost. Patterns always have a "consequences" section in their description, where good and bad consequences are listed. A pattern should only be used if the goodness outweights the badness.
Dependency injection is powerful and enables some goodness. It is also often complex and thus introduces a lot of badness.
The data portal is designed for simplicity. It is designed to provide a very abstract technique for moving objects between client and server (if there is a server).
I find it hard to envision a scenario where someone would want to replace the data portal itself - especially for testing, when most bugs occur because people do something that violates one of the data portal's rules. You want to go through the data portal or you'll miss the most important bugs in your tests!
What people really want to do for testing is to transparently replace their DAL.
Months ago I ripped the data portal apart and started to rewrite it to open it up. The further into that process I got, the more I realized what a nightmare I was creating. If people can do wholesale replacement of the data portal they can totally break most/all of CSLA's features. And (in theory) I'd have to support people who did such a silly thing. Not gonna happen!
Even a simpler scenario, like allowing replacement of SimpleDataPortal and ChildDataPortal seems iffy to me. Easy for me to do, but the consequences are huge!
Those two objects implement a sequence of events that MUST HAPPEN for CSLA to work. If you look through the (really quite simple) code in SimpleDataPortal you see a sequence of steps. Every one of those steps MUST HAPPEN. Failure to perform a step, or performing a step out of sequence, introduces a bug that cascades through the entire framework's operation.
Take Create():
This is the simplest of the operations (and I'm ignoring exception handling, which must be done in a very specific manner).
If I allowed replacement of SimpleDataPortal (and ChildDataPortal of course), you could alter the overall flow somewhat, but you MUST end up having done steps 1, 3, 4, 6 and 7. Only 2 and 5 are really negotiable - and skipping them could easily break existing business object code.
It gets worse with Fetch() and very nasty with Update().
But, if I did this, I suppose you could decide to entirely ignore the current data portal model and devise a completely different scheme for creating/loading your object with data - as long as the result is marked new, and you do steps 6-7.
Maybe something like:
The pre- and post-processing events would be up to the DI framework or something, as would any error handling event. You'd still need to wrap this whole thing in the same error handling code from SimpleDataPortal of course.
As I said, I went down this whole road. And then it occurred to me that I could get the same flexibility by using a provider model to get at my DAL - and that approach is a lot simpler, so I abandoned this idea.
I have yet to be convinced that the DI pattern provides a better, simpler or cleaner result here than using a provider model for the DAL. If someone establishes how that would be the case then I would consider making this change to the data portal. In the meantime, my recommendation is to use a provider model to load your DAL - which allows mocking the DAL in a very simple and clean manner.
And interestingly enough, your DAL itself needs to be designed pretty much the same to support DI or the provider model, because your data access methods (either way) need to be able to interact interchaneably with the real or mock DAL. Remember that your DAL can't load your object's properties, it must load your object's fields - and to avoid breaking encapsulation this means your object must load its own fields. This is true regardless of what other patterns we apply around this process.
Rocky,
We seem to be “missing” each other on the main focus of our posts. Perhaps I should better explain my intentions and motivations behind my most posts on the subject of dependency injection. In addition, I shall attempt to more fully define my understanding of each concept such that any confusion may be avoided.
One of my primary goals is to minimize coupling (references to concrete types) between components in my code. I fully understand that some degree of coupling is necessary, for example, I’m tightly coupled to the System.String class whenever I work with a string. In many ways this type of coupling may not be undesirable, provided that I’m comfortable being bound to any changes that could be made to the System.String class.
The “issue” of coupling to the CSLA is really a non-issue. Just as I am comfortable being coupled to System.String and many other .NET base classes, I am also comfortable doing so with the CSLA and more particularly the DataPortal. I’m not interested in re-writing the DataPortal. Rocky, you’ve done a tremendous job with the framework. It’s very well documented, well supported and the advantages it brings to increasing object maintainability and portability are indispensable.
Now, with all of that addressed I would like to elaborate upon what I see as a limitation of, not the CSLA, but mobile objects in general because of their very nature as mobile objects; in short, a caveat of working in a client/server environment.
Two of the most common methods for avoiding tight coupling to concrete types and instead relying on contract definitions (interfaces) are known as “service locators” and “dependency injection”.
The service locator pattern, commonly and perhaps mistakenly referred to as an object broker, is where a single static, global object provides access to new objects. Whenever we need a new object, we go to the broker and ask for a new object that implements the desired interface. Any object is free to go to the broker/locater to ask for a concrete instance of any interface.
Dependency injection on the other hand, while it may share similarities with a service locator, namely having a single global, static “broker” object, has one significant difference: Each component or group of classes organized for a single purpose does not reference the broker or even know of the broker’s existence. The component, in order to receive references to its dependencies (such as a logger, database connection, etc.), has to have them injected during construction.
For further review of some of the advantages of dependency injection over service locators, please refer to the following article: http://ubik.com.au/article/named/service_locator_vs_dependency_injection
The “gotcha” that I’ve come across when attempting to reconcile dependency injection and mobile objects is that many types of dependencies a CSLA-derived class (a BusinessBase object) may need are not serializable and thus cannot be injected and shuttled back and forth across the wire during roundtrips to the DataPortal.
This means, as far as I can determine, that the only other possibility which can be used to obtain dependent references, other than direct coupling with a concrete type, is to use a service locator.
In conclusion, I just wanted others to be aware of this “issue” when attempting to implement a dependency injection pattern with a mobile object – you must ensure that any and all dependencies are fully serializable and you must also be aware of the additional payload those dependencies carry when transferring them back and forth across the wire. These complications can be avoided when using a service locator, meaning a direct reference to the global, static broker object from within the component, and not serializing the dependencies in question.
As for our approach used by my team, we have gone with a hybrid model. We use dependency injection for our non-BusinessBase objects which frees them of any knowledge of the broker, whereas the BusinessBase-based classes are free to access the object broker to obtain their dependencies.
Rocky,
I appreciate your time and effort on this.
I'm always able to learn something new from you -- Thank you!
We are building a pretty complicated medical system using CSLA.
The expectation is we will have at least couple of thousands
unit tests…
* So far in my case the existence of DI is mostly affecting how I write my unit
tests.
BTW: I was thought to distinguish between unit and integrating tests.
- Unit tests shall be atomic and shall not cross layers;
- Integration tests usually exercise the whole vertical slice UI to Database
My goal was/is to cover my public methods with atomic unit tests!
In general, the more atomic the tests are the better; the fewer tests will break if a bug is introduced.
I understand that going through the Data Portal is very important and it should be tested! (And it this in our integration tests, actually there are cases where integration tests are the only option)
So, using DI + Some Mocking Framework to mock the DAL in order to stay atomic and for speed purposes (Unit tests are way faster than Integration and they are executed more often) was perceived to be a good thing in our team…
**
The second thing with DI is: It can be used to introduce new behavior on the Client or in the Server. All I have to do is update a config file and put e new functionality in newly added assembly…
***
I never thought a change in the Data Portal is needed to support DI in CSLA.
CSLA is just fine.
I can use DI on the server or in the client, why would I want to break the Data Portal?
Here is one approach…
(It would be cool if the implementations of the IMyChildObject are also BOs)
The injection could take place in
the DataPortal_Create
or in the Properties..
Something like:
//In the properties _myChildObject is declared as IMyChildObject
[RunLocal()]
protected override void
DataPortal_Create()
{
_myChildObject =
StructureMap.ObjectFactory.GetInstance<IMyChildObject>();
//OR use the
NamedInstance:
//_myChildObject =
StructureMap.ObjectFactory.GetNamedInstance<IMyChildObject>("Implementaion1");
}
(In 3.5 LoadProperty
will be used…)
(You need to be familiar with StructureMap and create an
appropriate StructureMap.config file)
Here is a goog start with StructureMap:
In theory the DI could take place on both sides: Client & Server…or on either of those.
It all depends on what is it exactly we want to accomplish…
Copyright (c) Marimer LLC