diff --git a/src/kiota.core/CodeDOM/CodeMethod.cs b/src/kiota.core/CodeDOM/CodeMethod.cs index 1ba2c0fbb9..0723d9e8eb 100644 --- a/src/kiota.core/CodeDOM/CodeMethod.cs +++ b/src/kiota.core/CodeDOM/CodeMethod.cs @@ -4,14 +4,23 @@ namespace kiota.core { + public enum CodeMethodKind + { + Custom, + ResponseHandler + } + public class CodeMethod : CodeTerminal, ICloneable { + public CodeMethodKind MethodKind = CodeMethodKind.Custom; public CodeType ReturnType; public List Parameters = new List(); + public bool IsStatic = false; public object Clone() { return new CodeMethod { + MethodKind = MethodKind, ReturnType = ReturnType.Clone() as CodeType, Parameters = Parameters.Select(x => x.Clone() as CodeParameter).ToList(), Name = Name.Clone() as string, diff --git a/src/kiota.core/CodeDOM/CodeParameter.cs b/src/kiota.core/CodeDOM/CodeParameter.cs index b9fa0810f7..6c38835c97 100644 --- a/src/kiota.core/CodeDOM/CodeParameter.cs +++ b/src/kiota.core/CodeDOM/CodeParameter.cs @@ -2,17 +2,23 @@ namespace kiota.core { + public enum CodeParameterKind + { + Custom, + QueryParameter + } + public class CodeParameter : CodeTerminal, ICloneable { + public CodeParameterKind ParameterKind = CodeParameterKind.Custom; public CodeType Type; public bool Optional = false; - public bool IsQueryParameter { get; set; } public object Clone() { return new CodeParameter{ Optional = Optional, - IsQueryParameter = IsQueryParameter, + ParameterKind = ParameterKind, Name = Name.Clone() as string, Type = Type.Clone() as CodeType, }; diff --git a/src/kiota.core/CodeDOM/CodeProperty.cs b/src/kiota.core/CodeDOM/CodeProperty.cs index 89e96fd624..70c7a4362c 100644 --- a/src/kiota.core/CodeDOM/CodeProperty.cs +++ b/src/kiota.core/CodeDOM/CodeProperty.cs @@ -1,12 +1,21 @@ namespace kiota.core { + public enum CodePropertyKind + { + Custom, + ResponseHandler + } + public class CodeProperty : CodeTerminal { + public CodePropertyKind PropertyKind = CodePropertyKind.Custom; + public override string Name { get; set; } public bool ReadOnly = false; public CodeType Type; + public string DefaultValue; } } diff --git a/src/kiota.core/KiotaBuilder.cs b/src/kiota.core/KiotaBuilder.cs index 0d901e3fd7..bdc7b7a6f8 100644 --- a/src/kiota.core/KiotaBuilder.cs +++ b/src/kiota.core/KiotaBuilder.cs @@ -221,7 +221,10 @@ private void CreateClass(CodeNamespace codeNamespace, OpenApiUrlSpaceNode node) logger.LogDebug("Creating method {name} of {type}", method.Name, method.ReturnType); codeClass.AddMethod(method); } + + CreateResponseHandler(codeClass); } + codeNamespace.AddClass(codeClass); @@ -246,12 +249,13 @@ private CodeIndexer CreateIndexer(string childIdentifier, string childType) return prop; } - private CodeProperty CreateProperty(string childIdentifier, string childType) + private CodeProperty CreateProperty(string childIdentifier, string childType, string defaultValue = null) { var prop = new CodeProperty() { Name = childIdentifier, - Type = new CodeType() { Name = childType } + Type = new CodeType() { Name = childType }, + DefaultValue = defaultValue }; logger.LogDebug("Creating property {name} of {type}", prop.Name, prop.Type.Name); return prop; @@ -279,7 +283,7 @@ private CodeMethod CreateOperationMethod(OperationType operationType, OpenApiOpe Name = "q", Type = new CodeType() { Name = parameterClass.Name, ActionOf = true, TypeDefinition = parameterClass }, Optional = true, - IsQueryParameter = true, + ParameterKind = CodeParameterKind.QueryParameter }; method.AddParameter(methodParameter); return method; @@ -380,5 +384,20 @@ private static string FixPathIdentifier(string identifier) } return identifier.ToCamelCase(); } + + private void CreateResponseHandler(CodeClass requestBuilder) + { + // Default ResponseHandler Implementation + var responseHandlerImpl = new CodeMethod { Name = "DefaultResponseHandler", IsStatic = true, MethodKind = CodeMethodKind.ResponseHandler }; + responseHandlerImpl.AddParameter(new CodeParameter { Name = "response", Type = new CodeType { Name = "object" } }); // replace native HTTP response object type in language refiner + responseHandlerImpl.ReturnType = new CodeType { Name = "object" }; + requestBuilder.AddMethod(responseHandlerImpl); + + // Property to allow replacing Response Handler + var responseHandlerProperty = CreateProperty("ResponseHandler", "Func", "DefaultResponseHandler"); // HttpResponseMessage, model + responseHandlerProperty.PropertyKind = CodePropertyKind.ResponseHandler; + responseHandlerProperty.ReadOnly = false; + requestBuilder.AddProperty(responseHandlerProperty); + } } } diff --git a/src/kiota.core/Refiners/CSharpRefiner.cs b/src/kiota.core/Refiners/CSharpRefiner.cs index 9668d8f587..4487a9ea5a 100644 --- a/src/kiota.core/Refiners/CSharpRefiner.cs +++ b/src/kiota.core/Refiners/CSharpRefiner.cs @@ -1,14 +1,46 @@ -using System.Linq; +using System.Linq; +using System.Text.RegularExpressions; namespace kiota.core { public class CSharpRefiner : CommonLanguageRefiner, ILanguageRefiner { + private static readonly Regex responseHandlerType = new Regex("<(.*),object>"); public override void Refine(CodeNamespace generatedCode) { generatedCode.AddUsing(new CodeUsing() { Name = "System" }); generatedCode.AddUsing(new CodeUsing() { Name = "System.Threading.Tasks" }); + generatedCode.AddUsing(new CodeUsing() { Name = "System.Net.Http" }); AddAsyncSuffix(generatedCode); AddInnerClasses(generatedCode); + MakeNativeResponseHandlers(generatedCode); + } + + private void MakeNativeResponseHandlers(CodeNamespace generatedCode) + { + foreach (var codeElement in generatedCode.InnerChildElements) + { + switch (codeElement) + { + case CodeClass c: + var responseHandlerProp = c.InnerChildElements.OfType().Where(e => e.PropertyKind == CodePropertyKind.ResponseHandler) + .FirstOrDefault(); + if (responseHandlerProp != null) + { + responseHandlerProp.Type.Name = responseHandlerType.Replace(responseHandlerProp.Type.Name, ">"); // TODO: We should probably generic types properly + } + var defaultResponseHandler = c.InnerChildElements.OfType() + .Where(m=> m.MethodKind == CodeMethodKind.ResponseHandler) + .FirstOrDefault(); + if (defaultResponseHandler != null) + { + defaultResponseHandler.Parameters.FirstOrDefault().Type.Name = "HttpResponseMessage"; + } + break; + case CodeNamespace n: + MakeNativeResponseHandlers(n); + break; + } + } } private void AddAsyncSuffix(CodeElement currentElement) { if(currentElement is CodeMethod currentMethod) diff --git a/src/kiota.core/Refiners/JavaRefiner.cs b/src/kiota.core/Refiners/JavaRefiner.cs index 934c904434..04c9194e7e 100644 --- a/src/kiota.core/Refiners/JavaRefiner.cs +++ b/src/kiota.core/Refiners/JavaRefiner.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; namespace kiota.core { public class JavaRefiner : CommonLanguageRefiner, ILanguageRefiner @@ -15,7 +15,7 @@ private void MakeQueryStringParametersNonOptionalAndInsertOverrideMethod(CodeEle if(currentElement is CodeClass currentClass && codeMethods.Any()) { codeMethods .SelectMany(x => x.Parameters) - .Where(x => x.IsQueryParameter) + .Where(x => x.ParameterKind == CodeParameterKind.QueryParameter) .ToList() .ForEach(x => x.Optional = false); currentClass.AddMethod(codeMethods @@ -28,9 +28,9 @@ private void MakeQueryStringParametersNonOptionalAndInsertOverrideMethod(CodeEle MakeQueryStringParametersNonOptionalAndInsertOverrideMethod(childElement); } private CodeMethod GetMethodClone(CodeMethod currentMethod) { - if(currentMethod.Parameters.Any(x => x.IsQueryParameter)) { + if(currentMethod.Parameters.Any(x => x.ParameterKind == CodeParameterKind.QueryParameter)) { var cloneMethod = currentMethod.Clone() as CodeMethod; - cloneMethod.Parameters.RemoveAll(x => x.IsQueryParameter); + cloneMethod.Parameters.RemoveAll(x => x.ParameterKind == CodeParameterKind.QueryParameter); return cloneMethod; } else return null; diff --git a/src/kiota.core/Writers/CSharpWriter.cs b/src/kiota.core/Writers/CSharpWriter.cs index ec94a55f62..8dc1eaa4c5 100644 --- a/src/kiota.core/Writers/CSharpWriter.cs +++ b/src/kiota.core/Writers/CSharpWriter.cs @@ -36,8 +36,17 @@ public override void WriteCodeClassEnd(CodeClass.End code) public override void WriteProperty(CodeProperty code) { - - WriteLine($"public {GetTypeString(code.Type)} {code.Name} {{get;}}"); + var simpleBody = "get;"; + if (!code.ReadOnly) + { + simpleBody = "get;set;"; + } + var defaultValue = string.Empty; + if (code.DefaultValue != null) + { + defaultValue = " = " + code.DefaultValue + ";"; + } + WriteLine($"public {GetTypeString(code.Type)} {code.Name} {{{simpleBody}}}{defaultValue}"); } public override void WriteIndexer(CodeIndexer code) @@ -47,7 +56,10 @@ public override void WriteIndexer(CodeIndexer code) public override void WriteMethod(CodeMethod code) { - WriteLine($"public Task<{GetTypeString(code.ReturnType)}> {code.Name}({string.Join(',', code.Parameters.Select(p=> GetParameterSignature(p)).ToList())}) {{ return null; }}"); + var staticModifier = code.IsStatic ? "static " : string.Empty; + // Task type should be moved into the refiner + WriteLine($"public {staticModifier}Task<{GetTypeString(code.ReturnType)}> {code.Name}({string.Join(',', code.Parameters.Select(p=> GetParameterSignature(p)).ToList())}) {{ return null; }}"); + } public override void WriteType(CodeType code)