Click here to Skip to main content
11,719,736 members (89,383 online)
Click here to Skip to main content

How to Send an XML File From a Client to a Server Via REST in a Web API C# Solution

, 29 Aug 2014 CPOL 22K 33
Rate this:
Please Sign up or sign in to vote.
Code to send an XML file over the wire using REST / Web API

Files Flying Over Wires

It is common to pass arguments inside the URI to REST methods, to wit:

http://localhost:21608/api/boomerangingTelescopicPhraseMaze/gus/gus/42

(where the "/gus/gus/42" part at the end of the URI are arg vals that are unpacked on the server, perhaps to be used as criteria vals in a query statement).

What if you need to send something, though, that is too long to fit within a URI, such as an entire file? You can theoretically use arcane and quasi-magical gyrations such as the "[FromBody]" and "[FromURI]" tags, but I discovered/uncovered a much easier way. The file is embedded within a stream and passed along with the HttpWebRequest and then simply read (and saved to file, in the code I show) in a Controller within the server.

That about says it all, I reckon; here's the code:

Client Code

private void buttonIn_Click(object sender, EventArgs e)
{
    String fullFilePath = @"C:\Platypi\Duckbills_JennyLind_CA.XML";
    String uri = @"http://localhost:21608/api/dplat/sendxml";
    SendXMLFile(fullFilePath, uri, 500);
}

public static string SendXMLFile(string xmlFilepath, string uri, int timeout)
{
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);

    request.KeepAlive = false;
    request.ProtocolVersion = HttpVersion.Version10;
    request.ContentType = "application/xml";
    request.Method = "POST";

    StringBuilder sb = new StringBuilder();
    using (StreamReader sr = new StreamReader(xmlFilepath))
    {
        String line;
        while ((line = sr.ReadLine()) != null)
        {
            sb.AppendLine(line);
        }
        byte[] postBytes = Encoding.UTF8.GetBytes(sb.ToString());

        if (timeout < 0)
        {
            request.ReadWriteTimeout = timeout;
            request.Timeout = timeout;
        }

        request.ContentLength = postBytes.Length;

        try
        {
            Stream requestStream = request.GetRequestStream();

            requestStream.Write(postBytes, 0, postBytes.Length);
            requestStream.Close();

            using (var response = (HttpWebResponse)request.GetResponse())
            {
                return response.ToString();
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
            request.Abort();
            return string.Empty;
        }
    }
}

Bonus for Those Stuck in the Past

For older versions of .NET that do not allow the "using" construct, you can do it this way-- add the following code between "requestStream.Close()" and the brace at the end of the try block:

HttpWebResponse response = null;
try
{
    response = (HttpWebResponse)request.GetResponse();
    return response.ToString();
}
finally
{
    IDisposable disposableResponse = response as IDisposable;
    if (disposableResponse != null) disposableResponse.Dispose();
}

Thanks to ctacke (AKA "The Windows CE/Compact Framework Whisperer") for the code above.

Server Code

public class DuckbillXMLController : ApiController
{
. . .

    [Route("api/dplat/sendXML")]
    public async void SendInventoryXML()
    {
        XDocument doc = XDocument.Load(await Request.Content.ReadAsStreamAsync());
        String saveLoc = @"C:\Duckbills\PlatypiOfJennyLindCalifornia.xml";
        doc.Save(saveLoc);
    }
}

Not So Fast There!

As you can see, the URI and file paths/names are hard-coded; fixing this to be more elegant/flexible is left as an exercise to the hopefully veracious and hopelessly voracious reader.

Client Determines Saved Filename

Okay, I'll show a little of the "exercise left to the reader" code; If you want the Client to specify the file name to be saved on the server, you could do it the following way if you want to use the same name for the file:

Client Code

private void buttonIn_Click(object sender, EventArgs e)
{
    String fullFilePath = @"C:\Platypi\Duckbills_JennyLind_CA.XML";
    string justFileName = Path.GetFileNameWithoutExtension(fullFilePath);
    // In this case, justFileName will now be simply "Duckbills_JennyLind_CA"
    String uri = String.Format(@"http://localhost:21608/api/dplat/sendXML/{0}", justFileName);
    SendXMLFile(fullFilePath, uri, 500);
}

