-
Notifications
You must be signed in to change notification settings - Fork 221
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
class to name conflict avoidance behaviour colliding with error default message behaviour in CSharp #4893
Comments
Hi @vvdb-architecture
Let us know if you have further questions. |
I first didn't t understand your answer. If you look at the definition: "Message": {
"type": "object",
"additionalProperties": false,
"properties": {
"something": {
"type": "string"
}
} I don't know where that But then in the code generation it seems that you derive this class from But then, why does kiota generates an override? In fact, that's why I filled an issue: the generated code just doesn't compile. /// <summary>The primary error message.</summary>
public override string MessageProp { get => base.Message; } This compilation fails because there is nothing to override. On a somewhat related matter, when looking at the code you referenced, the mechanism looks a bit fragile. If both a |
Types that are used as error definitions end up with the override when the
Since the intent is to override the message property from the Exception class so as to enable meaningful exception messages, I don't think we should rename the property. Maybe the class should be renamed here. This could be done by potentially updating the filter here to rename the errorDefinition className as well when its names match one of the reserved words for errors properties.
Any chance you'd be willing to try that out and submit a PR? |
Isn't this problem caused by the fact that the model type inherits from Granted, it would also be a problem for those clients who presuppose that some models inherit from ApiException, so probably the change at this point would be impossible. |
@vvdb-architecture how would you throw an instance of something that doesn't inherit from exception? (which is the parent of ApiException and where the message property is ultimately defined) |
Well, of course I don't know the code very well, but if you look at https://github.com/microsoft/kiota-http-dotnet/blob/6c1e799f63a26b9209e7153d7f1eb2d2c730e9f6/src/HttpClientRequestAdapter.cs#L381 you see this: if(result is not Exception ex)
throw new ApiException($"The server returned an unexpected status code and the error registered for this code failed to deserialize: {statusCodeAsString}")
{
ResponseStatusCode = statusCodeAsInt,
ResponseHeaders = responseHeadersDictionary
};
if(result is ApiException apiEx)
{
apiEx.ResponseStatusCode = statusCodeAsInt;
apiEx.ResponseHeaders = responseHeadersDictionary;
} The |
It's strange that you bring "Go" into this discussion. What has C# code generation to do with Go, TypeScript, ....: surely there is no rule that says you are limited to the lowest common denominator of the implementable patterns in all the supported languages? Everything starts with the single OpenAPI spec and you don't program in Go like you program in C#, TypeScript, Java, ...
That's fine with me. Something still needs to be done for the non-compileable code generation that override nonexistent methods. I'm out of my depth here, and I'll leave this up to someone with a better understanding than I. |
Go: it's a delicate balance between inter-language consistency, and taking advantages of what the platform supports to offer a better experience. Leveraging platform specificities is one of the main reasons why TypeScript composed types support is still not available (we're getting there), which itself is one of the only remaining reasons why TypeScript is not stable yet. Those specificities have a higher cost. To be clear, we're talking about this fix and nothing else at this point, correct? (i.e. we want the property name to remain Message and not MessageProp). I'm not forgetting about anything else? |
If the name of the property is identical to the name of its enclosing type(as is the case here, because Kiota forces the model to inherit from So, respecting the current mechanics of the Kiota code, in this case you need to rename the I wonder if you need to generate a public property And for the life of me, I still am unable to understand the motivation for all this. I'm still unable to find code evidence for @andrueastman's statement that this mechanism returns "a meaningful error message that is returned from the API.". It's also very puzzling that the renaming is inconsistent in Kiota. For example, if
... then the appropriate schema section in the above OpenApi spec would become: "MyMessage": {
"type": "object",
"additionalProperties": false,
"properties": {
"message": {
"type": "string"
}
} ... and because of the insistence of generating the model class inheriting from #pragma warning disable CS1591
public class MyMessage : ApiException, IParsable
#pragma warning restore CS1591
{
/// <summary>The message property</summary>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public string? MessageEscaped { get; set; }
#nullable restore
#else
public string MessageEscaped { get; set; }
#endif
} I was expecting to see I do not understand this design. This is why any PR should be done by someone smarter than me. I would be glad if the generated code could just compile correctly so that I can really start investigating if this is a good replacement for NSwag. |
The fact that it calls the base property is just a placeholder. The idea is you would decorate your description with the right extension so kiota knows where to get the message value from in response payload. This way when the service returns an error an exception is thrown and the message you get in the exception is the main message from the service. I think there are two possibly three mechanisms interacting with each other and adding to the confusion of the situation here:
Assumptions probably have been made in the error mechanisms which is why we override behavior is not consistent when the property has been renamed to something else to avoid collisions. Thank you for your continuous investigation of the problem. I think you're close to getting to a solution. Let us know if you have further questions. |
I've spend time reading https://learn.microsoft.com/en-us/openapi/kiota/errors, #3744 and #3066 and could find no reference about how to "decorate your description with the right extension".
I think not. The generated code does not compile. Your reactivity is much better than with NSwag (that's not very difficult) but I am in exactly the same place as when I started this issue, with a lot more questions and incomprehension. I understand you made some design decisions that are irreversible. That's OK, but I shudder to think about my incomprehension if/when Kiota will generate something that actually compiles correctly. I do appreciate your answers. But I didn't expect to invest so much time for such a simple issue. For me, this stops here. Kiota isn't the product we are looking for, even if we had time to invest in its development. |
Understood. |
We appreciate your input here. Unfortunately translating HTTP failure modes into programing language exceptions in a way that is both maintainable across many languages and feels natural in each of those languages isn't a simple issue. My gut reaction to this issue is that inheriting from ApiException does feel wrong to me. But I have not been involved in the implementation details of this area, so I am not intimately familiar with all the challenges. Even without generics, I feel like I would rather catch an APIException class that has Content property on it that I need to cast. e.g. something like catch(ApiException exception) {
var message = exception.Content as Message;
...
} |
What are you generating using Kiota, clients or plugins?
API Client/SDK
In what context or format are you using Kiota?
Windows executable
Client library/SDK language
Csharp
Describe the bug
I have a controller defined as follows:
With
Message1
defined as follows:The generated
Message1
model of kiota is as expected (I've omitted some of the lines for brevity):Now I just rename the class
Message
instead. I change nothing else, but just re-generate the C# code using the same kiota version. And here is what I get (again, some the lines that are identical are omitted for brevity):This fails, because there is no
public override string MessageProp { get => base.Message; }
!For the life of me, I can't fathom where this
MessageProp
property comes from. I don't even know where the summary comment of the property comes from, only that it doesn't occur in any of our code or internal frameworks.It seems to be related to
kiota/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs
Line 1504 in 0254c19
I do not understand how renaming a type can have such an effect.
Expected behavior
Except for the renaming, the generated code should be exactly the same
How to reproduce
See the above description.
Open API description file
Kiota Version
1.15.0+b535a94064cd8c14a022aaba42964467d5db525a
Latest Kiota version known to work for scenario above?(Not required)
No response
Known Workarounds
No realistic workarounds, we can't just start renaming stuff just because of a code generation anomaly. What's so special about
Message
that it cannot be used?Configuration
Windows 10, 64 bit, VS2022 ASP.NET Core 8.0
Debug output
Debug doesn't seem to work.
Other information
None
The text was updated successfully, but these errors were encountered: