ic3man7019
ic3man7019

Reputation: 711

How can I serialize my ViewModel to XML and send it to a remote server?

I have an ASP.NET MVC 5 application in which I am trying to serialize my ViewModel and send it to a remote, third-party server for data processing. I am not exactly sure what I'm doing wrong, but below is the code that I have tried.

Firstly, here is the POST method in my controller in which I am trying to serialize the ViewModel and send it to the remote server:

[HttpPost]
        public ActionResult Index(Transmission t)
        {
            ViewBag.ErrorMessage = "";
            ViewBag.OtherMessage = "";

            try
            {
                //serialize the ViewModel
                XmlResult xrs = new XmlResult(t);
                XDocument xdoc = XDocument.Parse(xrs.ToString());
                Stream stream = new MemoryStream(); //the memory stream to be used to save the xdoc
                XmlActionResult xar = new XmlActionResult(xdoc);
                xdoc.Save(stream);
                //xrs.ExecuteResult(ControllerContext);

                //POST the data to the external URL
                var url = "theUrl";
                var PostData = xar;


                var Req = (HttpWebRequest)WebRequest.Create(url);
                Req.ContentType = "application/xml";
                Req.Method = "POST";
                Req.Timeout = 60000;
                Req.KeepAlive = false;


                //build the string to send
                StringBuilder sb = new StringBuilder();

                using(StreamReader sr = new StreamReader(stream))
                {
                    string line; 
                    while((line = sr.ReadLine()) != null)
                    {
                        sb.AppendLine(line);
                    }
                    byte[] postBytes = Encoding.ASCII.GetBytes(sb.ToString());
                    Req.ContentLength = postBytes.Length;


                    using (Stream requestStream = Req.GetRequestStream())
                    {
                        requestStream.Write(postBytes, 0, postBytes.Length);
                        requestStream.Close();
                    }

                   using (var response = (HttpWebResponse)Req.GetResponse())
                    {
                        ViewBag.OtherMessage = response.ToString();
                        return View("Error"); //TODO: change this to success when I get the 500 error fixed
                    }
                }

            }
            catch (Exception ex)
            {
                string message = ex.Message;
                ViewBag.ErrorMessage = ex.Message;
                return View("Error");
            }
        }
    }

As you can see above, I am using two classes, called XmlActionResult and XmlResult, respectively. The XmlResult class is being used to serialize the ViewModel. Here is the implementation of the XmlResult class:

public class XmlResult : ActionResult
    {
        private object objectToSerialize;

        /// <summary>
        /// Initializes a new instance of the <see cref="XmlResult"/> class.
        /// </summary>
        /// <param name="objectToSerialize">The object to serialize to XML.</param>
        public XmlResult(object objectToSerialize)
        {
            this.objectToSerialize = objectToSerialize;
        }

        /// <summary>
        /// Gets the object to be serialized to XML.
        /// </summary>
        public object ObjectToSerialize
        {
            get { return objectToSerialize; }
        }

        /// <summary>
        /// Serializes the object that was passed into the constructor to XML and writes the corresponding XML to the result stream.
        /// </summary>
        /// <param name="context">The controller context for the current request.</param>
        public override void ExecuteResult(ControllerContext context)
        {
            if (objectToSerialize != null)
            {
                context.HttpContext.Response.Clear();
                var xs = new System.Xml.Serialization.XmlSerializer(objectToSerialize.GetType());
                context.HttpContext.Response.ContentType = "xml";
                xs.Serialize(context.HttpContext.Response.Output, objectToSerialize);
            }
        }
    }

After the XmlResult class serializes the ViewModel, I am attempting to create a XDocument using the XmlActionResult class. Here is the implementation of the XmlActionResult class:

public sealed class XmlActionResult : ActionResult
    {
        private readonly XDocument _document;

        public Formatting Formatting { get; set; }
        public string MimeType { get; set; }

        public XmlActionResult(XDocument document)
        {
            if (document == null)
                throw new ArgumentNullException("document");

            _document = document;

            // Default values
            MimeType = "text/xml";
            Formatting = Formatting.None;
        }

        public override void ExecuteResult(ControllerContext context)
        {
            context.HttpContext.Response.Clear();
            context.HttpContext.Response.ContentType = MimeType;

            using (var writer = new XmlTextWriter(context.HttpContext.Response.OutputStream, Encoding.UTF8) { Formatting = Formatting })
                _document.WriteTo(writer);
        }
    }

I believe this is where my first problem lies. I want to create a XDocument from the serialized ViewModel object -- t in this case -- using the XmlResult class, but I am getting an error saying "Data at the root level is invalid. Line 1, position 1. " This tells me that the XDocument class is having a problem parsing the serialized ViewModel object. What have I done wrong here?

Next, I am trying to save the XDocument (after it has been successfully created) in a MemoryStream. The idea is to build a byte array from a StringBuilder object that is accessing the XDocument that is saved in the MemoryStream via a StreamReader, and send that to the remote server via the HttpWebRequest object. However, I haven't gotten this far yet, thanks to the above error.

Any help is greatly appreciated. I'm willing to change this entire approach if I need to. I'm not certain the latter part will work even if I get the first part working, so any advice will be heeded. Thank you.

Update: Further Information about Exception

The exception is being thrown at this line:

XDocument xdoc = XDocument.Parse(xrs.ToString());

The innerException is null. The Message is "Data at the root level is invalid. Line 1, position 1."

Upvotes: 0

Views: 1090

Answers (1)

Z.R.T.
Z.R.T.

Reputation: 1603

public async Task<ActionResult> Index(Transmission t)
    {
        ViewBag.ErrorMessage = "";
        ViewBag.OtherMessage = "";

        try
        {

            var xmlSerializer = new XmlSerializer(typeof(Transmission));
            using (StringWriter sw = new StringWriter())
            {
                xmlSerializer.Serialize(sw, t);
                var contentData = sw.ToString();
                var httpContent = new StringContent(contentData, Encoding.UTF8, "application/xml");
                var httpClient = new HttpClient();
                httpClient.Timeout = new TimeSpan(0, 1, 0);
                var response = await httpClient.PostAsync("", httpContent);
                ViewBag.OtherMessage = await response.Content.ReadAsStringAsync();
                return View("Error"); //TODO: change this to success when I get the 500 error fixed
            }
        }
        catch (Exception ex)
        {
            string message = ex.Message;
            ViewBag.ErrorMessage = ex.Message;
            return View("Error");
        }
    }

Upvotes: 2

Related Questions