[C#] GET request met raw-data

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • mrFoce
  • Registratie: Augustus 2004
  • Laatst online: 18-07 00:38
Ik probeer via C# i.c.m .NET Core 3.1 de TransIP api aan te roepen. De eenvoudige dingen werken zonder problem, maar requests die raw-data versturen krijg ik niet werkend. Resulteerd telkens in een 504 - Gateway Timeout.

Volgens de documentatie van TransIP moet ik het volgende request maken:

code:
1
2
3
4
5
6
7
8
9
10
11
12
curl -X GET \
-H "Content-Type: application/json" \
-H "Authorization: Bearer [your JSON web token]" \
-d '
{
  "domainNames": [
    "example.com",
    "example.nl"
  ]
} 
' \
"https://api.transip.nl/v6/domain-availability"


Na 2 avonden googlen op van alles en nog wat (b.v., 'SendAsync results in timeout') ben ik nog niets tegen gekomen wat me verder op weg helpt. Via Fiddler gekeken of ik kon inzien wat er fout gaat, maar dat heeft ook geen effect omdat de verbinding niet tot stand komt. Vraag me af het gewoon niet ondersteund wordt?

Mijn C# code:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token);

string body = "{\"domainNames\": [\"example.com\", \"example.nl\"]}";

HttpRequestMessage request = new HttpRequestMessage
{
    Method = HttpMethod.Get,
    RequestUri = new Uri("https://api.transip.nl/v6/domain-availability"),
    Content = new StringContent(body, Encoding.UTF8, "application/json")
};

HttpResponseMessage response = await client.SendAsync(request).ConfigureAwait(false);
response.EnsureSuccessStatusCode();


Het response object op lijn 13 geeft 504 - Gateway Timeout aan.

Zover ik kan nagaan, zet ik de juiste headers die TransIP verwacht.

Afbeeldingslocatie: https://tweakers.net/i/ymLFGqvua4v4KI_D4wnRcnJiKwk=/800x/filters:strip_exif()/f/image/TVg1tUOTKWIJvylICq3gomfi.png?f=fotoalbum_large


Afbeeldingslocatie: https://tweakers.net/i/vY0LBiqGfhpkN-HkpnZ2C4FDLSQ=/800x/filters:strip_exif()/f/image/x8EclcJD3dgg5xy69ZCFPRS5.png?f=fotoalbum_large
--

De NuGet packages voor TransIP die ik kon vinden ondersteunen voornamelijk de SOAP versie die deprecated is.

Weet iemand wat ik fout doe? Of is het gewoon niet mogelijk?

[ Voor 3% gewijzigd door mrFoce op 05-08-2020 07:00 ]

Alle reacties


Acties:
  • +1 Henk 'm!

  • SavageNL
  • Registratie: November 2001
  • Laatst online: 18:18
Je code en vraag heeft veel weg van deze:
https://stackoverflow.com...request/47902348#47902348
Daar worden ook andere mogelijkheden genoemd.

Als het goed is komt er wel een verbinding tot stand want je krijgt een error code. Die zou je anders niet krijgen.

Als Fiddler niets laat zien, probeer dan eens een request te doen naar bijvoorbeeld https://webhook.site/ (even unieke url kopieren en request daar naartoe doen), dan krijg je als het goed is te zien of wat je denkt te sturen ook echt is wat je stuurt.

Niet dat je hier iets aan hebt omdat je de API van een andere partij wilt benaderen, maar JSON body in een GET request is niet echt standaard. Dat wordt bij die StackOverflow vraag ook genoemd:
"HTTP GET with a body is a somewhat unconventional construct that falls in a gray area of the HTTP specification"

Acties:
  • +1 Henk 'm!

  • Damic
  • Registratie: September 2003
  • Laatst online: 20:36

Damic

Tijd voor Jasmijn thee

In de plaats van async doe eens sync en gebruik Fidler ;)

Al wat ik aanraak werk niet meer zoals het hoort. Damic houd niet van zijn verjaardag


