1- using Newtonsoft.Json;
2- using Newtonsoft.Json.Converters;
3- using Newtonsoft.Json.Linq;
4- using Newtonsoft.Json.Serialization;
51using System;
62using System.Collections.Generic;
73using System.IO;
84using System.Linq;
95using System.Net.Http;
106using System.Net.Http.Headers;
117using System.Text;
8+ using System.Text.Json;
9+ using System.Text.Json.Serialization;
1210using System.Threading.Tasks;
1311using {{ spec .title | caseUcfirst }}.Converters;
1412using {{ spec .title | caseUcfirst }}.Extensions;
@@ -29,26 +27,28 @@ namespace {{ spec.title | caseUcfirst }}
2927
3028 private static readonly int ChunkSize = 5 * 1024 * 1024;
3129
32- public static JsonSerializerSettings DeserializerSettings { get; set; } = new JsonSerializerSettings
30+ public static JsonSerializerOptions DeserializerOptions { get; set; } = new JsonSerializerOptions
3331 {
34- MetadataPropertyHandling = MetadataPropertyHandling.Ignore ,
35- NullValueHandling = NullValueHandling.Ignore ,
36- ContractResolver = new CamelCasePropertyNamesContractResolver() ,
37- Converters = new List< JsonConverter >
32+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase ,
33+ DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull ,
34+ PropertyNameCaseInsensitive = true ,
35+ Converters =
3836 {
39- new StringEnumConverter(new CamelCaseNamingStrategy()),
40- new ValueClassConverter()
37+ new JsonStringEnumConverter(JsonNamingPolicy.CamelCase),
38+ new ValueClassConverter(),
39+ new ObjectToInferredTypesConverter()
4140 }
4241 };
4342
44- public static JsonSerializerSettings SerializerSettings { get; set; } = new JsonSerializerSettings
43+ public static JsonSerializerOptions SerializerOptions { get; set; } = new JsonSerializerOptions
4544 {
46- NullValueHandling = NullValueHandling.Ignore ,
47- ContractResolver = new CamelCasePropertyNamesContractResolver() ,
48- Converters = new List< JsonConverter >
45+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase ,
46+ DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull ,
47+ Converters =
4948 {
50- new StringEnumConverter(new CamelCaseNamingStrategy()),
51- new ValueClassConverter()
49+ new JsonStringEnumConverter(JsonNamingPolicy.CamelCase),
50+ new ValueClassConverter(),
51+ new ObjectToInferredTypesConverter()
5252 }
5353 };
5454
@@ -69,14 +69,14 @@ namespace {{ spec.title | caseUcfirst }}
6969 _headers = new Dictionary<string , string >()
7070 {
7171 { "content-type", "application/json" },
72- { "user-agent" , "{{spec .title | caseUcfirst }}{{ language .name | caseUcfirst }}SDK/{{ sdk .version }} ($ {Environment.OSVersion.Platform}; $ {Environment.OSVersion.VersionString})"},
72+ { "user-agent" , $ "{{spec .title | caseUcfirst }}{{ language .name | caseUcfirst }}SDK/{{ sdk .version }} ({Environment.OSVersion.Platform}; {Environment.OSVersion.VersionString})"},
7373 { "x-sdk-name", "{{ sdk .name }}" },
7474 { "x-sdk-platform", "{{ sdk .platform }}" },
7575 { "x-sdk-language", "{{ language .name | caseLower }}" },
76- { "x-sdk-version", "{{ sdk .version }}"}{% if spec .global .defaultHeaders | length > 0 %},{% endif %}
76+ { "x-sdk-version", "{{ sdk .version }}"}{% if spec .global .defaultHeaders | length > 0 %},
7777 {%~ for key ,header in spec .global .defaultHeaders %}
7878 { "{{key }}", "{{header }}" }{% if not loop .last %},{% endif %}
79- {%~ endfor %}
79+ {%~ endfor %}{% endif %}
8080
8181 };
8282
@@ -86,8 +86,6 @@ namespace {{ spec.title | caseUcfirst }}
8686 {
8787 SetSelfSigned(true);
8888 }
89-
90- JsonConvert.DefaultSettings = () => DeserializerSettings;
9189 }
9290
9391 public Client SetSelfSigned(bool selfSigned)
@@ -158,19 +156,23 @@ namespace {{ spec.title | caseUcfirst }}
158156 {
159157 if (parameter.Key == "file")
160158 {
161- form.Add(((MultipartFormDataContent)parameters["file"]).First()!);
159+ var fileContent = parameters["file"] as MultipartFormDataContent;
160+ if (fileContent != null)
161+ {
162+ form.Add(fileContent.First()!);
163+ }
162164 }
163165 else if (parameter.Value is IEnumerable<object > enumerable)
164166 {
165167 var list = new List<object >(enumerable);
166168 for (int index = 0; index < list.Count; index++)
167169 {
168- form.Add(new StringContent(list[index].ToString()! ), $"{parameter.Key}[{index}]");
170+ form.Add(new StringContent(list[index]? .ToString() ?? string.Empty ), $"{parameter.Key}[{index}]");
169171 }
170172 }
171173 else
172174 {
173- form.Add(new StringContent(parameter.Value.ToString()! ), parameter.Key);
175+ form.Add(new StringContent(parameter.Value? .ToString() ?? string.Empty ), parameter.Key);
174176 }
175177 }
176178 request.Content = form;
@@ -243,16 +245,27 @@ namespace {{ spec.title | caseUcfirst }}
243245 }
244246
245247 if (contentType.Contains("application/json")) {
246- message = JObject.Parse(text)["message"]!.ToString();
247- type = JObject.Parse(text)["type"]?.ToString() ?? string.Empty;
248+ try
249+ {
250+ using var errorDoc = JsonDocument.Parse(text);
251+ message = errorDoc.RootElement.GetProperty("message").GetString() ?? "";
252+ if (errorDoc.RootElement.TryGetProperty("type", out var typeElement))
253+ {
254+ type = typeElement.GetString() ?? "";
255+ }
256+ }
257+ catch
258+ {
259+ message = text;
260+ }
248261 } else {
249262 message = text;
250263 }
251264
252265 throw new {{spec .title | caseUcfirst }}Exception(message, code, type, text);
253266 }
254267
255- return response.Headers.Location.OriginalString;
268+ return response.Headers.Location? .OriginalString ?? string.Empty ;
256269 }
257270
258271 public Task<Dictionary <string , object ?>> Call(
@@ -298,8 +311,19 @@ namespace {{ spec.title | caseUcfirst }}
298311 var type = "";
299312
300313 if (isJson) {
301- message = JObject.Parse(text)["message"]!.ToString();
302- type = JObject.Parse(text)["type"]?.ToString() ?? string.Empty;
314+ try
315+ {
316+ using var errorDoc = JsonDocument.Parse(text);
317+ message = errorDoc.RootElement.GetProperty("message").GetString() ?? "";
318+ if (errorDoc.RootElement.TryGetProperty("type", out var typeElement))
319+ {
320+ type = typeElement.GetString() ?? "";
321+ }
322+ }
323+ catch
324+ {
325+ message = text;
326+ }
303327 } else {
304328 message = text;
305329 }
@@ -311,13 +335,13 @@ namespace {{ spec.title | caseUcfirst }}
311335 {
312336 var responseString = await response.Content.ReadAsStringAsync();
313337
314- var dict = JsonConvert.DeserializeObject <Dictionary <string , object >>(
338+ var dict = JsonSerializer.Deserialize <Dictionary <string , object >>(
315339 responseString,
316- DeserializerSettings );
340+ DeserializerOptions );
317341
318- if (convert != null)
342+ if (convert != null && dict != null )
319343 {
320- return convert(dict! );
344+ return convert(dict);
321345 }
322346
323347 return (dict as T)!;
@@ -337,7 +361,16 @@ namespace {{ spec.title | caseUcfirst }}
337361 string? idParamName = null,
338362 Action<UploadProgress >? onProgress = null) where T : class
339363 {
364+ if (string.IsNullOrEmpty(paramName))
365+ throw new ArgumentException("Parameter name cannot be null or empty", nameof(paramName));
366+
367+ if (!parameters.ContainsKey(paramName))
368+ throw new ArgumentException($"Parameter {paramName} not found", nameof(paramName));
369+
340370 var input = parameters[paramName] as InputFile;
371+ if (input == null)
372+ throw new ArgumentException($"Parameter {paramName} must be an InputFile", nameof(paramName));
373+
341374 var size = 0L;
342375 switch(input.SourceType)
343376 {
@@ -347,10 +380,16 @@ namespace {{ spec.title | caseUcfirst }}
347380 size = info.Length;
348381 break;
349382 case "stream":
350- size = (input.Data as Stream).Length;
383+ var stream = input.Data as Stream;
384+ if (stream == null)
385+ throw new InvalidOperationException("Stream data is null");
386+ size = stream.Length;
351387 break;
352388 case "bytes":
353- size = ((byte[])input.Data).Length;
389+ var bytes = input.Data as byte[];
390+ if (bytes == null)
391+ throw new InvalidOperationException("Byte array data is null");
392+ size = bytes.Length;
354393 break;
355394 };
356395
@@ -364,10 +403,16 @@ namespace {{ spec.title | caseUcfirst }}
364403 {
365404 case "path":
366405 case "stream":
367- await (input.Data as Stream).ReadAsync(buffer, 0, (int)size);
406+ var dataStream = input.Data as Stream;
407+ if (dataStream == null)
408+ throw new InvalidOperationException("Stream data is null");
409+ await dataStream.ReadAsync(buffer, 0, (int)size);
368410 break;
369411 case "bytes":
370- buffer = (byte[])input.Data;
412+ var dataBytes = input.Data as byte[];
413+ if (dataBytes == null)
414+ throw new InvalidOperationException("Byte array data is null");
415+ buffer = dataBytes;
371416 break;
372417 }
373418
@@ -393,14 +438,16 @@ namespace {{ spec.title | caseUcfirst }}
393438 // Make a request to check if a file already exists
394439 var current = await Call<Dictionary <string , object ?>>(
395440 method: "GET",
396- path: $"{path}/{parameters[idParamName]}",
441+ path: $"{path}/{parameters[idParamName! ]}",
397442 new Dictionary<string , string > { { "content-type", "application/json" } },
398443 parameters: new Dictionary<string , object ?>()
399444 );
400- var chunksUploaded = (long)current["chunksUploaded"];
401- offset = chunksUploaded * ChunkSize;
445+ if (current.TryGetValue("chunksUploaded", out var chunksUploadedValue) && chunksUploadedValue != null)
446+ {
447+ offset = Convert.ToInt64(chunksUploadedValue) * ChunkSize;
448+ }
402449 }
403- catch (Exception ex)
450+ catch
404451 {
405452 // ignored as it mostly means file not found
406453 }
@@ -413,6 +460,8 @@ namespace {{ spec.title | caseUcfirst }}
413460 case "path":
414461 case "stream":
415462 var stream = input.Data as Stream;
463+ if (stream == null)
464+ throw new InvalidOperationException("Stream data is null");
416465 stream.Seek(offset, SeekOrigin.Begin);
417466 await stream.ReadAsync(buffer, 0, ChunkSize);
418467 break;
@@ -445,12 +494,12 @@ namespace {{ spec.title | caseUcfirst }}
445494 var id = result.ContainsKey("$id")
446495 ? result["$id"]?.ToString() ?? string.Empty
447496 : string.Empty;
448- var chunksTotal = result.ContainsKey ("chunksTotal")
449- ? (long)result["chunksTotal"]
450- : 0 ;
451- var chunksUploaded = result.ContainsKey ("chunksUploaded")
452- ? (long)result["chunksUploaded"]
453- : 0 ;
497+ var chunksTotal = result.TryGetValue ("chunksTotal", out var chunksTotalValue) && chunksTotalValue != null
498+ ? Convert.ToInt64(chunksTotalValue)
499+ : 0L ;
500+ var chunksUploaded = result.TryGetValue ("chunksUploaded", out var chunksUploadedValue) && chunksUploadedValue != null
501+ ? Convert.ToInt64(chunksUploadedValue)
502+ : 0L ;
454503
455504 headers["x-appwrite-id"] = id;
456505
@@ -463,7 +512,11 @@ namespace {{ spec.title | caseUcfirst }}
463512 chunksUploaded: chunksUploaded));
464513 }
465514
466- return converter(result);
515+ // Convert to non-nullable dictionary for converter
516+ var nonNullableResult = result.Where(kvp => kvp.Value != null)
517+ .ToDictionary(kvp => kvp.Key, kvp => kvp.Value!);
518+
519+ return converter(nonNullableResult);
467520 }
468521 }
469522}
0 commit comments