Architecture Advice Required

T

terry.holland

I have a three tiered CRM application (ASP.Net UI, VB.Net Business
Layer & VB.Net Data Access Layer) that consists of number of classes.
The application will be deployed to a number of clients. Some of our
clients have no existing CRM system and are happy that our application
stores Client information. Other clients have already got a CRM system
and want our application for the additional functionality that it
offers. These clients would want core Client information (ID, Name,
Phone, Address etc) to be looked up from their existing system, and
have our system store additional information that relates to these
clients.

As I have seperated the business & data access logic into discrete
layers I should easily be able to create a IClient interface and have
classes clsClientA_BLL and clsClientB_BLL implement this common
interface. Each of these classes should then be able to access client
data from the correct data store, and enforce client specific business
rules.

My initial architecture is similar to this

Solution: MyCRM
Project1: MyCRM_WEB
Project2: MyCRM_BLL
Project3: MyCRM_DAL

MyCRM_WEB has a reference to MyCRM_BLL
MyCRM_BLL has a reference to MyCRM_DAL

I need to modify this so that MyCRM_BLL is split so that I have
MyCRM_BLL.dll (all common classes)
MyCRM_ClientA_BLL (only ClientA specific business classes)
MyCRM_ClientB_BLL (only ClientB specific business classes)
MyCRM_ClientA_DAL (only ClientA specific data-access classes)
MyCRM_ClientB_DAL (only ClientB specific data-access classes)

Im not sure how to organise these components as, for ClientA, they
cannot have the ClientB specific dlls (or vica versa). How do I
arrange my solution so that the WEB project has references to
MyCRM.dll and MyCRM_ClientA_BLL.dll or MyCRM_ClientB_BLL.dll,
depending on who it is being deployed to?
 
G

Gillard

maybe it could be resolved with a boolean value wrotten to the registry at
setup time
 
T

terry.holland


I have used this on my last project. The question still remains, even
using CSLA. ie How do I build my UI if at ClientA site, it needs to
instantiate an object from ClientA_BLL.dll; and at ClientB site, it
needs to instantiate an object from ClientB_BLL.dll. My understanding
is that the UI would need a reference to both ClientA_BLL.dll and
ClientB_BLL.dll. If this is the case, then when I deploy to ClientA,
without shipping ClientB_BLL.dll, the UI is going to complain.
Likewise, when I deply to ClientB, without shipping ClientA_BLL.dll
then the UI is going to complain.

Id appreciate if someone could give me a concrete example of how to
sort this out.

tia
 
S

sloan

http://sholliday.spaces.live.com/feed.rss
Find the "Simple Factory Pattern" article.

Look at the reflection example.
Or the Key example.

You'll have to do something with a deployment build script for each client I
think.
MSBuild and MSBuildTasks ...you could use them to build a deployment for
you, and then strip out the dll from the deployment package.

Basic example:
http://groups.google.com/group/microsoft.public.dotnet.framework.aspnet/msg/5c2634d01c5cf829?hl=en

create a

client1.bat ( do the msbuild stuff , and then delete Client2.dll from the
result directory)
client2.bat (do the same, but delete client1.dll )
 
T

Terry Holland

http://sholliday.spaces.live.com/feed.rss
Find the "Simple Factory Pattern" article.

Look at the reflection example.
Or the Key example.

You'll have to do something with a deployment build script for each client I
think.
MSBuild and MSBuildTasks ...you could use them to build a deployment for
you, and then strip out the dll from the deployment package.

Basic example:http://groups.google.com/group/microsoft.public.dotnet.framework.aspn...

create a

client1.bat  ( do the msbuild stuff , and then delete Client2.dll from the
result directory)
client2.bat  (do the same, but delete client1.dll )












- Show quoted text -

I like the reflaction solution as this is configurable. While waiting
for some responses, I came up with the follwoing method.

Solution: MyCRM
Project1: MyCRM_WEB
Project2: MyCRM_Common_BLL
Project3: MyCRM_ClientA_BLL
Project4: MyCRM_ClientB_BLL
Project5: MyCRM_Interfaces