Acties:
  • +1 Henk 'm!

  • Haan
  • Registratie: Februari 2004
  • Laatst online: 13:58

Haan

dotnetter

Doe eens het volgende :
maak een C# class die het json object voorstelt dat je moet versturen. Google even op 'generate C# from json' en dan heb je zo een online tool te pakken die dat voor je doet.
Vervolgens maak je een instance van die class aan met de data die je wil versturen en die instance serialize je naar een string. Dat kan met NewtonSoft.Json of met de Json converter class die nu standaard in .NET Core beschikbaar is.
De json string die je nu zelf maakt klopt namelijk waarschijnlijk niet helemaal.

Je kan eerst trouwens ook nog proberen om de strings met dubbele quotes te escapen ipv met een backslash.

[ Voor 9% gewijzigd door Haan op 05-08-2020 07:33 ]

Kater? Eerst water, de rest komt later


Acties:
  • +1 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Ik zie niet direct wat je fout doet in jouw code, maar wat ik sowieso zou aanraden is om het niet eens zelf te maken. Er is gewoon een Open API Spec beschikbaar: https://api.transip.nl/rest/openapi.yaml

Je kunt dus eenvoudig zelf een client genereren met tooling :)

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • +2 Henk 'm!

  • YakuzA
  • Registratie: Maart 2001
  • Niet online

YakuzA

Wat denk je nou zelluf hey :X

Mijn vraag 1 zou zijn:
Werkt het wel als je hetzelfde request los vanuit PostMan doet?

Death smiles at us all, all a man can do is smile back.
PSN


Acties:
  • 0 Henk 'm!

  • mrFoce
  • Registratie: Augustus 2004
  • Laatst online: 18-07 00:38
SavageNL schreef op woensdag 5 augustus 2020 @ 07:12:
Je code en vraag heeft veel weg van deze:
https://stackoverflow.com...request/47902348#47902348
Daar worden ook andere mogelijkheden genoemd.

Als het goed is komt er wel een verbinding tot stand want je krijgt een error code. Die zou je anders niet krijgen.

Als Fiddler niets laat zien, probeer dan eens een request te doen naar bijvoorbeeld https://webhook.site/ (even unieke url kopieren en request daar naartoe doen), dan krijg je als het goed is te zien of wat je denkt te sturen ook echt is wat je stuurt.

Niet dat je hier iets aan hebt omdat je de API van een andere partij wilt benaderen, maar JSON body in een GET request is niet echt standaard. Dat wordt bij die StackOverflow vraag ook genoemd:
"HTTP GET with a body is a somewhat unconventional construct that falls in a gray area of the HTTP specification"
Damic schreef op woensdag 5 augustus 2020 @ 07:15:
In de plaats van async doe eens sync en gebruik Fidler ;)
Heb gekeken naar alternatieven, maar lijkt erop dat de request zelf eruit ziet zoals verwacht van de documentatie.
Woy schreef op woensdag 5 augustus 2020 @ 09:06:
Ik zie niet direct wat je fout doet in jouw code, maar wat ik sowieso zou aanraden is om het niet eens zelf te maken. Er is gewoon een Open API Spec beschikbaar: https://api.transip.nl/rest/openapi.yaml

Je kunt dus eenvoudig zelf een client genereren met tooling :)
Ben niet zo heel bekend met openapi dingen, maar ga me daar is in verdiepen.
YakuzA schreef op woensdag 5 augustus 2020 @ 09:08:
Mijn vraag 1 zou zijn:
Werkt het wel als je hetzelfde request los vanuit PostMan doet?
Werkt ook niet, als ik de URL vervang naar webhook.site werkt het wel.Dus lijkt erop dat de TransIP server een grotere rol speelt dan ik dacht in het niet accepteren van het request. Geeft mij in ieder geval wat meer aanknopingspunten.

Acties:
  • +1 Henk 'm!

  • Kontsnorretje
  • Registratie: Augustus 2011
  • Laatst online: 14-06-2024
