ESRI is changing the way the ArcGIS Server works in ArcGIS 10.1, See Considerations for ArcGIS Server developers: A look toward 10.1
We build a lot of SOA webservices leveraging the ArcGIS Server. These are mostly built using the pattern shown here: How to create a geocode and search Web service one of the reasons for building our web services using this pattern, was that the support for Server Object Extensions were poor and still is in ArcGIS 10. You needed to create COM enabled classes that has to be registered on the server etc, no tools, you need to write own tool (Or download SOExplorer) see: SOE Web services
To make the transition easier, I think that ESRI need to give us better tools to handle the SOE, SOAP and REST in ArcGIS Server and in ArcGIS Desktop/Engine. Also provide a solid pattern on how to build enterprise systems where the GIS systems can communicate with other business systems.
Showing posts with label ArcGIS Server. Show all posts
Showing posts with label ArcGIS Server. Show all posts
Friday, May 13, 2011
Saturday, February 19, 2011
Consume ArcGIS Server REST API using WCF.
Have been trying this all day (It does not work), so I write my findings down so it can be continued another day. Found a great blog post here How to consume REST services with WCF that I tried to adapt create a client proxy against ArcGIS Server REST API. The first part creating a Operation contract an adding an endpoint to was easy to do:
The app.config is configured like this:
And the code for running sending a query looks like this:
What's not working? Well seems like the response is "text/plain" (checked with fiddler) instead of "application/json". I haven't found a way to force it to be sent as "application/json". The error I get is: "The incoming message has an unexpected message format 'Raw'. The expected message formats for the operation are 'Xml'; 'Json'. This can be because a WebContentTypeMapper has not been configured on the binding. See the documentation of WebContentTypeMapper for more details."
Update: To make it work read: http://mathiaswestin.blogspot.com/2011/02/solved-incoming-message-has-unexpected.html
[ServiceContract ]
public interface IArcGISApi
{//http://help.arcgis.com/en/arcgisserver/10.0/apis/rest/index.html
//http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StateCityHighway_USA/MapServer/1/query?geometry=-125.4,35.2,-118.7,43.8&geometryType=esriGeometryEnvelope
[OperationContract ]
[WebGet (
BodyStyle = WebMessageBodyStyle .Bare,
ResponseFormat = WebMessageFormat .Json,
UriTemplate = "?f=json&Where={query}&returnGeometry=true&returnIdsOnly=false&outFields=*" )]
//UriTemplate = "?method=flickr.interestingness.getList&api_key={apiKey}&extras={extras}")]
QueryResponse Query(string query);
}The app.config is configured like this:
<?xml version= "1.0 " encoding= "utf-8 " ?>
<configuration>
<system.serviceModel>
<client>
<endpoint address= "http://server.arcgisonline.com/ArcGIS/rest/services/Demographics/USA_Median_Household_Income/MapServer/4/query "
binding= "webHttpBinding "
bindingConfiguration= "ArcGISBinding "
behaviorConfiguration= "ArcGIS "
contract= "TestRestWCFClient.IArcGISApi "
name= "ArcGISREST " />
</client>
<bindings>
<webHttpBinding>
<binding name= "ArcGISBinding " maxReceivedMessageSize= "10000000 "/>
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name= "ArcGIS ">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
And the code for running sending a query looks like this:
ChannelFactory <IArcGISApi > factory = new ChannelFactory <IArcGISApi >("ArcGISREST" );
var proxy = factory.CreateChannel();
var response = proxy.Query(" );
((IDisposable )proxy).Dispose();
What's not working? Well seems like the response is "text/plain" (checked with fiddler) instead of "application/json". I haven't found a way to force it to be sent as "application/json". The error I get is: "The incoming message has an unexpected message format 'Raw'. The expected message formats for the operation are 'Xml'; 'Json'. This can be because a WebContentTypeMapper has not been configured on the binding. See the documentation of WebContentTypeMapper for more details."
Update: To make it work read: http://mathiaswestin.blogspot.com/2011/02/solved-incoming-message-has-unexpected.html
Saturday, February 12, 2011
Zoom in to feature in ArcGIS Engine using ArcGIS Server and IFind
The second blog post on how to use ArcGIS Server from ArcGIS Engine. This post show how to zoom in on a feature using a IFind searching for a specific value on an attribute.
Basic steps include getting the layer from the map and casting the layer to the IFind interface and searching the layer for the feature. The project are expecting that the layer href="http://server.arcgisonline.com/ArcGIS/rest/services/Demographics/USA_Median_Household_Income/MapServer is loaded in the map.
The code for getting the layer from the map.
The code that does the actual IFind. We cast the layer to IFind and use the Find method on the interface. Important to note is that it only work when you search for a value on an attribute, you can't do a custom query on serveral attributes.
The same result as I got in the previous blog post, load the layer showing whole US:

And after running the find tool it shows Alaska:
Basic steps include getting the layer from the map and casting the layer to the IFind interface and searching the layer for the feature. The project are expecting that the layer href="http://server.arcgisonline.com/ArcGIS/rest/services/Demographics/USA_Median_Household_Income/MapServer is loaded in the map.
Private Sub FindUsingIFindToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles FindUsingIFindToolStripMenuItem.Click
OnFind()
End Sub
Private Sub OnFind()
Dim state As String = "Alaska"
Dim attribute As String = "Name"
Dim layername As String = "States"
Dim control As AxMapControl = axMapControl1
Dim layer As ILayer = getLayer(layername)
Dim stateGeometry As IGeometry = Me.Find(layer, attribute, state, control.ActiveView)
control.ActiveView.Extent = stateGeometry.Envelope
control.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewAll, Nothing, Nothing)
End Sub
The code for getting the layer from the map.
Private Function getLayer(ByVal name As String) As ILayer
Dim retLayer As ILayer = Nothing
Dim control As AxMapControl = axMapControl1
For i As Integer = 0 To control.Map.LayerCount - 1
Dim layer As ILayer = control.Map.Layer(i)
retLayer = Me.getLayer(name, layer)
If Not retLayer Is Nothing Then
Exit For
End If
Next
Return retLayer
End Function
Private Function getLayer(ByVal name As String, ByVal layer As ILayer) As ILayer
Dim retLayer As ILayer = Nothing
If TypeOf layer Is ICompositeLayer Then
Dim gLayer As ICompositeLayer = CType(layer, ICompositeLayer)
For i As Integer = 0 To gLayer.Count - 1
Dim l As ILayer = gLayer.Layer(i)
'söker rekursivt efter lagret
retLayer = Me.getLayer(name, l)
If Not retLayer Is Nothing Then
Exit For
End If
Next
Else
If layer.Name.Equals(name) Then
retLayer = layer
End If
End If
Return retLayer
End Function
The code that does the actual IFind. We cast the layer to IFind and use the Find method on the interface. Important to note is that it only work when you search for a value on an attribute, you can't do a custom query on serveral attributes.
Private Function Find(ByVal layer As ILayer, ByVal field As String, ByVal value As String, ByVal activeView As IActiveView) As IGeometry5
Dim findLayer As IFind = CType(layer, IFind)
Dim fields As String() = {field}
'Söker med IFind efter features med attributet satt till value.
Dim array As IArray = findLayer.Find(value, True, fields, activeView.ScreenDisplay.CancelTracker)
Dim polygon As IPolygon5 = Nothing
For i As Integer = 0 To array.Count - 1
Dim featureFindData As IFeatureFindData2 = CType(array.Element(i), IFeatureFindData2)
Dim featureFields As IFields = featureFindData.Feature.Fields
Dim feature As IFeature = featureFindData.Feature
If (polygon Is Nothing) Then
polygon = CType(feature.Shape, IPolygon5)
Else
Dim topOp As ITopologicalOperator6 = CType(feature.Shape, ITopologicalOperator6)
polygon = CType(topOp.UnionEx(CType(polygon, IGeometry), True), IPolygon5)
End If
Next
Return CType(polygon, IGeometry5)
End Function
The same result as I got in the previous blog post, load the layer showing whole US:

And after running the find tool it shows Alaska:
Labels:
ArcGIS Engine,
ArcGIS Server,
ESRI,
IFind,
VB.Net
Friday, February 11, 2011
Zoom-in to feature in ArcGIS Engine using ArcGIS Server and REST
The first blog post on how to use ArcGIS Server from ArcGIS Engine. This post show how to zoom in on a feature using a custom query.
I start by creating JSON query:
Check out the service http://server.arcgisonline.com/ArcGIS/rest/services/Demographics/USA_Median_Household_Income/MapServer/4/query to find out what questions you can ask.
The ZoomTo method looks like this and loops through the result for the features returned and zoom in to the extent of the polygon returned:
I'm making a lot of assumptions here, that the result is a polygon, that there is only one polygon returned. But it shows the concept of getting features using REST.
The test application shows US when I start:

And zoom in on Alaska when I run the test method:

I have not done anything to boost the performance, so it feels very slow.
I start by creating JSON query:
Private Sub TestREST2ToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TestREST2ToolStripMenuItem.Click
Dim state As String = "Alaska"
'Skapar fråga för REST:
Dim requestUri As String = "http://server.arcgisonline.com/ArcGIS/rest/services/Demographics/USA_Median_Household_Income/MapServer/4/query"
Dim data As New StringBuilder()
data.AppendFormat("?f={0}", "json")
'case sensitive
data.AppendFormat("&Where=Name%3D'" & state & "'")
data.AppendFormat("&returnGeometry=true")
data.AppendFormat("&returnIdsOnly=false")
data.AppendFormat("&outFields=*")
ZoomTo(requestUri, data.ToString())
End Sub
Check out the service http://server.arcgisonline.com/ArcGIS/rest/services/Demographics/USA_Median_Household_Income/MapServer/4/query to find out what questions you can ask.
The ZoomTo method looks like this and loops through the result for the features returned and zoom in to the extent of the polygon returned:
Sub ZoomTo(ByVal requestUri As String, ByVal data As String)
'Ställer REST frågan:
Dim request As HttpWebRequest = TryCast(WebRequest.Create(requestUri & data), HttpWebRequest)
'Hanterar resultat
Using response As HttpWebResponse = TryCast(request.GetResponse(), HttpWebResponse)
Dim reader As New StreamReader(response.GetResponseStream())
Dim responseString As String = reader.ReadToEnd()
Dim jss As New System.Web.Script.Serialization.JavaScriptSerializer()
jss.MaxJsonLength = 10000000
'Skulle kunna köra med datakontrakt, men då måste man skapa objektstrukturen.
'DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(object))
'Parsar resultatet för att skapa upp polygon.
Dim results As IDictionary(Of String, Object) = TryCast(jss.DeserializeObject(responseString), IDictionary(Of String, Object))
If results IsNot Nothing AndAlso results.ContainsKey("features") Then
Dim features As IEnumerable(Of Object) = TryCast(results("features"), IEnumerable(Of Object))
For Each feature As IDictionary(Of String, Object) In features
Dim geometries As IDictionary(Of String, Object) = TryCast(feature("geometry"), IDictionary(Of String, Object))
Dim polygon As Polygon = New Polygon()
Dim rings As IEnumerable(Of Object) = TryCast(geometries("rings"), IEnumerable(Of Object))
Dim i As Integer = rings.Count()
For Each ring As IEnumerable(Of Object) In rings
Dim pointCol As IPointCollection = New Ring()
For Each vertex As IEnumerable(Of Object) In ring
Dim point As IPoint = New Point()
point.X = Convert.ToDouble(vertex.ElementAt(0))
point.Y = Convert.ToDouble(vertex.ElementAt(1))
pointCol.AddPoint(point)
Next
polygon.AddPointCollection(pointCol)
Next
'Sätter om extent via polygonens
Dim control As AxMapControl = axMapControl1
control.ActiveView.Extent = TryCast(polygon, IPolygon).Envelope
control.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewAll, Nothing, Nothing)
'GetLegend()
'Dim attributes As IDictionary(Of String, Object) = TryCast(feature("attributes"), IDictionary(Of String, Object))
Next
End If
End Using
End Sub
I'm making a lot of assumptions here, that the result is a polygon, that there is only one polygon returned. But it shows the concept of getting features using REST.
The test application shows US when I start:

And zoom in on Alaska when I run the test method:

I have not done anything to boost the performance, so it feels very slow.
Labels:
ArcGIS Engine,
ArcGIS Server,
ESRI,
REST,
VB.Net
Subscribe to:
Posts (Atom)