Search

Locations of visitors to this page

Categories

On this page

What's new in WF v4.0
Sharing STS object between Active & Passive clients
Serializing Faults using XmlSerializer

Archive

Blogroll

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

RSS 2.0 | Atom 1.0 | CDF

Send mail to the author(s) E-mail

Total Posts: 50
This Year: 6
This Month: 1
This Week: 1
Comments: 69

Sign In

 Monday, November 03, 2008
Monday, November 03, 2008 10:42:36 AM (GMT Standard Time, UTC+00:00) ( WF )

At the PDC .net Framework 4.0 was announced which will be released along with Visual Studio 2010. Along with .Net Framework 4.0, a new version of Windows Workflow Foundation (WF v4.0) will also be released. This version of WF is greatly improved and enhanced compared to the 1st version (released with .net Framework 3.0). These enhancements address performance and scalability issues along with few key customer scenarios (XAML only workflows, transaction flow etc).

Here are some of the highlights of WF v4.0

·         First class support for authoring XAML only workflows.

·         Rich Activity Data Model which eliminates the need for falling back to code.

·         Simplified Activity Authoring: In this new model there are two ways to author activities:

o   WorklfowElement based authoring mechanism: Exposes the richness and breadth of workflow runtime to the activities.

o   Activity based authoring: Enables a declarative activity authoring (primarily by encapsulating other activities as part of activity definition).

·         Several WorkflowRuntime enhancements:

o   Much better support for high frequency dispatch scenarios. This is done by updating the internal scheduler’s machinery.

o   Support for no-persist zones. This is extremely useful and much demanded feature for Asynchronous scenarios.

o   Support for transaction flow into workflow runtime. E.g If when a transaction is flown as part of a WCF call, WF now can use that transaction in its workflow logic.

o   Support for both Text and Binary serialization for the Persistence service. (WCF DataContract Serializer is now used for Serialization).

§  Support for extracting workflow state as part of persistence and store in a query able relational form.

·         Distributed compensation using the WS-BussinessActivity.

·         Partial Trust support

·         Rules are now tightly integrated with activities and are executed in the same way as activities (no more CodeDom statements/expressions).

·         New WPF based workflow and activity designers. (Writing a custom designer is now a breeze – killer GDI+ expertise not needed anymore J)

·         Rich set of new activities (Database access, PowerShell etc)

·         Support of FlowChart workflow type.

·         Programming Model Alignment with WCF. (Support for WCF extension model as a replacement for WF Service Provider/ Service Container).

·         Better integration among WF,WCF & WPF for writing composite application.

·         Support for new enhanced Expression syntax (derived from VB).

·         Dependency Properties are removed and new Activity Data Model is the preferred way to represent state and argument in activities.

·         Plus much more ...

All of this goodness come with cost which is: WF 4.0 is not backward compatible with WF 1.0. However WF v4.0 will support side by side execution with WF v1.0 and there will be an Interop activity which will let you execute any WF 1.0 activity inside a WF v4.0 workflow.

In next few weeks I will talk more about these enhancements as I explore so stay tuned ...

Comments [0] | | # 
 Sunday, August 17, 2008
Saturday, August 16, 2008 11:19:02 PM (GMT Standard Time, UTC+00:00) ( Zermatt )

Geneva Framework (aka Zermatt) has clean separation between token issuance object model (SecurityTokenService, RequestSecurityTokenRequest etc) and the protocol used to request token. By exploiting this separation, I will show you how to share a single SecurityTokenService object between active (WS-Trust) and passive (WS-Federation) clients. I have already written about Geneva and active clients here so in this post I will focus on passive clients.

Geneva Framework comes with a sample which implements WS-Federation protocol handler in an ASPX page and for most of the scenarios you will use the same approach. Please refer to "Federation Scenario For Passive Clients" sample for details. The approach I am highlighting here is specific to those scenarios where you want to share the STS object between active & passive clients (Or you don't want to take a dependency on asp.net pipeline). To achieve this I will create a WCF based protocol handler (using the WCF http support) for WS-Federation protocol. In this handler I will convert the WS-Federation token issuance request into Zermatt token issuance object model (which is very much similar to WS-Trust protocol) and will then forward the request to a shared STS object.

The service contract for my WS-Federation protocol handler looks like following:

[ServiceContract]

public interface IWSFederationService

{

    [OperationContract]

    [WebGet]

    Message Issue(string wa, string wtrealm, string wreply, string wctx, string wct);

}

I have deliberately named the parameters of this method based on the elements of WS-Federation protocols. This enables WCF QueryStringFormatter to correctly map the values from the HTTP Get “query string” on to these parameters.

public class ProcessService : IWSFederationService

{

    public Message Issue(string wa, string wtrealm, string wreply, string wctx, string wct)

    {

        var col = OperationContext.Current.IncomingMessageProperties["UriTemplateMatchResults"] as UriTemplateMatch;

        // Get the shared STS object.

        var sts = SingletonSTS.Instance;

       

        var fedSerializer = new WSFederationSerializer();

        //create a WS-Federation message for the input data.

        SignInRequestMessage fedRequest = (SignInRequestMessage)WSFederationMessage.CreateFromUri(col.RequestUri);

        //convert the federation request into the common WS-Trust based STS model.

        var rst = fedSerializer.CreateRequest(fedRequest, new WSTrustSerializationContext());

        var rstr = sts.Issue(ClaimsPrincipal.Current,rst);

       

        var rstrStr = fedSerializer.GetResponseAsString(rstr, new WSTrustSerializationContext());

        //serialize the token response back into WS-Federation message.

        var fedResponse = new SignInResponseMessage(new Uri(wreply), rstrStr);

        fedResponse.Write(Console.Out);

        // Set appropriate content-type etc.

        var httpMsg =  Message.CreateMessage(MessageVersion.None, "",new BinaryBodyWriter(fedResponse));

        httpMsg.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Raw));

        HttpResponseMessageProperty rmp = new HttpResponseMessageProperty();

        rmp.Headers[HttpResponseHeader.ContentType] = "text/html";

        httpMsg.Properties.Add(HttpResponseMessageProperty.Name, rmp);

 

        return httpMsg;

    }

}

