1

I am having trouble with a single Wcf Service that we have in an application. It has about 150 [OperactionContract] within it. I can now no longer Update Service Reference within Visual Studio 2008.

I receive all kinds of strange errors, varying from "Socket Forcibly Closed" to "Invalid Type" and other strange messages when I try to call an update. If I comment out 10-20 operations it works fine.

I have read all kinds of posts here, on MSDN, and many blogs. They all point to binding configurations that need to be changed, either on the main binding or on the MetadataExchange binding.

My problem is that I have tried all of this and have yet to get it to work reliably.

I am self hosting the service in an application, and that same application is also the client. They share the same configuration file (currently) because we are in the process of breaking the application into 2 pieces via the Wcf service layer.

Here is an excerpt showing my bindings I have defined:

<system.serviceModel>

    <bindings>
      <netTcpBinding>
        <binding name="NetTcpBinding_IRhinoServices"
                 closeTimeout="00:05:00"
                 openTimeout="00:05:00"
                 receiveTimeout="00:15:00"
                 sendTimeout="00:05:00"
                 transactionFlow="false"
                 transferMode="Buffered"
                 transactionProtocol="OleTransactions"
                 hostNameComparisonMode="StrongWildcard"
                 listenBacklog="100"
                 maxBufferPoolSize="2147483647"
                 maxBufferSize="2147483647"
                 maxConnections="100"
                 maxReceivedMessageSize="2147483647">
          <readerQuotas maxDepth="2147483647"
                        maxStringContentLength="2147483647"
                        maxArrayLength="2147483647"
                        maxBytesPerRead="2147483647"
                        maxNameTableCharCount="2147483647" />
          <reliableSession ordered="true"
                           inactivityTimeout="00:10:00"
                           enabled="false" />
          <security mode="None">
          </security>
        </binding>
      </netTcpBinding>

      <customBinding>
        <binding name="customMex">
          <textMessageEncoding>
            <readerQuotas maxDepth="2147483647"
                          maxStringContentLength="2147483647"
                          maxArrayLength="2147483647"
                          maxBytesPerRead="2147483647"
                          maxNameTableCharCount="2147483647" />
          </textMessageEncoding>
          <tcpTransport transferMode="Buffered"
                        maxReceivedMessageSize="2147483647"
                        maxBufferSize="2147483647"/>
        </binding>
      </customBinding>

    </bindings>

    <client>
      <endpoint address="net.tcp://localhost:8523/RhinoServices"
                binding="netTcpBinding"
                bindingConfiguration="NetTcpBinding_IRhinoServices"
                contract="RhinoServicesReference.IRhinoServices"
                name="NetTcpBinding_IRhinoServices">
        <identity>
          <dns value="localhost" />
        </identity>
      </endpoint>
    </client>

    <services>
      <service behaviorConfiguration="CounterSketchServer.RhinoServicesBehavior"
               name="CounterSketchServer.RhinoServices">
        <endpoint address=""
                  binding="netTcpBinding"
                  contract="CounterSketchServer.IRhinoServices">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>

        <endpoint address="mex"
                  binding="customBinding"
                  contract="IMetadataExchange"
                  name=""
                  bindingConfiguration="customMex"
                  listenUriMode="Explicit" />

        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://localhost:8523/RhinoServices" />
          </baseAddresses>
        </host>
      </service>
    </services>

    <behaviors>
      <serviceBehaviors>
        <behavior name="CounterSketchServer.RhinoServicesBehavior">
          <serviceMetadata httpGetEnabled="false" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>

  </system.serviceModel>

I need to be able to generate the proxy class by clicking on Update Service Reference, which has worked well this past 2 weeks, till I hit this mysterious limit.

Most of the examples I have seen to resolve this talk about http bindings for mex, but I would like to stick with just netTcp if possible since I am self hosting.

Can anyone please help me?

Thank you.

* UPDATE *

