Yossi Dahan [BizTalk]

Google
 

Monday, September 07, 2009

On ASMX, WCF, namespaces and generated schemas (in BizTalk 2006)

Recently we’ve started to consume a new version of a web service we’ve been using for a while.
We’ve known that, as a whole, not much had changed, only that they have now moved to WCF; they would have migrated their classes to VS 2008 but would expose pretty much the same functions, using pretty much the same parameters.

Still – it appears that BizTalk now insists on generating multiple schemas for the web reference, and as more of the service is moved across more schemas are introduced.

This caused Oleg a fair amount of pain as, when new schemas would be introduced, they would re-order the existing schemas, so reference1.xsd (in the web reference) would suddenly become reference2.xsd, which in turn break out maps.

The process of finding out the logic behind which schemas are created was fairly short and simple, but as I’ve documented it I thought I might as well share it -

Initial observation revealed that whilst the ASMX services’ WSDL file contains all the schemas needed, the WCF services using import statements in the WSDL file; the schemas exist in separate ‘files’.

The ASMX services always uses the XmlSerializer, WCF services use the DataContractSerializer by default, but can be configured to use the XmlSerializer if required.

Here’s a walk thorugh of the scenarios we’ve compared (using BizTalk 2006) -

Standard WCF project, DataContractFormat
We’ll start by comparing the standard WCF sample project generated when you create a new WCF service application in Visual Studio 2008 -

[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);

[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
}

[DataContract]
public class CompositeType
{
bool boolValue = true;
string stringValue = "Hello ";

[DataMember]
public bool BoolValue
{
get { return boolValue; }
set { boolValue = value; }
}

[DataMember]
public string StringValue
{
get { return stringValue; }
set { stringValue = value; }
}
}



Looking at the WSDL generated, 3 schemas are imported –

1.       The usual generic types


2.       The definition of the compositeType type


3.       The definition of the service’s messages (GetData, GetDataResposne, GetDataUusingDataContarct, GetDataUsing DataContractResponse)





Adding a web reference to this service from a BizTalk 2006 project we can see it represents this fairly accurately -


We can see all 3 schemas downloaded from the service, but within the reference.map generated code  a single reference.odx defined the methods in the form of ports and web-messages, and reference.xsd defineds the compositeType schema.



Equivalent project in an ASMX service

I’ve created an equivalent ASMX service, which looks like this –



[WebService(Namespace = "http://tempuri.org/")]
public class Service1 : System.Web.Services.WebService
{

[WebMethod]
public CompositeType HelloWorld(CompositeType composite)
{
CompositeType response = new CompositeType();
response.StringValue = "Hello World";
return response;
}
}

public class CompositeType
{
bool boolValue = true;
string stringValue = "Hello ";

public bool BoolValue
{
get { return boolValue; }
set { boolValue = value; }
}

public string StringValue
{
get { return stringValue; }
set { stringValue = value; }
}
}



Publishing this service I can see it’s WSDL contains (does not use import, but that proved to be insignificant) a single schema that represents the service’s messages and the compositeType definition.



Consume this service from a BizTalk 2006 project and only the WSDL file is downloaded (there are no ‘external schemas’ to worry about) but within the reference.map pretty much the same odx and xsd files are generated, no real difference between ASMX and WCF here.



Next I’ve looked at changing the serializer the WCF service works with from DataContract to XmlSerializer –



Standard WCF project, XmlSerializerFormatter

Now we will change the serializer to XmlSerializer  by adding XmlSerializerFormatAttributre to both the service and the data contracts  



   [ServiceContract]
