Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions src/NSwag.CodeGeneration.CSharp.Tests/CodeGenerationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,58 @@ public async Task When_path_starts_with_numeric_can_generate_client()
CSharpCompiler.AssertCompile(code);
}

[Fact]
public async Task When_media_type_contains_quotes_can_generate_client()
{
// Arrange
const string mediaType = "application/vnd.api+json; ext=\"https://jsonapi.org/ext/atomic https://www.jsonapi.net/ext/openapi\"";
string mediaTypeJsonEscaped = mediaType.Replace("\"", "\\\"");

string json =
$$"""
{
"openapi": "3.0.1",
"paths": {
"/Test": {
"post": {
"requestBody": {
"content": {
"{{mediaTypeJsonEscaped}}": {
"schema": {
"type": "object"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"{{mediaTypeJsonEscaped}}": {
"schema": {
"type": "object"
}
}
}
}
}
}
}
}
}
""";

var document = await OpenApiDocument.FromJsonAsync(json);
var codeGenerator = new CSharpClientGenerator(document, new CSharpClientGeneratorSettings());

// Act
var code = codeGenerator.GenerateFile();

// Assert
await VerifyHelper.Verify(code);
CSharpCompiler.AssertCompile(code);
}

private static OpenApiDocument CreateDocument()
{
var document = new OpenApiDocument();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -427,10 +427,10 @@ public async Task When_controllertarget_aspnet_and_multiple_controllers_then_onl
var code = codeGen.GenerateFile();

// Assert
var fromHeaderCustomAttributeCount = Regex.Matches(code, "public class FromHeaderAttribute :").Count;
var fromHeaderCustomAttributeCount = Regex.Count(code, "public class FromHeaderAttribute :");
Assert.Equal(1, fromHeaderCustomAttributeCount);

var fromHeaderCustomBindingCount = Regex.Matches(code, "public class FromHeaderBinding :").Count;
var fromHeaderCustomBindingCount = Regex.Count(code, "public class FromHeaderBinding :");
Assert.Equal(1, fromHeaderCustomBindingCount);

await VerifyHelper.Verify(code);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@


namespace MyNamespace
{
using System = global::System;

public partial class Client
{
#pragma warning disable 8618
private string _baseUrl;
#pragma warning restore 8618

private System.Net.Http.HttpClient _httpClient;
private static System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _settings = new System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(CreateSerializerSettings, true);
private Newtonsoft.Json.JsonSerializerSettings _instanceSettings;

#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
public Client(string baseUrl, System.Net.Http.HttpClient httpClient)
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
{
BaseUrl = baseUrl;
_httpClient = httpClient;
Initialize();
}

private static Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings()
{
var settings = new Newtonsoft.Json.JsonSerializerSettings();
UpdateJsonSerializerSettings(settings);
return settings;
}

public string BaseUrl
{
get { return _baseUrl; }
set
{
_baseUrl = value;
if (!string.IsNullOrEmpty(_baseUrl) && !_baseUrl.EndsWith("/"))
_baseUrl += '/';
}
}

protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _instanceSettings ?? _settings.Value; } }

static partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings);

partial void Initialize();

partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url);
partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder);
partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response);

public virtual System.Threading.Tasks.Task<object> TestAsync(object body)
{
return TestAsync(body, System.Threading.CancellationToken.None);
}

public virtual async System.Threading.Tasks.Task<object> TestAsync(object body, System.Threading.CancellationToken cancellationToken)
{
var client_ = _httpClient;
var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings);
var content_ = new System.Net.Http.StringContent(json_);
content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/vnd.api+json; ext=\"https://jsonapi.org/ext/atomic https://www.jsonapi.net/ext/openapi\"");
request_.Content = content_;
request_.Method = new System.Net.Http.HttpMethod("POST");
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/vnd.api+json; ext=\"https://jsonapi.org/ext/atomic https://www.jsonapi.net/ext/openapi\""));

var urlBuilder_ = new System.Text.StringBuilder();
if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl);
// Operation Path: "Test"
urlBuilder_.Append("Test");

PrepareRequest(client_, request_, urlBuilder_);

var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);

PrepareRequest(client_, request_, url_);

var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = new System.Collections.Generic.Dictionary<string, System.Collections.Generic.IEnumerable<string>>();
foreach (var item_ in response_.Headers)
headers_[item_.Key] = item_.Value;
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}

ProcessResponse(client_, response_);

