<commit_before>﻿using SignalGo.Shared.Helpers;
using SignalGo.Shared.Log;
using SignalGo.Shared.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;

namespace SignalGo.Client
{
    [XmlRoot(ElementName = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
    public class Envelope<T>
    {
        [XmlElement(ElementName = "Header", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
        public string Header { get; set; }
        [XmlElement(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
        public T Body { get; set; }
        [XmlAttribute(AttributeName = "soap", Namespace = "http://www.w3.org/2000/xmlns/")]
        public string Soap { get; set; }
        [XmlAttribute(AttributeName = "xsd", Namespace = "http://www.w3.org/2000/xmlns/")]
        public string Xsd { get; set; }
        [XmlAttribute(AttributeName = "xsi", Namespace = "http://www.w3.org/2000/xmlns/")]
        public string Xsi { get; set; }
    }

    public class WebServiceProtocolSettings
    {
        public int RetryCount { get; set; }
        public TimeSpan? Timeout { get; set; }
        public string EncodingName { get; set; } = "utf-8";
        public Encoding Encoding { get; set; } = Encoding.UTF8;
        public WebHeaderCollection ResponseHeaders { get; set; }
        public WebHeaderCollection RequestHeaders { get; set; } = new WebHeaderCollection();
    }

    /// <summary>ISO-8859-1
    /// log service
    /// </summary>
    public interface IWebServiceProtocolLogger
    {
        /// <summary>
        /// before method call
        /// </summary>
        LoggerAction BeforeCallAction { get; set; }
        /// <summary>
        /// after method call
        /// </summary>
        LoggerAction AfterCallAction { get; set; }

        WebServiceProtocolSettings Settings { get; set; }
    }
    public delegate void LoggerAction(string url, string actionUrl, string methodName, ParameterInfo[] args, object data);
    public static class WebServiceProtocolHelper
    {

        public static T CallWebServiceMethod<T>(IWebServiceProtocolLogger logger, string headerTemplate, string url, string actionUrl, string targetNamespace, string methodName, ParameterInfo[] args)
        {
            StringBuilder stringBuilder = new StringBuilder();
            if (args != null)
            {
                foreach (ParameterInfo item in args)
                {
                    stringBuilder.AppendLine(item.Value.Replace($"<?xml version=\"1.0\" encoding=\"{logger.Settings.EncodingName}\"?>", ""));
                }
            }
            string defaultData = $@"<?xml version=""1.0"" encoding=""{logger.Settings.EncodingName}""?>
<soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
	<soap:Header>
          {headerTemplate}
	</soap:Header>
	<soap:Body>{stringBuilder.ToString().Trim()}</soap:Body>
</soap:Envelope>";
#if (!NETSTANDARD1_6)

            using (IO.TimeoutWebClient client = new IO.TimeoutWebClient(logger.Settings.Timeout))
            {
                if (!string.IsNullOrEmpty(actionUrl))
                    client.Headers["SOAPAction"] = actionUrl;
                client.Headers.Add(HttpRequestHeader.ContentType, $"text/xml; charset={logger.Settings.EncodingName};");
                foreach (var item in logger.Settings.RequestHeaders.AllKeys)
                {
                    client.Headers.Add(item, logger.Settings.RequestHeaders[item]);
                }
                logger?.BeforeCallAction?.Invoke(url, actionUrl, methodName, args, defaultData);
                string data = client.UploadString(url, defaultData);
                logger.Settings.ResponseHeaders = client.ResponseHeaders;
                if (typeof(T) == typeof(object))
                    return default(T);
                logger?.AfterCallAction?.Invoke(url, actionUrl, methodName, args, data);
                XDocument doc = XDocument.Parse(data);
                List<XElement> elements = new List<XElement>();
                var firstElement = doc.Elements().First();//
                var findElement = FindElement(doc.Elements(), typeof(T).Name);
                var attributes = firstElement.Attributes().ToList();
                attributes.AddRange(findElement.Attributes());
                findElement.ReplaceAttributes(attributes);
                var myResult = (T)Deserialize(logger, findElement, typeof(T));
                return myResult;
            }
#else
            throw new NotSupportedException();
#endif
        }
#if (!NETSTANDARD1_6 && !NET35 && !NET40)
        static System.Net.Http.HttpClient _httpClient = new System.Net.Http.HttpClient();

        private static string SerializeHeaders(this System.Net.Http.Headers.HttpRequestHeaders headers)
        {
            var response = new System.Text.StringBuilder();
            foreach (var k in headers)
                response.AppendLine(k.Key + ": " + k.Value.FirstOrDefault());
            return response.ToString();
        }

        public static async Task<T> CallWebServiceMethodAsync<T>(IWebServiceProtocolLogger logger, string headerTemplate, string url, string actionUrl, string targetNamespace, string methodName, ParameterInfo[] args)
        {
            StringBuilder stringBuilder = new StringBuilder();
            if (args != null)
            {
                foreach (ParameterInfo item in args)
                {
                    stringBuilder.AppendLine(item.Value.Replace($"<?xml version=\"1.0\" encoding=\"{logger.Settings.EncodingName}\"?>", ""));
                }
            }
            string defaultData = $@"<?xml version=""1.0"" encoding=""{logger.Settings.EncodingName}""?>
<soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
	<soap:Header>
          {headerTemplate}
	</soap:Header>
	<soap:Body>{stringBuilder.ToString().Trim()}</soap:Body>
</soap:Envelope>";
            //using (IO.TimeoutWebClient client = new IO.TimeoutWebClient(logger.Settings.Timeout))
            //{

            int tryCount = 0;
            logger?.BeforeCallAction?.Invoke(url, actionUrl, methodName, args, defaultData);

            TryAgainLabel:
            var httpRequestMessage = new System.Net.Http.HttpRequestMessage();
            var content_ = new System.Net.Http.StringContent(defaultData);
            content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/xml");
            httpRequestMessage.Content = content_;

            if (!string.IsNullOrEmpty(actionUrl))
                httpRequestMessage.Headers.TryAddWithoutValidation("SOAPAction", actionUrl);
            httpRequestMessage.Headers.TryAddWithoutValidation("ContentType", "application/xml");
            foreach (var item in logger.Settings.RequestHeaders.AllKeys)
            {
                var value = logger.Settings.RequestHeaders[item];
                httpRequestMessage.Headers.TryAddWithoutValidation(item, value);
            }

            httpRequestMessage.RequestUri = new Uri(url);
            httpRequestMessage.Method = new System.Net.Http.HttpMethod("POST");
            try
            {
                var cts = new CancellationTokenSource();
                if (logger.Settings.Timeout.HasValue)
                    cts.CancelAfter(logger.Settings.Timeout.Value);
                try
                {
                    using (System.Net.Http.HttpResponseMessage response = await _httpClient.SendAsync(httpRequestMessage, System.Net.Http.HttpCompletionOption.ResponseContentRead, cts.Token))
                    {
                        var data = await response.Content.ReadAsStringAsync();

                        logger.Settings.ResponseHeaders = new WebHeaderCollection();
                        foreach (var item in response.Headers)
                        {
                            logger.Settings.ResponseHeaders.Add(item.Key, item.Value.FirstOrDefault());
                        }

                        //System.Diagnostics.Debug.WriteLine(data, $"Response: {url} ac:{actionUrl}");
                        if (typeof(T) == typeof(object))
                            return default(T);
                        logger?.AfterCallAction?.Invoke(url, actionUrl, methodName, args, data);
                        XDocument doc = XDocument.Parse(data);
                        var firstElement = doc.Elements().First();//
                        var findElement = FindElement(doc.Elements(), typeof(T).Name);
                        if (findElement == null)
                        {
                            findElement = doc.Elements().FirstOrDefault(x => x.Name.LocalName.EndsWith("envelope", StringComparison.OrdinalIgnoreCase));
                            findElement = findElement.Elements().FirstOrDefault(x => x.Name.LocalName.EndsWith("body", StringComparison.OrdinalIgnoreCase));
                            findElement = findElement.Elements().FirstOrDefault();
                            XmlDocument node = new XmlDocument();
                            node.LoadXml(findElement.Elements().First().ToString());
                            //var name = findElement.Name.LocalName;
                            //data = data.Replace(name, typeof(T).Name);
                            //doc = XDocument.Parse(data);
                            //firstElement = doc.Elements().First();//
                            //findElement = FindElement(doc.Elements(), typeof(T).Name);
                            string json = Newtonsoft.Json.JsonConvert.SerializeXmlNode(node);<commit_msg>add exception message for webserviceprotocol when there is no xml content type<commit_after>﻿using SignalGo.Shared.Helpers;
using SignalGo.Shared.Log;
using SignalGo.Shared.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;

namespace SignalGo.Client
{
    [XmlRoot(ElementName = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
    public class Envelope<T>
    {
        [XmlElement(ElementName = "Header", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
        public string Header { get; set; }
        [XmlElement(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
        public T Body { get; set; }
        [XmlAttribute(AttributeName = "soap", Namespace = "http://www.w3.org/2000/xmlns/")]
        public string Soap { get; set; }
        [XmlAttribute(AttributeName = "xsd", Namespace = "http://www.w3.org/2000/xmlns/")]
        public string Xsd { get; set; }
        [XmlAttribute(AttributeName = "xsi", Namespace = "http://www.w3.org/2000/xmlns/")]
        public string Xsi { get; set; }
    }

    public class WebServiceProtocolSettings
    {
        public int RetryCount { get; set; }
        public TimeSpan? Timeout { get; set; }
        public string EncodingName { get; set; } = "utf-8";
        public Encoding Encoding { get; set; } = Encoding.UTF8;
        public WebHeaderCollection ResponseHeaders { get; set; }
        public WebHeaderCollection RequestHeaders { get; set; } = new WebHeaderCollection();
    }

    /// <summary>ISO-8859-1
    /// log service
    /// </summary>
    public interface IWebServiceProtocolLogger
    {
        /// <summary>
        /// before method call
        /// </summary>
        LoggerAction BeforeCallAction { get; set; }
        /// <summary>
        /// after method call
        /// </summary>
        LoggerAction AfterCallAction { get; set; }

        WebServiceProtocolSettings Settings { get; set; }
    }
    public delegate void LoggerAction(string url, string actionUrl, string methodName, ParameterInfo[] args, object data);
    public static class WebServiceProtocolHelper
    {

        public static T CallWebServiceMethod<T>(IWebServiceProtocolLogger logger, string headerTemplate, string url, string actionUrl, string targetNamespace, string methodName, ParameterInfo[] args)
        {
            StringBuilder stringBuilder = new StringBuilder();
            if (args != null)
            {
                foreach (ParameterInfo item in args)
                {
                    stringBuilder.AppendLine(item.Value.Replace($"<?xml version=\"1.0\" encoding=\"{logger.Settings.EncodingName}\"?>", ""));
                }
            }
            string defaultData = $@"<?xml version=""1.0"" encoding=""{logger.Settings.EncodingName}""?>
<soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
	<soap:Header>
          {headerTemplate}
	</soap:Header>
	<soap:Body>{stringBuilder.ToString().Trim()}</soap:Body>
</soap:Envelope>";
#if (!NETSTANDARD1_6)

            using (IO.TimeoutWebClient client = new IO.TimeoutWebClient(logger.Settings.Timeout))
            {
                if (!string.IsNullOrEmpty(actionUrl))
                    client.Headers["SOAPAction"] = actionUrl;
                client.Headers.Add(HttpRequestHeader.ContentType, $"text/xml; charset={logger.Settings.EncodingName};");
                foreach (var item in logger.Settings.RequestHeaders.AllKeys)
                {
                    client.Headers.Add(item, logger.Settings.RequestHeaders[item]);
                }
                logger?.BeforeCallAction?.Invoke(url, actionUrl, methodName, args, defaultData);
                string data = client.UploadString(url, defaultData);
                logger.Settings.ResponseHeaders = client.ResponseHeaders;
                if (typeof(T) == typeof(object))
                    return default(T);
                logger?.AfterCallAction?.Invoke(url, actionUrl, methodName, args, data);
                XDocument doc = XDocument.Parse(data);
                List<XElement> elements = new List<XElement>();
                var firstElement = doc.Elements().First();//
                var findElement = FindElement(doc.Elements(), typeof(T).Name);
                var attributes = firstElement.Attributes().ToList();
                attributes.AddRange(findElement.Attributes());
                findElement.ReplaceAttributes(attributes);
                var myResult = (T)Deserialize(logger, findElement, typeof(T));
                return myResult;
            }
#else
            throw new NotSupportedException();
#endif
        }
#if (!NETSTANDARD1_6 && !NET35 && !NET40)
        static System.Net.Http.HttpClient _httpClient = new System.Net.Http.HttpClient();

        private static string SerializeHeaders(this System.Net.Http.Headers.HttpRequestHeaders headers)
        {
            var response = new System.Text.StringBuilder();
            foreach (var k in headers)
                response.AppendLine(k.Key + ": " + k.Value.FirstOrDefault());
            return response.ToString();
        }

        public static async Task<T> CallWebServiceMethodAsync<T>(IWebServiceProtocolLogger logger, string headerTemplate, string url, string actionUrl, string targetNamespace, string methodName, ParameterInfo[] args)
        {
            StringBuilder stringBuilder = new StringBuilder();
            if (args != null)
            {
                foreach (ParameterInfo item in args)
                {
                    stringBuilder.AppendLine(item.Value.Replace($"<?xml version=\"1.0\" encoding=\"{logger.Settings.EncodingName}\"?>", ""));
                }
            }
            string defaultData = $@"<?xml version=""1.0"" encoding=""{logger.Settings.EncodingName}""?>
<soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
	<soap:Header>
          {headerTemplate}
	</soap:Header>
	<soap:Body>{stringBuilder.ToString().Trim()}</soap:Body>
</soap:Envelope>";
            //using (IO.TimeoutWebClient client = new IO.TimeoutWebClient(logger.Settings.Timeout))
            //{

            int tryCount = 0;
            logger?.BeforeCallAction?.Invoke(url, actionUrl, methodName, args, defaultData);

            TryAgainLabel:
            var httpRequestMessage = new System.Net.Http.HttpRequestMessage();
            var content_ = new System.Net.Http.StringContent(defaultData);
            content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/xml");
            httpRequestMessage.Content = content_;

            if (!string.IsNullOrEmpty(actionUrl))
                httpRequestMessage.Headers.TryAddWithoutValidation("SOAPAction", actionUrl);
            httpRequestMessage.Headers.TryAddWithoutValidation("ContentType", "application/xml");
            foreach (var item in logger.Settings.RequestHeaders.AllKeys)
            {
                var value = logger.Settings.RequestHeaders[item];
                httpRequestMessage.Headers.TryAddWithoutValidation(item, value);
            }

            httpRequestMessage.RequestUri = new Uri(url);
            httpRequestMessage.Method = new System.Net.Http.HttpMethod("POST");
            try
            {
                var cts = new CancellationTokenSource();
                if (logger.Settings.Timeout.HasValue)
                    cts.CancelAfter(logger.Settings.Timeout.Value);
                try
                {
                    using (System.Net.Http.HttpResponseMessage response = await _httpClient.SendAsync(httpRequestMessage, System.Net.Http.HttpCompletionOption.ResponseContentRead, cts.Token))
                    {
                        var data = await response.Content.ReadAsStringAsync();
                        if (response.Content.Headers.TryGetValues("Content-Type", out IEnumerable<string> values))
                        {
                            string type = values.FirstOrDefault();
                            if (type != null && !type.ToLower().Contains("text/xml"))
                            {
                                tryCount = logger.Settings.RetryCount;
                                throw new Exception($"I just support text/xml as content type your type is {type} and your data is :\\r\\n {data}");
                            }
                        }

                        logger.Settings.ResponseHeaders = new WebHeaderCollection();
                        foreach (var item in response.Headers)
                        {
                            logger.Settings.ResponseHeaders.Add(item.Key, item.Value.FirstOrDefault());
                        }

                        //System.Diagnostics.Debug.WriteLine(data, $"Response: {url} ac:{actionUrl}");
                        if (typeof(T) == typeof(object))
                            return default(T);
                        logger?.AfterCallAction?.Invoke(url, actionUrl, methodName, args, data);
                        XDocument doc = XDocument.Parse(data);
                        var firstElement = doc.Elements().First();//
                        var findElement = FindElement(doc.Elements(), typeof(T).Name);
                        if (findElement == null)
                        {
                            findElement = doc.Elements().FirstOrDefault(x => x.Name.LocalName.EndsWith("envelope", StringComparison.OrdinalIgnoreCase));
                            findElement = findElement.Elements().FirstOrDefault(x => x.Name.LocalName.EndsWith("body", StringComparison.OrdinalIgnoreCase));
                            findElement = findElement.Elements().FirstOrDefault();
                            XmlDocument node = new XmlDocument();
                            node.LoadXml(findElement.Elements().First().ToString());
                            //var name = findElement.Name.LocalName;
                            //data = data.Replace(name, typeof(T).Name);
                            //doc = XDocument.Parse(data);
                            //firstElement = doc.Elements().First();//
                            //findElement = FindElement(doc.Elements(), typeof(T).Name);
                            string json = Newtonsoft.Json.JsonConvert.SerializeXmlNode(node);
{'fraction_non_alphanumeric': 0.1194246694755194, 'fraction_numerical': 0.005714562448544723, 'mean_word_length': 2.119335347432024, 'pattern_counts': {'":': 2, '<': 60, '<?xml version=': 8, '>': 64, 'https://': 0, 'lorem ipsum': 0, 'www.': 14, 'xml': 45}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '922319', 'n_tokens_mistral': 5319, 'n_tokens_neox': 5096, 'n_words': 1033}