Creating a Custom Administration Setting

Creating a Custom Administration Setting

  • Comments 8
  • Likes

Introduction

Most of our ISV Partners will need to provide some custom administration settings to allow their customers to configure the partners' solutions. For example, you may want to store a server name and database name to connect to as part of a workflow and then access that information at the time the workflow runs. As a partner you would want to make it easy for your customers to edit this configuration and do so in a way that is consistent with the rest of the Service Manager product.

The Settings view in the Administration workspace is the "catch all" view for Service Manager administrators to view these kinds of settings. Out of the box, we put things like grooming settings, incident management settings like the Target Time to Resolution settings, and many others in this view.

The question is – "How do I add my own custom settings to this view and provide a user experience for administrators to get/set these settings?"

Starting with the End in Mind

This is what we are trying to achieve:

  • A row in the Settings view that the user can either select and click Properties for in the task pane or can double click on
  • When the user clicks Properties or double clicks a custom form pops up to capture the user input in the Service Manager database
  • The data is stored as properties of an object so that it is easy to access and store

This is what the user experience looks like:

When the user double-clicks or clicks Properties:

Implementation

First we need to create a management pack with our new Admin Setting class in it. If we derive from System.SolutionSettings our item will automatically show up in the Settings view. Further, since we aren't going to be creating multiple instances of this class we should set it to Singleton="true". For this demo, I'm adding a couple of basic properties creatively named Property1 and Property2.

<ClassType ID="Microsoft.Demo.AdminSetting.Example"

Accessibility="Public"

Abstract="false"

Base="AdminItem.Library!System.SolutionSettings"

Hosted="false"

Singleton="true"

Extension="false">

<Property ID="Property1"

Type="string"

AutoIncrement="false"

Key="false"

CaseSensitive="false"

MaxLength="256"

MinLength="0"

Required="false"

/>

<Property ID="Property2"

Type="string"

AutoIncrement="false"
Key="false"

CaseSensitive="false"

MaxLength="256"

MinLength="0"

Required="false"

/>

</ClassType>

Then we need to define a console task handler so that when the user clicks the Properties link in the task pane our form will come up. Notice how the task is targeted at our singleton class. It will call the class in the referenced assembly which I'll show you in a minute.

<ConsoleTask ID="ConsoleTask.Microsoft.Demo.AdminSetting.Example.Edit"

Accessibility="Public"

Enabled="true"

Target="Microsoft.Demo.AdminSetting.Example" RequireOutput="false">

<Assembly>Console!SdkDataAccessAssembly</Assembly>

<Handler>

Microsoft.EnterpriseManagement.UI.SdkDataAccess.ConsoleTaskHandler

</Handler>

<Parameters>

<Argument Name="Assembly">AdminSettingsExample</Argument>

<Argument Name="Type">

Microsoft.Demo.AdminSettings.AdminSettingsExample

</Argument>

</Parameters>

</ConsoleTask>

Then we need to set a couple of categories:

<Category ID="Category.DoubleClickEditAdminSetting"

Target="ConsoleTask.Microsoft.Demo.AdminSetting.Example.Edit" Value="Console!Microsoft.EnterpriseManagement.ServiceManager.UI.Console.DoubleClickTask" />

<Category ID="SCSMMPCategory"

Value="Console!Microsoft.EnterpriseManagement.ServiceManager.ManagementPack">

<ManagementPackName>Microsoft.Demo.AdminSettings</ManagementPackName>

<ManagementPackVersion>7.0.5244.0</ManagementPackVersion>

The first one tells Service Manager that when the singleton class object is selected in the Settings view that the doubleclick task is the one defined in this management pack.

The second one tells Service Manager that this is an MP intended to be used in Service Manager. This is necessary to make sure that the console task shows up in the Service Manager console.

Then of course we add the usaul Language Pack stuff. I won't go over that again, but remember there is more information on localizing management packs if you need it.

That's it for the management pack. Now let's take a look at the form – it's really easy. All I did was add a new WPF User Control to my project and then changed it to derive from wpfwiz:WizardRegularPageBase.

<wpfwiz:WizardRegularPageBase x:Class="Microsoft.Demo.AdminSettings.AdminSettingConfigurationPage"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:local="clr-namespace:Microsoft.Demo.AdminSettings"

xmlns:wpfwiz="clr-namespace:Microsoft.EnterpriseManagement.UI.WpfWizardFramework;assembly=Microsoft.EnterpriseManagement.UI.WpfWizardFramework" Loaded="WizardRegularPageBase_Loaded">

<Grid Name="ConfigurationGrid" Margin="15,25,15,25">

<ScrollViewer Margin="0,50,0,50" Name="scrollViewer" CanContentScroll="True" VerticalScrollBarVisibility="Auto">