var status_ = (int)response_.StatusCode;
if (status_ == 200)
{
var objectResponse_ = await ReadObjectResponseAsync<object>(response_, headers_, cancellationToken).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
}
return objectResponse_.Object;
}
else
{
var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}

protected struct ObjectResponseResult<T>
{
public ObjectResponseResult(T responseObject, string responseText)
{
this.Object = responseObject;
this.Text = responseText;
}

public T Object { get; }

public string Text { get; }
}

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
private static System.Threading.Tasks.Task<string> ReadAsStringAsync(System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken)
{
#if NET5_0_OR_GREATER
return content.ReadAsStringAsync(cancellationToken);
#else
return content.ReadAsStringAsync();
#endif
}

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
private static System.Threading.Tasks.Task<System.IO.Stream> ReadAsStreamAsync(System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken)
{
#if NET5_0_OR_GREATER
return content.ReadAsStreamAsync(cancellationToken);
#else
return content.ReadAsStreamAsync();
#endif
}

public bool ReadResponseAsString { get; set; }

protected virtual async System.Threading.Tasks.Task<ObjectResponseResult<T>> ReadObjectResponseAsync<T>(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary<string, System.Collections.Generic.IEnumerable<string>> headers, System.Threading.CancellationToken cancellationToken)
{
if (response == null || response.Content == null)
{
return new ObjectResponseResult<T>(default(T), string.Empty);
}

if (ReadResponseAsString)
{
var responseText = await ReadAsStringAsync(response.Content, cancellationToken).ConfigureAwait(false);
try
{
var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(responseText, JsonSerializerSettings);
return new ObjectResponseResult<T>(typedBody, responseText);
}
catch (Newtonsoft.Json.JsonException exception)
{
var message = "Could not deserialize the response body string as " + typeof(T).FullName + ".";
throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception);
}
}
else
{
try
{
using (var responseStream = await ReadAsStreamAsync(response.Content, cancellationToken).ConfigureAwait(false))
using (var streamReader = new System.IO.StreamReader(responseStream))
using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader))
{
var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings);
var typedBody = serializer.Deserialize<T>(jsonTextReader);
return new ObjectResponseResult<T>(typedBody, string.Empty);
}
}
catch (Newtonsoft.Json.JsonException exception)
{
var message = "Could not deserialize the response body stream as " + typeof(T).FullName + ".";
throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception);
}
}
}

private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo)
{
if (value == null)
{
return "";
}

if (value is System.Enum)
{
var name = System.Enum.GetName(value.GetType(), value);
if (name != null)
{
var field_ = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name);
if (field_ != null)
{
var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field_, typeof(System.Runtime.Serialization.EnumMemberAttribute))
as System.Runtime.Serialization.EnumMemberAttribute;
if (attribute != null)
{
return attribute.Value != null ? attribute.Value : name;
}
}

var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo));
return converted == null ? string.Empty : converted;
}
}
else if (value is bool)
{
return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant();
}
else if (value is byte[])
{
return System.Convert.ToBase64String((byte[]) value);
}
else if (value is string[])
{
return string.Join(",", (string[])value);
}
else if (value.GetType().IsArray)
{
var valueArray = (System.Array)value;
var valueTextArray = new string[valueArray.Length];
for (var i = 0; i < valueArray.Length; i++)
{
valueTextArray[i] = ConvertToString(valueArray.GetValue(i), cultureInfo);
}
return string.Join(",", valueTextArray);
}

var result = System.Convert.ToString(value, cultureInfo);
return result == null ? "" : result;
}
}





public partial class ApiException : System.Exception
{
public int StatusCode { get; private set; }

public string Response { get; private set; }

public System.Collections.Generic.IReadOnlyDictionary<string, System.Collections.Generic.IEnumerable<string>> Headers { get; private set; }

public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary<string, System.Collections.Generic.IEnumerable<string>> headers, System.Exception innerException)
: base(message + "\n\nStatus: " + statusCode + "\nResponse: \n" + ((response == null) ? "(null)" : response.Substring(0, response.Length >= 512 ? 512 : response.Length)), innerException)
{
StatusCode = statusCode;
Response = response;
Headers = headers;
}

public override string ToString()
{
return string.Format("HTTP Response: \n\n{0}\n\n{1}", Response, base.ToString());
}
}

public partial class ApiException<TResult> : ApiException
{
public TResult Result { get; private set; }

public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary<string, System.Collections.Generic.IEnumerable<string>> headers, TResult result, System.Exception innerException)
: base(message, statusCode, response, headers, innerException)
{
Result = result;
}
}

}
Loading
Loading