运行应用程序可执行文件时,在 WinForm 应用程序中托管 WCF 服务不起作用

Posted

技术标签:

【中文标题】运行应用程序可执行文件时,在 WinForm 应用程序中托管 WCF 服务不起作用【英文标题】:Hosting WCF Service within WinForm Application doesn't work when running the application executable 【发布时间】:2018-05-21 03:42:06 【问题描述】:

在过去的几周里,我开发了一个 64 位 WinForms 应用程序,它需要与 32 位 DLL 通信(工作规范需要它)。

在互联网上进行了一些阅读并发现这样做没有任何有趣的方式后,我决定在我的 WinForms 应用程序中托管一个 WCF 服务应用程序,以便与 32 位 DLL 进行通信。 .. 或者我以为我在做。

在开发过程中(在 Visual Studio 中运行时)它一直运行良好,但是当然,现在我需要部署,我遇到了问题。我无法对 WCF 服务有足够深入的了解,无法知道我是否会以一种糟糕的方式处理这个问题,或者我是否只是遗漏了一些细节。

我以管理员身份创建了项目。 完成开发后,我尝试运行 WinForm 可执行文件(调试和发布)WindowsFormsApplication1.exe。应用程序启动了,但在我尝试完成涉及使用 WCF 服务的任务后,抛出异常:

这让我相信 Visual Studio 在开发过程中托管服务而不是 WinForm 应用程序,或者我的配置和/或目录结构不正确。

[更新] WCF 服务 Web.config:

<?xml version="1.0"?>
<configuration>

  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5.2" />
    <httpRuntime targetFramework="4.5.2" maxRequestLength="2147483647"/>
  </system.web>

  <system.net>
    <defaultProxy>
      <proxy usesystemdefault="False"/>
    </defaultProxy>
  </system.net>

  <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>
      <source name="myUserTraceSource"
              switchValue="Information, ActivityTracing">
        <listeners>
          <add name="xml"/>
        </listeners>
      </source>
    </sources>
    <sharedListeners>
      <add name="xml"
           type="System.Diagnostics.XmlWriterTraceListener"
                 initializeData="C:\logs\Traces.svclog" />
    </sharedListeners>
  </system.diagnostics>

  <system.serviceModel>
    <diagnostics wmiProviderEnabled="true">
      <messageLogging
           logEntireMessage="true"
           logMalformedMessages="true"
           logMessagesAtServiceLevel="true"
           logMessagesAtTransportLevel="true"
           maxMessagesToLog="3000"
       />
    </diagnostics>
    <behaviors>
      <serviceBehaviors>
        <behavior name="metadadiscovery>
          <!-- 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>

<services>
  <service name="ServiceReference1.Service1" behaviorConfiguration="metadadiscovery">
    <endpoint address="" binding="basicHttpBinding" contract="ServiceReference1.IService1"></endpoint>
  </service>
</services>

    <protocolMapping>
        <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>    
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled="false"/>
  </system.webServer>

</configuration>

WinForm App.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
  </startup>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IService2" />
        <binding name="BasicHttpBinding_IService3" />
        <binding name="BasicHttpBinding_IService1" />
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://localhost:45053/Service2.svc" binding="basicHttpBinding"
        bindingConfiguration="BasicHttpBinding_IService2" contract="ServiceReference2.IService2"
        name="BasicHttpBinding_IService2" />
      <endpoint address="http://localhost:46351/Service3.svc" binding="basicHttpBinding"
        bindingConfiguration="BasicHttpBinding_IService3" contract="ServiceReference3.IService3"
        name="BasicHttpBinding_IService3" />
      <endpoint address="http://localhost:44848/Service1.svc" binding="basicHttpBinding"
        bindingConfiguration="BasicHttpBinding_IService1" contract="ServiceReference1.IService1"
        name="BasicHttpBinding_IService1" />
    </client>
  </system.serviceModel>
  <appSettings>
    <add key="ClientSettingsProvider.ServiceUri" value="" />
  </appSettings>
  <system.web>
    <membership defaultProvider="ClientAuthenticationMembershipProvider">
      <providers>
        <add name="ClientAuthenticationMembershipProvider" type="System.Web.ClientServices.Providers.ClientFormsAuthenticationMembershipProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" />
      </providers>
    </membership>
    <roleManager defaultProvider="ClientRoleProvider" enabled="true">
      <providers>
        <add name="ClientRoleProvider" type="System.Web.ClientServices.Providers.ClientRoleProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" cacheTimeout="86400" />
      </providers>
    </roleManager>
  </system.web>