I have tried @Aliostad suggestion, and it appeared to work well at first. Until I tried some of our Wcf calls which update UI elements. These happened to work when using NetTCP bindings with the Proxy Class generated by Visual Studios (Add Service Reference) tool. But when using the Channel Factory it does not work.

I have tried looking at the SyncrhonizationContext in Juval's WCF book, but nothing I did seemed to work.

I have tried using both Named Pipes and NetTCP as the binding for the Channel I create using the ChannelFactory, and they do seem to behave very differently from eachother related to long running Wcf operations, but neither work to update UI elements.

My services are actually running in a plugin for the Rhino 3D CAD engine, and ceratin calls (Render, etc.) trigger UI in Rhino to update. I assume this is causing a thread boundary issue. The exception I receive is: attempted to read or write protected memory

If anyone has any suggestions to use the ChannelFactory method effectively in this scenario or to fix my problem with too many Operations in a given Wcf class to generate the Service Proxy I would appreciate your help.

Thank You!

Jason Stevenson
  • 4,004
  • 3
  • 29
  • 49
  • Also, I should clarify while I am writing both the Client piece and the Service piece. They are each seperate plugins within the Rhino Application, so I guess I am not technically Self Hosting. – Jason Stevenson Apr 15 '11 at 15:55

2 Answers2

2

First of all, I believe the only solution is to remove the reference, and add it back again.


Alternatively, if you own both the Client and the Service - which I seem to get from reading your question that you do - may I strongly suggest that you share you service interfaces with your clients - instead of using a service reference?

This is definitely the preferred approach when you own both client and the server (and will save you from all the troubles you are having) and I believe it is also preferred if you do not own the client, you just share the entities/dtos and the interfaces.

This requires you to:

  • Create a class library project for you entities/dtos. Share it with the client.
  • Create a class library project for you service interfaces. Share it with the client.
  • Create a class library project for you service implementation. Stays only on the server.
  • The client uses ChannelFactory<T> to create factory and then create a proxy by calling CreateChannel()
Aliostad
  • 80,612
  • 21
  • 160
  • 208
  • Forgive my ignorance, I am new to Wcf. So you are saying to just reference the Interfaces in both the Client and Server applications. And spin up the Channel Factory for the given service, then specify it's endpoint in code? – Jason Stevenson Apr 13 '11 at 22:05
  • No you would still have to manually configure but you hopefully do it once and in the process, learn more about the configuration. You can use `SvcConfigEditor.exe` to help you with the configuration. – Aliostad Apr 13 '11 at 22:07
  • One of the reasons we are switching to this architecture is to completely separate our UI from the CAD engine that it is dependant upon. We are invoked as a plugin to the engine, and so we currently have references deep into the CAD engine. This causes a lot of issues with Expression Blend (our UI is in Wpf). If I switch to this method won't I lose the "proxy" classes that I was able to use to bring some CAD types up into our UI? – Jason Stevenson Apr 13 '11 at 22:19
  • 1
    You will never lose any separation of concerns by doing this. Actually you even no more need proxy classes. Remember by sharing service interface (contract) and entities (messages) you are bringing as much as WSDL/service reference brings. I joined the company I am working and they were doing service reference and everytime something was changing, there was a havoc. I have changed it to sharing libraries and now, it is all transparent and easy. – Aliostad Apr 13 '11 at 22:28
  • Do we also then have to write our own Async logic? No big deal, I've just never used the Channel Factory way of things. – Jason Stevenson Apr 13 '11 at 22:30
  • I am rewriting now... If this works out I will mark your answer. I hope to have it done in the next hour. Thanks Dude! – Jason Stevenson Apr 13 '11 at 22:31
  • Yes, async is something that you lose. Probably the only thing worth considering. – Aliostad Apr 13 '11 at 22:31
  • No probs, I hope I have helped. This definitely worked for me and ourcompany... hope it does for you as well. – Aliostad Apr 13 '11 at 22:32
  • So given this method, I should configure then endpoints for the ServiceHost all in code then? Or am I still missing something? – Jason Stevenson Apr 13 '11 at 23:30
  • I would use configuration for server as well. – Aliostad Apr 14 '11 at 08:47
  • @Aliostad I have got this successfully working! Thank you for your guidance, I have since gone and read Juval Lowry's WCF book, which talks about this method. I have also switched to NamedPipes since I am only communicating via the same machine. -- Jason – Jason Stevenson Apr 14 '11 at 16:12
  • @Aliostad, I think I have to switch back to using the Proxy class. I am having a ton of issues with getting certain methods to work that update UI. I have tried all of the SynchronizationContext ideas suggested my Juval, but nothing seems to work. For some reason the proxy class generated by Visual Studio just worked for us. Except for hitting the MEX limitations, which I guess I can refactor contracts into seperate classes to limit the number of them. Do you have any suggestions, or have you ever tried to call methods which Update UI over Wcf services created by CreateChannel() methods? – Jason Stevenson Apr 15 '11 at 15:45
