1
votes

Over the past few weeks I have developed a 64-bit WinForms application that needs to communicate with a 32-bit DLL (job specs require it).

After doing some reading around the internet and finding out that there is not going to be any fun way of doing this, I decided to go with hosting a WCF Service Application within my WinForms application for communicating to the 32-bit DLL... or so I thought I was doing.

During development (while running within Visual Studio) it has been working really well, but of course, now that I need to deploy, I am running into problems. I am having trouble getting a strong enough understanding of WCF Services to know if I am going about this in a terrible way or if I am just missing some minute detail.

I created the project as Admin. After development was finished I tried to run the WinForm executable (both debug and release), WindowsFormsApplication1.exe. The application started up, but after I tried to complete a task involving the use of the WCF service, an exception was thrown:

exception messages

This has led me to believe that Visual Studio was doing the hosting of the service during development instead of the WinForm application, or my configs and/or directory structures are incorrect.

[UPDATED] WCF Service 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>

Directory Where EXE resides:

directory

The directory containing the WCF Service resides within the directory WcfService1 from the image above.

I have mostly been using the following method of instantiating the service:

ServiceReference1.Service1Client = new ServiceReference1.SErvice1Client();

Once I tried to switch to using a service host (below), but when I used that method, the service would timeout whenever it tried to communicate to the DLL.

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

And then I closed the host later. At this point, I am willing to try anything to get this working.

[EDIT] Below is the code of my WindowsFormsApplication1.exe.config file. All three contracts are giving the warning that they're "invalid according to its datatype 'clientContractType'". I think this could be the source of my problems, but I do not know why it is showing this warning:

<?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>

Thank you for any help and guidance you can provide.

2

2 Answers

0
votes

There is no endpoint configured for your service.

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

Above I have configured for Service2 ,similarly you have to configure for Service1 and Service3.

0
votes

After sufficient struggling I decided to get rid of the WCF service that visual studio generates for you when you create it as a new project. I instead followed this tutorial verbatim:

Hosting Service In App

Doing this came with huge advantages:

  1. No configuration file was necessary
  2. Running it this way must've gotten rid of a large amount of overhead because the communication to the DLL (what I am using the service for) used to take several seconds to do large amounts of calls to the DLL, but now is able to handle 10k+ calls in the blink of an eye.
  3. No service reference is necessary. I just needed the file for my main function, the file containing the service function implementations and the file containing the interface for the implementation.

So far, this has been the easiest and most robust way I have found for using a 32 bit DLL in a 64 bit application. Let me know if I can give any guidance for anyone else who may be struggling with this problem. I know this is not a fun thing to deal with if you've never done anything like it before.