Archive for November, 2008

Fast unknown method invocation for loose coupling

November 26, 2008

I was recently tasked to refactor a WinForms application. Now familiar with ASP.NET MVC, I wondered how easy it would be to apply existing ASP.NET MVC constructs to WinForms.  Implementing an IController is easy enough, but there’s still the matter of loose coupling within the IController’s execute method.

I’ve previously shown using reflection to allow loosely-coupled method invocation in ArcGIS Server Object Extensions, but reflection is wicked slow.  I knew that people were writing ORM binding using IL op-codes, and I figured that Microsoft had done something similar for ASP.NET MVC.

It turns out that LINQ expressions can be compiled into IL op-codes and that people are doing it to invoke unknown code quickly, without reflection.  No need to fire up Reflector to see Microsoft’s worth seeing LINQ implemenation, you can simply check CodePlex.

Fast SQL’08 Geometry Insertion

November 25, 2008

If you’re inserting SQL’08 Native Spatial Datatypes into a brand new table, favor SqlBulkCopy over Insert. Its ridiculously faster. Below is some reduced code to show the basic idea:

// use minimal transaction logging during upload
new SqlCommand("alter database [" + dbName + "] SET RECOVERY BULK_LOGGED", connection).ExecuteNonQuery();

// create and a datatable of points
DataTable dt = new DataTable();
dt.Columns.Add("Shape", typeof(SqlGeometry));

// populate your SqlGeometry
dt = magicFunction_fillMyDataTableWithGeometry();

// copy data, use batches and tablelock to ensure small minimal transaction log sizes
using (SqlBulkCopy sbc = new SqlBulkCopy(connectionString(dbName), SqlBulkCopyOptions.TableLock))
{
    sbc.DestinationTableName = tableName;
    sbc.BatchSize = 10000;
    sbs.ColumnMappings.Add("Shape", "Shape");
    sbc.WriteToServer(dt);
    sbc.Close();
}

// use normal transaction logging after upload
new SqlCommand("alter database [" + dbName + "] SET RECOVERY FULL", connection).ExecuteNonQuery();

Using ProjNET for point reprojection

November 21, 2008

Are you – yes, you– firing up ArcObjects code just to do simple point reprojection?  Check out Proj.NET.  Grab the EPSG-code reader and point projection code from the very helpful FAQs and you’ll get something like this: [edit: fixed, thanks Morten ... definitely read the comments, this code was meant to show how easy things could be... its definitely not the ProjNet best practices]

public static double[] projectFromWgs84(double X, double Y, int destinationEpsgCode)
{
   double[] input = new double[] { X, Y };
   SC.ICoordinateSystem destProj = SridReader.GetCSbyID(destinationEpsgCode);
   SC.ICoordinateSystem sourceProj = SridReader.GetCSbyID(4236);
   SCT.CoordinateTransformationFactory ctf = new SCT.CoordinateTransformationFactory();
   SCT.IMathTransform xForm = ctf.CreateFromCoordinateSystems(sourceProj, destProj).MathTransform;
   return xForm.Transform(input);
}

AGS SOE’s without the SOAP

November 19, 2008

Vish recently wrote about calling AGS SOEs via SOAP instead of DCOM.  He doesn’t mention that AGS doesn’t make you use SOAP, nor XML for that matter. This low-tech JSON-RPC invoker shows the proof-of-concept:

public string HandleStringRequest(string Capabilities, string request){
  MethodCall mc = JavaScriptConvert.DeserializeObject<MethodCall>(request);
  object result = this.GetType().GetMethod(mc.name).Invoke(this, mc.parameters);
  return JavaScriptConvert.SerializeObject(result);
}

public string test(string str1, string str2){
  return str1 + str2;
} 

class MethodCall{
  public string name;
  public object[] parameters;
}

 Here’s an action shot…

fiddler

ASP.NET MVC + Ext + WCF … v2.0

November 14, 2008

My last post on wiring up JSON to ASP.NET MVC showed how to use an ActionFilter to deserialize JSON into .NET objects.  However, using a custom IModelBinder is a cleaner and in many ways the more correct solution:

using System;
using System.Web.Mvc;
using System.Text;
using System.Xml;
using System.Runtime.Serialization.Json;

namespace NRPC.Citation.Web.Controllers
{
    public class JsonBinderAttribute : CustomModelBinderAttribute
	{
		public override IModelBinder GetBinder()
		{
			return new JsonModelBinder();
		}