[XmlSerializerFormat]
public interface IService1
{


…and



[DataContract]
[XmlSerializerFormat]
public class CompositeType
{


The WSDL in this case includes only one import, for a single schema representing both the service messages and the compositeType schema (basic types are not exposed) and BizTalk now only has one schema downloaded, but again – the reference.map code remained identical (one ODX, one schema)



How will adding a second namespace affect these behaviours? Lets investigate -



WCF project, two namespaces DataContractFormat

To demonstrate this I’ll add another data contract - AnotherCompositeType, specify an explicit namespace for it and include it as a second parameter to the GetDataUsingDataContract operation -



[DataContract(Namespace="HttpL://SomeNamespace")]
public class AnotherCompositeType
{
bool boolValue = true;
string stringValue = "Hello ";

[DataMember]
public bool BoolValue
{
get { return boolValue; }
set { boolValue = value; }
}

[DataMember]
public string StringValue
{
get { return stringValue; }
set { stringValue = value; }
}
}

[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite, AnotherCompositeType anotherComposite);



Using DataContractFormat again, but with two classes, representing two different namespaces, we’re now getting yet another schema - the fourth one - representing the added data contract (if the namespaces of both data contracts were the same, the DataContractFormat would have included them in the same schema)



On the BizTalk side, the reference.map code now also contains a second schema, one describes the original CompositeType, and a second describes the second type – AnotherCompositeType and here as well – were the two types in the same namespace, a single schema would exist, describing both.



Let’s look at the same again, using the XmlSerializerFormat



WCF project, two namespaces XmlSerializerFormat

Adding the XmlSerializerFormat, I also have to remember to include the XmlRoot attribute to set the namespace, as the serializer does not look at the DataContract attribute -



[DataContract(Namespace = "http://SomeNamesapce")]
[XmlSerializerFormat]
[XmlRoot(Namespace = "http://SomeNamesapce")]
public class AnotherCompositeType
{
bool boolValue = true;
string stringValue = "Hello ";

[DataMember]
public bool BoolValue
{
get { return boolValue; }
set { boolValue = value; }
}

[DataMember]
public string StringValue
{
get { return stringValue; }
set { stringValue = value; }
}
}



Now the WSDL for this service, using the XmlSerialiserFormat imports two schemas – one for the service messages, and the CompositeType schema, all reside in the same namespace, and a second for AnotherCompositeType which is defined in a separate namespace



Consuming this from BizTalk and again I’m getting two schemas – one for each namespace.

So far – switching between DataContractFormat and XmlSerializerFormat made no difference to the generated code under reference.map, but it did change the way the WSDL is constructed (import vs. embededed schemas) and therefore the downloaded components (wsdl and schemas, vs. wsdl only)



Note - another thing I’ve noticed is that when a new schema needs to be generated under the reference.map code, as a result of a change to the service, updating web reference does not seem to do so; I had to delete the web reference and re-add it to see the newly added schema.



Last  - let’s look at how the ASMX service behaves with two namespaces –



ASMX service with two namespaces

I’ve added the second class, and added it as a parameter to my web method



[XmlRoot(Namespace = "http://AontherNamespace")]
public class AnotherCompositeType
{
bool boolValue = true;
string stringValue = "Hello ";

public bool BoolValue
{
get { return boolValue; }
set { boolValue = value; }
}

public string StringValue
{
get { return stringValue; }
set { stringValue = value; }
}
}


And, still consistent – when consumed from BizTalk 2006 I’m getting only the WSDL downloaded (two schemas are embedded) but the reference.map code contains two schemas – one for each namespace.



To summarise -



Using the DataContractFormat you will always get one schema for generic types, one schema for the service’s messages, and then one schema for each namespace any other types are declared in (0..n)



Using the XmlSerializerFormat  schemas are embedded in the WSDL file, and you would get one per xml namespace used.



As far as BizTalk generated code is concerned, however, there’s no difference between the two.



 



What this meant to us – well – we understand better, but there’s still not much we can do.



In our case – we control the service, and – in fact - we know that the only reason we encounter multiple xml namespaces in the service contract is because the various classes exist in several .net namespaces, and they have not supplied the DataContract attribute on any class, they have certainly no supplied the namespace parameter to that attribute, which meant the .net namespace was used as the xml namespace, resulting with multiple namespaces and therefore multiple schemas.



One that team added the attribute, and used a consistent xml namespace throughout, our immediate problem was solved; however - had it been a third party’s service we would not have that luxury and we would have had to update our code whenever we update our web reference, even if only new types were added in a backwards compatible way (as the schema ordering may have changed)



On that – it’s probably easier to simply rename the schemas (and the underlying .net types) under the reference.map generated code rather than the referencing maps and messages.


Labels: , ,

Thursday, August 20, 2009

Loosely coupled - Part I

I’m working on a fairly large BizTalk implementation, which in many ways does not fit the classic BizTalk project pattern in that, whilst it has a large element of integration to it, it is even more a business process rich application.

One of the things that constantly keeps us busy is trying to strike the right balance between complexity/performance and maintenance, and a big part of that is finding just how loosely coupled the solution can and should be; this is something I find ourselves spending more and more time on.

There are two parts to this challenge for us – one is about ensuring our processes are not too tightly coupled with any of the many services we’re calling (internal or external) and the other is that different ‘areas’ of our solution, although implemented on BizTalk, and even in most cases within the same group, are treated as independent ‘services’ and are decoupled from each other; we’ve learnt the hard way the price of not getting good enough – mostly in terms of maintenance complexity and cost and are keen to find the right answers, if there are any.

In this part I would like to start tackling the first point – calling services -

In a recent post I ranted somewhat about the WCF’s adapter lack of support for multi-part messages, a topic I’m likely to come back to every now and then I suspect.

This was triggered by my attempt to prototype a way to call services from orchestrations in a loosely coupled way – ideally without the orchestration having to know about the service implementation (isn’t that the promise behind BizTalk Server?)

Naively, I started with a very simple plan – the orchestration would have its own representation for the service call, which it would publish to the message box; the send port, configured with the WCF adapter, would pick up the request based on some subscription, a map in the send port would convert the request to the service’s format and the service would be called; the response would be handled in a similar way.

I have documented that approach here

This worked pretty well in my little prototype, and I was rather pleased with myself for a short while, at least until Ben was tasked with taking this approach into our real world; it took very little time for it to break – all he had to do is call a real service - one that takes more than one parameter (how’s that for a lesson to not over simplify prototypes…)

To be fair, this needn’t be an issue, had we not used multipart messages in our processes, but – accustomed to using the SOAP adapter were using multi-part messages to represent the numerous parameters to the service, and – as I’ve hinted in my previous post – I do sincerely believe this to be the better approach.

That meant two things – 1. the WCF adapter would not be able to transmit the message, as it does not support multipart messages, and - 2. we would only be able to map the body part of the message.

These pretty much put a lid on my idea.

The WCF adapter’s lack of support for multi-part messages we could probably work around using a custom assembler or encoder – such a component could take a multipart message and convert it to a single part message using some pre-defined rules and/or part names, context properties, etc. but the map limitation really puts the lid on this approach.

What can we do then? well – we’d have to create a schema in our process that contains all the parts needed for the service calls, this does not have to look like the service contract, but it does have to contain all the information required to construct the service’s request and effectively means describing the multipart message in XSD; this makes me slightly uncomfortable as, in a sense, this schema exists specifically for this service; it also means we would have to work harder in the process to construct this message – on top of creating and deploying another schema, we would also need some map to convert the multiple messages containing the information to the single entity (or use some code to achieve the same), but it would work – once we have the single part message, we could publish it, map it to the service’s format in the port and deliver it to the service, in the exact same way that worked in my prototype.

At the moment, this looks to me as our only bet, but I’m looking for alternatives, if anyone has any suggestions?

Labels: , ,

Wednesday, March 18, 2009

ASMX, WCF and enums woes

We’ve been slowly migrating our services from asmx to WCF, but as we’re still using BizTalk 2006 with no support for WCF we’ve been exposing endpoints configured for basicHttpBinding and consume them using the SOAP adapter.

Generally speaking things have been going well, although we completely gave up on the idea of moving the services to WCF and NOT have to change the client, until yesterday we’ve stumbled into a serialisation issue –

The SOAP adapter, as part of its work deserialises the request message arriving through the send port into t he web service proxy class it generated, before calling the web service (which would result in the class now being serialised back into xml, which is another story); that deserialisation failed.

The error message was clear enough and indicated it failed to deserialise an enum parameter the service was expecting, and that ran a bell – I posted on exactly that back in September, but after carefully checking and re-checking everything we could swear that our message (which was now suspended) matches perfectly the schema generated by the add web reference wizard; what’s going on then??

After chasing our tail for a short while we brought up reflector to the rescue and found out the cause of our woe is a combination of a difference in behaviour between WCF and ASMX and the use of BizTalk – here are the details –

Consider the following asmx web method  –

[WebMethod]
public string GetDataUsingDataContract(CompositeType.someEnum myEnum)
{
return "Hello World";
}

With CompositeType being

public class CompositeType
{
public enum someEnum
{
Value1,
Value2
}
}

(..and pretend CompositeType has many more things, but these are irrelevant to this topic)


The definition for myEnum in the WSDL looks like

<s:element minOccurs="1" maxOccurs="1" name="myEnum" type="tns:someEnum" />

Where the type tns:someEnum looks like

<s:simpleType name="someEnum">
<
s:restriction base="s:string">
<
s:enumeration value="Value1" />
<
s:enumeration value="Value2" />
</
s:restriction>
</
s:simpleType>

As a result the definition of the enum in a proxy generated via the add web reference VS 2005 option (which is what BizTalk would use) looks like –

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "2.0.50727.3053")]
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://tempuri.org/")]
public enum someEnum
 {
Value1,
Value2,
}

