I have a C# remoting app that has 2 pieces. One runs in the current user context and is a Windows Application. The 2nd piece runs as a windows service and they communicate just fine with each other using Remoting.

However, I cannot find a good solution to my problem. Where should I store global data? Both the windows service and the windows app need to access settings.xml. Since Vista/Windows 7 both use the virtualization, these two apps cannot access the same folder (since they run on different accounts). Windows 7 and Vista also use registry virtualization which has also become quite the nightmare.

To repeat: Where should we be storing our settings.xml and other related files so both the windows service and the app can access it?

Recommended Answers

All 2 Replies

What are you storing where they both need the same data? I typically store the configuration in my service and use the windows application to ask the service for data, or set values. This way the server handles the get/set requests of data and maintains the configuration file. You also don't have to worry about file concurrency and locating the XML.

To store the configuration variables you should use the Configuration class.

Here is a part of my ServiceConfig.cs for a service. It might not compile but you will get the idea (I have to remove some code):

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.Data;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Timers;
using VSS.IPC;
using VSS.NamedPipe;
using System.Xml;
using System.Xml.Serialization;

namespace VSS.Core
{
  /* -------------------------------------------------------------------- */
  /// <summary>
  /// Gives stringly typed names to configuration options in the xml config
  /// </summary>
  internal enum VSSConfigurationOption
  {
    LoggingEnabled,
    ConnectionString,
  }
  private static object configLock;
  private static Configuration config;
    /// <summary>
    /// Call this when the service first starts up. You could also use a static constructor for this
    /// class and start it when the assembly is loaded but that slows down your service start time
    /// and can lead to problems. I start this up in a separate thread.
    /// </summary>
    internal static void Start()
    {
      configLock = new object();
      ReloadConfig();
    }
    internal static void Stop()
    {
      configLock = null;
    }
    /// <summary>
    /// Refreshes the configuration from the configuration file
    /// </summary>
    public static void ReloadConfig()
    {
      lock (configLock)
      {
        if (config != null)
          ConfigurationManager.RefreshSection(ConfigSectionName);

        config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
        CheckFields();

        LoggingEnabled = config.AppSettings.Settings[VSSConfigurationOption.LoggingEnabled.ToString()].Value.Equals("Y");
        ConnectionString = config.AppSettings.Settings[VSSConfigurationOption.ConnectionString.ToString()].Value;
....
....
      }
  }
    /// <summary>
    /// Saves settings to disk
    /// </summary>
    public static void Save()
    {
      config.AppSettings.Settings[VSSConfigurationOption.LoggingEnabled.ToString()].Value = (LoggingEnabled ? "Y" : "N");
      config.AppSettings.Settings
      SaveConfigurationToDisk();
    }
    private static void SaveConfigurationToDisk()
    {
      if (config.HasFile)
        config.Save(ConfigurationSaveMode.Modified);
      else
        config.Save(ConfigurationSaveMode.Full, true); //throws an exception if the file exists
    }
    /// <summary>
    /// Adds XML elements for configuration elements.
    /// I use this to avoid dealing with null return values.
    /// </summary>
    /// <param name="config"></param>
    private static void CheckFields()
    {
      string[] values = Enum.GetNames(typeof(VSSConfigurationOption));
      foreach (string value in values)
      {
        if (config.AppSettings.Settings[value] == null)
          config.AppSettings.Settings.Add(value, string.Empty);
      }
    }

I guess you could use the app.config of the project but my logic for the service is an independant assembly so I can add it to a console app or form app to get the same behavior for debugging it. I also removed a lot of my lock() code to match brackets.

Just ask the service:
App asks service: What is your connection string?
App tells service: Your connection string is S
App tells service: Test your SQL connection and report the results to me.

Just be crafty in the methods you use for remoting.

I think you misuse Remoting if you come to ask this question, because as Windows service is running you can hold variables on it (I assume you are holding connection strings, user name, etc..).

That was abstraction, let's move to the next step, does both applications running on the same PC?
Then you can use Process Domain techniques, it may be on different on the same network so the solution is Sockets, please tell us more about that.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.