locked
Sharing (private) information between 2 different assemblies RRS feed

  • Question

  • Hi;

    After stay a whole night without sleep, i can't work on a better title for this thread. But...
    I'm having a hard time dealing with something that appears to be so simple.

    I have a business object that look like this (short version):

    Public Class UserAccount
    
      Friend _userName As String
      Friend _password As String
      Friend _userId As Integer
    
      Public Sub New(ByVal username As String, ByVal password As String)
        _userName = username
        _password = password
      End Sub
      Public ReadOnly Property Username As String
        Get
          Return _userName
        End Get
      End Property
      Public ReadOnly Property UserId As Integer
        Get
          Return _userId
        End Get
      End Property
    
      Public Property Name As String
    
    End Class
    

    The UserId property is read only because the id is supposed to be grabbed from DB after the record is saved. For similar reasons other properties are read only as well.

    When bussiness objects and data access were in the same assembly it was easy because after save I could inject the values into the properties using the "Friend" fields but now that each layer is on it's own assembly i can't access the "Friend" fields anymore.
    So, what are my options and/or best practices here?

    These are the two options I'm aware of:

    a) All properties as read/write since it's just being used to send data from one layer to another. However I will end up with a class where the user can edit properties like the ID property and a few others. Besides the fact that I will have to write more code to deal with that and have a more confusing object and documentation, it's not elegant.

    b) Use <Assembly: InternalsVisibleTo(MY_OTHER_ASSEMBLY)> so the fields are shared between the 3 assemblies, however, I don't know if it's as secure as keeping everything inside the same assembly. If people can tamper with ower code through that.

    Hope I can get some advice in here.
    Thanks in advance.

     

    Monday, November 8, 2010 4:34 PM

Answers

  •  

    The DAL must be able to create the Entity with the password. I would create a DTO in the DAL, store the password and other properties in there. Then create an interface that only allows read access to those properties.

    In the BLL create the Domain Entity that implements the interface. Now you can ask the DAL for IAcount and there you go.

    In c# this would look like:

    IAccount account = dal.CreateAccount(userName, password);

    The call in the BL would look like: 
    BllAccount restrictedAccount = dal.GetAccount(userName);

     

    Kind regards,
    Tom de Koning


    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    • Proposed as answer by Tom de Koning Tuesday, November 9, 2010 9:00 PM
    • Marked as answer by CodeMaster2008 Thursday, November 11, 2010 7:34 PM
    Tuesday, November 9, 2010 9:00 PM