<StackPanel Name="stackPanel" Orientation="Vertical">

<Label Height="25" Padding="0" Margin="0,0,0,0" Name="displayamelabel" Content="Property 1:"/>

<TextBox Height="25" Margin="0,-8,0,10" Name="displaynameTextBlock">

<TextBox.Text>

<Binding Path="Property1" Mode="TwoWay" FallbackValue=""/>

</TextBox.Text>

</TextBox>

<Label Height="25" Padding="0" Margin="0,0,0,0" Name="datafilepathLabel" Content="Property 2:"/>

<TextBox Height="25" Margin="0,-8,0,10" Name="domainTextBlock">

<TextBox.Text>

<Binding Path="Property2" Mode="TwoWay" FallbackValue=""/>

</TextBox.Text>

</TextBox>

</StackPanel>

</ScrollViewer>

</Grid>

</wpfwiz:WizardRegularPageBase>

There is a very small amount of code behind that we need to put into the .cs file that is associated with this .xaml file. You'll see that this implementation is very similar to the task handler provided in the CSV Connector example. We are using the same concept of a "Wizard" in property page mode to display the UI to get/set the property values.

public partial class AdminSettingConfigurationPage : WizardRegularPageBase

{

private AdminSettingWizardData adminSettingWizardData = null;

public AdminSettingConfigurationPage(WizardData wizardData)

{

InitializeComponent();

this.DataContext = wizardData;

this.adminSettingWizardData = this.DataContext as AdminSettingWizardData;

}

private void WizardRegularPageBase_Loaded(object sender, RoutedEventArgs e)

{

}

}

This code simply binds the WizardData object to the form as part of the constructor. Now let's look at the task handler code and associated WizardData class. The only tricky/new part of this is highlighted below in the code comments.

namespace Microsoft.Demo.AdminSettings

{

public class AdminSettingsExample : ConsoleCommand

{

public AdminSettingsExample()

{

}

public override void ExecuteCommand(IList<NavigationModelNodeBase> nodes, NavigationModelNodeTask task, ICollection<string> parameters)

{

/*

This GUID is generated automatically when you import the Management Pack with the singleton admin setting class in it.

You can get this GUID by running a query like:

Select BaseManagedEntityID, FullName where FullName like '%<enter your class ID here>%'

where the GUID you want is returned in the BaseManagedEntityID column in the result set

*/

String strSingletonBaseManagedObjectID = "79893B9E-04AC-9D3A-51D8-B085BEE6EA78";

//Get the server name to connect to and connect to the server

String strServerName = Registry.GetValue("HKEY_CURRENT_USER\\Software\\Microsoft\\System Center\\2010\\Service Manager\\Console\\User Settings", "SDKServiceMachine", "localhost").ToString();

EnterpriseManagementGroup emg = new EnterpriseManagementGroup(strServerName);

//Get the Object using the GUID from above - since this is a singleton object we can get it by GUID

EnterpriseManagementObject emoAdminSetting = emg.EntityObjects.GetObject<EnterpriseManagementObject>(new Guid(strSingletonBaseManagedObjectID), ObjectQueryOptions.Default);

//Create a new "wizard" (also used for property dialogs as in this case), set the title bar, create the data, and add the pages

WizardStory wizard = new WizardStory();

wizard.WizardWindowTitle = "Edit Admin Setting";

WizardData data = new AdminSettingWizardData(emoAdminSetting);

wizard.WizardData = data;

wizard.AddLast(new WizardStep("Configuration",

typeof(AdminSettingConfigurationPage), wizard.WizardData));

//Show the property page

PropertySheetDialog wizardWindow = new PropertySheetDialog(wizard);

//Update the view when done so the new values are shown

bool? dialogResult = wizardWindow.ShowDialog();

if (dialogResult.HasValue && dialogResult.Value)

{

RequestViewRefresh();

}

}

}

class AdminSettingWizardData : WizardData

{

#region Variables

private String strProperty1 = String.Empty;

private String strProperty2 = String.Empty;

private Guid guidEnterpriseManagementObjectID = Guid.Empty;

public String Property1

{

get

{

return this.strProperty1;

}

set

{

if (this.strProperty1 != value)

{

this.strProperty1 = value;

}

}

}

public String Property2

{

get

{

return this.strProperty2;

}

set

{

if (this.strProperty2 != value)

{

this.strProperty2 = value;

}

}

}

public Guid EnterpriseManagementObjectID

{

get

{

return this.guidEnterpriseManagementObjectID;

}

set

{

if (this.guidEnterpriseManagementObjectID != value)

{

this.guidEnterpriseManagementObjectID = value;

}

}

}

#endregion

internal AdminSettingWizardData(EnterpriseManagementObject emoAdminSetting)

{

//Get the server name to connect to and connect

String strServerName = Registry.GetValue("HKEY_CURRENT_USER\\Software\\Microsoft\\System Center\\2010\\Service Manager\\Console\\User Settings", "SDKServiceMachine", "localhost").ToString();

EnterpriseManagementGroup emg = new EnterpriseManagementGroup(strServerName);

//Get the AdminSettings MP so you can get the Admin Setting class

ManagementPack mpAdminSetting = emg.GetManagementPack("Microsoft.Demo.AdminSettings", null, new Version("1.0.0.0"));

ManagementPackClass classAdminSetting = mpAdminSetting.GetClass("Microsoft.Demo.AdminSetting.Example");

this.Property1 = emoAdminSetting[classAdminSetting, "Property1"].ToString();

this.Property2 = emoAdminSetting[classAdminSetting, "Property2"].ToString();

this.EnterpriseManagementObjectID = emoAdminSetting.Id;

}

public override void AcceptChanges(WizardMode wizardMode)

{

//Get the server name to connect to and connect

String strServerName = Registry.GetValue("HKEY_CURRENT_USER\\Software\\Microsoft\\System Center\\2010\\Service Manager\\Console\\User Settings", "SDKServiceMachine", "localhost").ToString();

EnterpriseManagementGroup emg = new EnterpriseManagementGroup(strServerName);

//Get the AdminSettings MP so you can get the Admin Setting class

ManagementPack mpAdminSetting = emg.GetManagementPack("Microsoft.Demo.AdminSettings", null, new Version("1.0.0.0"));

ManagementPackClass classAdminSetting = mpAdminSetting.GetClass("Microsoft.Demo.AdminSetting.Example");

//Get the Connector object using the object ID

EnterpriseManagementObject emoAdminSetting = emg.EntityObjects.GetObject<EnterpriseManagementObject>(this.EnterpriseManagementObjectID, ObjectQueryOptions.Default);

//Set the property values to the new values

emoAdminSetting[classAdminSetting, "Property1"].Value = this.Property1;

emoAdminSetting[classAdminSetting, "Property2"].Value = this.Property2;

//Update Connector instance

emoAdminSetting.Commit();

this.WizardResult = WizardResult.Success;

}

}

Deploying this Solution

In order to deploy this solution you need to import the management pack .xml file and copy the AdminSettingsExample.dll file to the %ProgramFiles%\Microsoft System Center\Service Manager 2010 directoy on all computers that will be accessing this form. That .dll contains the task handler code and the XAML form.

Conclusion

Now you know how to:

