C# WCF 服务-在多用户情况下访问 FoxPro DLL

标签: dll C#
发布时间: 2013/12/7 17:25:56
注意事项: 本文中文内容可能为机器翻译,如要查看英文原文请点击上面连接.

我计划作为 Windows 服务运行 WCF 控制台应用程序。在 WCF 控制台应用程序调用一个 FoxPro DLL 来访问 FoxPro DBF (读和写) 中的数据。不同的客户端 (WPF 应用程序) 应消耗的控制台应用程序,通过它来显示和编辑的数据从 FoxPro DBF 的 WCF 服务。

如果仅有一次一个客户端调用 WCF 控制台应用程序,一切工作正常。但是,WCF 控制台应用程序不会正确地处理来自多个客户端并行调用。

WCF 控制台应用程序包含这些类:

  • 主类: 从 ServiceBase 派生的可以从控制台调用或作为服务启动

    公共类服务: ServiceBase {公开给上一步给上一步 = 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: 安装的服务,从安装程序派生

[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。

作为多线程的 COM 服务器生成 FoxPro DLL,它是否已正确注册和 VFP9T。使用 DLL。函数 loadData(),以测试并行调用中有一个小的延迟。当我从多个 FoxPro 实例调用 DLL 时,一切都按预期方式工作。如果在 WPF 应用程序中包括该 dll,并从那里叫它,它也工作。只与通过 WCF 控制台应用程序的多个调用,它不会正确工作。

当我通过控制台运行 WCF 控制台应用程序,使每行之前 Console.WriteLine 在 TestServer.LoadData() 中时,第二个调用保持前面的 hangig

DataAccess.accessData.CTABLE = "patient";

直到完成了第一次调用。最糟糕的事情是: 返回的 XML 字符串是相同时并行打电话。立即在同一个 ID 第一次调用后,我开始了第二个电话与一个不同的 id。这两个电话我得到的 XML 字符串与第二个 id。

什么可以更改,以获取对 FoxPro DLL 内 WCF 控制台应用程序工作的并行调用?我试过每个组合的 InstanceContextMode 和 ConcurrencyMode,但没有成功。我需要线程安全吗?如果是这样,我要改变什么?使用 ODBC 或 SQL Server 都没有为这一项目的选项。

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

编辑: 如果我重新启动 WCF 控制台应用程序,只有第一个并行测试提供了错误的 XML 字符串。如果我做第二次的并行调用,所返回的 XML 字符串是正确的。但与并行调用问题仍然存在。

解决方法 1:

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

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

更新:

Is DataAccess.accessData static?如果是-,需要改变。静态数据是在多个线程间共享。因此,服务可以返回数据更新由另一个调用,如果 InstanceContextMode.PerCall 使用。ConcurrencyMode.Single仍然可以使用具有可变静态数据,但你会得到所有的单个线程的可伸缩性问题。

赞助商