Global User object and multiple applications

Global User object and multiple applications

Old forum URL: forums.lhotka.net/forums/t/2008.aspx


applecran posted on Tuesday, December 19, 2006

I'm hoping someone can point me in the right direction on how to solve a problem i'm having.

I'm in the middle of creating a framework for our company that currently has multiple custom apps, each with their own security DB and settings etc, but for the same users across all apps. 

So we are creating a centeral security/profile db and integrating it with the apps.

We are starting by upgrading an asp app to asp.net and I am now integrating CSLA.NET into what little code I already have.

 I have a CommonUser Object that has the User's info and profile etc in it.  My plan was to inherit from this object in each of my applications and just add the extra properties that I would need that are specific to each of these applications, just want to have some code re-use.

My first problem is with something as simple as loging in.  I have a Login Function on my CommonUser object that is static and returns a CommonUser object using the DataPortal_Fetch() function.  That works fine.

The problem is that really I don't want other developers to have to deal with the CommonUser object and I was going to put a Login Function on my CustomAppUser Object that would call the base class (CommonUser) login function.  But I don't think this will work.

I'm just not sure that inheritance is the best way to do this, and if it is, i'm not sure how I should implement this login process as I really want to keep the CommonUser dataaccess etc in that object and have seperate data access for the customAppUsers in each CustomApp.

Here is what I was going to do

[Serializable()]
public class CommonUser : BusinessBase<CommonUser>

{

   protected GUID _id;
   protected string _username;
   protected string _password;
   //assocated public properties would be available


   protected static CommonUser Login(sting username, string password)
   {
            return DataPortal.Fetch<CommonUser>(new LoginCriteria(username, password));
   }

   private void DataPortal_Fetch(Criteria criteria)
   { 
         //fill up the object
   }

}

 

public class AppUser : CommonUser
{
   private string _AppUserProperty
   //apropriate public properites would go with these appuser properties

   public static AppUser Login(UserName, Password)
   {
         //this is where i'm not sure what to do.

         option 1. 

         AppUser user = (AppUser) base.Login(username, password);

         user.Fill() //some private method that then fills up the app specific properties with anther DB call
   }

}

Am i going about this all wrong?

Any help is appreciated.

 

SonOfPirate replied on Tuesday, December 19, 2006

The way you've described it isn't all bad.

What you don't show is that you'll have to override the DataPortal_x methods in your AppUser class in order to incorporate any additional properties that will be passed to/from the database.  (Unless you use a CommandBuilder/DataMapper to handle that.) 

I'm concerned that perhaps you should make the CommonUser class generic?  I would have to retrace the DataPortal code, but I believe that the statement: DataPortal_Fetch<CommonUser>(...) will cause the data portal to instantiate an object of type CommonUser.  You obviously want this to be AppUser or the returned object will be CommonUser and you'll get casting errors as soon as you try working with it as an AppUser.

One other thing to consider, find a different name or signature for the base class Login method.  You'll get compiler warnings because you can't override static methods so you'll be prompted to add the "new" keyword to your declaration.  I tend to use the prefix "Perform" or "Execute" for my base class methods like this.  So, you'd have CommonUser.PerformLogin(username, password).

Consider making CommonUser abstract as well.  Just to satisfy a couple of those OOP rules floating around out there...

HTH

applecran replied on Tuesday, December 19, 2006

Yes for the AppUser I was thinking of this

 public static AppUser Login(UserName, Password)
   {
          AppUser user = (AppUser) base.Login(username, password);

         user.Fill() //some private method that then fills up the app specific properties with another    DB call
   }

So there I will be casting the CommonUser that is returned by base.Login to an AppUser (I think that will work).  I'm not sure if that stops the need for the CommonUser to be generic.

If I were to make common user generic how would that be declared.  Sorry for what is probably an entry level question but this is my first time really working with Generics and with CSLA.

Now, my Fill function would call my DataPortal_Fetch method I guess.  This is really where my confusion lies.  Do I want to call the base.Login function and then the DataPortal_Fetch on the AppUser?  Is that even possible since the DataPortal.Fetch<object>(Criteria()) function creates a new instance of the object? 

I'm jsut not sure where how to go about creating the object and how the DataPortal_xxxxx functions will work since I would already have an object from the base.Login() function.

By making the CommonUser class abstract though, I would not be able to instantiate an instance and this could be problematic because I will also have a management app that will allow users porofiles etc. to be updated and added to applications.  This will be at the CommonUser level so I think I would need to be able to instantiate these users.

I'll deffinately consider renaming my functions as that could be quite annoying.

Thanks for taking the time to help me with this.

 

SonOfPirate replied on Tuesday, December 19, 2006

Here's how it works:

You call AppUser.Login(username, password).  Execution then passes to your CommonUser base class Login method which calls DataPortal.Fetch(...)  When control reaches the data portal server (SimpleDataPortal), a new instance of your object will be instantiated and its DataPortal_Fetch method called.

I checked the source code and the Criteria object that you pass to DataPortal.Fetch is what controls the data type of the class that is instantiated.  If the object is derived from Criteria, then Criteria.ObjectType defines what type if created.  Otherwise, the same type as the criteria argument is created.

So, to ensure that you instantiate an AppUser object instead of CommonUser, you'll need to make sure that the ObjectType of the LoginCriteria object is set to AppUser.  Maybe add the type as a parameter to the constructor and pass it to the CommonUser.Login method.

This would also allow you to avoid working with generics if you're not familiar with them.

Make your DataPortal_Fetch method protected virtual in the CommonUser class and handle the properties you have defined in that class.  Then override this method in AppUser, handle the additional properties and defer back to the base.DataPortal_Fetch so that CommonUser can do its thing.

Once the DataPortal_Fetch method returns, the new object will be passed back through the data portal to your Login method where you can cast it to AppUser and work with it as desired.

HTH

 

 

applecran replied on Thursday, December 21, 2006

Thanks SonOfaPirate.

That really helps.

I ended up doing it slightly differently because once I got the the casting to AppUser part, I was getting a cast exception. 

What I ended up doing is this:

  public static AppUser Login(sting username, string password)
   {
            return DataPortal.Fetch<AppUser>(new LoginCriteria(username, password, Type.GetType("AppUser")));
   }

   protected override void DataPortal_Fetch(LoginCriteria criteria)
   { 

      //call the CommonUser dataportal_fetch and have that class fill it's own proeprties
       base.DataPortal_Fetch(criteria);

         //deal with the appuser properties.
   }

 

The LoginCriteria is defined within the commonuser class and inherties from CriteriaBase so that I can pass in the type that is actually needed just to make sure there are no problems.

This seems to work and I think it is flowing through the csla framework properly without going back and forth through the dataportal uneccesarily (i traced it in debugging).

If there is a better way or someone has another idea then that would be great.

I'll need to do simmilar processes for the other DataPortal_xxxxx functions depending on what I want to do as I may not want a delete call in the appuser to do a delete or anything for that matter in the commonUser.

Thanks again.

SonOfPirate replied on Thursday, December 21, 2006

Looks like you've got it.

 

Copyright (c) Marimer LLC