- You have my complete admiration for attempting this. You may be insane, but I'm discounting that possibility.
- Since you say ArcObjects / ArcEngine, I'm assuming a .NET implementation
- I would definitely start here. Somehow, you need to get generated classes from the XSD, and while you could do it yourself for whatever subset you need, it's gonna hurt. If there's any way to use LINQ (and it appears there is), I'd try that route.
If you can give a few more details on what you're trying to accomplish (r/o? r/w?), I suspect that someone can probably give you more specifics. What you're attempting is a largish, but not insurmountable problem.
Oh, and one quick (obvious in retrospect) question - does the server you're talking to generate WSDL? If so, then you should be able to get VS2008 or 2010 to consume that directly, making life much more pleasant.
Edit: Add specifics from minor experimentation:
Starting from the link previously, I was able to generate C# classes using XSD. This generates classes that will fail at runtime due to the problem of XSD & .NET not generating strongly typed lists correctly. I also tried the suggestions / fixes from this post, just to see what's changed. I'm unconvinced that changing the underlying data types from double/int, etc. to string is the greatest idea ever, but it should work. In both cases the command to generate classes is:
xsd.exe gml.xsd ..\..\xlink/1.0.0\xlinks.xsd ..\..\iso\19139\20070417\gmd\gmd.xsd ..\..\iso\19139\20070417\gco\gco.xsd ..\..\iso\19139\20070417\gss\gss.xsd ..\..\iso\19139\20070417\gts\gts.xsd ..\..\iso\19139\20070417\gsr\gsr.xsd /classes
And yeah, it's ugly. It also assumes that you've downloaded the entire set of schemas from OpenGIS.net (available here), which you've got to have to resolve all the references.
A quick comparison of the two resulting sets of classes shows surprisingly few differences (the original data type in parenthesis after the name of the changed member:
DirectPositionType.Text (double)
DirectPositionListType.Text (double)
GridType.axisLabels (NCName)
ParameterValueType.integerValueList (integer)
MeasureListType.Text (double)
So, worst case, if you really needed to, you might want to use the "fixed" version of 3.2.1, and then update those few members to use custom serialization to get a more strongly typed implementation instead of simply using strings.
As I look at it, without the benefit of what you're looking for with the ICursor, I don't know that you need to fire this off into a new thread. I've used SDE Connections like yours many times. Below is an example from my code base that is currently working (I have an issue when I attempt to CREATE a feature class against a FGDB, but my sde is connecting great)
public IWorkspace OpenSDEWorkspace(String server, String instance, String database,
String version, String user, String password)
{
try
{
//create and populate the property set.
IPropertySet2 propertySet = new PropertySetClass();
propertySet.SetProperty("SERVER", server);
propertySet.SetProperty("INSTANCE", instance);
propertySet.SetProperty("DATABASE", database);
propertySet.SetProperty("USER", user);
propertySet.SetProperty("PASSWORD", password);
propertySet.SetProperty("VERSION", version);
IWorkspaceFactory2 sdeWorkspaceFactory;
sdeWorkspaceFactory = (IWorkspaceFactory2)new SdeWorkspaceFactoryClass();
IWorkspace workspace = (IWorkspace)sdeWorkspaceFactory.Open(propertySet, 0);
return workspace;
}
catch (Exception e)
{
throw new Exception(String.Format("arcSDEWorkspaceOpen: {0}", e.Message), e);
}
}
public ArrayList GetDomainValues(String codedvaluedomain)
{
ArrayList arrayList = new ArrayList();
IWorkspace ws = (IWorkspace)ArcMap.Editor.EditWorkspace;
if(ws == null)
{
ws = OpenSDEWorkspace("ip", "5151", "database", "version", "user", "password");
}
IWorkspaceDomains domains = (IWorkspaceDomains)ws;
object[] domainobject = null;
IEnumDomain domainEnum = domains.Domains;
IDomain domain = domainEnum.Next();
String name = "";
while (domain != null)
{
name = domain.Name;
domain = domainEnum.Next();
if (name.Equals(codedvaluedomain))
{
break;
}
}
ICodedValueDomain codeddomain = new CodedValueDomainClass();
codeddomain = domains.get_DomainByName(name) as ICodedValueDomain;
domainobject = new object[codeddomain.CodeCount];
for (int a = 0; a < codeddomain.CodeCount; a++)
{
object domainvalue = codeddomain.get_Value(a);
String domainvaluename = codeddomain.get_Name(a);
arrayList.Add(domainvaluename);
}
return arrayList;
}
give your code a run without the thread and let it all run on the main and let me know what happens.
Good luck
Luke
Best Answer
We have, on a large project, managed quite well to isolate ArcObjects code from our business logic. That is generally the way to go, I'd say, rather than attempting to mock it all out, even if it is possible using mocking frameworks to get some of the way.
Ask yourself, Why it is you feel the need to mock. Typically, it is because of a missing abstraction. Think small responsibilities and minimize the surface of the huge, ugly ArcObject monster. Avoid dragging around ArcObject types just because some aspect of them is needed somewhere.
I can give one concrete example from our project. A portion of the code seemed to depend on IMxDocument. It turned out the only reason was that the active view needed to be refreshed. So we created an IViewRefresher interface instead and only worked on that; easy to mock and test. Additionally, it makes the intent of the code much clearer and removes the temptation for someone to start doing funny things with the IMxDocument that they weren't supposed to do because all we wanted to do here was refresh. The same exercise can be done with a lot of the ArcObjects code.
Also, we wrapped all access to feature classes in type safe wrappers, again providing mockable code shielding the business code from ArcObjects.
We've discussed not even using the geometry types of ArcObjects, but currently we do allow those interfaces to be used directly in our code. (However, interface knowledge only is allowed and all instantiations of geometries use our own geometry factory.)
In summary, I'm not disencouraging mocking but I'd encourage mocking at a different level of abstraction than ArcObjects.