All makes sense.


Now, let’s look at what WCF does in the same case; consider the following service –

[ServiceContract]
public interface IService1
{

[OperationContract]
string GetDataUsingDataContract(CompositeType.someEnum myEnum);
}

[DataContract]
public class CompositeType
{

public enum someEnum
{
Value1,
Value2
}
}

The WSDL generated looks like

<xs:simpleType name="CompositeType.someEnum">
<
xs:restriction base="xs:string">
<
xs:enumeration value="Value1" />
<
xs:enumeration value="Value2" />
</
xs:restriction>
</
xs:simpleType>
<
xs:element name="CompositeType.someEnum" nillable="true" type="tns:CompositeType.someEnum" />

The key difference is that the name of the class containing the enum has made it into the type name for the enum, which never happened in the ASMX version.


As a result the proxy is generated as such -

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="CompositeType.someEnum",
Namespace="http://schemas.datacontract.org/2004/07/WcfService1")]
public enum CompositeTypesomeEnum : int
{
[System.Runtime.Serialization.EnumMemberAttribute()]
Value1 = 0,
[System.Runtime.Serialization.EnumMemberAttribute()]
Value2 = 1,
}

Again – note the name given to the element now contains the class name and, crucially, a dot (‘.’).


On it’s own – nothing to malicious – although it’s another nail in the coffin for the idea that you can substitute web service with WCF service, configured them to use basicHttpBinding and all should be the same (ok – am I the only one still wishing this was possible?)