in MyCRM_Common_BLL I have a number of classes that are common to all
clients and all of the classes that the MyCRM_WEB project expects to
see.
For the classes that would have a client specific imlementation I have
created an interface in MyCRM_Interfaces.
Public Interface IPerson
ReadOnly Property Name() As String
End Interface

Then in MyCRM_ClientA_BLL I will implement a ClientA specific class
ie

Public Class clsPerson
Implements Interfaces.IPerson

Public ReadOnly Property Name() As String Implements
Interfaces.IPerson.Name
Get
Return "Person A"
End Get
End Property
End Class

Then in MyCRM_ClientB_BLL I will implement a ClientB specific class
ie

Public Class clsPerson
Implements Interfaces.IPerson

Public ReadOnly Property Name() As String Implements
Interfaces.IPerson.Name
Get
Return "Person B"
End Get
End Property
End Class

Going back to MyCRM_Common_BLL I have the following Person class

Public Class clsPerson
Inherits BLL_Custom.clsPerson

Implements Interfaces.IPerson

'All implementation code in in
'seperate BLL_Custom.dll assemblies


End Class

The whole thing works because I create Project3: MyCRM_ClientA_BLL &
Project4: MyCRM_ClientB_BLL giving them both the same Assembly Name
and default namespace (BLL_Custom). While developing I only reference
one of these at a time (this is a pain). When I build the solution,
the bin directory of MyCRM_WEB will contain the BLL_Custom.dll of the
assembly that was referenced during the build. To deploy to ClientA
(default) I deploy all of the files in this directory. To deploy to
ClientB I deploy the same files, but overwrite the BLL_Custom.dll file
with the BLL_Custom.dll for ClientA.

Does anyone see any problem with this approach? The only prob Ive
encountered up til now is that I cant have BLL_Custom.dll for more
than one client referenced at a time - as I get errors saying that
clsPerson is declared more than once in same namespace
 
S

sloan

//
The only prob Ive
encountered up til now is that I cant have BLL_Custom.dll for more
than one client referenced at a time - as I get errors saying that
clsPerson is declared more than once in same namespace//

That doesn't sound right dude. If you're referring to everything on the
"outside" as ISomething, then you should be able to reference both dll's
without issue.

I think you have a maintenance nightmare there.

I can't solve your issue, I can only point you to OO principles.

It sounds like a classic Factory Pattern need. Google the factory pattern,
try www.dofactory.com, and work through my example(s) I provided to learn
the Design Pattern.

Can you make it work your way? Sure.
But I don't think its the best approach.

Public Class clsPerson
Implements Interfaces.IPerson
(with the same namespace (fullname )) in 2 different assemblies is kinda
whack IMHO.

I would also do a refresher on namespaces, esp in vb.net where the namespace
gets hidden from you.




http://sholliday.spaces.live.com/feed.rss
Find the "Simple Factory Pattern" article.

Look at the reflection example.
Or the Key example.

You'll have to do something with a deployment build script for each client
I
think.
MSBuild and MSBuildTasks ...you could use them to build a deployment for
you, and then strip out the dll from the deployment package.

Basic
example:http://groups.google.com/group/microsoft.public.dotnet.framework.aspn...

create a

client1.bat ( do the msbuild stuff , and then delete Client2.dll from the
result directory)
client2.bat (do the same, but delete client1.dll )












- Show quoted text -

I like the reflaction solution as this is configurable. While waiting
for some responses, I came up with the follwoing method.

Solution: MyCRM
Project1: MyCRM_WEB
Project2: MyCRM_Common_BLL
Project3: MyCRM_ClientA_BLL
Project4: MyCRM_ClientB_BLL
Project5: MyCRM_Interfaces


in MyCRM_Common_BLL I have a number of classes that are common to all
clients and all of the classes that the MyCRM_WEB project expects to
see.
For the classes that would have a client specific imlementation I have
created an interface in MyCRM_Interfaces.
Public Interface IPerson
ReadOnly Property Name() As String
End Interface