  • create your own singleton class,
  • host it in the Administration workspace Settings view,
  • add a double-click task handler,
  • use the wizard framework to display a custom form to the user,
  • create a simple custom form using XAML,
  • display the form to the user using a custom task handler

The solution files are here:

http://cid-17faa48294add53f.skydrive.live.com/self.aspx/.Public/AdminSettingsExample.zip

Follow me on Twitter:

http://twitter.com/radtravis

 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Dear Travis,

    I'm creating a wizard consisting of multiple custom forms which is feasible thanks to your above instruction. When navigating from one form to another within the wizard using built-in Next buttons of the wizard, I'm struggling to find the events when these buttons are clicked so that I can validate the data of previous forms to meet business rules

    Please help with details on how I can capture the event when Next/Previous button is clicked

    Thank you very much. Highly appreciate your help

    Nga

  • @Nga -

    I dont know that we have a event handler for the Next button click event.  Instead we try to proactively validate the form as the user is filling it out.  You can hook various other events on the form and perform a validation.  When the form meets your business logic, then you can change .IsNextButtonEnabled = true.

    Hope that helps!

  • Thanks Travis, we found ways around with LoadState and SaveState event for validation

    Cheers,

    Nga

  • Hi Travis,

    I'm trying to do this using the 2010 Authoring Tool... I've been able to create the form but I'm missing the part where I have to create the dll (assembly).

    Do I have to install Visual Studio and create a C# project to create the dll file?

    I'm actually building an improved version of SLA Management... and I have everything working but this.

    Thanks in advance!

    German.

  • @German Minicucci

    Hi German - sorry for the delayed response. I'm on week 4 of a 4 week world tour for SCSM now and it's been hard to keep up.  It's probably not necessary to write cod to have a settings dialog, but it is an option.  Please send me an email at scsmbeta [at] live [dot] com with some more details on what you are trying to do and I'll try to make a recommendation.

  • Hi Travis,

    How can I call my wizard(same as yours) in the management pack?

  • But Great Post! Saved me a lot of time. Thanks.

  • Solution file is gone :(