Enters BizTalk.


When you use the add web reference wizard to add a reference to the WCF service, BizTalk generates all the schemas and proxy for you, which is what you would use to create requests going to the service (and process responses).


Because the WSDL of the WCF service contains the longer name of the enum (with the class name, the dot and the enum name) the .net proxy generated is identical to the one created for the WCF service above; the schema, however, is generated incorrectly!


BizTalk “kindly” decides that having dots in the element name is not a good idea and removes it so the schema generated looks like this –

<xs:schema xmlns:tns="http://schemas.datacontract.org/2004/07/WcfService1" elementFormDefault="qualified" 
targetNamespace="http://schemas.datacontract.org/2004/07/WcfService1"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="CompositeTypesomeEnum" type="tns:CompositeTypesomeEnum" />
<
xs:simpleType name="CompositeTypesomeEnum">
<
xs:restriction base="xs:string">
<
xs:enumeration value="Value1" />
<
xs:enumeration value="Value2" />
</
xs:restriction>
</
xs:simpleType>
</
xs:schema>

“CompositeTypesomeEnum”??????


Well, we’ve seen this, and created a message with exactly that element, which – of course – the SOAP adapter failed to deserialise into

[System.Runtime.Serialization.DataContractAttribute(Name="CompositeType.someEnum", 
Namespace="http://schemas.datacontract.org/2004/07/WcfService1")]
public enum CompositeTypesomeEnum : int
{
[System.Runtime.Serialization.EnumMemberAttribute()]
Value1 = 0,
[System.Runtime.Serialization.EnumMemberAttribute()]
Value2 = 1,
}


