c# example res/json web API ?

Within this forum we want to offer discussions all around our .NET based Map control including all .Net-language specific questions concerning calls of the xServer-API. Attention: xServer-relevant concepts can be found in further forums such as xRoute or xTour.
Clement.Sorriaux

c# example res/json web API ?

Post by Clement.Sorriaux »

Hello,

I just recieved a demand from a customer and I can't find such example so far.

I sent to the customer the democenter in c# with sources and everything.
here is his question :
I've notice that the example of WCF service are all in SOAP/XML, is there any c# sample with REST/JSON webService or webAPI ?

if you need more precision, feel free to ask for some.

have a good day
Best regards
Clément
User avatar
Bernd Welter
Site Admin
Posts: 2564
Joined: Mon Apr 14, 2014 10:28 am
Contact:

Re: c# example res/json web API ?

Post by Bernd Welter »

Hello Clement,

I spoke to some developers and they recommended to use frameworks such as JSON.NET (or the expensive, high performant alternative https://servicestack.net/text). But I also hope that Oliver can provide a real sample for this.

Best regards,
Bernd
Bernd Welter
Technical Partner Manager Developer Components
PTV Logistics - Germany

Bernd at... The Forum,LinkedIn, Youtube, StackOverflow
I like the smell of PTV Developer in the morning... :twisted:
User avatar
Oliver Heilig
Posts: 154
Joined: Tue May 13, 2014 12:10 pm
Location: Karlsruhe, Germany
Contact:

Re: c# example res/json web API ?

Post by Oliver Heilig »

My recommendation is JSON.NET (https://www.newtonsoft.com/json). It's some kind of de-facto standard, even Microsoft uses in their projects. But there are many flavors for serializing and deserializing your objects, here are two:
  • The JavaScript way: You can use .NET anonymous / dynamic types. This doesn't require any specific types, but it isn't very convenient at design-time, see code below and attached sample.
  • With typed classes: Find an example JSON, for example from the Raw-Request-Runner, then create your classes by pasting the Request/Response to http://json2csharp.com/. You can (de)serialize them with JSON.NET then.
Oli

Sample with dynamic types:

Code: Select all

using System;
using Newtonsoft.Json;
using System.IO;
using System.Net;

namespace XServerJson
{
    class Program
    {
        // Make a request on xServer with JSON, using JSON.NET and dynamic/anonymous types.
        // This means we don't have any types defined for our requests and responses and do it like JavaScript.
        static void Main(string[] args)
        {
            // for input just use an anonymous type
            var gco = new
            {
                addr = new
                {
                    country = "L",
                    postCode = "",
                    city = "Schengen",
                    city2 = "",
                    street = "Rue de la Moselle 5",
                    houseNumber = ""
                }
            };

            // Create the request
            // When using using xServer-internet you need a token!
            var request = WebRequest.Create("https://xlocate-eu-n-test.cloud.ptvgroup.com/xlocate/rs/XLocate/findAddress");
            request.Credentials = new NetworkCredential("xtok", "<your xServer-internet token>");
            request.Method = "POST";
            request.ContentType = "application/json";

            // serialize object to the request stream 
            // should do some proper error-handly here
            using (var s = request.GetRequestStream())
            using (var writer = new StreamWriter(s))
            using (var jsonWriter = new JsonTextWriter(writer))
            {
                var ser = new JsonSerializer();
                ser.Serialize(jsonWriter, gco);
            }

            // now just parse it to a dynamic object           
            dynamic result;
            using (var response = request.GetResponse())
            using (var rs = response.GetResponseStream())
            using (var sr = new StreamReader(rs))
            {
                result = JsonConvert.DeserializeObject(sr.ReadToEnd());
            }

            // now work with the object like in JavaScript
            // You don't have intellisense, but can view the fields in the watch window of the debugger.
            foreach (var ra in result.resultList)
            {
                Console.WriteLine($"{ra.country} {ra.postCode} {ra.city} {ra.street} {ra.houseNumber}");
            }

            Console.ReadKey();
        }
    }
}
Attachments
XServer-Json-Dynamic.zip
(4.22 KiB) Downloaded 591 times
Oliver Heilig
Chief Developer Logistic Services
PTV GROUP - Germany

https://github.com/oliverheilig/
User avatar
Oliver Heilig
Posts: 154
Joined: Tue May 13, 2014 12:10 pm
Location: Karlsruhe, Germany
Contact:

Re: c# example res/json web API ?

Post by Oliver Heilig »

Addendum: i'd rather use the async version (using HttpClient) these days:

Code: Select all

using System;
using System.Threading.Tasks;
using System.Net.Http;
using System.Text;
using Newtonsoft.Json;

namespace XServerJson
{
    class Program
    {
        // Make a request on xServer with JSON, using JSON.NET and dynamic/anonymous types.
        // This means we don't have any types defined for our requests and responses and do it like JavaScript.
        // This is the async version using HttpClient
        static void Main(string[] args)
        {
            ExecAsync().Wait();

            Console.ReadKey();
        }

        static async Task ExecAsync()
        {
            // input address for geocoding as anonymous type
            var result = await GeocodeAsync(new
            {
                addr = new
                {
                    country = "L",
                    postCode = "",
                    city = "Schengen",
                    city2 = "",
                    street = "Rue de la Moselle 5",
                    houseNumber = ""
                }
            });

            // now work with the object like in JavaScript
            // You don't have intellisense, but can view the fields in the watch window of the debugger.
            foreach (var ra in result.resultList)
            {
                Console.WriteLine($"{ra.country} {ra.postCode} {ra.city} {ra.street} {ra.houseNumber}");
            }
        }

        static async Task<dynamic> GeocodeAsync(object address)
        {
            // Create the request Client
            var httpClient = new HttpClient();

            // When using using xServer-internet you need a token!
            httpClient.DefaultRequestHeaders.Authorization = 
                new System.Net.Http.Headers.AuthenticationHeaderValue("Basic",
                    Convert.ToBase64String(Encoding.UTF8.GetBytes("xtok:<your xServer-internet token>")));

            // The content (body)
            var content = new StringContent(JsonConvert.SerializeObject(address), Encoding.UTF8, "application/json");

            // Do the POST
            var response = await httpClient.PostAsync("https://xlocate-eu-n-test.cloud.ptvgroup.com/xlocate/rs/XLocate/findAddress", content);

            // throws an exception if not status 200
            response.EnsureSuccessStatusCode();

            // Just return as dynamic object
            return JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync());
        }
    }
}
Oliver Heilig
Chief Developer Logistic Services
PTV GROUP - Germany

https://github.com/oliverheilig/
User avatar
Oliver Heilig
Posts: 154
Joined: Tue May 13, 2014 12:10 pm
Location: Karlsruhe, Germany
Contact:

Re: c# example res/json web API ?

Post by Oliver Heilig »

Hello,

this is part three:

... while the sample above also works well with .NET Core, it doesn't use pascal-casing. Pascal-casing is default for .NET fields while camel-casing is default for JSON/JavaScript. Another caveat is that xServer (especially xServer-2) uses polymorphic parameter types. These require a type-inference using a $type attribute which is somehow cumbersome, especially when working with dynamic typing.

I've added a helper class XServerSerializerSettings which handles both pascal-casing and type-inference with $type. You can write the input/output field names pascal-casing, and a field named ObjectType can be used to specify the $type value. See the example below.

A general way to overcome the $type constraint for xServer is to use another moniker and replace it before and after serialization. This is what we do for xServer.NET https://github.com/ptv-logistics/xserve ... #L109-L113.

While this may look complex it works well and it's very fast. I would prefer it over SOAP any time. We are looking to make the xServer API definitions more accesible to other languages in future releases.

Code: Select all

static async Task ExecAsync()
{
    // input address for geocoding as anonymous type
    var result = await GeocodeAsync(new
    {
        // required by xLocate2, mapped to $type
        ObjectType = "SearchByAddressRequest",
        // request and response types are pascal-casing
        Address = new {
            Country = "L",
            PostalCode = "",
            City = "Schengen",
            Street = "Rue de la Moselle 5",
        }
    });

    // now work with the object like in JavaScript
    // You don't have intellisense, but can view the fields in the watch window of the debugger.
    Console.WriteLine($"Result is of type: {result.ObjectType}");
    foreach (var ra in result.Results)
    {
        Console.WriteLine($"Match Type: {ra.Type}, Match Quality: {ra.MatchQuality.TotalScore} " +
            $"Lat/Lng: {ra.Location.ReferenceCoordinate.Y}/{ra.Location.ReferenceCoordinate.X}");
    }
}
Attachments
XServerSerializerSettings.zip
XServer with pascal-casing and $type support
(3.96 KiB) Downloaded 447 times
Oliver Heilig
Chief Developer Logistic Services
PTV GROUP - Germany

https://github.com/oliverheilig/
User avatar
Oliver Heilig
Posts: 154
Joined: Tue May 13, 2014 12:10 pm
Location: Karlsruhe, Germany
Contact:

Re: c# example res/json web API ?

Post by Oliver Heilig »

Hello,

xServer-2 now supports OpenAPI specification (as draft).

This means you can now create your C# classes using autorest:

Code: Select all

npm install -g autorest

autorest --input-file=https://xserver2-europe-eu-test.cloud.ptvgroup.com/services/openapi/2.17/swagger.json --csharp --namespace=XServerClient --generate-empty-classes
generates the client methods (sync and async) for xServer with truely typed classes, which dramatically simplifies the workflow (see attachment).
Attachments
XServerOpenApi.zip
xLocate with autorest-generated client
(500.11 KiB) Downloaded 440 times
Oliver Heilig
Chief Developer Logistic Services
PTV GROUP - Germany

https://github.com/oliverheilig/
User avatar
Oliver Heilig
Posts: 154
Joined: Tue May 13, 2014 12:10 pm
Location: Karlsruhe, Germany
Contact:

Re: c# example res/json web API ?

Post by Oliver Heilig »

Hello, it's me again,

the xServer-2 OpenAPI specification is now final. To create a C# client via autorest:

Code: Select all

npm install -g autorest

autorest --input-file=https://xserver2-europe-eu.cloud.ptvgroup.com/services/openapi/2.19/swagger.json --csharp --namespace=XServerClient --generate-empty-classes
I have attached a sample using the xTour jobs api. As you can see, this creates quite nice client methods. Read here for more details.
Attachments
XTourOpenApi.zip
xTour with autorest
(563.45 KiB) Downloaded 374 times
Oliver Heilig
Chief Developer Logistic Services
PTV GROUP - Germany

https://github.com/oliverheilig/
stefan.rotaru
Posts: 7
Joined: Sat Mar 13, 2021 2:03 pm

Re: c# example res/json web API ?

Post by stefan.rotaru »

Hi,

I have tried to autorest the
https://xserver2-europe-eu-test.cloud.p ... agger.json
but it gives me an error
System.InvalidOperationException: Sequence contains more than one matching element

Can you please tell me if it works on your side or maybe attach the generated files for the XLocate and XRoute services (c#)?

Thank you.
User avatar
Bernd Welter
Site Admin
Posts: 2564
Joined: Mon Apr 14, 2014 10:28 am
Contact:

Re: c# example res/json web API ?

Post by Bernd Welter »

Hello Stefan,

how about the clients here?

https://xserver2-europe-eu-test.cloud.p ... 3%7C_____0

Bernd
Bernd Welter
Technical Partner Manager Developer Components
PTV Logistics - Germany

Bernd at... The Forum,LinkedIn, Youtube, StackOverflow
I like the smell of PTV Developer in the morning... :twisted:
stefan.rotaru
Posts: 7
Joined: Sat Mar 13, 2021 2:03 pm

Re: c# example res/json web API ?

Post by stefan.rotaru »

Hello,

In the link that you gave me, there is this sentence:
If you like to use the JSON API, there is also the possibility to generate clients from OpenAPI Documents.

Generating client (from VS or command prompt) with this command:
autorest --input-file=https://xserver2-europe-eu-test.cloud.p ... agger.json --csharp --namespace=XServerClient --generate-empty-classes
(like shown in the example from Oliver) I received the error I posted.

I have downloaded the example generated by Oliver for the XTourOpenAPI (the post from May 13 2020) and that is how I want to use it for other services (XLocate, XRoute). Can you please tell me how can I do that?

Thank you!
Post Reply