With that I can host this service as any other WCF service and I’m ready to issue tokens based on WS-Federation protocol.

class Program

{

    static CustomSecurityTokenService sts;

    static void Main(string[] args)

    {

        string stsAddress = "http://localhost:9000/STS";

        SingletonSTS.Init(stsAddress);

        // For active clients, simply expose this sts over a WS-Trust endpoint.

        WSTrustServiceHost wsTrustSTSHost = new WSTrustServiceHost(new WSTrustServiceContract(SingletonSTS.Instance), new Uri(stsAddress));

        wsTrustSTSHost.AddServiceEndpoint(typeof(IWSTrustFeb2005SyncContract),

           new WSHttpBinding(), new Uri(stsAddress));

        // Make the Active STS ready.

        wsTrustSTSHost.Open();

        Console.WriteLine("STS is now ready ...");

        foreach(var ep in wsTrustSTSHost.Description.Endpoints)

            Console.WriteLine(ep.Address.Uri.AbsoluteUri);

 

        //make passive STS ready.

        var wsFedSTSHost = new WebServiceHost(typeof(ProcessService), new Uri("http://localhost/wcf/federation"));

        wsFedSTSHost.AddServiceEndpoint(typeof(IWSFederationService), new WebHttpBinding(), "");

        wsFedSTSHost.Open();

        Console.ReadLine();

 

        wsFedSTSHost.Close();

        wsTrustSTSHost.Close();

    }

}

I have attached completed solution (which contains a test website as well). Feel free to download and experiment.

Download: SharedSTS.zip

Comments [1] | | # 
 Friday, August 15, 2008
Friday, August 15, 2008 9:37:30 PM (GMT Standard Time, UTC+00:00) ( WCF )

Update (25/08/2008): .net Framework 3.5 SP1 has added the support for serializing faults using XML Serializer.

[XmlSerializerFormat(SupportFaults=true)]: by setting SupportFaults=true will result in the use of Xml Serializer for fault serialization as well. The default value is false to maintain backward compatibility. The approach mentioned in this article is still valid for scenarios where you want to use DataContractSerializer for input & output messages but XML Serializer for faults (a rare requirement though).

------------------------------------------------------------------------------------------------------------------------------------------

 

Today someone asked me how to serialize the TDetail part of FaultException<TDetail> using XmlSerializer. The scenario was to interoperate with an existing schema using some of the XSD features (attributes etc.), which are currently not supported by DataContractSerializer. The solution is to Subclass the MessageFault class and use XmlSerializer to serialize the TDetail.

public class XmlSerializerMessageFault : MessageFault

{

    FaultCode code;

    FaultReason reason;

    object details;

    public XmlSerializerMessageFault(FaultCode code, FaultReason reason, object details)

    {

        this.details = details;

        this.code = code;

        this.reason = reason;

    }

    public override FaultCode Code

    {

        get { return code; }

    }

    public override bool HasDetail

    {

        get { return (details != null); }

    } 

    protected override void OnWriteDetailContents(System.Xml.XmlDictionaryWriter writer)

    {

        var ser = new XmlSerializer(details.GetType());

        ser.Serialize(writer, details);

        writer.Flush();

    } 

    public override FaultReason Reason

    {

        get { return reason; }

    }

}

Fault was created from a global error handler (IErrorHandler).

public class ErrorHandlerEx : IErrorHandler

{

    public bool HandleError(Exception error)

    {

        return true;

    } 

    public void ProvideFault(

        Exception error, MessageVersion version, ref Message fault)

    {

        if (error is FaultException)

        {

            // extract our FaultContract object from the exception object.

            var detail = error.GetType().GetProperty("Detail").GetGetMethod().Invoke(error, null);

            // create a fault message containing our FaultContract object

            var msgFault = new XmlSerializerMessageFault(FaultCode.CreateSenderFaultCode("systemDown", "http://zamd.net"), new FaultReason("System is down"), detail);

            fault = Message.CreateMessage(version, msgFault, "http://zamd.net/action");

        }

    }

}

Xml output

<Fault xmlns="http://schemas.microsoft.com/ws/2005/05/envelope/none">

  <Code>

    <Value>Sender</Value>

    <Subcode>

      <Value xmlns:a="http://zamd.net">a:systemDown</Value>

    </Subcode>

  </Code>

  <Reason>

    <Text xml:lang="en-GB">System is down</Text>

  </Reason>

  <Detail>

    <GreaterThan3Fault ErrorCode="90192" Location="ISB" xmlns="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

      <FaultMessage>Count cannot be greate than 3. Please try again later.</FaultMessage>

    </GreaterThan3Fault>

  </Detail>

</Fault>

Comments [2] | | #