The solution was fairly simple – we’ve simple change our xsl to put the element name as the .net proxy requires it, and not as the schema describes it, and it all worked well.

Labels: , ,

Sunday, January 25, 2009

Specifying the user for a service to run as

Mostly a reminder for myself, but hopefully useful to somebody else -

Often it is important to specify a specific user for a service to run as; it appears the setup is completely different when using IIS 5.1 or 6 (and higher).

 

When using IIS 5.1

  • Set the anonymous user on the virtual directory to the user you want to run as.
  • Disable any other authentication method on the vdir
  • In the web.config turn impersonation ON (<identity impersonate="true" /> under System.web.)
  • Under System.serviceModel add  <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
  • To the service class add  [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]

 

When using IIS 6.0

  • In the web.config turn impersonation OFF(<identity impersonate="false" /> under System.web.)
  • Set the required identity in the app pool your virtual directory runs under.

 

(which one do you prefer? ;-))

Labels: ,

Tuesday, January 13, 2009

Calling a service with federated identity from BizTalk Server [2009] – Part I

Finally I’ve reached the point where I’m ready to hook up BizTalk to my STS implementation to participate in a federated identity scenario.

My goal is to confirm two scenarios -

1. Being able to call from a BizTalk process a service that uses the ws2007FederationHttpBinding (and requires that the caller provide a token issued by a specific STS)

2. Being able to expose a service in BizTalk that would use the ws2007FederationHttpBinding requiring the caller to provide such token.

If you followed my previous posts you would probably know that I already have a fairly extensive federated identity scenario – I have a custom STS built using the Geneva Framework, a few web sites and a test WCF service all use the STS for their authentication (and, indirectly, authorisation), so it is just a case of hooking BizTalk to all of that, and to start with I decided to try and consume that test service from a BizTalk process.

I’m using BizTalk 2009 Beta to keep things interesting, but I’m pretty sure it would all be exactly the same for R2.

The beginning was easy – in my BizTalk project I’ve used the “Consume WCF Service” wizard from the “Add Generated Items” menu to generate all the artifacts needed to consume my service; the generation went very smoothly and soon enough I had an orchestration that could receive a dummy trigger message, create the service request, receive the service response and deliver it to a send port for me to check it out.

I’ve deployed the project and then imported the binding file generated by the wizard to create the WCF send port.

Checking the port configuration, though, I found a few issues -

The port uses the WCF-Custom adapter, which was correctly configured with the service’s endpoint and the ws2007FederationHttpBinding; however – my STS endpoint is configured to use the ws2007HttpBinding and requires UserName credentials, but these settings were not copied over to the client configuration from the service's contract, the client configuration should have looked like -

<security mode="Message">
  <message algorithmSuite="Default" issuedKeyType="SymmetricKey"
    issuedTokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1"
    negotiateServiceCredential="true">
    <issuer address="[STS URL HERE]” binding="ws2007HttpBinding" bindingConfiguration="stsBinding">
      <identity>
        <dns value="STS"/>
      </identity>
    </issuer>
    <issuerMetadata address="[STS MEX ENDPOINT HERE]" />
  </message>
</security>

(with corresponding Ws2007HttpBinding named stsBinding with all the relevant configuration), but the binding attribute and the bindingConfiguration attribute were missing.

It is worth noting here that this problem is by no means BizTalk specific – exactly the same thing (missing configuration) happens when I add a reference to my service from a ny standard .net app.

