Tuesday, November 25, 2008
Posted on Tuesday, November 25, 2008 11:29:12 AM (Mountain Standard Time, UTC-07:00)  Comments [6] | 
Categories: .NET | Ajax | ASP.NET MVC | Javascript | Unit Testing

We've been having a good time developing applications on the ESRI Javascript API, but we are seeing some limitations to the REST API, and are working around this by creating our own services. Since there are likely others out there who are running into these same issues, I thought I'd share how we are tacking this.

What's Wrong?

Good question, and the answer is nothing. The REST API works quite nicely for a generic API. In the standard scenario, you create an esri.map on the page, setup some tasks (i.e. a QueryTask, FindTask, or IdentifyTask ) and all is well.

out-of-the-box 

Both the map and the tasks are designed to talk to the REST API, and that's pretty good.

But there are some limitations. First, I'd like to do more on the server in a single request. Instead of just locating a parcel by it's PIN, I want to locate the businesses within say 500 yards, and view them on the map and in a results window. Why make multiple requests to the REST API, and write a whole lot of complex javascript, when I can do this in one operation via ArcObjects or <shudder> the WebADF?

Second, given our requirements, I regularly need to access functionality that's not exposed via the REST API - i.e. linear referencing, or 1:M type reporting.

A related issue is that I'd like to be able to write solid unit tests for the code. While it's possible to use something like DOH or jsunit to write unit tests for javascript, it's much easier to write tests in .NET (i.e. TestDriven.netMbUnit & RhinoMocks). So - if I have a choice of making 3 requests to the REST API, and aggregating the results in the browser (in javascript), vs. making a single request to a custom, very testable service, I'll take the second option every time.

Solution: Custom Services

The idea here is pretty simple - instead of using  the out of the box tasks and the REST API, I create my own "tasks" (not real "tasks" in the ESRI parlance - just classes which request and process data) that make calls back to a custom service that does what I want, how I want it.

custom-services

We've done this a number of ways... in all cases we write custom code in one or more "worker classes" that live in a standard class library assembly. Depending on the requirements, these worker classes can be designed to run on a SOC box (i.e. they make direct ArcObjects calls w/o ServerContext.CreateObject), they can run on a web server (i.e. use ServerContext.CreateObject) or if it needs to scale out across a lot of SOC boxes, they can be packaged as Server Object Extensions. Regardless, at the core they are just a set of methods, and so we have another assembly with unit tests that ensures that these methods work as expected.

ASP.NET JSON WebServices (.asmx)

Since all the logic is in the "worker class", the web service is just a thin veneer of serialization / deserialization, most of which is handled automatically by marking up the service as a Script Service.

ASP.NET Handlers (.ashx)

Handlers are very similar to the web service option, but you don't get any json serialization for "free". They are also more difficult to debug and test, so we avoid them. No need to "look for pain" ;-)

ASP.NET MVC Controllers

For a wide variety of reasons, the ASP.NET MVC framework is very attractive - none the least of which is that is was designed to be much more testable than WebForms. We recently did a project that used Controllers as the service tier, and it worked out really really well. As with all things you learn as you go, so I will be doing more active refactoring on the controllers, and taking a more RESTful approach to the URI space in the future.

Summary

I hope this gives you some ideas about how you can "mashup" the ESRI Javascript API with additional back-end services. I have a number of interesting projects that will be doing a lot of this style of interaction, and I'll post more detailed descriptions of them as they go live.

Tuesday, November 25, 2008 12:53:15 PM (Mountain Standard Time, UTC-07:00)
Can't wait to see some real world examples!
Tuesday, November 25, 2008 12:53:21 PM (Mountain Standard Time, UTC-07:00)
Forgive the naive question, but how do you trigger "worker classes ... designed to run on a SOC box" that aren't packaged as a Server Object Extension?
Anonymous
Tuesday, November 25, 2008 4:24:33 PM (Mountain Standard Time, UTC-07:00)
@Anonymous...

You can access the worker classes in a web service by just instantiating it, if the web service itself lives on a SOC box (i.e. the ArcObjects are local to the instantiation). Of course the limit here is scalability, so when you need to run the worker across multiple servers, you need to move to the Server Object Extension.

Cheers,

Dave
Wednesday, November 26, 2008 7:01:56 AM (Mountain Standard Time, UTC-07:00)
Sounds pretty cool. Would love to see a simple example.
Erikk
Saturday, November 29, 2008 5:02:14 PM (Mountain Standard Time, UTC-07:00)
Looks great,
I would be glad to see some samples or hear for some already created methods within this worker class.


Thanks
Thursday, December 11, 2008 4:15:47 AM (Mountain Standard Time, UTC-07:00)
I understand the benefits you pointed out by writing your own custom services. The same result, however could be achieved by using the geoprocessor task available in the Javascript API. Geoprocessing services are REST enabled. You could write your .net class and deploy as a geoprocessing service, which you call using from your JS apps. Hence you won't need to send multiple request. In this case, you have the added benefit of using the features ArcGIS Server to tune your service i.e. object pooling, isolation, recycling etc..
Ravin
Comments are closed.