Local server services

View on GitHubSample viewer app

Demonstrates how to start and stop the Local Server and start and stop a local map, feature, and geoprocessing service running on the Local Server.

Image of local server services

Use case

For executing offline geoprocessing tasks in your apps via an offline (local) server.

How to use the sample

Click Start Local Server to start the Local Server. Click Stop Local Server to stop the Local Server.

The Map Service control lets you to pick a local service that is available.

After browsing for the desired file, click Start Service to start the selected service.

When the running service's url appears, select it and click Navigate to service. To stop this running service, click Stop Service.

How it works

To start a LocalServer and attach a LocalService:

  1. Create and run a local server with LocalServer.Instance.
  2. Start the server asynchronously with server.StartAsync().
  3. Create and run a local service. Here is an example of running a LocalMapService:
    1. Instantiate LocalMapService(Url) to create a local map service with the given URL path to map package (mpk or mpkx file).
    2. Start the job with LocalMapService.StartAsync(). The service is added to the LocalServer automatically.
  4. Stop the local server with LocalServer.Instance.StopAsync().

Relevant API

  • LocalFeatureService
  • LocalGeoprocessingService
  • LocalMapService
  • LocalServer
  • LocalServerStatus
  • LocalService

Offline data

Additional information

Local Server can be downloaded for Windows and Linux platforms from the developers website. Local Server is not supported on macOS.

Tags

feature, geoprocessing, local services, map, server, service

Sample Code

LocalServerServices.xaml.csLocalServerServices.xaml.csLocalServerServices.xaml
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
// Copyright 2021 Esri.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
// language governing permissions and limitations under the License.

using ArcGIS.Samples.Managers;
using Esri.ArcGISRuntime.LocalServices;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;

namespace ArcGIS.WPF.Samples.LocalServerServices
{
    [ArcGIS.Samples.Shared.Attributes.Sample(
        name: "Local server services",
        category: "Local Server",
        description: "Demonstrates how to start and stop the Local Server and start and stop a local map, feature, and geoprocessing service running on the Local Server.",
        instructions: "Click `Start Local Server` to start the Local Server. Click `Stop Local Server` to stop the Local Server.",
        tags: new[] { "feature", "geoprocessing", "local services", "map", "server", "service" })]
    [ArcGIS.Samples.Shared.Attributes.OfflineData("85c34847bbe1402fa115a1b9b87561ce", "92ca5cdb3ff1461384bf80dc008e297b", "a680362d6a7447e8afe2b1eb85fcde30")]
    public partial class LocalServerServices
    {
        // Hold references to the individual services
        private LocalMapService _localMapService;
        private LocalFeatureService _localFeatureService;
        private LocalGeoprocessingService _localGeoprocessingService;

        // Generic reference to the service selected in the UI
        private LocalService _selectedService;

        public LocalServerServices()
        {
            InitializeComponent();

            // Set up the sample
            Initialize();
        }

        private void Initialize()
        {
            try
            {
                // Subscribe to event notification for the local server instance
                LocalServer.Instance.StatusChanged += (o, e) =>
                {
                    UpdateUiWithServiceUpdate("Local Server", e.Status);
                };
            }
            catch (Exception ex)
            {
                var localServerTypeInfo = typeof(LocalMapService).GetTypeInfo();
                var localServerVersion = FileVersionInfo.GetVersionInfo(localServerTypeInfo.Assembly.Location);

                MessageBox.Show($"Please ensure that local server {localServerVersion.FileVersion} is installed prior to using the sample. The download link is in the description. Message: {ex.Message}", "Local Server failed to start");
            }
        }

        private void UpdateUiWithServiceUpdate(string server, LocalServerStatus status)
        {
            // Construct the new status text
            string updateStatus = String.Format("{0} status: {1} \t\t {2}\n{3}", server, status,
                DateTime.Now.ToShortTimeString(), StatusTextbox.Text);

            // Update the status box text
            StatusTextbox.Text = updateStatus;

            // Update the list of running services
            ServicesListbox.ItemsSource = LocalServer.Instance.Services.Select(m => m.Name + " : " + m.Url);
        }

        private void CreateServices()
        {
            try
            {
                // Arrange the data before starting the services
                string mapServicePath = GetMpkPath();
                string featureServicePath = GetFeatureLayerPath();
                string geoprocessingPath = GetGpPath();

                // Create each service but don't start any
                _localMapService = new LocalMapService(mapServicePath);
                _localFeatureService = new LocalFeatureService(featureServicePath);
                _localGeoprocessingService = new LocalGeoprocessingService(geoprocessingPath);

                // Subscribe to status updates for each service
                _localMapService.StatusChanged += (o, e) => { UpdateUiWithServiceUpdate("Map Service", e.Status); };
                _localFeatureService.StatusChanged += (o, e) => { UpdateUiWithServiceUpdate("Feature Service", e.Status); };
                _localGeoprocessingService.StatusChanged += (o, e) => { UpdateUiWithServiceUpdate("Geoprocessing Service", e.Status); };

                // Enable the UI to select services
                ServiceSelectionCombo.IsEnabled = true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Failed to create services");
            }
        }