Also worth noting that in my case, and I don’t know how representing this is, this resulted in WCF trying to open the CardSpace card selector when I tried running the process, resulting in an error - “The channel is configured to use interactive initializer 'System.ServiceModel.Security.InfocardInteractiveChannelInitializer', but the channel was Opened without calling DisplayInitializationUI.  Call DisplayInitializationUI before calling Open or other methods on this channel.”

Easy enough to fix, I thought, as I opened the adapter’s configuration for the send port finding that indeed there are the equivalent fields in the UI (the image shows them AFTER I have typed in the values I needed) -

image

However, after adding the missing two values and confirming the changes I kept getting the same error; it only took two minutes of head scratching to realise what was going on – opening the send port configuration again showed that the values I’ve carefully typed in have not been persisted, and are now gone again; this must be a bug, which I’ve since confirmed exists in BizTalk 2006 R2 as well;in fact – even the issuer address, which was previously there, was removed from the configuration when trying to apply my additions.

Luckily importing these settings through a bindings file does work (as was evident from the fact that the issuers address did exist initially), and so I’ve edited my bindings file manually to include the missing settings (as well as the issuer identity setting which I later found out was missing for my scenario) and imported it using the admin console; checking the send port configuration I could now see my values for the “binding” and “bindingConfiguration” properties.

This raised another question, though – how do I configure this binding? ws2007FederationHttpBinding is somewhat “special” in the sense that there’s effectively an endpoint inside an endpoint:

Using this binding you have your service’s endpoint and it’s binding configuration; then the message security element of the ws2007FederationHttpBinding has the issuer element which is effectively the endpoint of the STS with the address, the binding and the binding configuration (there is no need for a contract attribute as the contract is known – it is the wsTrust contract); this means that I now need to have another set of binding configuration in my WCF configuration – for the STS – which in my case uses ws2007HttpBinding, but there isn’t a way to add another binding through the send port configuration dialog directly.

Initially I tried to add the relevant configuration to the BizTalk configuration file (BTSNTSVC.exe.config), but it didn’t work – and I can’t quite explain why yet.; what did work, which is good enough for me for now, was to put that exact same configuration in the machine.config; no idea why, but it works.

Another options, described in the documentation  is to use the Import option or the ExplorerOM API.

And so – once I’ve done that, when I ran my process it called the send port going to my service, but the WCF adpater contacted my custom STS first, retrieved a security token from it, and then called my test service passing this token, which meant the service was allowed to execute.

I’m impressed!

There is one, fairly big, inefficiency here now, though – BizTalk does not appear to be caching service proxies, which means it will not cache anywhere the issued token, which in turn means a call to the STS must precede every call to my protected service; not ideal.

Luckily - one of the WCF samples provided by MS demonstrates how to create a behaviour that would cache such tokens locally; at some point (probably not right now, unfortunately) I will have to see how well this plugs into BizTalk (if at all), but I suspect it’ll work well; find that sample here.

Labels: , , ,

Saturday, November 29, 2008

Calling a service without adding a reference in BizTalk 2006 and BizTalk 2006 R2

We’ve been experimenting with calling ASMX web services from orchestrations without having to add a web reference (for the SOAP adapter) or use the generated items (for the R2 WCF adapter).

The idea, in short, is to achieve increased decoupling between systems even in a web service scenario -

Generally when you add a reference to a service in BizTalk 2006 or in R2 (although there are some clear differences between the implementation) the schemas for the request and response types are generated for you as well as an orchestration which defines message and port types using those schemas.

When using the SOAP adapter the types generated are somewhat “special” and they encapsulate a little bit of black magic; luckily the WCF adapter which shipped with R2 is much better in the sense that there’s nothing special about any of these artifacts (which also explains why it is now “Add Generated Items” and not “Add Service Reference” – as this is all it’s doing).

What this means is that if you follow the path that BizTalk leads you through you will get all these artifacts in the same assembly with your orchestration, which means you are now tightly coupled with the web service contract; not the end of the world, but if you want to stay true to the idea behind BizTalk - in which your processes can be masked from changes in the other applications you have to play pretend a little bit.

