SOA Symposium Next Week

I’ll be at the SOA Symposium in Amsterdam next week, and am really excited about it. Amsterdam’s a great place, I’ve been there a few times, and this is looking like it will be a really good event. I could do without yet-another trans-Atlantic flight, but, I’m getting pretty good at doing them.

At the Symposium, I’ll be doing:

  • My first-ever public-facing Oslo presentation, and to the best of my knowledge the second-ever conference presentation on Oslo by a non-Microsoft person (my friend David Chappell was first with one at TechEd this year). This is huge, and a major milestone that I can now talk about at least some of the vision (more will become public at PDC).
  • A panel on the future of ESBs
  • Visiting a user group in Utrecht and doing to do a BizTalk Development Best Practices presentation/workshop

I also plan to do Oslo presentations at a couple of locations in SoCal after PDC (I promise!), including my own user group in San Diego, and the L.A. CodeCamp. More on that later, I have to somehow make it align with a near-100% travel schedule, which will be a challenge, but I think/hope November may be slower, with hopefully “only” 50% or so travel.

Technorati Tags: BizTalk,Oslo,SOA,ESB

The Bloggers Guide to Oslo and Connected Systems V0.2

It’s been a very busy week in terms of announcements. “Dublin” has been announced, and Darren Jefford probably has the best summary of what Dublin is and how it will affect us. Channel 9 has published some great webcasts looking at Visual Studio 2010 and the testing and UML features included in the new release.
I like working with UML, but it’s not had that much exposure on the .net platform. I fought hard with Rational XDE for Visual Studio.net for a few days back in the day, and have also dabbled with Visio, but never found it a satisfying experience. The Top Down design webcast shows that the UML features are comprehensive, and should be very productive, whilst the Bottom Up webcast shows how you can easily visualise a complex project, and drill down into the detailed architecture aspects very easily.

There have also been some great posts relating to “Oslo” and BizTalk Services, so I’ve compiled a new version of “The Bloggers Guide to Oslo”, and renamed it to “The Bloggers Guide to Oslo and Connected Systems” to reflect the changes in scope of the codenames. It’s up on the “BloggersGuides.net” website in the downloads section.

Update to /dev/null R2 Adapter

Antti Somersalo brought to my attention that there was a bug in my R2
version of the /dev/null adapter. The bug manifested itself when you tried to
export the bindings of any BizTalk Application that used the adapter in one of its
send ports, failing with an ArgumentNullException.

The problem was simple: The adapter management class was returning null from
the GetConfigSchema() call. Fixing it was just as simple: Just change
the implementation so that it returns an empty Xml schema:

public string GetConfigSchema(ConfigType
configType) {
   return @"<schema
xmlns='http://www.w3.org/2001/XMLSchema'/>"
;
}

I’ve updated the ZIP
file with the code snapshot.

Tool for undeploying BizTalk assemblies

Ever found it challenging to uninstall a schema or an orchestration? This tool was designed to find all referencing assemblies and related BizTalk artifacts such as Ports, Locations and Orchestrations.

Installing the tool:

The zip-file includes both source code and binaries.

Using the tool:

Important! For the tool to be able to find assembly references, those BizTalk assemblies need to be installed on the same machine as the one you are running the tool on.

 

By selecting one assembly, the tool marks all assemblies that is referencing the one you selected. If the selected assembly includes orchestrations, the tool will look through all orchestration ports for referencing pipeline and transformation assemblies.

 

Before you choose to undeploy, you'll be given a list of all assemblies and BizTalk artifacts related to those assemblies. You'll be given an option to leave the ports, in case the ports will be reconfigured to use passthrough pipelines and no in- or outbound transformations.

Downloads 

Please provide me with feed-back if you find any problems or bugs.

//Mikael

Software in the cloud: Cloud Workflow

As promised in my last posting let’s take a look at the new “Workflow in the cloud” functionality offered in the July drop of the BizTalk Services

This cloud based workflow system leverages Windows Workflow and is hosted in our datacenter and extended as appropriate through “cloud-scale” runtime services and infrastructure.  The idea being that you can run your workflows on our infrastructure which will scale to your throughput needs – subject to appropriate payments.   These workflows will be durable and resilient to any failures – all of this will be transparent to you, simply deploy your workflows and away you go.

As it currently stands you only get one workflow type to use, a sequential workflow which is of course well suited to straight-forward predictable machine workflows.  Within this workflow you get to use Activities but you can’t however use the complete palette of WF activities that you get in the .NET framework.

