3

I have a windows service that is hosting a WCF service on a server. I am using InstanceContextMode.PerSession attribute. The services function well per my requirements.

I would now like to implement a visual feedback for the WCF service, like a logger, preferably in a list box in a windows form. I would like all calls from all clients and the subsequent actions to be recorded in this form. I read that having a UI for a service is not a good idea. Can someone point me in a direction to achieve this in a thread safe way.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
swiftgp
  • 997
  • 1
  • 9
  • 17

4 Answers4

4

I think that the simpliest answer is this one. Basically what you can do is to define a custom trace listener for your wcf service. You can modify the example in order to get the results you want.

Custom Trace implementation looks like this:

namespace WcfTrace.Trace
{
    public class WebTraceListener : TraceListener
    {
        public override void Write(string message)
        {
            //write you custom code here
            Debug.WriteLine(message);
        }

        public override void WriteLine(string message)
        {
            //write your custom code here
            Debug.WriteLine(message);
        }
    }
}

Configuration on your service host has to include this:

<system.diagnostics>
    <sources>
      <source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true">
        <listeners>
          <add name="xml" />
        </listeners>
      </source>
      <source name="System.ServiceModel.MessageLogging">
        <listeners>
          <add name="xml" />
        </listeners>
      </source>
    </sources>
    <sharedListeners>
      <add name="xml" type="WcfTrace.Trace.WebTraceListener,WcfTrace.Trace" />
    </sharedListeners>
  </system.diagnostics>

  <system.serviceModel>
    <diagnostics>
      <messageLogging
      logEntireMessage="true"
      logMalformedMessages="false"
      logMessagesAtServiceLevel="true"
      logMessagesAtTransportLevel="false"
      maxMessagesToLog="300000"
      maxSizeOfMessageToLog="200000"/>
    </diagnostics>
  </system.serviceModel>

Personally I like this idea, the tracer class independet from the client (the app with the listbox you mention) can consume information from this custom trace implementation, as well as anything else can do in the future.

danielQ
  • 2,016
  • 1
  • 15
  • 19
  • Quick question, can I have custom messages to be logged through this mechanism. In other words, can I somehow in my WCF service request to emit a custom message that the trace listener can capture. – swiftgp Sep 19 '12 at 14:48
  • No, with this approach `messageLogging` configuration tag is all the customization you got. – danielQ Sep 19 '12 at 15:00
1

The Service does not have a UI but the host may.

This is just a console host but it displays text from the service.

Those Console.WriteLine in the Service display in the host.

namespace MagicEightBallServiceHost
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("**** Console Based WCF Host *****");

            using (ServiceHost serviceHost = new ServiceHost(typeof(MagicEightBallService)))
            {
                serviceHost.Open();
                Console.WriteLine("The service is running");
                Console.ReadLine();
            }

[ServiceBehavior (InstanceContextMode=InstanceContextMode.PerSession)]
    public class MagicEightBallService : IEightBall, IDisposable
    {
        private DateTime serviceStartTime;
        public void Dispose()
        {

            Console.WriteLine("Eightball dispose ... " + OperationContext.Current.SessionId.ToString() + " " + serviceStartTime.ToLongTimeString());          
        }
        public MagicEightBallService()
        {
            serviceStartTime = DateTime.Now;
            Console.WriteLine("Eightball awaits your question " + OperationContext.Current.SessionId.ToString() + " " + serviceStartTime.ToLongTimeString());
        }
        public string ObtainAnswerToQuestion(string userQuestion)
        {
            Console.WriteLine("Eightball ObtainsAnser " + OperationContext.Current.SessionId.ToString() + " " + serviceStartTime.ToLongTimeString());
            return "maybe " + OperationContext.Current.SessionId.ToString() + " " + serviceStartTime.ToLongTimeString() ;
        }
paparazzo
  • 44,497
  • 23
  • 105
  • 176
  • But my host is a windows service, so should I just initialize a form with a static function to write and keep calling it from the WCF service? – swiftgp Sep 18 '12 at 16:31
  • @user1556110, no. That would be the wrong way to do it. Windows services can no longer interact directly with the desktop due to services isolation (introduced in Vista, I believe). So writing to the Console from your Windows service won't help you. In short, you need to develop a UI that can communicate with your Windows service using some IPC mechanism - sockets, pipes, shared memory, etc. I've provided an example of how to do this via WCF in my answer. – Matt Davis Sep 18 '12 at 17:01
  • A Service as in a Windows Service does not have a UI. This simple trick only work when hosting the Service in console. Limited but easy. – paparazzo Sep 18 '12 at 17:43
1

What you're talking about essentially is having your WCF service within your Windows service provide event notifications to a UI front-end when something "interesting" happens. Fortunately, there is a Publish-Subscribe Framework developed by Juval Lowy, author of Programming WCF Services. The details are described in this excellent MSDN article, and the source code is available for free at Lowy's website.

The neat thing about this framework is that it decouples the publisher, e.g., your WCF service in your Windows service, from any subscribers, e.g., your GUI. The publisher "publishes" events that are of interest to the Pub/Sub Service, which is always available. From the publisher's point of view, it doesn't matter if there are any subscribers or not. The Pub/Sub Service takes care of routing events to any and all registered subscribers. In this way, your WCF service in your Windows service publishes events as they occur, your GUI will subscribe/unsubscribe to the Pub/Sub Service when it loads/exits, and the Pub/Sub Service will notify your GUI as events occur.

I have used this setup in my project, and it works extremely well.

EDIT: I understand the desire to have your own UI that displays events from your Windows service-hosted WCF service. Another option would be to leverage an application log that is accessible from the Windows native Event Viewer (eventvwr.msc). If this approach is acceptable, take a look at my instructions here for how to set that up from your Windows service.

Community
  • 1
  • 1
Matt Davis
  • 45,297
  • 16
  • 93
  • 124
0

Use something like log4net to log the information you want to display that represents the web service activity of interest. By using log4net you can filter what type of information is logged by just changing the configuration file. You can also change where and how you want the information to by logged in the configuration file. One of the appenders you can configure for log4net is a SysLogAppender. This sends the log information to a remote SysLog Server (it can be deployed with the web service as well). There are a number of SysLog Servers available like Kiwi which will provide a rolling display of the log events and provides filters and actions on certain events (ex: send an email to the administrator when an error occurs). There is also open source SysLog Severs available. This effectively decouples the viewing and handling of the log information from the actual logging.

Community
  • 1
  • 1
Kevin Junghans
  • 17,475
  • 4
  • 45
  • 62