We thought that if we had the web service schemas in a separate assembly, and our process only used it’s own representation of the data (which would, ideally, be less than the entire data provided by the, mostly generic, web service) we could then map between the two in the port rather than in the orchestration, which would mean that if the web service changes, all we will need to do (in theory, at least) is re-deploy the assembly with service’s schemas assembly the and the map.

 

So – how I went about doing that with the WCF adapter -

Following best practice I had an assembly to hold all of “My” schemas – these are the ones describing entities in my domain.

I then created an orchestration assembly to contain my orchestration, which references the schemas assembly; the orchestration assembly has no other dependencies.

I then created a third assembly to include all the types for the service - I went through the “Add Generated Items” wizard to get all the artifacts, but I only really used the schemas (and not the message or port types); this assembly, like the schemas assembly, has no dependencies.

I then progressed to create a fourth assembly to hold the mapping between my schemas and the service’s schemas; naturally this assembly references both projects, but, crucially, it is referenced by no-one.

So – at the end of this we get the following -

 

image

I then imported the send port bindings generated by the wizard to create the send port; I could have quite happily created it from scratch as there’s nothing special in that port - with the exception of one point, discussed next - so this was really just to save me some time, and added the two maps I’ve created to map the process output format to the service request and the service response to the process input format.

Goal achieved – the process knows nothing about the service – all is done externally to the process through port configuration.

But did it work? Almost - running this scenario I received a soap fault from the service complaining about a misunderstood soap action; makes sense I thought – how would BizTalk know which service operation I wanted?

Well, the WCF adapter has a very nice way to figure out the soap action to use (in my view) – as part of the port configuration there’s a bit of xml that provides mapping between an orchestration send port’s operation name and the required soap action; the setting looks something like this -

 

image

In the generated port type the operation name matches the operation name in the service description (“HelloWorld”, in my example), which, in turn, is mapped through this xml to the relevant soap action; as I did not use the generated types the operation name did not match – I simply left it as the default “Operation_1” (naturally…); that meant that when the request came the adapter failed to find a matching operation.

Somewhat annoyingly, what the adapter does when it can’t resolve the name is to assume that the entire setting should be used as the soap action and so the entire xml was written to the header;  this behaviour is there to allow one to specify a fixed header to use, but I think the experience could be a bit better there – they could have had two different settings, or at least realise that if I’ve put a BtsActionMapping xml in there I do not intend for it to be used as the header itself(!), and so, if the relevant entry was not found the request should be suspended rather than going out incorrectly to the service; never-the-less the operation could not be resolved, of course, and the service returned a soap fault.

Fixing the issue was easy and simply meant adding the correct entry in the xml and running the scenario again, this time it completed successfully.

 

How does that differ using the SOAP adapter?

Using the SOAP adapter the approach was naturally very similar; pretty much the same assemblies, pretty much the same artifacts; there are three key differences though -

For starters the soap adapter requires a proxy; in most scenarios you’re using a web port type which provides the adapter with a proxy and so in most cases you don’t have to worry about this at all; I can imagine that some are probably not even aware but the send port, using the SOAP adapter, will have the web service proxy set in the “Web Service” tab of the adapter configuration to “Orchestration Web Port”.

Alternatively you can provide a custom proxy class, which is a topic by itself (and you can check it out in Richard Seroter’s post on the topic here), but in most standard cases this is not required.

As I’m not following the “standard” approach I had to create a custom proxy for my send port; I did this by using WSDL.exe and configuring the proxy class in the send port as described in Richard’s post.

In my case, however, unlike Richard’s, I did not wish to pre-defined the method called in the send port; luckily – the configuration allows you to set it to “Specify Later”, which means the method name will be provided per request through the message context (using the SOAP.MethodName property).

Taking the “Specify Later” approach means I don’t have to have a send port per method, which is good of course, but pay attention to my note regarding number of ports in the summary below.

Now that I have the send port and proxy configuration sorted I needed to get the web service’s schemas; I could do that by using XSD.exe and add the output to my service types assembly.

