WF 3.5 and SendActivity issue.

I am working on some .net 3.5 workflows, I’ve read that a migration to the fourth version of the framework is strongly reccomended for reasons spacing from perfomance to a better integration with WCF. Anyway, I was not able to invoke a WCF having a basicHttpBinding, in order to get it working I had to add a wsHttpBinding. Apart from that, at this link there are all the infos needed on how to invoke a WCF service (in my case it had a one-way contract) from a workflow using a SendActivity : http://msdn.microsoft.com/en-us/library/cc626077.aspx.

Increase message size in WCF

During the testing of a WCF service, for certain requests I started to get the following error : “The maximum string content length quota (8192) has been exceeded while reading XML data”. While on a classic asmx web service in order to specify the maximum lenght for a request with the tag <httpRuntime> in WCF things have changed a bit.

If you’re using WCF 4 you should already have noticed the huge simplification in the configuration if compared to versions 3.0/3.5. Much less stuff to care about if you want a simple service up and running, but of course if there is the need to tweak it, there’s no escape from the config, and this is the case because to increase the size of the request to the service we need to add some keys in the config. Luckly, the “Service Configuration Editor” shipped with Visual Studio make this changes almost painless.

Start by opening the configuration file within the tool and add a new service. Choose the assembly of your WCF project and select the service you want to configure:

image

Next step is to create an endpoint where we will specify the characteristics of the message:

image

Once this is done your configuration file should look like this:

<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
          <binding name="LargeContent" maxReceivedMessageSize="655360000">
            <security mode="None"/>
            <readerQuotas maxDepth="32"
                          maxStringContentLength="655360000"
                          maxArrayLength="163840"
                          maxBytesPerRead="4096"
                          maxNameTableCharCount="1638400" />
          </binding>
      </basicHttpBinding>
    </bindings>
    <services>
      <service name="CompanyName.PrintGiftMessage.Services.PrintGiftMessage">
        <endpoint address="" binding="basicHttpBinding" bindingConfiguration="LargeContent"
          name="PrintMessageEndPoint" contract="CompanyName.PrintGiftMessage.Services.IPrintGiftMessage" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="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>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
</configuration>

You are using tools (like web service studio) to test the service, you can change the value of includeExceptionDetailInFaults to true so you can get the full exception details in case of errors.

WCF – Merge WSDL in a single file

It can happen that old clients dislike the way WCF separate WSDL descriptors. By default, a WCF service contains the full WSDL in an external “link” specified by the wsdl:import directive. If I browse the following service http://localhost:8695/GiftMessageService.svc?wsdl i’ll get a description of the service (like ports, address) but nothing about the soap actions and messages we’ll need to use. There is the wsdl:import for that.

<wsdl:import namespace="http://tempuri.org/" location="http://localhost:8695/GiftMessageService.svc?wsdl=wsdl0" />

So, if we navigate to “http://localhost:8695/GiftMessageService.svc?wsdl=wsdl0″ we’ll get an extensive description of the operations supported, the types and so on. What WCF doesn’t allow to do is to merge these two wsdl in one file (url).  Luckly there are a few tools out there helping us, I’ve tried WCFExtras: it does a loads of feature not provided natively with WCF and one of these features is the chanche of combining the WSDL in one file only.

Download the component, add it as a reference in your project and follow the documentation, the relevant section we will need in the config is the following:

<endpointBehaviors>
  <behavior name="Sample.WsdlSampleEndpointBehavior">
    <wsdlExtensions singleFile="true"/>
  </behavior>
</endpointBehaviors>

Let’s give a try by browsing the service. We’ll probably get this error:

An ExceptionDetail, likely created by IncludeExceptionDetailInFaults=true, whose value is: System.InvalidOperationException: An exception was thrown in a call to a WSDL export extension: WCFExtras.Wsdl.WsdlExtensions Endpoint: http://localhost:8695/GiftMessageService.svc —-> System.ApplicationException: Single file option is not supported in multiple wsdl files.

In order to fix it both the class and the contract MUST have the same namespace:

[ServiceContract(Namespace= "http://Sample/GiftMessageService")]
public interface IGiftMessageService
{
  [OperationContract]
  string GetEncodedGiftMessageImage(int deliveryNumber, int lineItem);

  [OperationContract]
  string GetEncodedGiftMessageImageWithQuality(int deliveryNumber, int lineItem, int quality);
}
[ServiceBehavior(Namespace = "http://Sample/GiftMessageService")]
public class GiftMessageService : IGiftMessageService
{....

Two easy ways to expose a WCF as a WebService (even asmx)

Assuming we’re all using Visual Studio 2010, start by creating two projects: a WCF Service library project and a WCF

image image

The service library will contain the contracts and their interfaces with all the service attributes while the service application will be the project exposed by our web server, it will have the *.svc and *.asmx files along with the config file containing all the WCF settings. Let’s see the simplest contract possible:

[ServiceContract]
public interface ITimeManager
{
   [OperationContract]
   DateTime GetActualTime();
}

public class TimeManager : ITimeManager
{
   public DateTime GetActualTime()
   {
       return DateTime.UtcNow;
   }
}

We create two services in the service application containing the reference to the contact, nothing prevent us from creating:

image

Where the markup will be the following:

//This will be included in TimeServiceSVC.svc
<%@ ServiceHost Language="C#" Debug="true" Service="Giorgio.WCFasWS.Library.TimeManager" %>

//This will be included in TimeServiceASMX.asmx
<%@ WebService  Language="C#" Debug="true" Class="Giorgio.WCFasWS.Library.TimeManager, Giorgio.WCFasWS.Library "%>

If we now try to browse one of the services on IIS we will probably get the following exception:  Could not load type ‘System.ServiceModel.Activation.HttpModule’ from assembly ‘System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′

Register Asp.Net 4.0 to fix the error by running aspnet_regiis -iru (go here for more details)

If you want your WS to be fully exposed (and declare it to use basic profile) decorate the contract as follows:

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1, EmitConformanceClaims = true)]
[ServiceContract]
public interface ITimeManager
{
    [WebMethod]
    [OperationContract]
    DateTime GetActualTime();
}

public class TimeManager : ITimeManager
{
    public DateTime GetActualTime()
    {
        return DateTime.UtcNow;
    }
}