</configuration>

EXE 所在目录:

包含 WCF 服务的目录位于上图中的目录 WcfService1 中。

我主要使用以下实例化服务的方法:

ServiceReference1.Service1Client = new ServiceReference1.SErvice1Client();

一旦我尝试切换到使用服务主机(如下),但当我使用该方法时,服务会在尝试与 DLL 通信时超时。

Uri address = new Uri("http://localhost:44848/Service1.svc");
ServiceHost host = new ServiceHost(typeof(ServiceReference1.Service1Client), address);
host.Open();

然后我稍后关闭了主机。在这一点上,我愿意尝试任何事情来让它发挥作用。

[编辑] 下面是我的 WindowsFormsApplication1.exe.config 文件的代码。所有三个合同都发出警告,称它们“根据其数据类型'clientContractType'无效”。我认为这可能是我的问题的根源,但我不知道为什么它会显示此警告:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
  </startup>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IService2" />
        <binding name="BasicHttpBinding_IService3" />
        <binding name="BasicHttpBinding_IService1" />
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://localhost:45053/Service2.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService2" contract="ServiceReference2.IService2" name="BasicHttpBinding_IService2" />
      <endpoint address="http://localhost:46351/Service3.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService3" contract="ServiceReference3.IService3" name="BasicHttpBinding_IService3" />
      <endpoint address="http://localhost:44848/Service1.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService1" contract="ServiceReference1.IService1" name="BasicHttpBinding_IService1" />
    </client>
  </system.serviceModel>
</configuration>

感谢您提供的任何帮助和指导。

【问题讨论】:

【参考方案1】:

没有为您的服务配置端点。

    <behaviors>
          <serviceBehaviors>
            <behavior name="metadadiscovery">
              <!-- 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>
     <service name="ServiceReference2.Yourimplementingservice" behaviorConfiguration="metadadiscovery">
      <endpoint address="" binding="basicHttpBinding" contract="ServiceReference2.IService2">          
       </endpoint>

上面我已经为Service2配置了,同样你必须为Service1和Service3配置。

【讨论】:

谢谢,很遗憾,这并没有解决我的问题。 您介意检查一下我更新的实现是否是您打算让我做的吗?我一直在用头撞墙,试图弄清楚这一点。 你能发布你的服务合同吗【参考方案2】:

经过充分的努力,我决定摆脱 Visual Studio 在您将其创建为新项目时​​为您生成的 WCF 服务。我改为逐字阅读本教程:

Hosting Service In App

这样做有很大的好处:

    不需要配置文件 以这种方式运行它一定已经摆脱了大量的开销,因为与 DLL(我使用该服务的目的)的通信过去需要几秒钟才能对 DLL 进行大量调用,但现在能够在眨眼间处理 10k+ 电话。 不需要服务参考。我只需要我的主要功能的文件,包含服务功能实现的文件和包含实现接口的文件。

到目前为止,这是我发现的在 64 位应用程序中使用 32 位 DLL 的最简单、最可靠的方法。让我知道我是否可以为其他可能遇到此问题的人提供任何指导。如果您以前从未做过类似的事情,我知道这不是一件有趣的事情。

【讨论】:

以上是关于运行应用程序可执行文件时,在 WinForm 应用程序中托管 WCF 服务不起作用的主要内容,如果未能解决你的问题,请参考以下文章

c#(winform)环境下使用动态链接库dll的详解

Winform程序及dll打包成一个可执行的exe

将Winform程序及dll打包成可执行的exe

Winform 执行exe

C#、 WINFORM以及 .NET之间关系。

Windows PE WinForm 应用程序未执行