Click to read:


In this (short) part I'll show you how I extended the application with some basic data management capabilities. Azure Maps Creator services create, store, and use various data types like:

  • Converted data
  • Dataset
  • Tileset
  • Feature stateset
  • Aliases

Besides these types there are also the uploaded Drawing packages that take up storage space (which is limited to 1Gb per Azure subscription and 100Mb per uploaded Drawing package).

To give an overview of all the items and uploads I added some data management options. It is presented in the UI by a new entry in the left menu below the 'Steps' entries that were already there (and shown collapsed in this image):

Clicking on a menuitem will show a list/grid with information on all the items found of that specific type. The grid allows for single and multi-select of the rows shown:

Some of the data types have date values as one or more of their properties. In that case I made the list sortable by those properties. You can sort (or reverse the sorting) by clicking on the column header:

Once you have made a selection, the 'Delete' button will remove the selected items from Azure Maps Creator. The screen will reflect what items have been deleted:

In some screens a 'Get' button will light up when a single item is selected. Clicking that button will show more details on the selected item. For instance with a Feature stateset you'll get an overview of the different styles, their type and associated rules (key-value pairs):

Because of the way the REST API is setup in a consistent way, most work needs to be done only once. All types have a 'Delete' and a 'List' operation. Once the code is written for one type you just need to copy and replace a couple of C# types to make it work for another Maps Creator type (a kind of D-R-Y but without the D). A lot of code was so 'generic' that I actually created a generic base class from which all the pages could inherit:

public class ListPageBase<TItem> : ComponentBase
{
    [Inject] protected IConfiguration Configuration { get; set; }

    protected MarkupString details;

    protected List<string> messages = new();

    protected List<TItem> itemList;
    protected List<IDetailsRowColumn<TItem>> Columns = new();
    protected Selection<TItem> Selection = new();

    protected string Geography { get; set; }
    protected string SubscriptionKey { get; set; }

Every page then needed a set of the same methods like GetData and Delete. In some pages there are also sort methods and/or a Get method to retrieve the details of a selected item. A GetData method typically looks like this (it is still a PoC, so no extensive eror handling, etc.):

public partial class ListDataPage : ListPageBase<MapDataDetailInfo>
{
    private MapDataListResponse mapDataResponse;

    private void GetData()
    {
        RestClient client = new($"https://{Geography}.atlas.microsoft.com/mapdata?subscription-key={SubscriptionKey}&api-version=2.0")
        {
            Timeout = -1
        };
        RestRequest request = new(Method.GET);

        IRestResponse response = client.Execute(request);

        if (response.IsSuccessful)
        {
            mapDataResponse = JsonSerializer.Deserialize<MapDataListResponse>(response.Content);
            itemList = new List<MapDataDetailInfo>(mapDataResponse.mapDataList);
        }
    }

The first term after the atlas.microsoft.com/ in the url determines what list operation will be executed. Once the result is in, I use the standard .NET Json method to read the reponse into the generated classes (see part 1 & 2). The responses can be quite extensive and I have not created classes for all possible answers. To show details for a selected item a similar approach is followed. In this case you need to supply the 'command' (after the atlas.microsoft.com/ part) and the id of the item. Once you have the response, you can walk through it's properties and build up a end-user friendly message. By using a MarkupString I can tell Blazor/Razor that the information has (HTML) markup that is already encoded. 

private void Get()
{
    messages.Clear();

    TilesetDetailInfo item = Selection.GetSelection()[0];

    RestClient client = new($"https://{Geography}.atlas.microsoft.com/tilesets/{item.tilesetId}?subscription-key={SubscriptionKey}&api-version=2.0")
    {
        Timeout = -1
    };

    RestRequest request = new(Method.GET);

    IRestResponse response = client.Execute(request);

    if (response.IsSuccessful)
    {
        TilesetDetailInfo tilesetGetResponse = JsonSerializer.Deserialize<TilesetDetailInfo>(response.Content);
        if (tilesetGetResponse != null)
        {
            StringBuilder sb = new StringBuilder(tilesetGetResponse.description);
            sb.AppendLine($"Dataset: {tilesetGetResponse.datasetId}");

            sb.AppendLine("Bounding box:");
            sb.AppendLine($"  Min lon/lat: {tilesetGetResponse.bbox[0]}, {tilesetGetResponse.bbox[1]}");
            sb.AppendLine($"  Max lon/lat: {tilesetGetResponse.bbox[2]}, {tilesetGetResponse.bbox[3]}");
            sb.AppendLine($"Min zoom: {tilesetGetResponse.minZoom}");
            sb.AppendLine($"Max zoom: {tilesetGetResponse.maxZoom}");
            sb.AppendLine($"Ontology: {tilesetGetResponse.ontology}");
            sb.AppendLine($"Description: {tilesetGetResponse.description ?? "-"}");

            details = (MarkupString)sb.ToString().Replace(" ", "&nbsp;").Replace("\r\n", "<br />");
        }

    }
    StateHasChanged();
}

 

As always, the code has been added to the GitHub repo. Any comments welcome.

Hope this helps!

Comments


Comments are closed