        public class JsonModelBinder : IModelBinder
        {
            public ModelBinderResult BindModel(ModelBindingContext bindingContext)
            {
                Encoding requestEncoding = bindingContext.HttpContext.Request.ContentEncoding;
                byte[] stringBytes = requestEncoding.GetBytes(bindingContext.HttpContext.Request.Form[bindingContext.ModelName]);
                XmlDictionaryReader rdr = JsonReaderWriterFactory.CreateJsonReader(stringBytes, XmlDictionaryReaderQuotas.Max);
                object o = new DataContractJsonSerializer(bindingContext.ModelType).ReadObject(rdr);
                return new ModelBinderResult(o);
            }
        }
	}
}
public ActionResult postDTO([JsonBinder]GridStateDTO colState){ ... }
    Ext.Ajax.request({
        url: '/myURL.mvc/postDTO',
        success: success,
        failure: failure,
        params: { 'colState': strDTO }
    });

Note how in this case I’m passing the JSON as a form value. This is notable in part because the code in my last post assumed the entire post body was JSON; while this code can co-exist with other form data.

ASP.NET MVC + Ext + WCF

November 14, 2008

Dave Bouwman wrote up a nice post about using MVC with AJAX.  Dave’s example, however, requires manual serialization / deserialization.  Fortunately, Omar Al Zabir wrote a filter that leverages WCF’s DataContractJsonSerializer to accomplish just this. 

I’ll spare the code duplication, but here’s how to call it from Ext:

 Ext.Ajax.request({
    url: ‘/myUrl.mvc/testDTO’,
    headers: { ‘Content-Type’: ‘application/json’ },
    success: mySuccessFunction,
    failure: myFailureFunction,
    jsonData: myJavascriptObject
});

Using the ArcSDE Java API in .NET

November 4, 2008

I’m a .NET guy.  I have no desire to fool around with ArcSDE’s C API’s… building them, COM interop, whatever the heck would be required.  I’m also definitely reluctant to call SDE’s command-line tools from code.

Enter IKVM.  “IKVM.NET is an implementation of Java for Mono and the Microsoft .NET Framework.”  “IKVM.NET includes ikvmc, a Java bytecode to .NET IL translator.”  Run the ArcSDE Java API jars through ikmc, and you’ve got yourself a .NET ArcSDE library:

ikvmc jpe_sdk.jar -target:library
ikvmc icu4j_3_2.jar -target:library
ikvmc jsde_sdk.jar -target:library -r:jpe_sdk.dll -r:icu4j_3_2.dll
ikvmc concurrent.jar -target:library

The above .BAT file will generate 4 ArcSDE .NET dlls; giving you access to the Java API from .NET.  You also need to include the IKVM dlls in your project.  You loose some of the intellisense and error reporting goodness, but a quick test makes it look like all is working. :c)

Json rtrees, part 2

November 3, 2008

In my previous post, I talked about using r-trees in JavaScript for fast client-side spatial indexing.  The idea is a mixed bag.  Its speedy enough to query tens-of-thousands of records in real time; the problem is that you can’t feed it tens-of-thousands of bounding-boxes quick enough.

The author of the original Java library, Robert Olofsson, was kind enough to host my C# port.  Either way, you can grab my port or visit the project page for more info.  Robert was also kind enough to let me leave the Json serialization code in.   :c)

In .NET you’d generate the Json r-tree something like this:

PRTree<NamedPoint> tree = new PRTree<NamedPoint>(new NamedPointConverter(), 4);
List<NamedPoint> points = getRandomPointData();
tree.load(points);

StringBuilder sb = new StringBuilder();
sb.Append("var myJsonRtree=");
tree.getRoot().toJSON(sb, new NamedPointConverter(), "{0:#.####}");
sb.Append(";");

And in JS you’d query the Json r-tree something like this:

var walkTree = function(node, searchArea, results) {
 if (node.i != undefined) {
  if (!(node.b[0] < searchArea[0] || node.b[0] > searchArea[2] || node.b[1] < searchArea[1] || node.b[1] > searchArea[3]))
   results.push(node.i);
 }else {
  if (!(node.b[2] < searchArea.minx || node.b[0] > searchArea.maxx || node.b[3] < searchArea.miny || node.b[1] > searchArea.maxy)) {
   var s = node.c.length - 1;
   for (var i = 0; i <= s; i++)
    walkTree(node.c[i], searchArea, results);
  }
 }
}

results = [];
var searchArea = [-180, -180, 180, 180];
walkTree(myJsonRtree, searchArea, results);

Special thanks also to Nate Irwin, for not treating me like I was crazy when I suggested client-side spatial indexing as a good idea.