1

I have got the Update Service Reference working again from both SvcUtil.exe and from Visual Studio 2008.

To do so I added the following section to the config files for both devenv.exe.config and SvcUtil.exe.config:

<!-- CUSTOM MetaDataExchaning Binding to all for LARGE WCF Services -->

<client>
    <endpoint name="net.tcp" binding="netTcpBinding" bindingConfiguration="GenericBinding"
    contract="IMetadataExchange" />
    <endpoint name="http" binding="wsHttpBinding" bindingConfiguration="SecureBinding" contract="IMetadataExchange" />
</client>

<bindings>

    <netTcpBinding>
        <binding name="GenericBinding" maxBufferPoolSize="2147483647"
        maxReceivedMessageSize="2147483647" >
            <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
            maxArrayLength="2147483647" maxBytesPerRead="2147483647"
            maxNameTableCharCount="2147483647" />
            <security mode="None"/>
        </binding>
    </netTcpBinding>

    <wsHttpBinding>
        <binding name="SecureBinding" maxBufferPoolSize="2147483647"
        maxReceivedMessageSize="2147483647" >
            <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
            maxArrayLength="2147483647" maxBytesPerRead="2147483647"
            maxNameTableCharCount="2147483647" />
            <security mode="Message">
                <transport clientCredentialType="Windows" />
            </security>
        </binding>
    </wsHttpBinding>
</bindings>

Then in my application Server plugin, I am still programmatically creating the ServiceHost so to enable meta data exchange I added another endpoint:

        // DATA ENDPOINT
        NetTcpBinding binding = new NetTcpBinding(SecurityMode.Transport, true);
        Uri baseAddress = new Uri("net.tcp://localhost:8555/RhinoServices");
        _rhinoServicesHost = new ServiceHost(typeof(RhinoServices), baseAddress);
        _rhinoServicesHost.AddServiceEndpoint(typeof(IRhinoServices), binding, baseAddress);

        // META ENDPOINT
        BindingElement bindingElement = new TcpTransportBindingElement();
        CustomBinding customBinding = new CustomBinding(bindingElement);
        ServiceMetadataBehavior metadataBehavior = _rhinoServicesHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
        if (metadataBehavior == null)
        {
            metadataBehavior = new ServiceMetadataBehavior();
            _rhinoServicesHost.Description.Behaviors.Add(metadataBehavior);
        }
        _rhinoServicesHost.AddServiceEndpoint(typeof(IMetadataExchange), customBinding, "MEX");

        _rhinoServicesHost.Faulted += RhinoServicesHost_Faulted;
        _rhinoServicesHost.Open();

I can now update the references regardless of the number of contracts.

I have to admit though, during this whole process the Attempted to read or write protected memory error that cropped up hasn't gone away since I switched back to this method.

So I guess I have to still track that down...

Also I found this solution on a different question (click to view), answered by @trendl. Thank you for your help.

Community
  • 1
  • 1
Jason Stevenson
  • 4,004
  • 3
  • 29
  • 49