        private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // Get the text of the selected item
            string selection = ((ComboBoxItem)ServiceSelectionCombo.SelectedItem).Content.ToString();

            // Update the selection
            switch (selection)
            {
                case "Map Service":
                    _selectedService = _localMapService;
                    break;

                case "Feature Service":
                    _selectedService = _localFeatureService;
                    break;

                case "Geoprocessing Service":
                    _selectedService = _localGeoprocessingService;
                    break;
            }

            // Return if selection is invalid
            if (_selectedService == null)
            {
                return;
            }

            // Update the state of the start and stop buttons
            UpdateServiceControlUi();
        }

        private void UpdateServiceControlUi()
        {
            if (_selectedService == null)
            {
                return;
            }

            // Update the UI
            if (_selectedService.Status == LocalServerStatus.Started)
            {
                ServiceStopButton.IsEnabled = true;
                ServiceStartButton.IsEnabled = false;
            }
            else
            {
                ServiceStopButton.IsEnabled = false;
                ServiceStartButton.IsEnabled = true;
            }
        }

        private async void StartServiceButtonClicked(object sender, RoutedEventArgs e)
        {
            try
            {
                // Start the selected service
                await _selectedService.StartAsync();

                // Update the UI
                UpdateServiceControlUi();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Failed to start service");
            }
        }

        private async void StopServiceButtonClicked(object sender, RoutedEventArgs e)
        {
            try
            {
                // Stop the selected service
                await _selectedService.StopAsync();

                // Update the UI
                UpdateServiceControlUi();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Failed to stop service");
            }
        }

        private static string GetMpkPath()
        {
            return DataManager.GetDataFolder("85c34847bbe1402fa115a1b9b87561ce", "RelationshipID.mpkx");
        }

        private static string GetFeatureLayerPath()
        {
            return DataManager.GetDataFolder("92ca5cdb3ff1461384bf80dc008e297b", "PointsOfInterest.mpkx");
        }

        private static string GetGpPath()
        {
            return DataManager.GetDataFolder("a680362d6a7447e8afe2b1eb85fcde30", "Contour.gpkx");
        }

        private async void StartServerButtonClicked(object sender, RoutedEventArgs e)
        {
            try
            {
                // LocalServer must not be running when setting the data path.
                if (LocalServer.Instance.Status == LocalServerStatus.Started)
                {
                    await LocalServer.Instance.StopAsync();
                }

                // Set the local data path - must be done before starting. On most systems, this will be C:\EsriSamples\AppData.
                // This path should be kept short to avoid Windows path length limitations.
                string tempDataPathRoot = Directory.GetParent(Environment.GetFolderPath(Environment.SpecialFolder.Windows)).FullName;
                string tempDataPath = Path.Combine(tempDataPathRoot, "EsriSamples", "AppData");
                Directory.CreateDirectory(tempDataPath); // CreateDirectory won't overwrite if it already exists.
                LocalServer.Instance.AppDataPath = tempDataPath;

                // Start the server
                await LocalServer.Instance.StartAsync();

                // Create the services
                CreateServices();
            }
            catch (Exception ex)
            {
                var localServerTypeInfo = typeof(LocalMapService).GetTypeInfo();
                var localServerVersion = FileVersionInfo.GetVersionInfo(localServerTypeInfo.Assembly.Location);

                MessageBox.Show($"Please ensure that local server {localServerVersion.FileVersion} is installed prior to using the sample. The download link is in the description. Message: {ex.Message}", "Local Server failed to start");
            }

            // Update the UI
            LocalServerStopButton.IsEnabled = true;
            LocalServerStartButton.IsEnabled = false;
        }

        private async void StopServerButtonClicked(object sender, RoutedEventArgs e)
        {
            // Update the UI
            ServiceStartButton.IsEnabled = false;
            ServiceStopButton.IsEnabled = false;
            LocalServerStartButton.IsEnabled = true;
            LocalServerStopButton.IsEnabled = false;

            try
            {
                // Stop the server.
                await LocalServer.Instance.StopAsync();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Failed to stop server");
            }

            // Clear references to the services
            _localFeatureService = null;
            _localMapService = null;
            _localGeoprocessingService = null;
        }

        private void NavigateButtonClicked(object sender, RoutedEventArgs e)
        {
            // Return if selection is empty
            if (ServicesListbox.SelectedItems.Count < 1) { return; }

            try
            {
                // Get the full text in the selection
                string strFullName = ServicesListbox.SelectedItems[0].ToString();

                // Create array of characters to split text by; ':' separates the service name and the URI
                char[] splitChars = { ':' };

                // Extract the service URL
                string serviceUri = strFullName.Split(splitChars, 2)[1].Trim();

                // Navigate to the service
                Process.Start(new ProcessStartInfo(serviceUri) { UseShellExecute = true });
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Couldn't navigate to service");
            }
        }
    }
}

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.