Last thing – when using the soap adapter you don’t generally need to have an XmlDisassembler in the pipeline; however – if you want BizTalk to be able to run a map it needs a “proper” message type in the context, not that awkward one the SOAP adapter puts, and so the XmlDisassembler becomes mandatory in this scenario.

other than that everything else is pretty much the same.

 

So – to summarise –

Calling a service from a process, without the process knowing ANYTHING about the service implementation is very easy, the story is slightly better in the WCF adapter case in my view, but both seem to me quite reasonable.

The only downside to this approach that I could think of so far, is that you are likely to end up with as many send ports as you have response output formats -

As far as requests from the orchestrations to the web service are concerned BizTalk will quite happily pick up the right map from a list of configured maps based on the input; so - if process A has one output format and Process B has a different output format and they both share the same send port – BizTalk will pick up the relevant map to convert either outputs to the service’s request.

On the way back, however, the incoming message (the service’s response) always looks the same, and so BizTalk will have no way of knowing which map to pick from the list.

That means that multiple send ports will have to be created for such cases so that there’s only one map for the service’s response; a large number of those may have some impact on the overall performance of the server group as the number of subscriptions that need to be evaluated increases; what “large” means in this context and how big is the impact is not something I could say easily, so I’d suggest doing some benchmarking to find out in your environment if you are concerned.

Labels: , ,

Sunday, November 02, 2008

Non-Optional Claims in the Geneva Framework

I'm currently doing some work with the Geneva Framework (formerly known as "Zermatt"), which I am very excited about;
With the SOA wave and now the coming Cloud wave, federated identity becomes a crucial component in the enterprise and it is great to see such a good story for it from Microsoft.

Using the "Zermatt" SDK (I now need to download the updated framework and align with it) I have succesfully, and quite simply, managed to create both an active STS scenario and a passive STS scenario, both sharing the same underlying STS code; this was a great experience and I hope to post some more details over the next few days.

I was, however, a little bit surprised by the behaviour of the framework around non-optional claims -

 

In my scenario the RP (=relaying party, the service the client actually want to call) indicates through its configuration that it requires a specific (custom) claims, which is not optional -

<security mode="Message">
  <message>
    <claimTypeRequirements>
      <add claimType="http://myCompany/claims/someClaim" isOptional="false"/>
      <add claimType=http://myCompany/claims/someOtherClaim isOptional="false"/>
    </claimTypeRequirements>
    <issuer address="http://localhost:6000/STS"/>
    <issuerMetadata address="http://localhost:6000/STS/mex"/>
  </message>
</security>

 

When the client adds a web reference to this service, it is correctly configured with the STS details and the required claims (not posted here, I will try and describe my scenario in detail in a separate post) and so when it calls the service, WCF ensures it first hits the STS requesting the claims as indicated in the config.

You would all probably know that when thinking about any aspect of security in WCF the story is very “tight”, in the sense that you could set up pretty much all the requirements in configuration should you wish to and you could trust that the service’s code will never get executed if these are not met; I believe this is a key design point for WCF - the implementer of the method should not need to worry about how authentication is implemented, nor should you need to change the code if you decide to change your authentication method.

Considering this I expected the STS to try and provide all the claims it can based on the request message and/or configuration for the RP, and then I would expect the channel on the RP side (using the "Geneva" Framework to reject any requests that arrived without all the non-optional claims BEFORE calling the service’s code.

When testing my scenario I deliberately set the STS code so that it does not provide the required and was surprised to find out this was not the case.
My service's method was called whether both claims existed or not; I did have, of course, full access to the claims in code and so it was fairly easy to validate the existence of the claims required, but this seemd a little misaligned with the WCF approach to all the other security aspects and quite wrong frankly.

I could not find much help online (this is still early days for the framework), and checking with a couple of people they all confirmed both my observation and my expectations; luckily for me, though, I was able to attend PDC and so I made sure to give a visit to the Identity folks' booth.

I'm happy to say that they as well have confirmed that the expectation is quite valid and indeed, they expect this behaviour to change before RTM; hopefully this will happen which would keep things nice and tidy.

Labels: , ,