Note: Passing the entire filename (including the extension (.xml)) discombobulates the Controller method and causes it to fail/not be found. That is why Path.GetFileName() is not good enough, and Path.GetFileNameWithoutExtension() had to be used above.

Alternatively, you could generate the file name by which to save the file on the server and pass that.

Server Code

[Route("api/dplat/sendXML/{filename}")] 
public async void SendInventoryXML(String fileName)
{
    XDocument doc = XDocument.Load(await Request.Content.ReadAsStreamAsync());
    String saveLoc = String.Format(@"C:\Duckbill\{0}.xml", fileName);
    doc.Save(saveLoc);
}

Server Determines Saved Filename

If you want the Server to generate/determine the file name to use, you can leave the Client code as originally shown, and change the Server code to something like this:

[Route("api/dplat/sendXML")] 
public async void SendInventoryXML()
{
    XDocument doc = XDocument.Load(await Request.Content.ReadAsStreamAsync());
    String fileName = "someEnchantedXMLFileName"; // call a method that generates the appropriate name
    String saveLoc = String.Format(@"C:\Duckbill\{0}.xml", fileName);
    doc.Save(saveLoc);
}

Not So Slow There!

If you find that this tip saves you time, recognizing that time is money, please send me 3.14% of the gross or 42% of the net amount thereby saved. If that is problematic, impossible, or out of the question, a homemade gooseberry pie would suffice.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

B. Clay Shannon
Founder "Across Time & Space"
United States United States
Ideaman and Coder at Across Time & Space, creator of "Mark Twain Central" at http://twaincentral.azurewebsites.net/

Peripatetic and picaresque, I have lived in eight states; specifically, besides my native California (where I was born and where I now again reside) in chronological order: New York, Montana, Alaska, Oklahoma, Wisconsin, Idaho, and Missouri.

I am also a writer of both fiction (for which I use a nom de plume, "Blackbird Crow Raven", as a nod to my Native American heritage - I am "½ Cowboy, ½ Indian") and nonfiction: http://www.lulu.com/spotlight/blackbirdcraven

You may also be interested in...

Comments and Discussions

 
GeneralMy vote of 4 Pin
vks900928-Aug-14 0:29
professionalvks900928-Aug-14 0:29 
SuggestionCleaner way Pin
codefabricator27-Aug-14 8:29
membercodefabricator27-Aug-14 8:29 
GeneralRe: Cleaner way Pin
B. Clay Shannon27-Aug-14 8:49
professionalB. Clay Shannon27-Aug-14 8:49 
GeneralMy vote of 2 Pin
Pawel Cioch26-Aug-14 5:41
memberPawel Cioch26-Aug-14 5:41 
SuggestionNon optimal approach - sorry :) Pin
Pawel Cioch26-Aug-14 5:39
memberPawel Cioch26-Aug-14 5:39 
AnswerRe: Bad approach - sorry :) Pin
B. Clay Shannon26-Aug-14 5:43
professionalB. Clay Shannon26-Aug-14 5:43 
GeneralRe: Bad approach - sorry :) Pin
Pawel Cioch26-Aug-14 6:50
memberPawel Cioch26-Aug-14 6:50 
GeneralRe: Bad approach - sorry :) Pin
B. Clay Shannon26-Aug-14 7:00
professionalB. Clay Shannon26-Aug-14 7:00 
GeneralRe: non optimal approach Pin
Pawel Cioch26-Aug-14 7:04
memberPawel Cioch26-Aug-14 7:04 
GeneralRe: non optimal approach Pin
B. Clay Shannon26-Aug-14 7:07
professionalB. Clay Shannon26-Aug-14 7:07 
GeneralRe: Bad approach - sorry :) Pin
Charles J Cooper27-Aug-14 9:49
memberCharles J Cooper27-Aug-14 9:49 
GeneralRe: Bad approach - sorry :) Pin
B. Clay Shannon27-Aug-14 10:28
professionalB. Clay Shannon27-Aug-14 10:28 
GeneralRe: Bad approach - sorry :) Pin
Sacha Barber28-Aug-14 11:59
mvpSacha Barber28-Aug-14 11:59 
GeneralMy vote of 5 Pin
Humayun Kabir Mamun25-Aug-14 19:12
memberHumayun Kabir Mamun25-Aug-14 19:12 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150901.1 | Last Updated 29 Aug 2014
Article Copyright 2014 by B. Clay Shannon
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid