Skip to content
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

.NET 8 has introduced stream operation for JsonSerializer of System.Text.Json, utilized this. #150

Closed
zijianhuang opened this issue Apr 8, 2024 · 5 comments
Labels

Comments

@zijianhuang
Copy link
Owner

.NET 6 had introduced Utf8JsonReader in .NET 6, and stream in .NET 8.

@ZijianFLG
Copy link
Contributor

@zijianhuang
Copy link
Owner Author

		public async Task<DemoWebApi.DemoData.Client.Company> CreateCompanyAsync(DemoWebApi.DemoData.Client.Company p, Action<System.Net.Http.Headers.HttpRequestHeaders> handleHeaders = null)
		{
			var requestUri = "api/Entities/createCompany";
   //         using var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri);
			//var contentJson = JsonSerializer.Serialize(p, jsonSerializerSettings);
			//var content = new StringContent(contentJson, System.Text.Encoding.UTF8, "application/json");
			//httpRequestMessage.Content = content;
			//handleHeaders?.Invoke(httpRequestMessage.Headers);
			var responseMessage = await client.PostAsJsonAsync<DemoWebApi.DemoData.Client.Company>(requestUri, p, jsonSerializerSettings);
            try
			{
				responseMessage.EnsureSuccessStatusCodeEx();
				if (responseMessage.StatusCode == System.Net.HttpStatusCode.NoContent) { return null; }
				var contentString = await responseMessage.Content.ReadAsStringAsync();
				return JsonSerializer.Deserialize<DemoWebApi.DemoData.Client.Company>(contentString, jsonSerializerSettings);
			}
			finally
			{
				responseMessage.Dispose();
			}
		}
		
		/// <summary>
		/// POST api/Entities/createCompany
		/// </summary>
		public DemoWebApi.DemoData.Client.Company CreateCompany(DemoWebApi.DemoData.Client.Company p, Action<System.Net.Http.Headers.HttpRequestHeaders> handleHeaders = null)
		{
			var requestUri = "api/Entities/createCompany";
			//using var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri);
			//var contentJson = JsonSerializer.Serialize(p, jsonSerializerSettings);
			//var content = new StringContent(contentJson, System.Text.Encoding.UTF8, "application/json");
			//httpRequestMessage.Content = content;
			//handleHeaders?.Invoke(httpRequestMessage.Headers);
			var responseMessage = client.PostAsJsonAsync<DemoWebApi.DemoData.Client.Company>(requestUri, p, jsonSerializerSettings).Result;
			try
			{
				responseMessage.EnsureSuccessStatusCodeEx();
				if (responseMessage.StatusCode == System.Net.HttpStatusCode.NoContent) { return null; }
				var contentString = responseMessage.Content.ReadAsStringAsync().Result;
				return JsonSerializer.Deserialize<DemoWebApi.DemoData.Client.Company>(contentString, jsonSerializerSettings);
			}
			finally
			{
				responseMessage.Dispose();
			}
		}

@zijianhuang
Copy link
Owner Author

Basically done, however, I found out that I have supported custom request headers manipulation, and the extensions do not support. So now I have to reverse the change, since custom header manipulation is important for many real world applications., then just keep a copy here:

    void RenderPostOrPutImplementation(string httpMethod)
        {
            //Create function parameters in prototype
            CodeParameterDeclarationExpression[] parameters = description.ParameterDescriptions.Where(p => p.ParameterDescriptor.ParameterBinder == ParameterBinder.FromUri
            || p.ParameterDescriptor.ParameterBinder == ParameterBinder.FromQuery || p.ParameterDescriptor.ParameterBinder == ParameterBinder.FromBody
            || p.ParameterDescriptor.ParameterBinder == ParameterBinder.None).Select(d =>
            {
                AddCustomPocoTypeForCs(d.ParameterDescriptor.ParameterType);
                CodeParameterDeclarationExpression exp = new CodeParameterDeclarationExpression(poco2CsGen.TranslateToClientTypeReference(d.ParameterDescriptor.ParameterType), d.Name);
                exp.UserData.Add(Fonlow.TypeScriptCodeDom.UserDataKeys.ParameterDescriptor, d.ParameterDescriptor);
                return exp;
            }
            ).ToArray();
            clientMethod.Parameters.AddRange(parameters);

            if (codeGenOutputsSettings.CancellationTokenEnabled)
            {
                clientMethod.Parameters.Add(new CodeParameterDeclarationExpression("System.Threading.CancellationToken", "cancellationToken"));
            }

            if (codeGenOutputsSettings.HandleHttpRequestHeaders)
            {
                clientMethod.Parameters.Add(new CodeParameterDeclarationExpression("Action<System.Net.Http.Headers.HttpRequestHeaders>", "handleHeaders = null"));
            }

            ParameterDescription[] fromBodyParameterDescriptions = description.ParameterDescriptions.Where(d => d.ParameterDescriptor.ParameterBinder == ParameterBinder.FromBody
                || (TypeHelper.IsComplexType(d.ParameterDescriptor.ParameterType) && (!(d.ParameterDescriptor.ParameterBinder == ParameterBinder.FromUri) || (d.ParameterDescriptor.ParameterBinder == ParameterBinder.None)))).ToArray();
            if (fromBodyParameterDescriptions.Length > 1)
            {
                throw new CodeGenException("Bad Api Definition")
                {
                    Description = String.Format("This API function {0} has more than 1 FromBody bindings in parameters", description.ActionDescriptor.ActionName)
                };
            }

            ParameterDescription singleFromBodyParameterDescription = fromBodyParameterDescriptions.FirstOrDefault();

            void AddRequestUriWithQueryAssignmentStatement()
            {

                string jsUriQuery = UriQueryHelper.CreateUriQuery(description.RelativePath, description.ParameterDescriptions);
                string uriText = jsUriQuery == null ? $"\"{description.RelativePath}\"" : RemoveTrialEmptyString($"\"{jsUriQuery}\"");

                clientMethod.Statements.Add(new CodeVariableDeclarationStatement(
                    new CodeTypeReference("var"), "requestUri",
                    new CodeSnippetExpression(uriText)));
            }

            AddRequestUriWithQueryAssignmentStatement();

            bool hasBody = singleFromBodyParameterDescription != null;
            if (!codeGenOutputsSettings.UseSystemTextJson // use Newtonsoft.Json
                || (codeGenOutputsSettings.UseSystemTextJson && codeGenOutputsSettings.UseHttpClientJsonExtensions && !hasBody))
            {
                clientMethod.Statements.Add(new CodeSnippetStatement(
                    ThreeTabs + $"using var httpRequestMessage = new HttpRequestMessage(HttpMethod.{httpMethod}, requestUri);"));
            }

            if (hasBody)
            {
                if (codeGenOutputsSettings.UseSystemTextJson)
                {
                    if (!codeGenOutputsSettings.UseHttpClientJsonExtensions)
                    {
                        clientMethod.Statements.Add(new CodeSnippetStatement(ThreeTabs + $"var contentJson = JsonSerializer.Serialize({singleFromBodyParameterDescription.ParameterDescriptor.ParameterName}, jsonSerializerSettings);"));
                        clientMethod.Statements.Add(new CodeSnippetStatement(ThreeTabs + @"var content = new StringContent(contentJson, System.Text.Encoding.UTF8, ""application/json"");"));
                    }
                }
                else
                {
                    clientMethod.Statements.Add(new CodeSnippetStatement(
    $"\t\t\tusing var requestWriter = new System.IO.StringWriter();{Environment.NewLine}\t\t\tvar requestSerializer = JsonSerializer.Create(jsonSerializerSettings);"
    ));
                    clientMethod.Statements.Add(new CodeMethodInvokeExpression(new CodeSnippetExpression("requestSerializer"), "Serialize",
                        new CodeSnippetExpression("requestWriter"),
                        new CodeSnippetExpression(singleFromBodyParameterDescription.ParameterDescriptor.ParameterName)));


                    clientMethod.Statements.Add(new CodeSnippetStatement(
    @"			var content = new StringContent(requestWriter.ToString(), System.Text.Encoding.UTF8, ""application/json"");"
                        ));
                }

                if (!codeGenOutputsSettings.UseHttpClientJsonExtensions)
                {
                    clientMethod.Statements.Add(new CodeSnippetStatement("\t\t\thttpRequestMessage.Content = content;"));
                    if (codeGenOutputsSettings.HandleHttpRequestHeaders)
                    {
                        clientMethod.Statements.Add(new CodeSnippetStatement("\t\t\thandleHeaders?.Invoke(httpRequestMessage.Headers);"));
                    }
                }
            }

            if (codeGenOutputsSettings.UseHttpClientJsonExtensions && hasBody)
            {
                AddResponseMessageJsonPostPutAsync(clientMethod, httpMethod, singleFromBodyParameterDescription.ParameterDescriptor.ParameterName);
            }
            else
            {
                AddResponseMessageSendAsync(clientMethod); //output: client.SendAsync(httpRequestMessage)
            }

            CodeVariableReferenceExpression resultReference = new CodeVariableReferenceExpression("responseMessage");

            if (returnTypeIsStream)
            {
                clientMethod.Statements.Add(new CodeMethodInvokeExpression(resultReference, statementOfEnsureSuccessStatusCode));

                //Statement: return something;
                if (returnType != null)
                {
                    AddReturnStatement(clientMethod.Statements);
                }
            }
            else
            {
                CodeTryCatchFinallyStatement try1 = new CodeTryCatchFinallyStatement();
                clientMethod.Statements.Add(try1);
                try1.TryStatements.Add(new CodeMethodInvokeExpression(resultReference, statementOfEnsureSuccessStatusCode));

                //Statement: return something;
                if (returnType != null)
                {
                    AddReturnStatement(try1.TryStatements);
                }

                try1.FinallyStatements.Add(new CodeMethodInvokeExpression(resultReference, "Dispose"));
            }

            if (singleFromBodyParameterDescription != null && !codeGenOutputsSettings.UseSystemTextJson)
            {
                //Add3TEndBacket(clientMethod);
            }

        }

        static string ThreeTabs => "\t\t\t";

        void AddResponseMessageSendAsync(CodeMemberMethod method)
        {
            string cancellationToken = codeGenOutputsSettings.CancellationTokenEnabled ? ", cancellationToken" : String.Empty;
            method.Statements.Add(new CodeVariableDeclarationStatement(
                new CodeTypeReference("var"), "responseMessage", forAsync ? new CodeSnippetExpression($"await client.SendAsync(httpRequestMessage{cancellationToken})") : new CodeSnippetExpression($"client.SendAsync(httpRequestMessage{cancellationToken}).Result")));
        }

        void AddResponseMessageJsonPostPutAsync(CodeMemberMethod method, string httpMethod, string bodyParamName)
        {
            string cancellationToken = codeGenOutputsSettings.CancellationTokenEnabled ? ", cancellationToken" : String.Empty;
            method.Statements.Add(new CodeVariableDeclarationStatement(
                new CodeTypeReference("var"), "responseMessage", forAsync ?
                new CodeSnippetExpression($"await client.{httpMethod}AsJsonAsync(requestUri, {bodyParamName}, jsonSerializerSettings{cancellationToken});")
                : new CodeSnippetExpression($"client.{httpMethod}AsJsonAsync(requestUri, {bodyParamName}, jsonSerializerSettings{cancellationToken}).Result")));
        }

@zijianhuang
Copy link
Owner Author

use this instead:

var content = System.Net.Http.Json.JsonContent.Create(p, mediaType: null, jsonSerializerSettings);

@zijianhuang
Copy link
Owner Author

done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants