I plan to run a WCF-Console-Application as a Windows service.
The WCF-Console-Application calls a FoxPro-DLL to access data in FoxPro-DBF (read and write).
Different clients (WPF-Application) should consume the WCF-Service of the Console-Application to display and edit the data from the FoxPro-DBF.
If only one Client at a time calls the WCF-Console-Application, everything works fine. But the WCF-Console-Application does not handle parallel calls from multiple clients correctly.
The WCF-Console-Application consists of these classes:
main Class: derived from ServiceBase, can be either called from console or started as service
public class Service : ServiceBase
{
public ServiceHost serviceHost = null;
const string CONSOLE = "console";
public Service()
{
this.ServiceName = "ServiceTest";
}
public static void Main(string[] args)
{
if (args.Length == 1 && args[0].Equals(CONSOLE))
{
new Service().startConsole();
}
else
{
ServiceBase.Run(new Service());
}
}
private void startConsole()
{
Console.WriteLine(string.Format("{0}::start Service...", GetType().FullName));
OnStart(null);
Console.WriteLine(string.Format("{0}::ready (ENTER to stop)", GetType().FullName));
Console.ReadLine();
OnStop();
Console.WriteLine(string.Format("{0}::stop Service", GetType().FullName));
}
protected override void OnStop()
{
if (this.serviceHost != null)
{
this.serviceHost.Close();
this.serviceHost = null;
}
}
protected override void OnStart(string[] args)
{
if (this.serviceHost != null)
{
this.serviceHost.Close();
}
this.serviceHost = new ServiceHost(typeof(Server.TestServer));
this.serviceHost.Open();
}
ServiceInstaller: installs the Service, derived from Installer
[RunInstaller(true)]
public class InstallService : Installer
{
public InstallService()
{
process = new ServiceProcessInstaller();
process.Account = ServiceAccount.LocalSystem;
service= new ServiceInstaller();
service.ServiceName = "ServiceTest";
service.Description = "ServiceTest";
service.DisplayName = "ServiceTest";
service.StartType = ServiceStartMode.Automatic;
Installers.Add(process);
Installers.Add(service);
}
}
- static class for accessing the FoxPro-DLL
public static class DataAccess
{
public static foxprotest.foxprotest accessData = new foxprotest.foxprotest();
}
- ITestServer, Interface with the ServiceContract
[ServiceContract(Namespace = "http:/localhost.TestServer", SessionMode = SessionMode.Allowed)]
public interface ITestServer
{
[OperationContract]
String loadData(int id);
}
- TestServer, implementation of ITestServer
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class TestServer : ITestServer
{
public String loadData(int id)
{
//set table
DataAccess.accessData.CTABLE = "patient";
//set ID
DataAccess.accessData.NPATIENT = id;
//fetch the data
DataAccess.accessData.FetchData();
//return data as XML
return DataAccess.accessData.CRESULT;
}
}
This is how the App.Config looks like: the binding is set to netTcpBinding
<system.serviceModel>
<services>
<service name="Server.TestServer" behaviorConfiguration="MyFileServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8888/"/>
<add baseAddress="net.tcp://localhost:52/"/>
</baseAddresses>
</host>
<endpoint address="TestServer" binding="basicHttpBinding"
name="b" contract="Server.ITestServer" />
<endpoint address="TestServer" binding="netTcpBinding"
name="c" contract="Server.ITestServer" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyFileServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceThrottling maxConcurrentCalls="80" maxConcurrentSessions="80"
maxConcurrentInstances="80" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
I used svcutil.exe to generate the output.config and TestServer.cs for the WPF-Application.
The FoxPro-DLL is built as multi-threaded COM server, it is registered correctly and VFP9T.DLL is used. There is a little delay in the function loadData(), to test the parallel calls. When I call the DLL from multiple FoxPro-Instances, everything works as expected. If I include the dll into the WPF-Application and call it from there, it also works. Only with multiple calls through the WCF-Console-Application, it does not work correctly.
When I run the WCF-Console-Application through console and make a Console.WriteLine before every line in TestServer.LoadData(), the second call keeps hangig in front of
DataAccess.accessData.CTABLE = "patient";
until the first call is finished. The worst thing is: the returned XML-string is the same when I make parallel calls. Immediately after the first call with an ID, i start a second call with a different ID. For both calls I get the XML-String with the second ID.
What can I change, to get the parallel call to the FoxPro-DLL inside the WCF-Console-Application working? I tried every combination of InstanceContextMode and ConcurrencyMode, without success. Do I need thread safety? If so, what do I have to change?
The use of ODBC or a SQL-Server are no option for this project.
Thanks for any suggestion and advice!
EDIT: If I restart the WCF-Console-Application, only the first parallel test delivers wrong XML-strings. If I do a second parallel call, the returned XML-strings are correct. But the problem with the parallel call still exists.