Introduction
The goal of this article is to provide a simple example of a method to manage settings in a Windows Service using WCF.
My first attempt to solve this situation was to develop a small Windows Dorms application which would directly edit the service EXE config file. I finally found it much more elegant to let the service itself deal with the settings savings, and provide a small WCF service inside of it to expose functionalities to my Windows Forms application.
P.S.: this is my first article, and I apologize for my rough English...
Background
This code makes use of a very basic implementation of a WCF Service. For those who have never used WCF, I would recommend the book with which I started: Microsoft Windows Communication Step By Step published by Microsoft Press and written by John Sharp.
Using the code
The demo is composed of three projects:
- SampleService, which implements the Windows Service and the WCF Service.
- SettingsApplication, which implements the forms app which manages the settings with a
PropertyGrid
control. - SampleServiceSetup, which is the setup project to install the Service and the Settings application.
The sample service exposes a simple WCF service contract in IAppSettingsService.cs:
[ServiceContract]
public interface IAppSettingsService
{
[OperationContract]
ServiceSettings GetSettings();
[OperationContract]
void SetSettings(ServiceSettings set);
}
[DataContract]
public class ServiceSettings
{
[DataMember]
public String Host { get; set; }
[DataMember]
public int Port { get; set; }
[DataMember]
public String User { get; set; }
[DataMember]
[PasswordPropertyText(true)]
public String Password { get; set; }
}
The contract implementation in AppSettingsService.cs provides the GetSettings
and SetSettings
methods. The SetSettings
method encrypts the settings using RsaProtectedConfigurationProvider
:
public ServiceSettings GetSettings()
{
try
{
return new ServiceSettings
{
Host = Settings.Default.Host,
Password = Settings.Default.Password,
Port = Settings.Default.Port,
User = Settings.Default.User
};
}
catch (Exception err)
{
throw GetErrMessage(err, "GetSettings");
}
}
public void SetSettings(ServiceSettings set)
{
Type type = set.GetType();
try
{
var config =
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var section = (ClientSettingsSection)
config.GetSection("applicationSettings/SampleService.Settings");
if (section.SectionInformation.IsProtected)
section.SectionInformation.UnprotectSection();
foreach (SettingElement t in section.Settings)
{
var propertyInfo = type.GetProperty(t.Name);
t.Value.ValueXml.InnerText = propertyInfo.GetValue(set, null).ToString();
}
if (!section.SectionInformation.IsProtected)
section.SectionInformation.ProtectSection("RsaProtectedConfigurationProvider");
section.SectionInformation.ForceSave = true;
config.Save(ConfigurationSaveMode.Full);
Settings.Default.Reload();
}
catch (Exception err)
{
throw GetErrMessage(err, "SetSettings");
}
}
...
On the client application side, I defined a ClientServiceSettings
class to provide additional information and possibly custom editors for the PropertyGrid
:
public class ClientServiceSettings
{
public ClientServiceSettings(ServiceSettings settings)
{
Host = settings.Host;
Port = settings.Port;
User = settings.User;
Password = settings.Password;
}
[DisplayName("Host")]
[Category("Server")]
[Description("Enter the host name or IP address.")]
public String Host { get; set; }
[DisplayName("Port Number")]
[Category("Server")]
[Description("Enter the port number.")]
public int Port { get; set; }
[DisplayName("User")]
[Category("Credentials")]
[Description("User login to access server.")]
public String User { get; set; }
[DisplayName("Password")]
[Category("Credentials")]
[PasswordPropertyText(true)]
[Description("The user's password. It will be encrypted " +
"in the configuration settings file.")]
public String Password { get; set; }
}
Then, retrieving the settings from the client application is as simple as:
using (var client = new AppSettingsServiceClient())
{
set = new ClientServiceSettings(client.GetSettings());
propertyGrid1.SelectedObject = set;
}
That's it. I hope some of you will find this modest contribution useful. Cheers and happy coding!