Friday, March 27, 2009

WCF CustomBinding Equivalent to WSHttpBinding

@YaronNaveh

It is sometimes useful to build a WCF CustomBinding equivalent to some other binding. This allows a richer set of customizations. Here is the CustomBinding equivalent to the WSHttpBinding defaults (windows authentication):

Update: Convert bindings automatically using the WCF BindingBox.


<customBinding>
   <binding name="MyBinding">
     <textMessageEncoding />
     <security authenticationMode="SecureConversation">
       <secureConversationBootstrap authenticationMode="SspiNegotiated" />
     </security>
     <httpTransport />
   </binding>
</customBinding>

@YaronNaveh

What's next? get this blog rss updates or register for mail updates!

Tuesday, March 17, 2009

Which Binding to Use - WSHttpBinding or WS2007HttpBinding?

@YaronNaveh

The default binding in Wcf 3.0 is WSHttpBinding. Wcf 3.5 brings the new WS2007HttpBinding binding but WSHttpBinding is still the default. These bindings do not interoperate together well due to the fact that WS2007HttpBinding uses some newer standards.

When the client uses WS2007HttpBinding and the server employs WSHttpBinding we may get this exception in the client side:


Secure channel cannot be opened because security negotiation with the remote endpoint has failed. This may be due to absent or incorrectly specified EndpointIdentity in the EndpointAddress used to create the channel. Please verify the EndpointIdentity specified or implied by the EndpointAddress correctly identifies the remote endpoint.


And the inner exception is:


"The message could not be processed. This is most likely because the action 'http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue' is incorrect or because the message contains an invalid or expired security context token or because there is a mismatch between bindings. The security context token would be invalid if the service aborted the channel due to inactivity. To prevent the service from aborting idle sessions prematurely increase the Receive timeout on the service endpoint's binding."


On the server side trace we see


System.ServiceModel.EndpointNotFoundException, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089


And the inner exception:


There was no channel that could accept the message with action 'http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue'.


When the client uses WSHttpBinding and the server employs WS2007HttpBinding we would get the same exceptions with http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue being replaced by http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue.

The reason for the errors is the different WS-Trust versions between the bindings. WS-Trust is used when the negotiateServiceCredential or establishSecurityContext settings are set to true (which is the default). In these cases infrastructure messages are exchanged between the client and the server and these messages require the WS-Trust version to match.

We can see the different versions if we use the reflector to check the bindings static constructors.

In WSHttpBinding:


static WSHttpBinding()
{
  WSMessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005
      WSSecureConversationFebruary2005WSSecurityPolicy11
BasicSecurityProfile10;
}


In WS2007HttpBinding:


static WS2007HttpBinding()
{
...
  WS2007MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13
      WSSecurityPolicy12
BasicSecurityProfile10;
}


