System.Xml.Linq.XContainer.Element(...) вернул null

Рейтинг: 1Ответов: 1Опубликовано: 19.02.2023

Есть метод postXmlData для отправки и получение Xml запросов/ответов. После получение ответа показываю на консоль атрибуты который начинаются с буква f, но получаю ошибку System.Xml.Linq.XContainer.Element(...) вернул null. Что я делаю не так?

postXmlData:

public static XmlDocument postXMLData(string xml)
        {
            var request = (HttpWebRequest)WebRequest.Create(Requests.url);
            byte[] bytes;
            bytes = System.Text.Encoding.ASCII.GetBytes(xml);
            request.ContentType = "text/xml; encoding='utf-8'";
            request.ContentLength = bytes.Length;
            request.Method = "POST";
            Stream requestStream = request.GetRequestStream();
            requestStream.Write(bytes, 0, bytes.Length);
            requestStream.Close();
            HttpWebResponse response;
            response = (HttpWebResponse)request.GetResponse();

            if (response.StatusCode == HttpStatusCode.OK)
            {
                using (var streamReader = new StreamReader(response.GetResponseStream()))
                {
                    var responseText = streamReader.ReadToEnd();
                    var result = new XmlDocument();
                    result.LoadXml(responseText);
                    return result;
                }
            }

            throw new Exception();
        }

Ответ от запроса:

<response result="0">
    <prov>
        <getStatus result="0">
            <pay date="2023-02-08T19:44:33+03:00" fatal="false" id="8022140013003" result="0" status="2" uid="26775263057008" value-date="2023-02-08T19:44:40+03:00">
            </pay>
        </getStatus>
    </prov>
</response>

Вывод атрибуты с использованием XElement:

XmlDocument doc = postXMLData(Requests.getStatus("08022140013003"));
            XElement e = XElement.Load(new XmlNodeReader(doc));
            Console.WriteLine(e); //here ok
           
            IEnumerable<XAttribute> attrs1 = e.Element("response").Element("prov").Element("getStatus").Element("pay")?.Attributes().Where(a => a.Name.LocalName.StartsWith("f"));
            Console.WriteLine(attrs1);
            Console.ReadKey();

Ответы

▲ 1Принят

Глупая ошибка, вы пытаетесь взять .Element("response") у какого элемента? Подумайте, посмотрите внимательно.

Вот решение:

IEnumerable<XAttribute> attrs1 = e.Element("prov").Element("getStatus").Element("pay")?.Attributes().Where(a => a.Name.LocalName.StartsWith("f"));

HttpWebRequest устарел лет 10 назад. Вот захотите потом перейти на новый .NET 8, который выйдет осенью 2023 года, а там HttpWebRequest вообще будет отсутствовать.

Метод postXMLData написан нелогично, на входе строка, на выходе XmlDocument. Ну ок, не меняя логики перепишу на HttpClient:

private static readonly HttpClient client = new HttpClient();

public static async Task<XmlDocument> PostXMLDataAsync(string url, string xml)
{
    using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, url))
    {
        request.Content = new StringContent(xml, Encoding.UTF8, "text/xml");
        using (HttpResponseMessage response = await client.SendAsync(request))
        {
            response.EnsureSuccessStatusCode();
            string responseText = await response.Content.ReadAsStringAsync();
            var result = new XmlDocument();
            result.LoadXml(responseText);
            return result;
        }
    }
}

Пользоваться так

XmlDocument doc = await PostXMLDataAsync(Requests.url, Requests.getStatus("08022140013003"));

Даже если категорически не хотите использовать HttpClient, поправьте хотя-бы кодировку отправляемых данных:

bytes = Encoding.UTF8.GetBytes(xml);