Als je de CURL request van TransIP kopieert, en daar jouw token in plakt, krijg je dan wel respons?

Acties:
  • 0 Henk 'm!

  • mrFoce
  • Registratie: Augustus 2004
  • Laatst online: 18-07 00:38
Kontsnorretje schreef op woensdag 5 augustus 2020 @ 14:12:
Als je de CURL request van TransIP kopieert, en daar jouw token in plakt, krijg je dan wel respons?
Werkt ook niet out of the box. Geeft ook die 504 timeout.

Kwam erachter dat als ik bijvoorbeeld https://api.transip.nl/v6...ainNames%5B%5D=example.ca doe, dat het wel werkt. Dan maar op die manier.

Acties:
  • +1 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Ah, sure, het meesturen van een body bij een get-request is niet echt standaard. Is het niet gewoon een documentatie fout?

https://stackoverflow.com...ttp-get-with-request-body

edit:
Hoewel ik even snel in de OpenAPI specification kijke dat ze inderdaad wel een requestBody specificeren bij het get request voor multiple domain names.

YAML:
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
  /domain-availability:
    get:
      responses:
        '200':
          content:
            application/json:
              examples:
                response:
                  value:
                    availability:
                      - actions:
                          - register
                        domainName: example.com
                        status: free
              schema:
                properties:
                  availability:
                    items: {}
                    type: array
                type: object
          description: OK
          headers: {}
      security:
        - oauth2: []
      tags:
        - Domains
      description: Check the availability for multiple domain names.
      operationId: Check the availability for multiple domain names
      requestBody:
        content:
          application/json:
            schema:
              example:
                domainNames:
                  - example.com
                  - example.nl
              properties:
                domainNames:
                  description: array of domainNames to check
                  type: array
              type: object
      summary: Check the availability for multiple domain names
  '/domain-availability/{domainName}':
    get:
      parameters:
        - description: Domain name
          example: example.com
          in: path
          name: domainName
          required: true
          schema:
            type: string
      responses:
        '200':
          content:
            application/json:
              examples:
                response:
                  value:
                    availability:
                      actions:
                        - register
                      domainName: example.com
                      status: free
              schema:
                properties:
                  availability:
                    properties:
                      actions:
                        description: >-
                          List of available actions to perform on this domain.
                          Possible actions are: 'register', 'transfer',
                          'internalpull' and 'internalpush'
                        items: {}
                        type: array
                      domainName:
                        description: The name of the domain
                        type: string
                      status:
                        description: >-
                          The status for this domain. Possible statuses are:
                          'inyouraccount', 'unavailable', 'notfree', 'free',
                          'internalpull' and 'internalpush'
                        type: string
                    required:
                      - domainName
                      - status
                      - actions
                    type: object
                type: object
          description: OK
          headers: {}
      security:
        - oauth2: []
      tags:
        - Domains
      description: This method allows you to check the availability for a domain name.
      operationId: Check availability for a domain name
      summary: Check availability for a domain name

De single domain name endpoint specificeert het wel netjes in de path. Ik denk dat het een stukje foutieve specificatie van de kant van TransIP is.

