Archive for August, 2008

How-to: Use the Disconnected Service Agent (DSA) with CompositeWPF (Prism)

A popular demand in Codeplex forums the past weeks has been related to working under temporarily connected scenarios. The Disconnected Service Agent Application Block that has been shipped with the SCSF since the May 2007 version was specially designed for this type of scenarios. Damian Schenkelman wrote a blog post overviewing the DSA to answer some of these questions.

Now that the Composite Application Guidance for WPF has been released, the issue became whether it was possible to use the DSA with Composite WPF. Therefore we decided to spend some time migrating the Disconnected Service Agent QuickStart from SCSF to its equal in Composite Application Library.

You can get the sample by downloading the latest change set of the CompositeWPF Contrib source control.

Using DSA in a Composite WPF application

All the Offline Blocks (Disconnected Service Agent, Endpoint Catalog and Connection Monitor) shipped with SCSF - May 2007 and higher versions do not have dependencies on CAB/SCSF.

To be able to use those blocks in a Composite WPF application you can do the following:

  1. Add the following configuration to the App.config file to configure the connection monitor and select the data storage that will be consumed by the DSA:
    <configuration>
      <configSections>
        <section name="ConnectionMonitor"
                 type="Microsoft.Practices.SmartClient.ConnectionMonitor.Configuration.ConnectionSettingsSection, Microsoft.Practices.SmartClient.ConnectionMonitor" />
        <section name="dataConfiguration"
                 type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data" />
      </configSections>
      <connectionStrings>
        <add name="QueueDatabase" connectionString="YourConnectionString" providerName="YourProvider" />
      </connectionStrings>
      <ConnectionMonitor>
        <Networks>
          <!– To check for internet connectivity–>
          <add Name="Internet" Address="http://www.google.com" />
        </Networks>
      </ConnectionMonitor>
      <dataConfiguration defaultDatabase="QueueDatabase">
        <providerMappings>
          <add databaseType="Microsoft.Practices.SmartClient.EnterpriseLibrary.SmartClientDatabase, Microsoft.Practices.SmartClient.EnterpriseLibrary"
               name="System.Data.SqlServerCe" />
        </providerMappings>
      </dataConfiguration>
    </configuration>

  2. Set up the Request Manager by overriding the ConfigureContainer method of your application’s Bootstrapper class.
    protected override void ConfigureContainer()
    {
        // Set up request manager.
        RequestManager requestManager = DatabaseRequestManagerIntializer.Initialize();
        requestManager.StartAutomaticDispatch();
    
        // Add the request queue to the Container. This queue will be used by service agents to enqueue requests.
        Container.RegisterInstance<IRequestQueue>(requestManager.RequestQueue, new ContainerControlledLifetimeManager());
    
        // Add the connection monitor to the Container. It will be used to determine connectivity status and provide    // feedback to the user accordingly.
        Container.RegisterInstance<IConnectionMonitor>(requestManager.ConnectionMonitor, new ContainerControlledLifetimeManager());
    
        base.ConfigureContainer();
    }

  3. Create an Agent service class that uses the IRequestQueue to define the offline behavior of your web service (in SCSF this is performed by the Create a Disconnected Service Agent recipe).
  4. Register an instance of your Agent class into your container. You can do this in your Module class.
    public void Initialize()
    {
        RegisterTypesAndServices();
    
        // Add your module views…
    }
    
    private void RegisterTypesAndServices()
    {
        Container.RegisterType<Agent>(new ContainerControlledLifetimeManager());
    }

Now you are able to inject your service agent in your classes.

Enjoy.

How To: Get the active view across multiple workspaces in a SCSF application

Last week I saw a question in the SCSF forum about getting the active view in an application with several types of workspaces. In his post CAB: Solving The Active View Problem, Chris Holmes tackles the scenario within the context of a single workspace. I found a way to apply another solution that gets the Active View by monitoring all workspaces. I created the ActiveViewMonitorService service that is in charge of doing this.

I made a sample application that shows how this service works. Download from here.

Change the application’s active view by clicking in the TextBox of each view. Then click in the Active View button in the main menu bar to verify the active view’s name.

Implementation Details

The ActiveViewMonitorService service monitors the SmartPartActivated and Enter events for each workspace in the application. The SmartPartActivated allows to know when the user is changing the active view in the context of the same workspace and the Enter event allows to know when the user is changing to a view in another workspace. The following is the service implementation:

public interface IActiveViewMonitorService
{
    void AddWorkspaceToMonitor(IWorkspace workspace);
    object ActiveView { get; }
}

public class ActiveViewMonitorService : IActiveViewMonitorService
{
    #region IActiveViewMonitorService Members

    public void AddWorkspaceToMonitor(IWorkspace workspace)
    {
        workspace.SmartPartActivated += new EventHandler<WorkspaceEventArgs>(OnSmartPartActivated);
        ActiveView = workspace.ActiveSmartPart;

        Control wk = workspace as Control;
        if (wk != null)
        {
            wk.Enter += new EventHandler(OnEnter);
        }
    }

    public object ActiveView { get; private set; }

    #endregion

    private void OnSmartPartActivated(object sender, WorkspaceEventArgs e)
    {
        ActiveView = e.SmartPart;
    }

    private void OnEnter(object sender, EventArgs e)
    {
        IWorkspace wk = sender as IWorkspace;

        if (wk != null)
        {
            ActiveView = wk.ActiveSmartPart;
        }
    }
}

Steps

  1. Register it as a service in the RootWorkItem.
  2. Add the workspaces you want to monitor using the AddWorkspaceToMonitor method (you can do this by adding an event handler to the Initialized event of the RootWorkItem in the ShellApplication class).
    // ShellApplication class
    protected override void AfterShellCreated()
    {
        RootWorkItem.Initialized += new EventHandler(RootWorkItem_Initialized);
    }
    
    private void RootWorkItem_Initialized(object sender, EventArgs args)
    {
        IActiveViewMonitorService activeViewMonitorService = RootWorkItem.Services.Get<IActiveViewMonitorService>();
    
        foreach (KeyValuePair<string, IWorkspace> key in RootWorkItem.Workspaces)
        {
            activeViewMonitorService.AddWorkspaceToMonitor(key.Value);
        }
    }

  3. Get the active view using the ActiveView property of the service.
Note: The ActiveViewMonitorService service accepts Workspaces that inherit from the Control class.

Enjoy

Technorati Tags: ,