Then in MyCRM_ClientA_BLL I will implement a ClientA specific class
ie

Public Class clsPerson
Implements Interfaces.IPerson

Public ReadOnly Property Name() As String Implements
Interfaces.IPerson.Name
Get
Return "Person A"
End Get
End Property
End Class

Then in MyCRM_ClientB_BLL I will implement a ClientB specific class
ie

Public Class clsPerson
Implements Interfaces.IPerson

Public ReadOnly Property Name() As String Implements
Interfaces.IPerson.Name
Get
Return "Person B"
End Get
End Property
End Class

Going back to MyCRM_Common_BLL I have the following Person class

Public Class clsPerson
Inherits BLL_Custom.clsPerson

Implements Interfaces.IPerson

'All implementation code in in
'seperate BLL_Custom.dll assemblies


End Class

The whole thing works because I create Project3: MyCRM_ClientA_BLL &
Project4: MyCRM_ClientB_BLL giving them both the same Assembly Name
and default namespace (BLL_Custom). While developing I only reference
one of these at a time (this is a pain). When I build the solution,
the bin directory of MyCRM_WEB will contain the BLL_Custom.dll of the
assembly that was referenced during the build. To deploy to ClientA
(default) I deploy all of the files in this directory. To deploy to
ClientB I deploy the same files, but overwrite the BLL_Custom.dll file
with the BLL_Custom.dll for ClientA.

Does anyone see any problem with this approach? The only prob Ive
encountered up til now is that I cant have BLL_Custom.dll for more
than one client referenced at a time - as I get errors saying that
clsPerson is declared more than once in same namespace
 
T

Terry Holland

//
The only prob Ive
encountered up til now is that I cant have BLL_Custom.dll for more
than one client referenced at a time - as I get errors saying that
clsPerson is declared more than once in same namespace//

That doesn't sound right dude.  If you're referring to everything on the
"outside" as ISomething, then you should be able to reference both dll's
without issue.

I think you have a maintenance nightmare there.

I can't solve your issue, I can only point you to OO principles.

It sounds like a classic Factory Pattern need.  Google the factory pattern,
trywww.dofactory.com, and work through my example(s) I provided to learn
the Design Pattern.

Can you make it work your way?  Sure.
But I don't think its the best approach.

  Public Class clsPerson
    Implements Interfaces.IPerson
(with the same namespace (fullname )) in 2 different assemblies is kinda
whack IMHO.


I agree that the factory patter is the way to go but Im having
difficulty implementing it. The reflection example that you quoted
sound perfect - but Im struggling to get it to work
 
S

sloan

My code should be complete and workable. (Did you find the zip download?)

Are you having trouble with my downloadable example OR the Vb.Net
translation?





//
The only prob Ive
encountered up til now is that I cant have BLL_Custom.dll for more
than one client referenced at a time - as I get errors saying that
clsPerson is declared more than once in same namespace//

That doesn't sound right dude. If you're referring to everything on the
"outside" as ISomething, then you should be able to reference both dll's
without issue.

I think you have a maintenance nightmare there.

I can't solve your issue, I can only point you to OO principles.

It sounds like a classic Factory Pattern need. Google the factory pattern,
trywww.dofactory.com, and work through my example(s) I provided to learn
the Design Pattern.

Can you make it work your way? Sure.
But I don't think its the best approach.

Public Class clsPerson
Implements Interfaces.IPerson
(with the same namespace (fullname )) in 2 different assemblies is kinda
whack IMHO.


I agree that the factory patter is the way to go but Im having
difficulty implementing it. The reflection example that you quoted
sound perfect - but Im struggling to get it to work
 
T

Terry Holland

My code should be complete and workable. (Did you find the zip download?)

Are you having trouble with my downloadable example OR the Vb.Net
translation?










I agree that the factory patter is the way to go but Im having
difficulty implementing it. The reflection example that you quoted
sound perfect - but Im struggling to get it to work- Hide quoted text -

- Show quoted text -

