WCF call that references Windows Service

I have a long-running service that gets data from one source, manipulates it, stores it in a database, etc.

I'd like to expose some methods on that service to other applications. Currently we do this via .NET Remoting but I'd like to move to WCF.

Unfortunately, I the endpoint I connect to is never the one I exposed via my long-running service. Below is a simple example:

    [ServiceContract]
    public interface ITestWcfService
    {
        [OperationContract]
        CounterResult GetCurrentValue();
    }

public class TestWcfService : ITestWcfService
    {
        private ITestWindowsService _service;
        public TestWcfService() { /*NOTE: For discoverability*/ }
        public TestWcfService(ITestWindowsService service)
        {
            _service = service;
        }

        public CounterResult GetCurrentValue()
        {
            return _service.GetCurrentValue();
        }
    }

public interface ITestWindowsService
    {
        CounterResult GetCurrentValue();
    }

Then I have my actual Windows Service, which self-hosts the WCF service via the ServiceHost class.

public partial class TestWindowsService : ServiceBase, ITestWindowsService
{
    private static ServiceHost _wcfService;

    public TestWindowsService()
    {
        InitializeComponent();
    }

    public void OnStart(string[] args)
    {
        //Create instance of WCF, passing in reference to this service instance
        TestWcfService wcf = new TestWcfService(this);
        _wcfService = new ServiceHost(wcf);
    }

        public CounterResult GetCurrentValue()
    {
        //Note: Some logic here
    }
}

Now, this more-or-less works except that each time I make a call to the TestWcfServiceClient(), it uses the default constructor and creates a new instance of the Wcf Service and does not use the instance created by the windows service. This means that when I call GetCurrentValue() I get a null reference because the _service member hasn't been set.

I've looked around for solutions and found some citing ServiceHostFactory and ServiceHost and IInstanceProvider but each has seemed to be very, very complicated.

Any thoughts you could provide would be most appreciated.

EDIT: Here's my ServiceModel info

<system.serviceModel>
    <services>
      <service name="WcfService.TestWcfService">
        <host>
          <baseAddresses>
            <add baseAddress = "http://localhost:8733/Design_Time_Addresses/WcfService/TestWcfService/" />
          </baseAddresses>
        </host>
        <!-- Service Endpoints -->
        <!-- Unless fully qualified, address is relative to base address supplied above -->
        <endpoint address="" binding="basicHttpBinding" contract="WcfService.ITestWcfService">
          <!-- 
              Upon deployment, the following identity element should be removed or replaced to reflect the 
              identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity 
              automatically.
          -->
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        <!-- Metadata Endpoints -->
        <!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. --> 
        <!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, 
          set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
          <!-- To receive exception details in faults for debugging purposes, 
          set the value below to true.  Set to false before deployment 
          to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

Answers


WCF is VERY extensible, but in order to provide such extensibility it is also very complicated. In my opinion, more than it should be so if you want to use this implementation that's the way to go. YOu have to create a behavior that changes the service factory so you can use the custom constructor instead of the empty one.

However, I think there might be another alternative. Since both the service and the WCF share the same app domain they can share values through static objects.

I would move the logic that carries the value you want to expose to un underlying assembly (if you didn't already) and both the service and WCF service would see the same instance therefore you don't need to change all the WCF plumbing.


You are trying to put a square peg in a round hole.

WCF is explicitly designed to enable calling business logic independent of how it is hosted. You are trying to maintain the old remoting design that has your business logic in the host layer (in this case a Window's service). As a result you are asking to pass information back up to the host in a way that is possible in WCF but ugly and is generally avoided for many good reasons.

If you want a clean WCF design you will need to create abstraction layers and move your business logic out of the existing TestWindowsService class. Then the windows service creates the WCF service host, the WCF host creates the WCF service, and the WCF service is not dependent on the classes that host it.

Having said all that...

To actually answer your question:

Conceptually the code that you have written should work. Passing an object instance into the ServiceHost constructor is by far the easiest way to avoid the complexity of writing a custom IInstanceProvider. A couple of things to check:

  1. When you pass a service instance into the ServiceHost constructor it needs to be marked as a singleton.

    [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]

  2. Make sure that initialization is really working the way you think it is:

    1. Put a guard on your TestService(ITestWindowsService) constructor that throws if service is null.
    2. You have a comment on the default constructor for TestWcfService() that says "for discoverability". I would remove that constructor (at least while you are troubleshooting). A piece of code might be using that constructor to host a service instance you don't want. This is likely to cause your app to start throwing exceptions or compile errors that point out your real problem.

If you are still having problems: What does the Service Model section of your app.config look like?


Need Your Help

R subset by date

r date subset

I have a dataset called EPL2011_12. I would like to make new a dataset by subsetting the original by date. The dates are in the column named Date The dates are in DD-MM-YY format.

Invoking C++/CLI code from C#

c# .net c++-cli

I have a pretty stupid problem: apparently my knowledge of .NET platform and how C# and C++/CLI communicate is very low, maybe it's that I just don't know some lifehacks or need-to-knows of MSVS.

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.