Easiest way to pass userid from Shell to View in business module

Topics: CAB & Smart Client Software Factory
Feb 28, 2007 at 12:46 PM
I am working on adding some simple authentication to our SCSF application. The user will log on prior to the the shell loading any of our business modules, as the user's security template will dictate which of our modules that user will see. Also, there are specific security considerations to take into account within the View of each module (certain options within each module can be disabled based on security). So what I am looking for is the best place to store or provide access to the UserId that was used authenticated and make it easily accessable inside the code of my UserControls. I've been looking at services and I'm assuming that I should somehow be able to utilize those to do this, but I have had a hard time finding examples of how to get that type of information from the Shell into my code of the UserControl (most of the examples I've seen show how to interact with the Shell's UI). Or is there a way to access the rootWorkItem from within my code for the UserControl and utilize the .state of the rootWorkItem to hold that information? I am fairly new to .NET so any insight/examples would be great.
Developer
Feb 28, 2007 at 2:30 PM
Edited Feb 28, 2007 at 2:39 PM
Hi, typically Thread.CurrentPrincipal is used to that purpose.

In SCSF you can create your AuthenticationService (implementing the IAuthenticationService interface) so you can do something like that:


public void Authenticate()
{
      IUserData user = _userSelector.SelectUser();
 
      if (user != null)
      {
            GenericIdentity identity = new GenericIdentity(user.Name);
 
            GenericPrincipal principal = new GenericPrincipal(identity, user.Roles);
 
            Thread.CurrentPrincipal = principal;
      }
      else
      {
            throw new AuthenticationException(Resources.NoUserProvidedForAuthentication);
      }
}

Take a look at BankBranchWorkbench application (included in SCSF). This application implements an Authentication Service, and also uses the ActionCatalog to implement a roles-based UI. (ms-help://ms.scsf.2006jun/SCSF/html/03-130-Action%20Catalog.htm)

Let me know if this helps,

Ezequiel Jadib
http://staff.southworks.net/blogs/ejadib
Feb 28, 2007 at 2:53 PM

Seritus wrote:
Or is there a way to access the rootWorkItem from within my code for the UserControl?


Yes, you can do that. That is what we do in our application.

In our application we have a need for more information than just a UserID. We like to have the EmployeeName of the person logged on, and their EmployeeID as well, because it is used to access certain data depending on which modules they have access to. So we wrap those fields into a custom readonly business object and then store it in the RootWorkItem under a strong name. Subsequent WorkItems and Presenters throughout the application then have access to this readonly object via dependency injection.

Code follows:

public class AuthenticationService : IAuthenticationService
    {
        private WorkItem _workItem;
 
        public AuthenticationService([ServiceDependency] WorkItem workItem)
        {
            _workItem = workItem;
        }
 
        #region IAuthenticationService Members
 
        public void Authenticate()
        {
            LoginView view = _workItem.SmartParts.AddNew<LoginView>();
 
            view.StartPosition = FormStartPosition.CenterScreen;
            view.ShowDialog();
 
            if (view.DialogResult != DialogResult.OK)
            {
                Environment.Exit(0);
            }
        }
 
        #endregion
    }

This is what our AuthenticationService looks like. It creates the Login view which is a classic View/Presenter pair. The Presenter gets dependency injected with the Root WorkItem and our real authentication service. The Presenter's constructor looks like this:

public LoginViewPresenter(
            [ServiceDependency] WorkItem rootWorkItem,
            [ServiceDependency] IGenericPrincipalAuthenticationService authenticationService)
        {
            RootWorkItem = rootWorkItem;
            _authenticationService = authenticationService;
        }

The Service is responsible for authenticating against a database. It returns an AuthenticationResponse object (our own make) that contains the authentication result and the readonly object, which we call UserData. If the person was authenticated, the code looks like this:

if (response.IsAuthenticated)
            {
                AppDomain currentDomain = AppDomain.CurrentDomain;
                
                IIdentity identy = new GenericIdentity(username);
                IPrincipal principal = new GenericPrincipal(identy, response.Roles);
                currentDomain.SetThreadPrincipal(principal);
 
                RootWorkItem.Items.Add(response.UserData, BusinessEntityNames.UserData);
                
                _view.ReturnOK();
            }

As you can see in the second-to-last line of code, the RootWorkItem gets a new item added to its collection, a UserData object and we give it a strong name of BusinessEntityNames.UserData.

Now we have a Presenter in a Module somewhere, and it can get that data through constructor injection (or property injection if you prefer) by doing the following:

 
    private UserData _userData;
 
    public MyPresenter([Dependency(Name = BusinessEntityNames.UserData)] UserData userData)
    {
        _userData = userData;
    }


Hope that helps :)
Jan 12, 2009 at 10:08 PM
Hi Chris,

Where did you put your LoginView? I wanted to to create a separate module for authentication but read your post on another thread that this is not a good idea.