I did get your code to run but Im having trouble applying it to my
problem. I need to go now but Id really appreciate if you could
continue to watch this thread as Id really like to get this working in
the 'correct way'
 
T

Terry Holland

I did get your code to run but Im having trouble applying it to my
problem.  I need to go now but Id really appreciate if you could
continue to watch this thread as Id really like to get this working in
the 'correct way'- Hide quoted text -

- Show quoted text -

I have come up with a solution that I believe is in essence following
your reflection method

I have a PersonFactory class in MyCRM_Common_BLL assembly as follows

Imports System
Imports System.Reflection

Public Class clsPersonFactory

Public Shared Function GetPerson() As Interfaces.IPerson
Dim objPerson As Interfaces.IPerson = Nothing
Dim objAssembly As Assembly = Nothing
Dim objType As Type = Nothing

objAssembly = Assembly.LoadFrom(My.Settings.ClientBLL &
".dll")
objType = objAssembly.GetType(My.Settings.ClientBLL &
".clsPerson")

objPerson = DirectCast(Activator.CreateInstance(objType),
Interfaces.IPerson)

Return objPerson
End Function

End Class

I added an app.config file to MyCRM_Common_BLL project and this has a
setting called ClientBLL. When I change the value of this setting to
MyCRM_ClientA_BLL and run the solution, a concrete ClientA clsPerson
is created; when I change the value of this setting to
MyCRM_ClientB_BLL, a concrete ClientB clsPerson is created

I may be misunderstanding the My.Settings because I thought that when
I build the solution, this setting would be stored in
MyCRM_Common_BLL.dll.config file and if I change the value of this (by
opening config file and manually changing setting), the compiled app
would pick up the new value at runtime. This is not happening. When
the app runs, the ClientBLL setting is always the value that was set
when solution built - even if I manually edit the value in a text
editor. btw I do copy the MyCRM_Common_BLL.dll.config file to my
deploy directory.

Do you have any ideas on this problem or any views on my factory
method?

deployed to ClientA, I could deploy the MyCRM_Common_BLL.dll.config
file with ClientBLL setting changed to and relevant MyCRM_Client_BLL
 
S

sloan

//I added an app.config file to MyCRM_Common_BLL project//

That doesn't work. The app.config values come from the presentation layer
(or executing assembly).

.................


My advice is to start fresh. Instead of tacking in my solution into what
you already have, start fresh and build (the factory) stuff from the ground
up.
Translate my code into VB.NET, and that at least you'll know the
fundamentals.....

