1

我计划将 WCF-Console-Application 作为 Windows 服务运行。WCF-Console-Application 调用 FoxPro-DLL 来访问 FoxPro-DBF 中的数据(读取和写入)。不同的客户端(WPF-Application)应该使用 Console-Application 的 WCF-Service 来显示和编辑来自 FoxPro-DBF 的数据。

如果一次只有一个客户端调用 WCF-Console-Application,则一切正常。但是 WCF-Console-Application 不能正确处理来自多个客户端的并行调用。

WCF-Console-Application 由以下类组成:

  • main Class:派生自ServiceBase,既可以从控制台调用,也可以作为服务启动

    公共类服务: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:安装Service,派生自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);                                     
    }
}
  • 用于访问 FoxPro-DLL 的静态类
public static class DataAccess
{
    public static foxprotest.foxprotest accessData = new foxprotest.foxprotest();
}
  • ITestServer,与 ServiceContract 的接口
[ServiceContract(Namespace = "http:/localhost.TestServer", SessionMode = SessionMode.Allowed)]
public interface ITestServer
{
    [OperationContract]
    String loadData(int id);
}
  • TestServer,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;
    }
}

这是 App.Config 的样子:绑定设置为 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>

我使用 svcutil.exe 为 WPF 应用程序生成 output.config 和 TestServer.cs。

FoxPro-DLL 构建为多线程 COM 服务器,已正确注册并使用 VFP9T.DLL。函数 loadData() 有一点延迟,用于测试并行调用。当我从多个 FoxPro 实例调用 DLL 时,一切都按预期工作。如果我将 dll 包含到 WPF 应用程序中并从那里调用它,它也可以工作。只有通过 WCF-Console-Application 进行多次调用,它才能正常工作。

当我通过控制台运行 WCF-Console-Application 并在 TestServer.LoadData() 的每一行之前创建一个 Console.WriteLine 时,第二个调用将 hangig 保持在前面

DataAccess.accessData.CTABLE = "patient";

直到第一次通话结束。最糟糕的是:当我进行并行调用时,返回的 XML 字符串是相同的。在使用 ID 进行第一次通话后,我立即使用不同的 ID 开始第二次通话。对于这两个调用,我都得到了带有第二个 ID 的 XML-String。

为了使 WCF-Console-Application 内的 FoxPro-DLL 并行调用正常工作,我可以更改什么?我尝试了 InstanceContextMode 和 ConcurrencyMode 的每种组合,但没有成功。我需要线程安全吗?如果是这样,我需要改变什么?该项目不能选择使用 ODBC 或 SQL-Server。

感谢您的任何建议和建议!

编辑:如果我重新启动 WCF-Console-Application,则只有第一个并行测试会提供错误的 XML 字符串。如果我进行第二次并行调用,则返回的 XML 字符串是正确的。但是并行调用的问题依然存在。

4

1 回答 1

0

BasicHttpBinding不支持会话。您需要使用InstanceContextMode.PerCall以确保每个调用都在其自己的线程中运行。

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class TestServer : ITestServer
{
   ...
}

更新:

DataAccess.accessData static吗?如果是 - 那需要改变。静态数据在多个线程之间共享。因此,如果使用,服务可以返回由另一个调用更新的数据InstanceContextMode.PerCallConcurrencyMode.Single仍然可以与可变静态数据一起使用,但您将遇到单线程的所有可伸缩性问题。

于 2013-05-29T15:26:31.187 回答