Archive for September, 2010

Clean paths with WCF Hosted Workflows

I am a big fan of the things added to WCF 4.0. One of those things is the deep integration with ASP.NET routes. Today, I was writing a service in WF and hosting the workflow with WCF. I really didn’t like the service URL-yeah, I’m a picky developer who doesn’t like exposing implementation details in the URL.

I knew a few things:

1. WF/WCF integration provides a ServiceHostFactory named WorkflowServiceHostFactory for hosting XAMLX files in WCF.

2. WorfklowServiceHostFactory will see CreateServiceHost called with some constructorString plus a bunch of baseAddresses.

3. I wanted the host to work on HTTP only-I don’t care about goofy URLs for net.tcp.

4. XAMLX services do not have a runtime defined type- they exist only in XAML.

My goal was to create a new route type, like ServiceRoute, that allowed me to pass in the desired path and the path to the XAMLX to instantiate. After a few minutes of thinking and hacking, I had the following:

 

public class WorkflowServiceRoute : ServiceRoute
{
  public class HostedWorkflowServiceHostFactory : 
    WorkflowServiceHostFactory
  {
    public HostedWorkflowServiceHostFactory(string xamlxPath)
    {
      XamlxPath = xamlxPath;
    }

    string XamlxPath { get; set; }

    public override System.ServiceModel.ServiceHostBase CreateServiceHost(
      string constructorString, Uri[] baseAddresses)
    {
      return base.CreateServiceHost(XamlxPath, baseAddresses);
    }
  }

  public WorkflowServiceRoute(string routePrefix, string xamlxPath)
    : base(routePrefix, 
           new HostedWorkflowServiceHostFactory(xamlxPath), 
           typeof(object))
  {
  }
}

I’m pretty happy with the succinctness of the class and the fact that it works on the few use cases I have at hand. Requests are directed to the correct locations and integration seems to be just fine. Use of the WorkflowServiceRoute is just:

routes.Add(new WorkflowServiceRoute("helloWorld", "SimpleWorkflow.xamlx"));

Frankly, this is the first implementation I thought to write, and it works. The code size is small. I don’t like a few things about it, but I’ll live. Things I don’t like:

1. Passing typeof(object) to the base constructor from the route seems wrong. The receiver code thinks it needs a reference to the service type at all times. I’m just lying to the ServiceRoute so that I can take advantage of everything good about it.

2. Custom ServiceHost just so the code can remember the path to the XAMLX. This bothers me until I think that this is the same thing that happens with each .SVC or other XAMLX file.

 

As a benefit, I get URLs that look like this:

http://scottseely-xps/WfHostApp/helloWorld
instead of:
 
http://scottseely-xps/WfHostApp/SimpleWorkflow.xamlx

 

This serves as yet another example of how good it is that WCF is super extensible and what a great design decision it was to build WCF on top of the extensibility points instead of along side them.

Leave a comment

How JSONP works (and some bits about implementing it in WCF)

In the world of the web, we have lots of security concerns. One of the concerns lies with cross site scripting, XSS. From a high level, XSS is any occasion where data is sent from code on a page from one site to another site. The code is usually via JavaScript, though flash and Silverlight are included in the terminology and mitigations. One way around this that is generally viewed as safe is JSON with Padding, aka JSONP. The way JSONP works is this: you pass an HTTP GET request to retrieve a resource from another site which you do not control. The request contains two pieces of information:

1. The resource you want to retrieve.

2. The callback function that should be executed when the resource is returned.

What makes this safe? The callback function is always something that you control. It is assumed that if your callback does bad things, so be it; that problem existed without involving JSONP.

There is a convention around JSONP. The URL that you call needs to understand a querystring parameter named callback, which identifies the function to call when the method returns. How does this work? Assume we have a resource that, when no callback is specified, returns the following when requesting the resource at

http://localhost/WcfJsonp/jsonp/names:

[{"FirstName":"Scott","LastName":"Seely"},

{"FirstName":"Aaron","LastName":"Skonnard"},

{"FirstName":"Matt","LastName":"Milner"}]

With JSONP, we would like a GET of the above data to execute a function on our page named updatePeople. JSONP indicates that we do this with a request for the resource at http://localhost/WcfJsonp/jsonp/names?callback=updatePeople. In so doing, the resource is now returned as:

updatePeople(

[{"FirstName":"Scott","LastName":"Seely"},

  {"FirstName":"Aaron","LastName":"Skonnard"},

  {"FirstName":"Matt","LastName":"Milner"}]);

This causes the function, updatePeople, to be called as soon as the resource is retrieved.

How does this work? Most of us will use jQuery to get the job done and not think about things. But, without jQuery, JSONP is still possible. I’ll first show you how this works by hand, then with jQuery. jQuery eliminates a number of potential bugs, so I recommend reading the by hand portion solely to understand things-don’t implement it in production code!

Assume you have the following HTML body:

 

<body>
    <div>
      <input type="button" onclick="getPeopleJsonp();" 
             value="Get people" />
    </div>
    <div id="people"></div>
    <script type="text/javascript" 
      src="/wcfjsonp/Scripts/jquery-1.4.1.min.js"></script>
    <script type="text/javascript">
        function updatePeople(data) {
          var innerHtml = "";
          for (i = 0; i < data.length; ++i) {
            innerHtml += data[i].FirstName + ' ' + 
                         data[i].LastName + '<br/>';
          }
          $("#people").html(innerHtml);
        }

        function getPeopleJsonp() {
          var innerHtml = "<script type='text/javascript' " + 
                          "src='http://scottseely-xps/wcfjsonp/" +
                          "jsonp/names?callback=updatePeople'></script>";
          $("#inject").html(innerHtml);
        }
    </script>
    <div id="inject"></div>
</body>

What is happening here? When someone clicks on the button, the page calls getPeopleJsonp. That code updates the content of the div whose id is inject to contain a script tag. The script tag points to a JSONP endpoint and passes the callback parameter indicating to call the function updatePeople upon success. That script is then evaluated, executes a local JavaScript function, and returns. Every time that same script is reinjected, the same behavior occurs.

Now, jQuery provides a more succinct mechanism for doing the same thing. Instead of having the previous two functions and updating the DOM ourselves, we would write this:

 

function getPeopleJquery() {
  $.ajax({
    dataType: 'jsonp',
    url: "http://scottseely-xps/WcfJsonp/jsonp/names",
    success: function (data) {
      var innerHtml = "";
      for (i = 0; i < data.length; ++i) {
        innerHtml += data[i].FirstName + ' ' + data[i].LastName + '<br/>';
      }
      $("#people").html(innerHtml);
    }
  });
}

The code to inject information into the DOM still occurs, as does the creation of a callback function. What jQuery does is it adds script tag to the DOM only until the callback (success function) is done executing. The tag is added to the header. It also adds a function to the window object which is called on return. The URL jQuery constructs looks like http://localhost/WcfJsonp/jsonp/names?callback=jsonp1283609644773. What it actually does is add the following:

blog-tagadded

Within the window object, a new function is added:

expandos

jsonp1283609644773 is just an object living on the window object and is a dynamically added function. When the function is done executing, it will remove itself from the window object, leaving a slot by the same name with a value of undefined. What does the function look like when it is alive?

function(q){n=q;b();d();z[i]=v;try{delete z[i]}catch(p){}A&&A.removeChild(B)}

So, yeah, not too intelligible, but it does appear to handle things just fine. b(), d(), and the other functions are all part of the minified jQuery library, meaning that it all makes sense in the context of the containing object. The call to b() is contains code to call the success function. Everything else is cleanup code (at least from what it looked like to me.). To make this whole thing work in WCF, you need to do a couple simple things:

1. Only use WebGet to fetch resources.

2. Make sure the resource is hard-coded to respond in JSON. Otherwise, the response will appear as XML and the callback code won’t execute.

3. Make sure your binding supports JSONP.

4. Make sure your service requires ASP.NET compatibility.

For example, to get the names, I have the following WCF code:

[ServiceContract]
[AspNetCompatibilityRequirements(
  RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class JsonpDemo
{
  [OperationContract]
  [WebGet(UriTemplate = "names", ResponseFormat = WebMessageFormat.Json)]
  public PersonName[] GetNames()
  {
    return new PersonName[]
              {
                new PersonName {FirstName = "Scott", LastName = "Seely"},
                new PersonName {FirstName = "Aaron", LastName = "Skonnard"},
                new PersonName {FirstName = "Matt", LastName = "Milner"}
              };
  }
}

Configuration has:

<system.serviceModel>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
  <standardEndpoints>
    <webHttpEndpoint>
      <standardEndpoint crossDomainScriptAccessEnabled="true"
                        automaticFormatSelectionEnabled="true"/>
    </webHttpEndpoint>
  </standardEndpoints>
</system.serviceModel>

 

The crossDomainScriptAccessEnabled flag turns on the ability to correctly parse and respond to the presence of the callback parameter in the query string.

Finally, I added a route to handle the service within my Global.asax:

var factory = new WebServiceHostFactory();
routes.Add(new ServiceRoute("jsonp", factory, typeof(JsonpDemo)));

I was looking at the technology only to evaluate how to use it and to understand, a bit more deeply, how JSONP actually works. I found myself looking for a post that explains the magic, but most of the information I found just said “use jQuery.” Handy-sure. But that didn’t help me understand all the magic goodness that jQuery was doing for me.

Leave a comment

Talking about REST

Mark and Clark over at developersmackdown.com just published ‘my’ show: http://developersmackdown.com/archives/SingleShow/30. We spent time talking about REST and SOAP as well as a number of other topics related to REST. One of the things that I don’t think was made clear enough was that REST and SOAP are not competing service techniques. Each technology/interface type has an appropriate use case. When integrating applications within an enterprise, the development team needs to worry about:

- Security

- Transactions

- Reliable delivery of messages

- Integration with tooling for other developers

In the enterprise case, WCF + SOAP/WS-* can make integration between systems pretty simple. Yes, the teams may struggle with getting the security setup just right between domains, but overall, things will go well, especially if the setup requires communicating between different WS-* implementations. Finally, enterprise integrations typically happen for applications running on the same network/VPN. The infrastructure for an enterprise is different than that for the web. It’s important to build your applications for their environment.

When integrating applications over the Internet, sometimes WS-* adds too much complexity. For extensive integration across partners who are connected via the Internet, there is some benefit to understanding REST. REST will allow your application to scale using the HTTP architecture. Features such as caching, proxy servers, and the general uniform interface exposed by HTTP helps make things work better on the global network.

Because of my point of view here, when asked “do you prefer SOAP or REST?”, I am forced to answer “For what scenario?” I’m not popular in either circle, but understanding both helps me get stuff done.

Leave a comment

Follow

Get every new post delivered to your Inbox.