So, which binding to use?
In many cases this does not matter since both bindings expose similar functionality.
You might want to consider the following:

  • WSHttpBinding is supported by .Net 3.0 clients.

  • WS2007HttpBinding uses WS-* standards while WSHttpBinding uses drafts. You might face a requirement to work with the standard.

  • Different soap stacks support different standards so if you need to interoperate with a specific framework verify the standards it supports.

  • In the long run WS2007HttpBinding should be used as it supports the actuall standard.


  • Nevertheless, for most services this decision will probably only have a very minor effect.

    @YaronNaveh

    What's next? get this blog rss updates or register for mail updates!

    Thursday, March 12, 2009

    OpenGIS With .Net 2.0 And WCF

    @YaronNaveh

    Geospatial and location based services became very popular these days. One concern for developers of such applications is how to represent the data in the system. This includes simple data types such as points or coordinate systems and complex ones such as advanced topologies. The correct approach is of course to use types from the standard schema set of the Open Geospatial Consortium (OGC).

    For a .Net developer this may imply the following needs:

  • Use xsd.exe to generate classes for serizliation


  • Create .Net 2.0 / WCF web services that utilize these schemas


  • Consume Wsdl's with these schemas



  • Unfortunetely the OpenGIS standard schemas are not interoperable with .Net. This has already been noticed by developers for older OpenGIS versions but newer versions seem to be equality incompatible.

    If you only want the fix without the details download it here and see in the end of the post the fix details:




    Here are some of the errors one gets when trying to consume Gml 3.1.1 and Gml 3.2.1 schemas in .Net:

    Gml 3.1.1 - WCF

    While using "add service reference" we get this error:


    Custom tool error: Failed to generate code for the service reference 'ServiceReference1'. Please check other error and warning messages for details.


    And after this an empty proxy code is generated:


    namespace ConsoleApplication1.ServiceReference1 {

    }



    Gml 3.1.1 - .Net 2.0

    The wsdl importing stage seems to work fine. Let's build a one line client:


    WebReference.Service c = new WebReference.Service();



    Such a simple client - what can possibly go wrong? Well nothing, except this:


    "There was an error reflecting property '_ReferenceSystem'."

    "There was an error reflecting type 'ConsoleApplication1.WebReference.AbstractReferenceSystemType'."
    ...

    "There was an error reflecting property 'Item'."
    ...
    "There was an error reflecting property 'Text'."

    "Member 'Text' cannot be encoded using the XmlText attribute. You may use the XmlText attribute to encode primitives, enumerations, arrays of strings, or arrays of XmlNode."


    And this is after I have omitted some inner exceptions.

    In some cases (depending on .Net 2.0 patch level) the below exception will appear - not much improvement:


    Unable to generate a temporary class (result=1).
    error CS0029: Cannot implicitly convert type 'ConsoleApplication70.localhost.LineStringSegmentType' to 'ConsoleApplication70.localhost.LineStringSegmentType[]'
    error CS0029: Cannot implicitly convert type 'ConsoleApplication70.localhost.LineStringSegmentType' to 'ConsoleApplication70.localhost.LineStringSegmentType[]'


    Finally, depending in the types we reference, we might get this one as well:


    There was an error reflecting type 'ConsoleApplication70.localhost.TopoSurfacePropertyType'.


    Gml 3.2.1 - WCF

    Proxy is generated but the simplest client throws this exception chain:


    There was an error reflecting type 'ConsoleApplication1.ServiceReference1.RingPropertyType'.

    "There was an error reflecting type 'ConsoleApplication1.ServiceReference1.RingType'."

    ...

    "Member 'Text' cannot be encoded using the XmlText attribute. You may use the XmlText attribute to encode primitives, enumerations, arrays of strings, or arrays of XmlNode."



    Gml 3.2.1 - .Net 2.0

    Guess what?


    "There was an error reflecting property '_ReferenceSystem'."

    "There was an error reflecting type 'ConsoleApplication1.WebReference.AbstractReferenceSystemType'."

    ...

    "Member 'Text' cannot be encoded using the XmlText attribute. You may use the XmlText attribute to encode primitives, enumerations, arrays of strings, or arrays of XmlNode."


    Why these errors happen?

    The errors appear in run-time when we instantiate the client proxy or web service. At this stage .Net creates the serialization assembly for each type and fails to do it for the proxy. Actually if we have marked the "generate serialization assembly" build option we could already see these errors in compile time.

    Now what?

    We need to fix the schemas or the proxy in order to make them interoperable with .Net. The fix must be compatible with the original schema, so it may change the schema syntax but must result in an isomorphic schema.

    Making Gml 3.2.1 work

    There are two reasons for this schema incomparability:

  • Cyclic schema references



  • From gml.xsd:


    <include schemaLocation="deprecatedTypes.xsd"/>


    From deprecatedTypes.xsd:


    <include schemaLocation="gml.xsd"/>


    One way to solve this is to remove deprecatedTypes.xsd altogether - it is not really required. We'll be nicer and just replace inside it the reference to gml.xsd with these direct references:


    <include schemaLocation="dynamicFeature.xsd"/>
    <include schemaLocation="topology.xsd"/>
    <include schemaLocation="coverage.xsd"/>
    <include schemaLocation="coordinateReferenceSystems.xsd"/>
    <include schemaLocation="observation.xsd"/>
    <include schemaLocation="temporalReferenceSystems.xsd"/>


  • Non-string lists


  • .Net does not support the xsd:list data type. When the list is of strings it works anyway since unresolved types are treated as strings. But for other types it is not supported. MSDN contains some more information on xsd:list support in .Net.

    basicTypes.xsd contains this:


    <simpleType name="doubleList">
       <annotation>
         <documentation>XML List based on XML Schema double type. An element of this type contains a space-separated list of double values</documentation>
       </annotation>
       <list itemType="double" />
    </simpleType>


    Which becomes this in the .Net proxy:


    ///
    [System.Xml.Serialization.XmlTextAttribute()]
    public double[] Value {
      get {
        return this.valueField;
      }
      set {
        this.valueField = value;
      }
    }


    which causes a run-time error since the XmlTextAttribute is only appropriate on strings.

    The solutions is to replace all non-string lists in the schema to strings so the above becomes:


    ...
    <list itemType="string" />
    ...


    And after this Gml 3.2.1 classes are serializable by .Net!


    Making Gml 3.1.1 work

    This version has two issues:

  • Same issue with lists as in 3.2.1 - same fix


  • I've seen this one a couple of times. Basically when there is a multidimensional array of a type which has a single child element in some cases .Net code generation is incorrect. Don't ask, long story... Just replace in geometryPrimitives.xsd:




  • <complexType name="LineStringSegmentArrayPropertyType">
      <sequence>
        <element ref="gml:LineStringSegment" minOccurs="0" maxOccurs="unbounded"/>
      </sequence>
    </complexType>


    With:


    <complexType name="LineStringSegmentArrayPropertyType">
      <sequence>
        <element ref="gml:LineStringSegment" minOccurs="0" maxOccurs="unbounded"/>
        <any />
      </sequence>
    </complexType>


    And we have 3.1.1 working as well!

    Download fix

    I have uploaded the fixed schemas to save your time:



    After you extract the zip the fixed schemas are in the below folders:


    opengis_net_fixed\gml\3.1.1_fixed
    opengis_net_fixed\gml\3.2.1_fixed

    @YaronNaveh

    What's next? get this blog rss updates or register for mail updates!

    Thursday, March 5, 2009

    Cryptic WCF error messages (part 1 of N)

    @YaronNaveh


    If you are a WCF developer then sooner or later you are going to meet some cryptic error messages. No, they are not as intimidating as “access violation at address FFFFFF” and the blue screen of death, but is “Keyset does not exist“ and the white screen of trace any better?

    This is the first out of a serious of posts in which I'll try to diminish the mystery of these errors. This time I’ll examine an X.509 related issue.

    The other day I was configuring my WsHttpBinding with X.509 certificates used for digital signature and encryption. When I ran my client application I got that annoying

    An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail.

    I hurried up and configured WCF tracing on my service only to get

    The EncryptedKey clause was not wrapped with the required encryption token 'System.IdentityModel.Tokens.X509SecurityToken'.

    This error is not so clear for those of us not familiar with the wire format of web services. However it does contain the essence of the problem: The client and the server are not using matching X.509 certificates. In order for the service to decrypt the message sent by the client it must use an X.509 containing a private key that matches the public key in the X.509 that the client is using for encryption.

    Now if you (like me at the time) insist that you are using the correct certificate, I suggest you would double and triple check the X.509 references in your web/app.config. If that doesn't help - remove and reinstall the relevant certificates from the windows certificate store. You’ll be surprised to find out you used an old version of the certificate at the client side or a wrong reference at the server. One common scenario where this can happen is if you are temporarily using the WCF or WSE sample certificates – it seems there are a few versions of them.

    @YaronNaveh

    What's next? get this blog rss updates or register for mail updates!