Smart Client Factory + ModuleLoadException

Topics: CAB & Smart Client Software Factory
Oct 31, 2007 at 12:05 PM
Edited Oct 31, 2007 at 12:07 PM
I added a business module (Login module) to a solution that was created using Smart Client Factory. I made sure to include the <ModuleInfo AssemblyFile="LoginModule.dll" />
in the ProfileCatalog.xml file. I am getting the following exception when I am running the application:

An unhandled exception of type 'Microsoft.Practices.CompositeUI.Services.ModuleLoadException' occurred in Infrastructure.Library.dll

Additional information: Failed to load module from assembly f1f4aeb5-23fa-4693-96d0-25bec1eb7e62. Error was:
Failed to load module from assembly Infrastructure.Layout, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null. Error was:
Exception has been thrown by the target of an invocation.


I tried tracing the code and found out that this error is occuring in the ModuleController.cs file included in the LoginModule, in the AddViews method.
Actually I have the following in the AddView Method:

LoginView view = WorkItem.SmartParts.AddNew<LoginView>();
WorkItem.WorkspacesWorkspaceNames.ModalWindows.Show(view); //the exception is occuring when this line is being executed

What could the problem be?
I need help because I am stuck!

Best Regards,
Lara
Nov 1, 2007 at 7:02 PM
Hi

Please, make sure that you have assigned the ModalWindows constant name to a Workspace. In a new SCSF solution, this constant is defined at the Infrastructure.Interface project, but it isn’t assigned to any Workspace at all.

If you are intending to load this view as a modal window, try the following steps:
  • In the AfterShellCreated() method in the ShellApplication.cs, add a WindowWorkspace, like this:
WindowWorkspace myWindowWorkspace = new WindowWorkspace(this.Shell);   //this line creates a new WindowWorkspace and sets its “ownerForm” to the Shell.
RootWorkItem.Workspaces.Add(myWindowWorkspace, WorkspaceNames.ModalWindows); //this line adds myWindowWorkspace to the RootWorkItem and sets its name to the constant ModalWindows
  • In the ModuleController.cs, add the following using statements:
using MyProject.LoginModule.Constants; //contains the ModalWindows constant (among others)
using Microsoft.Practices.CompositeUI.WinForms; //contains WindowSmartPartInfo
  • In the AddViews() method in the ModuleController.cs, add the LoginView with WindowSmartPartInfo, so that you can set the property Modal to true:
LoginView view = WorkItem.SmartParts.AddNew<LoginView>();
WindowSmartPartInfo myWindowSmartPartInfo = new WindowSmartPartInfo();
myWindowSmartPartInfo.Modal = true; //setting the Modal property to true
WorkItem.RootWorkItem.Workspaces[WorkspaceNames.ModalWindows].Show(view, myWindowSmartPartInfo);
Please let me know if this helps.

Ignacio Baumann Fonay
http://staff.southworks.net/blogs/ibaumann/
Nov 2, 2007 at 7:05 AM
Thank you Ignacio for your help, the error is resolved now :)

I am still new to Smart Client Factory and I am trying to build up a small shell.
I created a new solution using Smart Client Factory and added a business module called Login Module which contains the LoginView.
The LoginView consists of:
3 fields: username, password and domain
2 buttons: login and cancel

I want to be able to access the ShellForm only when I click on the Login button and the user is authenticated.
However in my case, if I click on the Login button, the Cancel button or event if I close the LoginView (by clicking on the x button up, for exiting the window) , the ShellForm will appear (is this due to the LoginView being modal, having as parent the ShellForm?)
How can I solve this issue, thus not allowing the ShellForm to appear if I click on Cancel or exit the window?

Thank you again for your help,
Lara

Nov 14, 2007 at 7:36 PM
Hi

Please have a look at the BankBranchWorkbench.sln RI implementation. The SmartClientApplication.cs class (in the *Source.Infrastructure.Library * project) adds to the RootWorkItem the SimpleWinFormAuthenticationService. This service uses the UserSelectorService.cs class which uses the UserSelectionForm form. The form contains the verification of the user behind the okButtonClick eventhandler, returning DialogResult.Ok if everything is ok.

Please let me know if this helps.

Ignacio Baumann Fonay
http://staff.southworks.net/blogs/ibaumann/
Nov 28, 2007 at 3:25 PM
Hi Ignacio,