I realize up front you probably won't do this. I don't know you, but I know
alot of developers. But that is my advice. Translate my sample into
VB.NET. (A complete translation, not 80%, especially in the "Settings" and
"Handler".

PS
I don't use
My.Settings
stuff. I parse the xml and create objects from it.
The "Settings" and "Handler" classes of my example.

Again, you're taking (yet another) shortcut. My.Settings doesn't allow any
future flexibility, and (in my opinion) promotes hack jobs.

Create a dedicated custom configuration handler (the "Handler") for you
data, and parse the xml, and push the values of the xml into a "Settings"
object.


Without the basic fundamentals down, you're just going to continue to
struggle.

I realize the first time through, the Settings and Handler items arent'
super simple. However, I can attest to this my personal experience, its
very hard the FIRST TIME, and after about the 3rd time, its fairly easy to
create a new Handler/Setting/Custom Config section.

The reason I'm hammering this is because its use so very often in the DotNet
world, you just haven't seen the underlying code.
Basically, ANYTHING you paste into web.config or app.config (from samples)
is done this way.
That is why it is so fundamental.






I did get your code to run but Im having trouble applying it to my
problem. I need to go now but Id really appreciate if you could
continue to watch this thread as Id really like to get this working in
the 'correct way'- Hide quoted text -

- Show quoted text -

I have come up with a solution that I believe is in essence following
your reflection method

I have a PersonFactory class in MyCRM_Common_BLL assembly as follows

Imports System
Imports System.Reflection

Public Class clsPersonFactory

Public Shared Function GetPerson() As Interfaces.IPerson
Dim objPerson As Interfaces.IPerson = Nothing
Dim objAssembly As Assembly = Nothing
Dim objType As Type = Nothing

objAssembly = Assembly.LoadFrom(My.Settings.ClientBLL &
".dll")
objType = objAssembly.GetType(My.Settings.ClientBLL &
".clsPerson")

objPerson = DirectCast(Activator.CreateInstance(objType),
Interfaces.IPerson)

Return objPerson
End Function

End Class

I added an app.config file to MyCRM_Common_BLL project and this has a
setting called ClientBLL. When I change the value of this setting to
MyCRM_ClientA_BLL and run the solution, a concrete ClientA clsPerson
is created; when I change the value of this setting to
MyCRM_ClientB_BLL, a concrete ClientB clsPerson is created

I may be misunderstanding the My.Settings because I thought that when
I build the solution, this setting would be stored in
MyCRM_Common_BLL.dll.config file and if I change the value of this (by
opening config file and manually changing setting), the compiled app
would pick up the new value at runtime. This is not happening. When
the app runs, the ClientBLL setting is always the value that was set
when solution built - even if I manually edit the value in a text
editor. btw I do copy the MyCRM_Common_BLL.dll.config file to my
deploy directory.

Do you have any ideas on this problem or any views on my factory
method?

deployed to ClientA, I could deploy the MyCRM_Common_BLL.dll.config
file with ClientBLL setting changed to and relevant MyCRM_Client_BLL
 
T

Terry Holland

//I added an app.config file to MyCRM_Common_BLL project//

That doesn't work.  The app.config values come from the presentation layer
(or executing assembly).

................

My advice is to start fresh.  Instead of tacking in my solution into what
you already have, start fresh and build (the factory) stuff from the ground
up.
Translate my code into VB.NET, and that at least you'll know the
fundamentals.....

I realize up front you probably won't do this.  I don't know you, but Iknow
alot of developers.  But that is my advice.  Translate my sample into
VB.NET. (A complete translation, not 80%, especially in the "Settings" and
"Handler".

PS
I don't use
My.Settings
stuff.  I parse the xml and create objects from it.
The "Settings" and "Handler" classes of my example.

Again, you're taking (yet another) shortcut.  My.Settings doesn't allowany
future flexibility, and (in my opinion) promotes hack jobs.

Create a dedicated custom configuration handler (the "Handler") for you
data, and parse the xml, and push the values of the xml into a "Settings"
object.

Without the basic fundamentals down, you're just going to continue to
struggle.

I realize the first time through, the Settings and Handler items arent'
super simple.  However, I can attest to this my personal experience, its
very hard the FIRST TIME, and after about the 3rd time, its fairly easy to
create a new Handler/Setting/Custom Config section.

The reason I'm hammering this is because its use so very often in the DotNet
world, you just haven't seen the underlying code.
Basically, ANYTHING you paste into web.config or app.config (from samples)
is done this way.
That is why it is so fundamental.






I have come up with a solution that I believe is in essence following
your reflection method

I have a PersonFactory class in MyCRM_Common_BLL assembly as follows

Imports System
Imports System.Reflection

Public Class clsPersonFactory

    Public Shared Function GetPerson() As Interfaces.IPerson
        Dim objPerson As Interfaces.IPerson = Nothing
        Dim objAssembly As Assembly = Nothing
        Dim objType As Type = Nothing

        objAssembly = Assembly.LoadFrom(My.Settings.ClientBLL &
".dll")
        objType = objAssembly.GetType(My.Settings.ClientBLL &
".clsPerson")

        objPerson = DirectCast(Activator.CreateInstance(objType),
Interfaces.IPerson)

        Return objPerson
    End Function

End Class

I added an app.config file to MyCRM_Common_BLL project and this has a
setting called ClientBLL.  When I change the value of this setting to
MyCRM_ClientA_BLL and run the solution, a concrete ClientA clsPerson
is created; when I change the value of this setting to
MyCRM_ClientB_BLL, a concrete ClientB clsPerson is created

I may be misunderstanding the My.Settings because I thought that when
I build the solution, this setting would be stored in
MyCRM_Common_BLL.dll.config file and if I change the value of this (by
opening config file and manually changing setting), the compiled app
would pick up the new value at runtime.  This is not happening.  When
the app runs, the ClientBLL setting is always the value that was set
when solution built - even if I manually edit the value in a text
editor.  btw  I do copy the MyCRM_Common_BLL.dll.config file to my
deploy directory.

Do you have any ideas on this problem or any views on my factory
method?

- Show quoted text -

I will endeavour to get a handle on the Settings and Handler stuff
this week. Thanks for your input
 
S

sloan

Here are helper links:


http://msdn.microsoft.com/en-us/library/2tw134k3.aspx

http://support.microsoft.com/default.aspx?scid=kb;en-us;309045





//I added an app.config file to MyCRM_Common_BLL project//

That doesn't work. The app.config values come from the presentation layer
(or executing assembly).

................

My advice is to start fresh. Instead of tacking in my solution into what
you already have, start fresh and build (the factory) stuff from the
ground
up.
Translate my code into VB.NET, and that at least you'll know the
fundamentals.....

I realize up front you probably won't do this. I don't know you, but I
know
alot of developers. But that is my advice. Translate my sample into
VB.NET. (A complete translation, not 80%, especially in the "Settings" and
"Handler".

PS
I don't use
My.Settings
stuff. I parse the xml and create objects from it.
The "Settings" and "Handler" classes of my example.

Again, you're taking (yet another) shortcut. My.Settings doesn't allow any
future flexibility, and (in my opinion) promotes hack jobs.

Create a dedicated custom configuration handler (the "Handler") for you
data, and parse the xml, and push the values of the xml into a "Settings"
object.

Without the basic fundamentals down, you're just going to continue to
struggle.

I realize the first time through, the Settings and Handler items arent'
super simple. However, I can attest to this my personal experience, its
very hard the FIRST TIME, and after about the 3rd time, its fairly easy to
create a new Handler/Setting/Custom Config section.

The reason I'm hammering this is because its use so very often in the
DotNet
world, you just haven't seen the underlying code.
Basically, ANYTHING you paste into web.config or app.config (from samples)
is done this way.
That is why it is so fundamental.






I have come up with a solution that I believe is in essence following
your reflection method

I have a PersonFactory class in MyCRM_Common_BLL assembly as follows

Imports System
Imports System.Reflection

Public Class clsPersonFactory

Public Shared Function GetPerson() As Interfaces.IPerson
Dim objPerson As Interfaces.IPerson = Nothing
Dim objAssembly As Assembly = Nothing
Dim objType As Type = Nothing

objAssembly = Assembly.LoadFrom(My.Settings.ClientBLL &
".dll")
objType = objAssembly.GetType(My.Settings.ClientBLL &
".clsPerson")

objPerson = DirectCast(Activator.CreateInstance(objType),
Interfaces.IPerson)

Return objPerson
End Function

End Class

I added an app.config file to MyCRM_Common_BLL project and this has a
setting called ClientBLL. When I change the value of this setting to
MyCRM_ClientA_BLL and run the solution, a concrete ClientA clsPerson
is created; when I change the value of this setting to
MyCRM_ClientB_BLL, a concrete ClientB clsPerson is created

I may be misunderstanding the My.Settings because I thought that when
I build the solution, this setting would be stored in
MyCRM_Common_BLL.dll.config file and if I change the value of this (by
opening config file and manually changing setting), the compiled app
would pick up the new value at runtime. This is not happening. When
the app runs, the ClientBLL setting is always the value that was set
when solution built - even if I manually edit the value in a text
editor. btw I do copy the MyCRM_Common_BLL.dll.config file to my
deploy directory.

Do you have any ideas on this problem or any views on my factory
method?

- Show quoted text -

I will endeavour to get a handle on the Settings and Handler stuff
this week. Thanks for your input
 

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