Your restricted to a number of new cloud activities provided which are as follows: CloudHttpSend, CloudHttpReceive, CloudIfElse, CloudSequence, CloudServiceBusSend, CloudDelay and CloudWhile.

All of these do exactly what they say on the tin, the CloudHttpSend activity enables you to send an HTTP GET or POST to a remote URI, the CloudHttpReceive enables something to send data to a running workflow instance via an HTTP POST.

The CloudServiceBusSend activity may be a new concept to you as it refers to invoking a Service exposed via the Internet Service Bus using the relay service which I covered in this posting. This means you can have a WCF service hosted within your corporate network but still enable it to be invoked from parties outside of your corporate boundary provided they have the appropriate permissions.  In the case of a cloud based workflow, it can invoke services hosted within a corporate boundary from a Microsoft data-center without having to punch new holes in your firewall but still maintain security.

So, let’s take a look at how you can create your own workflow, deploy and execute it using the BizTalk Services release that you can all use.  To start you’ll need to create an account at http://biztalk.net and download/install the BizTalk Services SDK.

The first step is to create a new Sequential Workflow, all cloud workflows must be Sequential Workflows and XOML only.  There is no way to have “code behind” files with these workflows, everything has to be expressed using a workflow, activities and as appropriate rules.  Once this has been created you should consider deleting the automatically created .cs file to avoid you accidently adding code which can’t be used.

Once you’ve done this you should see the new cloud based activities in your toolbox as shown below, if not you may need to right click the toolbox, choose “Choose Items..” and then ensure that the cloud prefixed workflow activities are selected.  These new activities are held within the System.ServiceBus.Workflow assembly under the %PROGRAMFILES%\Microsoft BizTalk Services SDK\Assemblies directory.

 

 

For the purposes of this simple Hello World cloud workflow we’ll just use one activity.  The CloudHttpReceive activity will be used to demonstrate how we can communicate with a running workflow instance.  You shoud have a workflow as shown below

The usual exclamation marks indicate that we have some configuration to do on this activity, for the cloudHttpReceive the only configuration we need to supply is a response that that will be returned as part of the remote HTTP post to our workflow, you can also configure the HTTP Status code to return as required.  For the purposes of this workflow and the code you’ll see in a bit, set the name of this activity to helloWorldHttpReceive and supply a response body of your choosing.

Now that our simple workflow is done let’s deploy it to the Cloud Workflow infrastructure hosted by Microsoft, right now there isn’t a Deploy addin to Visual Studio although there is an underlying Web Service.  For now we need to perform a simple copy/paste deployment model.

Firstly we need to get the XOML representation of the workflow, a quick way of doing this is to right Click the workflow in Solution Explorer, Chose “Open With..” and then choose “XMl Editor”, you can now copy the XOML representation into the clipboard.

We now need to deploy the workflow via the BizTalk Services website, browse to https://workflow.biztalk.net/ and supply your BizTalk Services credentials to view the workflow management portal as shown below.

Click “Manage Types” on the right hand side to manage the workflow types under your account, then click Add New to access the Workflow Deployment page which is shown below.  For the purposes of this demo we’ll call our Workflow “Hello World” and you can now paste the XOML representation into the supplied box.

Click Save changes and your cloud workflow is now ready to go!  Note the “Rules” tab in the previous screenshot, this is where you can also provide any rules associated with your cloud workflow.

Now our workflow is created how can we go about kicking it off within the Microsoft datacenter?  It’s pretty straight forward once you know how to do it and the BizTalk Services SDK has a sample to help you out.   Those of you familiar with BizTalk Orchestrations you’d expect that we could now perform a simple HTTP POST at a special URI and have a workflow instance created automagically?  Not right now, I’m afraid – you have to manually crete an instance, then start it before you can submit an HTTP post, this as I understand it will be changed as the product teams progress.

The code to create, start and then HTTP POST to a workflow instance is shown below, it’s all pretty straight forward and a lot of it is demonstrated in the SDK sample.  The key thing in the code is how to target your HTTP POST of a running workflow instance.  The URI is made up as follows:

http://workflow.biztalk.net/servicesHttp/YOURBIZTALKSERVICESUSERNAME/workflows/YOURWORKFLOWNAME/instances/YOURWORKFLOWINSTANCEID/HTTPRECEIVEACTIVITYNAME

And an example for my scenario here is as follows:

http://workflow.biztalk.net/servicesHttp/darrenj/workflows/HelloWorld/instances/83734f1c-d08f-4cc9-b396-b76ebdb60979/helloWorldHttpReceive

You’ll need to add assembly references to your project for System.ServiceBus.dll, System.ServiceBus.Workflow.dll and System.ServiceModel.dll

[TestMethod]
public void TestMethod1()
{
   
// Create a new Workflow Instance in the cloud, we then get the InstanceID back
  
string instanceId = CreateWorkflowInstanceInTheCloud();

    // The Workflow Type
  
string workflowTypeName = “HelloWorld”;

    // The PlaceOrder Workflow starts with a cloudHttpReceive activity called “placeOrderHttpReceive”
    // We must target this directly when posting our Order information to the cloud workflow
  
string httpActivityName = “helloWorldHttpReceive”;

    // Build up the URL to directly target our newly created Workflow Instance and to post XML directly to the
    // waiting cloudHttpReceive activity

   Uri serviceUri = new Uri(
        string.Format(WorkflowClientConfig.HttpUri + “{1}/workflows/{2}/instances/{3}/{4}”,
        WorkflowClientConfig.WorkflowHostName, _bizTalkServicesUsername, workflowTypeName, instanceId, httpActivityName));

    string httpPostBody = “<HelloWorldWorkflow><Message>Hello World</Message></HelloWorldWorkflow>”;

    // Prepare to perform an HTTP POST to the waiting workflow
  
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(serviceUri);
    request.Method = “POST”;
    request.ContentType = “text/xml”;
    request.ContentLength = httpPostBody.Length;
   
// Add the special header which contains our STS token retrieved from the cloud
  
request.Headers.Add(“X-MS-Identity-Token”, GetTokenFromCloudSts());

    using(StreamWriter writer = new StreamWriter(request.GetRequestStream()))
    {
       
// Write the OrderInformation XML representation into the stream
      
writer.Write(httpPostBody);
       writer.Flush();

        // Wait for a response from the Cloud Workflow, the cloudHttpReceive activity is configured to respond with a fixed
        // Response if succesful;
      
HttpWebResponse response = (HttpWebResponse)request.GetResponse();

        using(StreamReader reader = new StreamReader(response.GetResponseStream()))
        {
            string returnMessage = reader.ReadToEnd();

            Trace.WriteLine(“Response message from the cloud is: ” + returnMessage);
           
           
// For some reason all responses from the cloudHttpReceive activity are wrapped into a <string> element
           
Assert.IsTrue(returnMessage.Contains(“Hello World Response”));
        }
    }
}

private string GetTokenFromCloudSts()
{
    // Using a tokenised URL let's build up a valid URL given the supplied BizTalk Services credentials
    // This URL when invoked will return an authentication token we can then use to perform administrative operations on
    // Our Workflow Configuration (Create, Start, etc.)
    string tokenUrl = string.Format(
            "https://{0}/issuetoken.aspx?u={1}&p={2}",
            WorkflowClientConfig.StsHostName,
            _bizTalkServicesUsername,
            _bizTalkServicesPassword);

    // Create an HttpWebRequest
    HttpWebRequest tokenRequest = (HttpWebRequest)WebRequest.Create(tokenUrl);
    Trace.WriteLine(tokenRequest.RequestUri);

    // No Request to send, just invoke the URL and get the authentication token
    HttpWebResponse tokenResponse = (HttpWebResponse)tokenRequest.GetResponse();

    // Get the token from the Response Stream
    byte[] tokenBody = new byte[500];
    int tokenBodyLength = tokenResponse.GetResponseStream().Read(tokenBody, 0, 500);

    // Convert to a UTF8 representation which we can then use in subsequent requests
    string authenticationToken = Encoding.UTF8.GetString(tokenBody, 0, tokenBodyLength);
    Trace.WriteLine(String.Format("Authentication Token: {0}", authenticationToken));

    return authenticationToken;
}
private string CreateWorkflowInstanceInTheCloud()
{
    // New up an instance of the provided System.ServiceBus.Workflow.WorkflowClient which provides a wrapper
    // around the cloud workflow SOAP Web Servics        
    WorkflowClient workflowClient = new WorkflowClient();

    // Provide BizTalk Services credentials
    workflowClient.CredentialType = TransportClientCredentialType.UserNamePassword;
    workflowClient.Credentials.UserName.UserName = _bizTalkServicesUsername;
    workflowClient.Credentials.UserName.Password = _bizTalkServicesPassword;

    workflowClient.Open();

    // Parameters can't be supplied in R12 of Cloud Services so we this empty
    // A shame as it would enable us to pass the OrderInformatoin directly
    Dictionary<string, object> parameters = new Dictionary<string, object>();

    // Create a workflow within the BizTalk Services username namespace 
    // The Workflow Type name is "HelloWorld"
    // No parameters in R12
    // Retrieve an authentication token from the BizTalk Services Cloud STS
    string instanceId = workflowClient.CreateWorkflowInstance(_bizTalkServicesUsername, "HelloWorld", parameters, GetTokenFromCloudSts());
    Trace.WriteLine("Workflow Instance Created:" + instanceId);

    // Once a workflow is created it must be explicitly started otherwise it won't active any activity shapes
    // In R12 there's no ability to create/start a workflow based on an external activity action such as an Http Send
    // The workflow instance was created within the BizTalk Services username namespace
    // The workflow Type name is "HelloWorld"
    // The instanceId was returned by the previous CreateWorkflowInstance call
    workflowClient.StartWorkflowInstance(_bizTalkServicesUsername, "HelloWorld", instanceId);
    Trace.WriteLine("Workflow Instance Started:" + instanceId);

    // Our work is done, close the WorkflowClient
    workflowClient.Close();

    // Return the InstanceId so we can identify the WorkflowInstance we've just created when we perform an HTTP post to it next
    return instanceId;
}