[ Voor 132% gewijzigd door Woy op 05-08-2020 15:35 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • +1 Henk 'm!

  • CodeCaster
  • Registratie: Juni 2003
  • Niet online

CodeCaster

Can I get uhm...

Misschien heeft de machine die deze code uitvoert een proxyserver ingesteld die de body van een GET-request niet meestuurt? En dat de TransIP-server blijft wachten op de body, en uiteindelijk een timeout geeft?
(Al zouden de relevante headers zoals Content-Length dan ook gestript moeten worden, en is het na het ontvangen van het request voor de server duidelijk dat er geen body meer komt...)

Het zal vast geen documentatiefout zijn, maar een designbeslissing. Ik heb zelf een hekel aan dit onpragmatische toepassen van REST. Als je dat zonodig overal waar het maar kan wil toepassen, zorg dan ook dat je je eraan houdt. Dat wordt dus één GET-call per URL naar de /domain-availability/$name-service, waarin het response-object je vertelt wat de status en beschikbaarheid van dat domein is, en dat is prima.

Nu willen ze echter doen alsof de batch-lookup van de beschikbaarheid van een stapeltje domeinen ook een REST-call is, en dus met GET moet omdat je enkel informatie ophaalt, maar dat is het simpelweg niet, het is RPC. Dit endpoint had prima POST kunnen accepteren. En wellicht ondersteunt het dat ook, probeer het eens?

[ Voor 16% gewijzigd door CodeCaster op 05-08-2020 15:40 ]

https://oneerlijkewoz.nl
Het ergste moet nog komen / Het leven is een straf / Een uitgestrekte kwelling van de wieg tot aan het graf


Acties:
  • +1 Henk 'm!

  • hostname
  • Registratie: April 2009
  • Laatst online: 17:02
Heb je al een POST-request geprobeerd? Het lijkt me gewoon een documentatiefout bij TransIP ;)

Als ik even snel door die API heen scroll lijkt dit namelijk ook de enige GET-request te zijn die een body wilt.

[ Voor 38% gewijzigd door hostname op 05-08-2020 15:40 ]


Acties:
  • +1 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
CodeCaster schreef op woensdag 5 augustus 2020 @ 15:36:
Het zal vast geen documentatiefout zijn, maar een designbeslissing. Ik heb zelf een hekel aan dit onpragmatische toepassen van REST. Als je dat zonodig overal waar het maar kan wil toepassen, zorg dan ook dat je je eraan houdt. Dat wordt dus één GET-call per URL naar de /domain-availability/$name-service, waarin het response-object je vertelt wat de status en beschikbaarheid van dat domein is, en dat is prima.

Nu willen ze echter doen alsof de batch-lookup van de beschikbaarheid van een stapeltje domeinen ook een REST-call is, en dus met GET moet omdat je enkel informatie ophaalt, maar dat is het simpelweg niet, het is RPC. Dit endpoint had prima POST kunnen accepteren. En wellicht ondersteunt het dat ook, probeer het eens?
Ja inderdaad, het idee is erg puristisch, maar je gaat gewoon tegen de standaard in, want die zegt
The GET method means retrieve whatever information ([...]) is identified by the Request-URI.
De body hoort daar dus niet bij.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • mrFoce
  • Registratie: Augustus 2004
  • Laatst online: 18-07 00:38
@Woy Het lijkt inderdaad niet op een documentatie fout, wat ik wel verwachte. De server accepteerd alleen een GET.
hostname schreef op woensdag 5 augustus 2020 @ 15:38:
Heb je al een POST-request geprobeerd? Het lijkt me gewoon een documentatiefout bij TransIP ;)

Als ik even snel door die API heen scroll lijkt dit namelijk ook de enige GET-request te zijn die een body wilt.
Is volgens mij het eerste wat ik geprobeerd had want ik dacht, raar om een body te sturen met een GET request. Maar nee, server laat alleen een GET toe voor die methode.

[ Voor 10% gewijzigd door mrFoce op 05-08-2020 16:01 ]


Acties:
  • 0 Henk 'm!

  • mrFoce
  • Registratie: Augustus 2004
  • Laatst online: 18-07 00:38
CodeCaster schreef op woensdag 5 augustus 2020 @ 15:36:
Misschien heeft de machine die deze code uitvoert een proxyserver ingesteld die de body van een GET-request niet meestuurt? En dat de TransIP-server blijft wachten op de body, en uiteindelijk een timeout geeft?
(Al zouden de relevante headers zoals Content-Length dan ook gestript moeten worden, en is het na het ontvangen van het request voor de server duidelijk dat er geen body meer komt...)

Het zal vast geen documentatiefout zijn, maar een designbeslissing. Ik heb zelf een hekel aan dit onpragmatische toepassen van REST. Als je dat zonodig overal waar het maar kan wil toepassen, zorg dan ook dat je je eraan houdt. Dat wordt dus één GET-call per URL naar de /domain-availability/$name-service, waarin het response-object je vertelt wat de status en beschikbaarheid van dat domein is, en dat is prima.