All replies

  •  

    Hi,

    Security is not an issue here; keeping the properties private is a matter of hiding implementation details and safeguarding good programming practices. 

    How about returning a new object after update / save in the Datalayer? 

    Next to that, if you are using your objects as DTO's without any logic, why not keep them Simple. Only shield logic when there is any (ie, in a DDD design).

    Kind regards,
    Tom de Koning


    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    Monday, November 8, 2010 6:03 PM
  • Hi;

    Thanks Tom.

    Return an object was my intention but that's the problem, if the properties are read only I can't populate them because I have no access to the fields as I would if I was manipulating the object inside the same assembly.

    The objects will be used as DTO but I'm try to avoid scenarios like this one:

    I need a password to create an account. After that i can't retrieve the password and there will be a method to update it.

    So, the idea was to pass the password to the class constructor, keep it in a field and access it on the data layer.
    If i create a property "Password" property it will work however, every time the user load an account to edit or whatever else he will end up with this object with a read/write password property that does nothing. So, It will look messy and will require a lot of explaining.

    The idea is to keep the implementation elegant and clean but I'm starting to think that even though it looks the interesting, it's not what people usually do, right?

    Monday, November 8, 2010 7:50 PM
  • Hi,

    Well, to be honest your scenario needs a bit of explaining right now. It's not exactly clear to me. 

    The logic for setting a password should not be contained in properties, but in methods. If you need to have a DTO with a password set when you populate it from the database, just set it using a constructor in the entity.

    Kind regards,
    Tom de Koning


    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    Tuesday, November 9, 2010 5:35 AM
  • All right, let me try to make it clear. Maybe you can help me figure this out.

    I have 3 projects (3 dll's): Business Logic, Business Objects and Data Access.Besides pass data from one layer to the other the Business objects has some basic property validation such as max length, not empty, things like that.

    Take a look at the class on my first post, its my business object.
    You will notice the password and username are set in the constructor.
    However, the username is displayed through a read only property and the password just add to a "Friend" field.

    The intention is:

    1- The user create a new instance of the class setting username and password via constructor and than populate the other properties.
    2- The user call a "AddAccount" method from the "AccountManager" class which resides in the business logic layer (a different assembly). The"AddAccount" method will do all the validation and logic and them call the data layer passing the object along.
    3- Here comes the problem: To create a membership account the data layer needs access to the password, which is on a "Friend" field and not available since we are now outside the assembly.

    So, "looks like" a perfect setup: you set the username and password on a constructor when creating a new instance of the account.
    However, every time you use the "RetrieveAccount" as bellow:

    Dim account As UserAccount = UserAccountManager.RetrieveAccount(2010)
    

    You endup with a nice and clean "UserAccount" object where there is no password property, the "Id" and "CreationDate" fields are ready only and things like that. So, I don't need to document: "You can't change the id... bla bla bla". It's auto explanatory.

    But to setup this read only properties, "Id" and "CreationDate", I need access to the "Friend" backing fields when I'm retrieving the data on the data access layer, which I don't have anymore.

    I could just have a plain object with all these read/write properties and use some of them just when creating a new account. The problem is that when the user retrieves an account from the database he will have that empty password property (which was used just to carry the password when creating the account), so, it start to gets confuse and requires more documentation.

    As i said before, maybe I'm not seeing it though, maybe I'm trying the harder way. I'm Not sure.
    But the main idea is basic: hide "all the wires" from the users of the api the same way we did when we had everything in just one single project/class library. We simplify the documentation, the users endup with a more easy to use api and everybody is happy.

     

    Tuesday, November 9, 2010 6:31 AM
  • Just make a call to the DAL from the BL with DAL.CreateAccount(userName, password) which returns an Account instance. Then do the rest. You could of course also call the DAL with more parameters, but that makes no difference.

    Kind regards,
    Tom de Koning


    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    Tuesday, November 9, 2010 3:41 PM
  • I see, looks like I'm almost there. The password is inside the object but the BLL also can't retrieve it because there is no password property, it was passed through the constructor.
    So, I could change the password to the BLL "AddAccount" method. Doesn't look as good as expected but works:

    Dim newPassword as String = "123456"
    Dim account as new UserAccount(username)
    UserAccountManager.AddAccount(account, newPassword)
    
    Now the BLL has the username (through a read only property of the object) and the password and can send it to the DAL.

    The missing part now is: How can the DAL return this "UserAccount" object with it's read only property "ID" populated with the new ID, since it has no access tho the backing field. Not either does the BLL.

     

    Tuesday, November 9, 2010 8:36 PM
  •  

    The DAL must be able to create the Entity with the password. I would create a DTO in the DAL, store the password and other properties in there. Then create an interface that only allows read access to those properties.

    In the BLL create the Domain Entity that implements the interface. Now you can ask the DAL for IAcount and there you go.

    In c# this would look like:

    IAccount account = dal.CreateAccount(userName, password);

    The call in the BL would look like: 
    BllAccount restrictedAccount = dal.GetAccount(userName);

     

    Kind regards,
    Tom de Koning


    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    • Proposed as answer by Tom de Koning Tuesday, November 9, 2010 9:00 PM
    • Marked as answer by CodeMaster2008 Thursday, November 11, 2010 7:34 PM
    Tuesday, November 9, 2010 9:00 PM
  • I believe this is going to work.
    Thanks a lot for your help.

    Wednesday, November 10, 2010 4:07 PM
  • Hi,

    Glad to see that you found useful information, by the way, please remember to mark the replies as answers if they help and unmark them if they provide no help. This can be beneficial to other community members reading the thread.


    Sincerely,
    Eric
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Thursday, November 11, 2010 6:09 AM