All pretty straight forward, and it’s a bit more complex then it should be due to the requirement to create and start a workflow instance before being able to perform an HTTP post but this should come in time.

If you navigate back to the https://workflow.biztalk.net site then you can review running workflow instances and check they’ve completed successfully.

That’s it for this post, this post has got rather large so I’ll do another post on calling ServiceBus services via the cloudServiceBusSend activity and also detail some limitations in this release of Cloud Workflow (it’s the first release for the team so don’t expect everything to be there straight away!).  I’ll also cover a handy little ISBTraceTool that I put together to aid with visualizing cloud workflow activity.

More soon!

 

Retrieving Manager details from active directory

The below is a sample of retrieving a Manager / ReportsTo DirectoryEntry from Active Directory for a specified account.

   1: using System.DirectoryServices;
   2: using System.DirectoryServices.ActiveDirectory;

   1: private DirectoryEntry GetDirectoryObject()
   2: {
   3:     DirectoryEntry de = new DirectoryEntry(_path, _username, _password, AuthenticationTypes.Secure);
   4:     return de;
   5: }
   6:  
   7: private DirectoryEntry GetUser(string account)
   8: {
   9:     try
  10:     {
  11:         DirectoryEntry de = GetDirectoryObject();
  12:         DirectorySearcher des = new DirectorySearcher();
  13:         des.SearchRoot = de;
  14:  
  15:         des.Filter = "(&(objectClass=user)(SAMAccountName=" + account + "))";
  16:         des.SearchScope = SearchScope.Subtree;
  17:         SearchResult results = des.FindOne();
  18:  
  19:         if (!(results == null))
  20:         {
  21:             de = new DirectoryEntry(results.Path, _username, _password, AuthenticationTypes.Secure);
  22:             return de;
  23:         }
  24:         else
  25:         {
  26:             return null;
  27:         }    
  28:     }
  29:     catch (DirectoryServicesCOMException dsce)
  30:     {                
  31:         throw;
  32:     }
  33: }
  34:  
  35: private DirectoryEntry GetManager(string account)
  36: {
  37:     try
  38:     {
  39:         DirectoryEntry de = GetUser(account);
  40:         return demanager = new DirectoryEntry(_path + "/" + de.Properties["manager"].Value.ToString(), _username, _password);
  41:     }
  42:     catch (DirectoryServicesCOMException dsce)
  43:     {                
  44:         throw;
  45:     }            
  46: }
  47:  
  48: private DirectoryEntry GetManager(DirectoryEntry de)
  49: {
  50:     try
  51:     {
  52:         return demanager = new DirectoryEntry(_path + "/" + de.Properties["manager"].Value.ToString(), _username, _password);
  53:     }
  54:     catch (DirectoryServicesCOMException dsce)
  55:     {
  56:         throw;
  57:     }
  58: }

Share this post: email it! | bookmark it! | digg it! | reddit! | kick it! | live it!