Nu willen ze echter doen alsof de batch-lookup van de beschikbaarheid van een stapeltje domeinen ook een REST-call is, en dus met GET moet omdat je enkel informatie ophaalt, maar dat is het simpelweg niet, het is RPC. Dit endpoint had prima POST kunnen accepteren. En wellicht ondersteunt het dat ook, probeer het eens?
Dit is precies mijn gedachte. Waarom doen ze het op deze manier en niet gewoon een POST. Zoiets als dit zou niet zo ingewikkeld moeten zijn. Gebruik nu inderdaad die /domain-availability/$name methode om de domeinen dan maar los van elkaar te checken, maar dacht iets fout te doen. Hoewel hun design keuzes niet standaard lijken. Een POST wordt niet geaccepteerd als methode bij hun server.
Als ik de token weg laat of geen body meestuur, krijg ik gelijk een response. Dus ik bereik de server wel.

Misschien toch maar een mailtje naar TransIP of ze weten wat er fout gaat.

Acties:
  • +1 Henk 'm!

  • Kontsnorretje
  • Registratie: Augustus 2011
  • Laatst online: 14-06-2024
mrFoce schreef op woensdag 5 augustus 2020 @ 15:18:
[...]

Werkt ook niet out of the box. Geeft ook die 504 timeout.

Kwam erachter dat als ik bijvoorbeeld https://api.transip.nl/v6...ainNames%5B%5D=example.ca doe, dat het wel werkt. Dan maar op die manier.
Met de Demo token krijg ik ook een 504. Het is dan inderdaad een kwestie van een request per domain doen en een support ticket aanmaken bij TransIP.

Acties:
  • 0 Henk 'm!

  • mrFoce
  • Registratie: Augustus 2004
  • Laatst online: 18-07 00:38
Opgelost met:

code:
1
2
3
4
5
6
7
8
9
10
11
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "token van account");

StringBuilder builder = new StringBuilder();
foreach (string domain in domains)
{
    builder.Append($"domainNames%5B%5D={domain}&");
}

string result = client.GetStringAsync($"https://api.transip.nl/v6/domain-availability/?{builder}").Result;
return JsonSerializer.Deserialize<AvailabilityResponses>(result, new JsonSerializerOptions());


Omdat het in principe een hobby projectje is, geen zin om er meer tijd in te stoppen als dit prima werkt.

[ Voor 13% gewijzigd door mrFoce op 06-08-2020 05:55 ]


Acties:
  • +1 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Je moet nog wel even je domain name url encoden

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • +1 Henk 'm!

  • Snake
  • Registratie: Juli 2005
  • Laatst online: 07-03-2024

Snake

Los Angeles, CA, USA

YakuzA schreef op woensdag 5 augustus 2020 @ 09:08:
Mijn vraag 1 zou zijn:
Werkt het wel als je hetzelfde request los vanuit PostMan doet?
En in Postman kan je dan C# genereren!

Going for adventure, lots of sun and a convertible! | GMT-8


Acties:
  • 0 Henk 'm!

  • mrFoce
  • Registratie: Augustus 2004
  • Laatst online: 18-07 00:38
Woy schreef op donderdag 6 augustus 2020 @ 06:15:
Je moet nog wel even je domain name url encoden
:o klopt, de domeinen die ik normaal check hebben geen speciale tekens ofzo dus zou niet tegen problemen aankomen, maar de correcte manier is inderdaad om ze ook te url encoden.

Mocht iemand willen weten hoe ik dat opgelost heb:
code:
1
2
3
4
5
6
StringBuilder builder = new StringBuilder();
UrlEncoder encoder = UrlEncoder.Create();
foreach (string domain in domains)
{
   builder.Append($"domainNames%5B%5D={ encoder.Encode(domain)}&");
}

* Niet exact mijn code, maar komt op hetzelde neer.
Pagina: 1