I'm pretty new to SCSF / CAB and I must admit I am finding it hard work to get my head round it all. I've just looked at the SimpleWinFormAuthenticationService example and I thought you would have to go down the MVP route i.e. when the user clicks OK it calls the presenter to validate the user rather than including the business logic ( UserData match = Array.Find<UserData>(_users, delegate(UserData test) ) in the form.

I need something similar but I'm confused on which route to go down:

The plan is to have a "simple" service which is dynamically loaded and when the user clicks on a tab in the OutlookBarWorkSpace it calls my service to see if I'm authenticated, if not then it will pop up a modal window asking the user for their details, this in turn will then call some external webservice.

I managed to get a ModalWindow working ok (but I frigged the DialogResult by providing it as an interface to the view - which obviosuly don't come as default).

In this respect is it too much work to go down the MVP route or should I just use something similar to your example.

Appreciate any help you can give as I'm going crazy :-)

Regards

Steve
Nov 28, 2007 at 6:22 PM


Ok I think I've finally got my head round it. In the end I went for the MVP approach, the tricky part for me was to get the Modal window working (and closing correctly). When the user clicks “OK” it calls the presenter, which then calls a web service to validate the user. If the user is valid then the presenter will also close the view. The OK button has its DialogResult set to none in the designer and the Cancel button has the DialogResult set to “Cancel” (which will in turn close the view anyway but I may change this so the presenter does all the closing).

The solution (I could do with an expert saying yeah that's ok or no you've done it wrong dumbo!)

The interface for the view is:

public interface ILogonView
{
bool IsAuthenticated();
}


In my service implementation the view is called via:

ILogonView logonView = null;

// work out if we need to add the smart part of get an existing one, via the view key
if (_parentWorkItem.RootWorkItem.SmartParts.Contains(LogonViewKey) == false)
{
logonView = _parentWorkItem.RootWorkItem.SmartParts.AddNew<LogonView>(LogonViewKey);
}
else
{
logonView = _parentWorkItem.RootWorkItem.SmartParts.Get<LogonView>(LogonViewKey);
}

DialogSmartPartInfo myWindowSmartPartInfo = new DialogSmartPartInfo("Some Title");
_parentWorkItem.RootWorkItem.WorkspacesWorkspaceNames.ModalWindows.Show(logonView, myWindowSmartPartInfo);


// Here I can then call IsAuthenticated which is an interface of ILogonView, this then will call the actual view, which will then get the value from the presenter.


The presenter looks like:

public partial class LogonViewPresenter : Presenter<ILogonView>
{
private bool _isValidUser = false;

/// <summary>
/// This method is a placeholder that will be called by the view when it has been loaded.
/// </summary>
public override void OnViewReady()
{
base.OnViewReady();
}

/// <summary>
/// Close the view
/// </summary>
public void OnCloseView()
{
base.CloseView();
}

/// <summary>
///
/// </summary>
/// <param name="userName"></param>
/// <param name="password"></param>
/// <returns></returns>
public bool ValidateUser(string userName, string password)
{
// we set this here rather than in the form, here we would then call our web service, db lookup, active directory etc ... for this example we'll return true!

_isValidUser = true;

OnCloseView();

// return the result
return _isValidUser;
}

/// <summary>
/// This is called FROM the form via the ILogonView interface
/// </summary>
public bool IsValidUser
{
get { return _isValidUser; }
}

}

The code for DialogSmartPartInfo is:

/// <summary>
/// SJG, this will give us a Modal Window at all times
/// Taken from: http://www.cabpedia.com/index.php?title=Consistentmodaldialogs
/// </summary>
public class DialogSmartPartInfo : WindowSmartPartInfo
{
public DialogSmartPartInfo(string windowsTitle)
{
Modal = true;
MaximizeBox = false;
MinimizeBox = false;
ControlBox = false;

Title = windowsTitle;

Keys.Add(WindowWorkspaceSetting.StartPosition, FormStartPosition.CenterParent);
Keys.Add(WindowWorkspaceSetting.FormBorderStyle, FormBorderStyle.FixedDialog);

}
}

Hope all that makes sense and is the right way of doing it. If anyone's interested I'll post an example but for today I've had enough of computers .. time to open the wine.

Cheers

Steve

Jan 4, 2008 at 5:50 PM
Edited Jan 4, 2008 at 5:52 PM
Can anyone help me solving my problem? I have been away from that and now I am back.

My ShellApplication.cs file is declared as follows:
class ShellApplication : SmartClientApplication<WorkItem, MainForm>

I added a LoginModule and set its view to be a ModalWindow.
My problem is that I have to call a host to get necessary information to display in my MainForm onLoad, however this should be done after the user logging in is authenticated.
Thus when I run my application, the Login window is shown at first but the background code of the MainForm is being executed since the MainForm is being loaded before the LoginModule due to the fact that it is specified in the declaration of the ShellApplication class.

How can I solve this problem? How can I let the code in the load of the MainForm executes right after the user is authenticated? The Login module specified in the ProfileCatalof file is loaded after the MainForm is loaded however it is showing first because it is displayed as Modal. Please do help me.
Best Regards!