locked
My Web API Generates XML without XML Root RRS feed

  • Question

  • User1493428334 posted

    My Web API generates output OK when consumed by JavaScript/jQuery. But when it is consumed in the ASP.NET code-behind, it causes an XmlException: Root element is missing.

    Below is the related Web API code:

        public class ProductController : ApiController {
    
            public IEnumerable<ProductView> Get() {
                return new Repository().Products
                    .Select(p => new ProductView(p));
            }
    .....
    .....

    Below is my code-behind code consuming the Web API:

                string url = "http://localhost:63223/api/Product/";
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                request.Method = "GET";
                Request.ContentType = "text/xml; encoding='utf-8'; version='1.0'";
    
                WebResponse response = request.GetResponse();
                Stream stream = response.GetResponseStream();
    
                DataSet ds = new DataSet();
                ds.ReadXml(stream); // THE EXCEPTION OCCURS HERE
                ......
                ......
    

    What am I missing here? Thanks for your help.

    Friday, November 9, 2018 11:26 PM

Answers

  • User753101303 posted

    Hi,

    Ask for XML using Request.Accept="application/xml";

    ContentType is the format of the payload you are sending or receiving. You could use HttpClient with which you can use extension methods to handle serialization/deserialization behind the scene: https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, November 10, 2018 7:49 PM
  • User1120430333 posted

    I made the change to return XML.  The default was Json being returned until I put the  highlighted code line in place.

     public Function  GetProjsByUserIdApi(userid As String) as List(of DtoProject) Implements IWebApi.GetProjsByUserIdApi
    
                dim dtoprojects = new List(Of DtoProject)
    
                dim url = "http://localhost/WebApiVB/api/project/GetProjectsByUserId?userid=" & userid
    
                Using webclient As New WebClient
                    webClient.Headers("content-type") = "application/xml"
                    dim json  = webclient.DownloadString(url)
                    Dim projects = JsonConvert.DeserializeObject(of List(Of DtoProject))(json)
                    dtoprojects = projects
                End Using
    
                Return dtoprojects
    
            End Function
           
    <?xml version="1.0"?>
    
    -<ArrayOfDtoProject xmlns="http://schemas.datacontract.org/2004/07/Entities" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    
    
    -<DtoProject>
    
    <ClientName>Arnold</ClientName>
    
    <Cost>200</Cost>
    
    <EndDate>2018-07-16T00:00:00</EndDate>
    
    <ProjectId>1012</ProjectId>
    
    <ProjectName>Bill</ProjectName>
    
    <ProjectType>1</ProjectType>
    
    <StartDate>2018-07-15T00:00:00</StartDate>
    
    <Technology>77777777</Technology>
    
    <UserId>duane@outlook.com</UserId>
    
    </DtoProject>
    
    
    -<DtoProject>
    
    <ClientName>Duane Arnold</ClientName>
    
    <Cost>200</Cost>
    
    <EndDate>2018-07-21T00:00:00</EndDate>
    
    <ProjectId>1015</ProjectId>
    
    <ProjectName>Ollis</ProjectName>
    
    <ProjectType>1</ProjectType>
    
    <StartDate>2018-07-15T00:00:00</StartDate>
    
    <Technology>.NET</Technology>
    
    <UserId>duane@outlook.com</UserId>
    
    </DtoProject>
    
    </ArrayOfDtoProject>

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, November 10, 2018 8:46 PM
  • User475983607 posted

    Hi Mgebhard,

    I am building an ASP.NET Web API app. And when I am consuming it from my ASP.NET code-behind, I set the content type Request.ContentType = "application/xml; charset='utf-8'"; I also tried Request.ContentType = "text/xml; charset='utf-8'"; both did not work.

    Thanks.

    Add an accept header to the HTTP GET as suggested by PatriceSc.  The following example is invoking the default Values controller template.

     class Program
        {
            static HttpClient client = new HttpClient();
            static void Main(string[] args)
            {
    
                RunAsync().GetAwaiter().GetResult();
            }
    
    
            static async Task RunAsync()
            {
                string path = "api/values/1";
    
                string xmlResult = await GetProductAsync(path, "application/xml");
                Console.WriteLine(xmlResult);
            }
    
            static async Task<string> GetProductAsync(string path, string accept)
            {
                string result = string.Empty;
                client.BaseAddress = new Uri("http://localhost:51702/");
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(accept));
    
                HttpResponseMessage response = await client.GetAsync(path);
                if (response.IsSuccessStatusCode)
                {
                    result = await response.Content.ReadAsStringAsync();
                }
                return result;
            }
        }

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, November 11, 2018 2:02 PM
  • User-474980206 posted

    GoldenMicrosoft

    Hi Mgebhard,

    I am building an ASP.NET Web API app. And when I am consuming it from my ASP.NET code-behind, I set the content type Request.ContentType = "application/xml; charset='utf-8'"; I also tried Request.ContentType = "text/xml; charset='utf-8'"; both did not work.

    Thanks.

    as stated ContentType is for the payload (which a get doesn't have). you want to set the Accept header to specify xml:

      Request.Accept = "application/xml; charset='utf-8'"; 

    this probably will not help, as xml should be the default, unless the webapi is asp.net core, in which case only JSON is supported by default. just access the webapi with the browser or postman to see the response type. if you will need to add xml support to the webapi core see:

     services
       .AddMvc()
       .AddXmlSerializerFormatters();

    now that you get a xml response, you will need to parse it. the xml procduced by your webapi may not be supported by a DataSet and you will need to write your own xml parser. 

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, November 12, 2018 4:04 PM

All replies

  • User1120430333 posted

    Well did you look at the retuned XML? What does it look like? You can use Postman and make the call to the API and get the response.

    Saturday, November 10, 2018 10:00 AM
  • User475983607 posted

    My Web API generates output OK when consumed by JavaScript/jQuery. But when it is consumed in the ASP.NET code-behind, it causes an XmlException: Root element is missing.

    Below is the related Web API code:

        public class ProductController : ApiController {
    
            public IEnumerable<ProductView> Get() {
                return new Repository().Products
                    .Select(p => new ProductView(p));
            }
    .....
    .....

    Below is my code-behind code consuming the Web API:

                string url = "http://localhost:63223/api/Product/";
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                request.Method = "GET";
                Request.ContentType = "text/xml; encoding='utf-8'; version='1.0'";
    
                WebResponse response = request.GetResponse();
                Stream stream = response.GetResponseStream();
    
                DataSet ds = new DataSet();
                ds.ReadXml(stream); // THE EXCEPTION OCCURS HERE
                ......
                ......

    What am I missing here? Thanks for your help.

    It could be an HTML error is returned.  Use the Visual Studio debugger to view the the response stream.

    Secondly, consider using HttpClient rather than HttpWebRequest and deserializing to List<ProductView> rather than a DataSet.

    https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client

    Saturday, November 10, 2018 2:05 PM
  • User1493428334 posted

    Thanks.

    Just before reading your response, I used StreamReader (code snippet below) to look at the returned XML. To my surprise, the return is not XML at all, it is JSON. I am bewildered because in the request I already specify the return be in XML: Request.ContentType = "text/xml; encoding='utf-8'; version='1.0'".

    Code snippet to look at the response:

                ......
                ......
                WebResponse response = request.GetResponse();
                Stream stream = response.GetResponseStream();
    
                StreamReader sr = new StreamReader(stream);
                string xmlString = sr.ReadToEnd();
                ......
                ......

    Saturday, November 10, 2018 5:50 PM
  • User1493428334 posted

    Thanks.

    The response from the Web API actually is in JSON, despite that I have requested an XML response by setting Request.ContentType = "text/xml; encoding='utf-8'; version='1.0'".

    I have a few questions:

    1. Why do I get a JSON response when asking for an XML one?
    2. My request is made from the server side, does HttpClient work from the server side? ("client" means Web API client, not user's browser client?)
    3. Could you give me an example of deserializing to List<ProductView>? Does it work for both JSON and XML?

    Thanks again,

    Saturday, November 10, 2018 6:32 PM
  • User1493428334 posted

    Actually both XML and JSON responses are serialized.

    Saturday, November 10, 2018 6:38 PM
  • User753101303 posted

    Hi,

    Ask for XML using Request.Accept="application/xml";

    ContentType is the format of the payload you are sending or receiving. You could use HttpClient with which you can use extension methods to handle serialization/deserialization behind the scene: https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, November 10, 2018 7:49 PM
  • User1493428334 posted

    Hi PatriceSC,

    Did you mean Request.ContentType? I have tried Request.ContentType="application/xml" and Request.ContentType="text.xml", without success.

    There is no Request.Accept (no such attribute). There is Request.AcceptTypes, but is ReadOnly.

    I will look at the link you suggested.

    Thanks.

    Saturday, November 10, 2018 8:21 PM
  • User475983607 posted

    If you are building an ASP Core then you have to add an XML serializer as Core defaults to JSON. 

    https://docs.microsoft.com/en-us/aspnet/core/web-api/advanced/formatting?view=aspnetcore-2.1

    If you building an ASP.NET Web API app, then content negotiation should work out of the box as long as the content-type is correct.

    https://docs.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/content-negotiation

    Saturday, November 10, 2018 8:41 PM
  • User1120430333 posted

    I made the change to return XML.  The default was Json being returned until I put the  highlighted code line in place.

     public Function  GetProjsByUserIdApi(userid As String) as List(of DtoProject) Implements IWebApi.GetProjsByUserIdApi
    
                dim dtoprojects = new List(Of DtoProject)
    
                dim url = "http://localhost/WebApiVB/api/project/GetProjectsByUserId?userid=" & userid
    
                Using webclient As New WebClient
                    webClient.Headers("content-type") = "application/xml"
                    dim json  = webclient.DownloadString(url)
                    Dim projects = JsonConvert.DeserializeObject(of List(Of DtoProject))(json)
                    dtoprojects = projects
                End Using
    
                Return dtoprojects
    
            End Function
           
    <?xml version="1.0"?>
    
    -<ArrayOfDtoProject xmlns="http://schemas.datacontract.org/2004/07/Entities" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    
    
    -<DtoProject>
    
    <ClientName>Arnold</ClientName>
    
    <Cost>200</Cost>
    
    <EndDate>2018-07-16T00:00:00</EndDate>
    
    <ProjectId>1012</ProjectId>
    
    <ProjectName>Bill</ProjectName>
    
    <ProjectType>1</ProjectType>
    
    <StartDate>2018-07-15T00:00:00</StartDate>
    
    <Technology>77777777</Technology>
    
    <UserId>duane@outlook.com</UserId>
    
    </DtoProject>
    
    
    -<DtoProject>
    
    <ClientName>Duane Arnold</ClientName>
    
    <Cost>200</Cost>
    
    <EndDate>2018-07-21T00:00:00</EndDate>
    
    <ProjectId>1015</ProjectId>
    
    <ProjectName>Ollis</ProjectName>
    
    <ProjectType>1</ProjectType>
    
    <StartDate>2018-07-15T00:00:00</StartDate>
    
    <Technology>.NET</Technology>
    
    <UserId>duane@outlook.com</UserId>
    
    </DtoProject>
    
    </ArrayOfDtoProject>

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, November 10, 2018 8:46 PM
  • User1493428334 posted

    Hi Mgebhard,

    I am building an ASP.NET Web API app. And when I am consuming it from my ASP.NET code-behind, I set the content type Request.ContentType = "application/xml; charset='utf-8'"; I also tried Request.ContentType = "text/xml; charset='utf-8'"; both did not work.

    Thanks.

    Sunday, November 11, 2018 5:08 AM
  • User1493428334 posted

    Hi DA924,

    Thanks. But I do not recognize the language used for your Function GetProjsByUserIdApi(), could you please tell me?

    Sunday, November 11, 2018 5:22 AM
  • User1120430333 posted

    It's VB.NET. C# and VB.NET use the same .NET Framework. So all you can do in VB.NET can be done in C# and visa versa..

    Sunday, November 11, 2018 5:31 AM
  • User475983607 posted

    Hi Mgebhard,

    I am building an ASP.NET Web API app. And when I am consuming it from my ASP.NET code-behind, I set the content type Request.ContentType = "application/xml; charset='utf-8'"; I also tried Request.ContentType = "text/xml; charset='utf-8'"; both did not work.

    Thanks.

    Add an accept header to the HTTP GET as suggested by PatriceSc.  The following example is invoking the default Values controller template.

     class Program
        {
            static HttpClient client = new HttpClient();
            static void Main(string[] args)
            {
    
                RunAsync().GetAwaiter().GetResult();
            }
    
    
            static async Task RunAsync()
            {
                string path = "api/values/1";
    
                string xmlResult = await GetProductAsync(path, "application/xml");
                Console.WriteLine(xmlResult);
            }
    
            static async Task<string> GetProductAsync(string path, string accept)
            {
                string result = string.Empty;
                client.BaseAddress = new Uri("http://localhost:51702/");
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(accept));
    
                HttpResponseMessage response = await client.GetAsync(path);
                if (response.IsSuccessStatusCode)
                {
                    result = await response.Content.ReadAsStringAsync();
                }
                return result;
            }
        }

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, November 11, 2018 2:02 PM
  • User1493428334 posted

    Thank so much for your complete code, which opens me up to the Async world, complely new to me.

    I have a couple questions:

    (1) HtpClient runs only in Async mode?

    (2) I modified your program so it could run in Visual Studio, and got into permanent wait (similar to an infinite loop),  ie, the program just kept running with nothing appearing on the screen. Below is the code, could you please spot any mistake within?

        public partial class ConsumeWebApi2 : System.Web.UI.Page
        {
            static HttpClient client = new HttpClient();
    
            protected void Page_Load(object sender, EventArgs e)
            {
                RunAsync().GetAwaiter().GetResult();
            }
    
            static async Task RunAsync()
            {
                string path = "http://localhost:63223/api/Product/";  //changed to my API address
    
                string xmlResult = await GetProductAsync(path, "application/xml");
                Console.WriteLine(xmlResult);
            }
    
            static async Task<string> GetProductAsync(string path, string accept)
            {
                string result = string.Empty;
                client.BaseAddress = new Uri("http://localhost:63223/");  // changed to my base address
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(accept));
    
                HttpResponseMessage response = await client.GetAsync(path);
                if (response.IsSuccessStatusCode)
                {
                    result = await response.Content.ReadAsStringAsync();
                }
                return result;
            }
        }

    Sunday, November 11, 2018 7:18 PM
  • User1493428334 posted

    Thank so much. I have been using HttpWebRequest, and I thought what I did in HttpWebRequest was equivalent to what you did in WebClient (setting Request.ContentType = "application/xml; charset='utf-8'"), but I will give your approach a try tonight after I am done with my weekend chores.

    Sunday, November 11, 2018 7:32 PM
  • User1493428334 posted

    Hi DA924,

    I just decided to try your approach right now while I am in it.

    I encountered a couple problems: (I converted your code to C#, see below)

    (1) WebClient returns neither JSON nor XML, instead a completely unformatted string, not even a blank space (<productview><category>Watersports</category><name>Kayak</name><price>275</price><productid>0</productid></productview><productview><category>Watersports</category><name>Lifejacket</name><price>48.95</price><productid>1</productid></productview><productview><category>Soccer</category><name>Soccer Ball</name><price>19.50</price><productid>2</productid></productview><productview><category>Soccer</category><name>Corner...).</name></productview>

    (2) JsonConvert.DeserializeObject(), as the name implies, is converting a JSON object, not an XML. In your code, WebClient is requested to return an XML. So there is a little inconsistency here.

    Below is your converted code (to C#), please let me know if you spot any mistake. Thanks again.

        public partial class ConsumeWebApi3 : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                WebClient myWebClient = new WebClient();
    
                string url = "http://localhost:63223/api/Product/";
    
                myWebClient.Headers["content-type"] = "application/xml";
                string myString  = myWebClient.DownloadString(url);
    
                List<ProductView> myList = JsonConvert.DeserializeObject<List<ProductView>>(myString);
    
    Response.Write(string.Format("<br/><b>20181108</b>:jsonString= {0}", myString));
    for (int i = 0; i < myList.Count; i++) Response.Write(string.Format("<br/><b>20181108</b>:myList[{0}]= {1}", i, myList[i].Name)); } }

    Sunday, November 11, 2018 8:18 PM
  • User1120430333 posted
    public partial class ConsumeWebApi3 : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                WebClient myWebClient = new WebClient();
    
                string url = "http://localhost:63223/api/Product/";
    
                myWebClient.Headers["content-type"] = "application/xml";
                string myString  = myWebClient.DownloadString(url);
    
    
    //I did not execute the code past the myWebClinet call, stopped the code on a debug breakepoint and used Quickwatch to look at the content myString doing a copy/paste of the content on a reply post.
    
    //what should have happened in your case is that you should have loaded the  string XML into a XMLDocument object.
    
    var doc = new XMLDocument();
    
    doc.Load(myString);
    
    or 
    
    doc.Load(myWebClient.DownloadString(url));
    
    Then you can use Linq-2-XML and queried the XMLDocument or XMLElement
    
    }

    https://www.dotnetcurry.com/linq/564/linq-to-xml-tutorials-examples

    Sunday, November 11, 2018 10:55 PM
  • User1493428334 posted

    DA924,

    I will give it a shot later today (Monday) in my spare time. Thanks for your suggestion.

    Monday, November 12, 2018 6:52 AM
  • User753101303 posted

    What is the exact class you are using ? I was thinking about https://docs.microsoft.com/en-us/dotnet/api/system.net.httpwebrequest.accept?view=netframework-4.7.2

    If you really want to use something else, rather than switching to WebClient, I would use HttpClient (this is the "modern" option and it also has support for handling serialization/deserialization behind the scene).

    ContentType is the format of the payload. (ie here what you are sending). Accept allows to tell what you want to get back...

    Monday, November 12, 2018 9:08 AM
  • User1120430333 posted

    If you really want to use something else, rather than switching to WebClient, I would use HttpClient (this is the "modern" option and it also has support for handling serialization/deserialization behind the scene).

    I found that HTTPClient is somewhat flakey at times where it flat-out couldn't find the controller's Action Method when  controller is using ActionName attribute . Why HTTPClient could not find it was beyond me, which happened in C# and VB solutions just flat-out couldn't find it (404 errors) that were very frustrating  to the point that I switched to WebClient,,   and wala, WebClient had no problems. 

    And then on the other hand,  HTTPClient when using it in C# Core solution had no problems. 

    Monday, November 12, 2018 11:18 AM
  • User-474980206 posted

    GoldenMicrosoft

    Hi Mgebhard,

    I am building an ASP.NET Web API app. And when I am consuming it from my ASP.NET code-behind, I set the content type Request.ContentType = "application/xml; charset='utf-8'"; I also tried Request.ContentType = "text/xml; charset='utf-8'"; both did not work.

    Thanks.

    as stated ContentType is for the payload (which a get doesn't have). you want to set the Accept header to specify xml:

      Request.Accept = "application/xml; charset='utf-8'"; 

    this probably will not help, as xml should be the default, unless the webapi is asp.net core, in which case only JSON is supported by default. just access the webapi with the browser or postman to see the response type. if you will need to add xml support to the webapi core see:

     services
       .AddMvc()
       .AddXmlSerializerFormatters();

    now that you get a xml response, you will need to parse it. the xml procduced by your webapi may not be supported by a DataSet and you will need to write your own xml parser. 

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, November 12, 2018 4:04 PM
  • User1493428334 posted

    Hi PatriceSc,

    Using request.Accept = "application/xml" does work, where request is of Class HttpWebRequest.

    Last time when trying your suggestion, instead of typing request.Accept, I accidentally typed Request.Accept (Request is a property of Page class), so it was not accepted since Page.Request has no Accept property. 

    Thanks for your succinct yet comprehensive explanation for the difference between "Accept" and Content-Type".

    The response from my Web API, after setting request.Accept correctly, now is indeed in XML. I did Server.HtmlEncode(xmlString) first before dumping it on the screen.

    Now the remaining problem is that Ikeep failing in  deserializing the XML string.

    (1) First, this is the XML string: <ArrayOfProductView xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/ClientDev"><ProductView><Category>Watersports</Category><Name>Kayak</Name><Price>275</Price><ProductID>0</ProductID></ProductView></ArrayOfProductView>

    (2) Below code is my first approach in deserializing the XML string (into List<ProductView>):

        public class ProductViewHolder
        {
            private List<ProductView> products = null;
    
            public ProductViewHolder()
            {
            }
    
            [XmlElement("ProductView")]
            public List<ProductView> MyProducts
            {
                get { return products; }
                set { products = value; }
            }
        }
    
        protected void Page_Load(object sender, EventArgs e)
        {
           ......
           ......
           string xmlString = sr.ReadToEnd();
           string ns = "http://schemas.datacontract.org/2004/07/ClientDev";
           XmlSerializer xs = new XmlSerializer(typeof(ProductViewHolder), ns);
    
           // Exception Below: <ArrayOfProductView 
           //   xmlns='http://schemas.datacontract.org/2004/07/ClientDev'> was not expected
           ProductViewHolder productHolder = (ProductViewHolder) xs.Deserialize(new StringReader(XmlString)); 
    
           List<ProductView> myList = productHolder.MyProducts;
    ......
    }

    (3) In the above, I also tried without using ns, Exception likewise.

    (4) Below is my other approach to deserialize the XML, which fails silently (produces zero tuple):

        protected void Page_Load(object sender, EventArgs e)
        {
           ......
           ......
           string xmlString = sr.ReadToEnd();
           XmlDocument xdoc = new XmlDocument();
           xdoc.LoadXml(XmlString);
    
           var products = xdoc.SelectNodes("ArrayOfProductView/ProductView");

    // Fails silently: products.Count is 0 below Response.Write(string.Format("<br/><br/><b>20181112</b>:products.Count= {0}", products.Count)); ...... }

    (5) Also tried HttpClient as suggested by DA924, Which I think run only in Async. I ran mgebhard's code in my Visual Studio, but the await never came back. Below is the code:

            static HttpClient client = new HttpClient();
    
            protected void Page_Load(object sender, EventArgs e)
            {
                RunAsync().GetAwaiter().GetResult();
            }
    
            static async Task RunAsync()
            {
                string path = "http://localhost:63223/api/Product/";
    
                string xmlResult = await GetProductAsync(path, "application/xml");
                Console.WriteLine(xmlResult);
            }
    
            static async Task<string> GetProductAsync(string path, string accept)
            {
                string result = string.Empty;
                client.BaseAddress = new Uri("http://localhost:63223/");
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(accept));
    
                HttpResponseMessage response = await client.GetAsync(path);
                if (response.IsSuccessStatusCode)
                {
                    result = await response.Content.ReadAsStringAsync();
                }
                return result;
            }

    Thanks again.

    Monday, November 12, 2018 11:56 PM
  • User1493428334 posted

    My response above to PatriceSC supercedes this.

    Tuesday, November 13, 2018 12:34 AM
  • User1493428334 posted

    Hi Bruce,

    Setting request.Accept to "application/xml" does work, but keep having problem in parsing it. Please see my recent response to PatriceSC for details.

    F.Y.I.: My web API default response is JSON. 

    Thanks for helping.

    Tuesday, November 13, 2018 12:45 AM
  • User1493428334 posted

    Hi DA924,

    Thanks for sharing your experiences.

    I tried WebClient per your suggestion and tried HttpWebRequest with request.Accept="application/xml" per PatriceSC suggestion. Both work for getting back response in XML.

    However, parsing the XML still fails (see my recent response to PatriceSC). There I posted my detailed code in using a garder-variety of methods, including XMLDocument.

    I tried HttpClient (I think it works only in Async ?), but the await never comes back. Below is the code (code from mgebhard I modified to suit VS):

            protected void Page_Load(object sender, EventArgs e)
            {
                RunAsync().GetAwaiter().GetResult();
            }
    
            static async Task RunAsync()
            {
                string path = "http://localhost:63223/api/Product/";
    
                string xmlResult = await GetProductAsync(path, "application/xml");
                Console.WriteLine(xmlResult);
            }
    
            static async Task<string> GetProductAsync(string path, string accept)
            {
                string result = string.Empty;
                client.BaseAddress = new Uri("http://localhost:63223/");
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(accept));
    
                HttpResponseMessage response = await client.GetAsync(path);
                if (response.IsSuccessStatusCode)
                {
                    result = await response.Content.ReadAsStringAsync();
                }
                return result;
            }

    Thanks for keep helping.

    Tuesday, November 13, 2018 12:58 AM
  • User1120430333 posted

    I guess I should ask why are you not just sending back a simple DTO? 

    https://en.wikipedia.org/wiki/Data_transfer_object

    https://www.codeproject.com/Articles/1050468/Data-Transfer-Object-Design-Pattern-in-Csharp

    This is a WebAPI tutorial.

    https://docs.microsoft.com/en-us/aspnet/web-api/overview/data/using-web-api-with-entity-framework/part-5

    I am using HTTPclient in a sync manner, which I can change it to comeback with XML instead of Json  using the DTO that is kept in a classlib project called Entities, and all projects that need to know about the DTO have reference to Entities, along with changing all of the code to work with an XMLDocument object.

    I could have just returned the XMLDocument on the client-side  out of the method, just worked with the XML inside the XMLDocument and never cast the XML back to DTO(s) if that's what I wanted to do.

    public List<DtoProject> GetProjsByUserIdApi(string userid)
            {
                var dtoprojects = new List<DtoProject>();
    
                using (var client = new HttpClient())
                {
                    var uri = new Uri("http://progmgmntcore2api.com/api/project/GetProjsByUserId?userid=" + userid);
    
                    var response = client.GetAsync(uri).Result;
    
                    if (!response.IsSuccessStatusCode)
                        throw new Exception(response.ToString());
    
                    var responseContent = response.Content;
                    var responseString = responseContent.ReadAsStringAsync().Result;
    
                    dynamic projects = JArray.Parse(responseString) as JArray;
    
                    foreach (var obj in projects)
                    {
                        DtoProject dto = obj.ToObject<DtoProject>();
    
                        dtoprojects.Add(dto);
                    }
                }
    
                return dtoprojects;
            }

    I happen to be using a DAL and the DAO pattern in the WebAPI. I am not a fan of the generic repository pattern. However, I am not saying not to use it.

    https://www.tutorialspoint.com/design_pattern/data_access_object_pattern.htm

    https://programmingwithmosh.com/entity-framework/common-mistakes-with-the-repository-pattern/

    https://blog.sapiensworks.com/post/2012/11/01/Repository-vs-DAO.aspx

    [HttpGet]
            [Route("GetProjsByUserId")]
            public List<DtoProject> GetProjectsByUserId(string userid)
            {
                return _daoProject.GetProjectsByUserId(userid);
            }
    public List<DtoProject> GetProjectsByUserId(string userid)
            {
                var dtos = new List<DtoProject>();
    
                using (var context = new ProjectManagementContext(_options))
                {
                    
                    dtos = (from a in context.Projects.Where(a => a.UserId.Contains(userid))
                        select new DtoProject
                        {
                            ProjectId = a.ProjectId,
                            ClientName = a.ClientName,
                            ProjectName = a.ProjectName,
                            Technology = a.Technology,
                            ProjectType = a.ProjectType,
                            UserId = a.UserId,
                            StartDate = a.StartDate,
                            EndDate = a.EndDate,
                            Cost = a.Cost
                        }).ToList();
                }
    
                return dtos;
            }
    using System;
    
    namespace Entities
    {
        public class DtoProject
        {
            public int ProjectId { get; set; }
            public string ClientName { get; set; }
            public string ProjectName { get; set; }
            public string Technology { get; set; }
            public string ProjectType { get; set; }
            public string UserId { get; set; }
            public DateTime StartDate { get; set; }
            public DateTime EndDate { get; set; }
            public decimal Cost { get; set; }
        }
    }
    

    Tuesday, November 13, 2018 2:07 AM
  • User1493428334 posted

    Hi DA924,

    I just marked one of your previous responses, mgebhard's, PatriceSC's, and Bruce's as an answer.

    Currently the remaining problem is not how to get an XML response from the Web API (you and others already gave me pointers on that), but how to deserialize the XML response. The problem is that all the parsers get choked up on the ns (namespace) on the root of the response. And I don't see any convenient way out of it. So I just close this issue.

    It does not mean I am blocked. In fact, I have been using JSON for response from the Web API, and it parses nicely into List<myDesiredClass> easily. 

    I will look at your DTO suggestion in due course. Running HttpClient in Sync mode is interesting.

    Thanks again.

    Tuesday, November 13, 2018 5:29 AM