Subscribe to The Rails Future        RSS Feed
-----

How to get a C# app to upload to rails (respond_to do |format|) XML

Icon Leave Comment
Imagine that you have data in a computer program you wrote, and you'd like to send that data up to your rails app. Well, this tutorial will illustrate exactly how to do that using C# as the language. In the process, you will learn more about that pesky respond_to do |format| syntax and what it does.

We will see how to setup the rails database correctly, and define the .xml method. Then compile the C# app and make an upload, and also a download...

Prerequisites:
a. Compile a C# app http://www.dreaminco...bian-in-my-net/
b. Have a rails test server setup

ref: http://www.digitalho...-json-requests/
ref: http://www.codeproje...et/XmlPost.aspx

Overview
1) Setup your rails app with the proper database scheme

2) Setup your C# client application, use either mono or .NET to run the code if you're using windows.

3) Tweak the respond_to code a little bit to fully understand what you can do.




1) Setup the rails app

$ rails new library
$ cd library
$ rails generate scaffold book title:string author:string isbn:string price:decimal
$ rake db:migrate


That should do it for the setup. You can now browse to /books and see something that looks familiar at this point I would expect.

In your controllers, you'll happen to have code that looks like this:
(books_controller.rb)
  .
  .
  .
  # POST /books
  # POST /books.xml
  def create
    @book = Book.new(params[:book])

    respond_to do |format|
      if @book.save
        format.html { redirect_to(@book, :notice => 'Book was successfully created.') }
        format.xml {render :xml => @book, :status => :created, :location => @book }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @book.errors, :status => :unprocessable_entity }
      end
    end
  end
  .
  .
  .




The important part is this chunck:

    respond_to do |format|
      if @book.save
        format.html { redirect_to(@book, :notice => 'Book was successfully created.') }
        format.xml {render :xml => @book, :status => :created, :location => @book }
      else
      .
      .
      .
      end
    end



That says that, if @book.save works fine (ie returns something other than false), then respond to the client in the following ways:

i. If it was an html request, then respond by redirecting their browser to @book (eg example.com/books/:id).

ii. If it was an xml request, then render @book as an XML file (eg, the same string that the client sent up to the server in the first place).


Let's watch it in action...







2) Setup the C# client

Hopefully you've got mono installed, or you have a windows client.


(railsClient.cs)
// compiles with 
// $  gmcs railsClient.cs

using System;
using System.Diagnostics;
using System.Net;
using System.IO;
using System.Text;


public class HelloWorld
{
    static public void Main()
    {
        Console.WriteLine("We're going to send an XML file to our rails database!");

        
        Console.WriteLine("Please input the path to your rails app and it's controller (or leave blank if you coded a default):");
        
        string path = Console.ReadLine();
        string response = "";
        
        if (path == "")
          response = sendXmlData("http://192.168.0.11:3000/books");
        else
          response = sendXmlData(path);
        
        
        Console.WriteLine("\n\n Output: \n");
        Console.WriteLine(response);
        Console.WriteLine("\n");
        
        
        Console.WriteLine("We're done!");
        Console.Read();
    }
    
    // return true if data is successfully stored (not yet working!)
    static private string sendXmlData(string pathToAction)
    {
        string response = "";
        
        HttpWebRequest req = null;
        HttpWebResponse rsp = null;
        try
        {
            string uri = pathToAction; 
            //string uri = "http://192.168.0.11:3000/books";
            
            string xmlData = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
            xmlData += "<book>";
            xmlData += "<author>Ex Emel</author>";
            xmlData += "<created-at type=\"datetime\">2008-05-26T05:58:38Z</created-at>";
            xmlData += "<id type=\"integer\">2</id>";
            xmlData += "<isbn>1234567890</isbn>";
            xmlData += "<price type=\"decimal\">34.99</price>";
            xmlData += "<title>Posted via XML 2</title>";
            xmlData += " <updated-at type=\"datetime\">2008-05-26T05:58:38Z</updated-at>";
            xmlData += "</book>";


            
            req = (HttpWebRequest)WebRequest.Create(uri);
            //req.Proxy = WebProxy.GetDefaultProxy(); // Enable if using proxy
            req.Method = "POST";        // Post method
            req.ContentType = "text/xml";     // content type
            req.Accept = "text/xml";

            // Wrap the request stream with a text-based writer
            StreamWriter writer = new StreamWriter(req.GetRequestStream());
            // Write the XML text into the stream
            writer.WriteLine(xmlData);
            writer.Close();

            // Send the data to the webserver
            rsp = (HttpWebResponse)req.GetResponse();

            Encoding enc = System.Text.Encoding.GetEncoding(1252);
            StreamReader loResponseStream = new
              StreamReader(rsp.GetResponseStream(), enc);

            response = loResponseStream.ReadToEnd();
            //response = rsp.StatusCode.ToString();    // you can return this if you'd prefer

            //MessageBox.Show(Response);
        }
        catch (WebException webEx)
        {
            // 
        }
        catch (Exception ex)
        {

        }
        finally
        {
            if (req != null) req.GetRequestStream().Close();
            if (rsp != null) rsp.GetResponseStream().Close();
        }
        
        return response;
    }
}



Compile with
$ gmcs railsClient.cs
Or use an IDE.


Note that the xml data it's transferring is parallel to this
(xml Data string)
<?xml version="1.0" encoding="UTF-8"?>
<book>
  <author>Ex Emel</author>
  <created-at type="datetime">2008-05-26T05:58:38Z</created-at>
  <id type="integer">2</id>
  <isbn>1234567890</isbn>
  <price type="decimal">34.99</price>
  <title>Posted via XML 2</title>
  <updated-at type="datetime">2008-05-26T05:58:38Z</updated-at>
</book>



You should be able to run the thing and get a response back. Feel free to hardcode the default value to match where your rails server is.


3) Tweak your response to be more efficient

It's a little wasteful to be sending back data that the client obviously already has. Luckily, you can control the responses of rails to be what ever you want.

I tweaked my response as below, but of course, you could simply comment out the whole render line if you'd prefer (although you really should be communicating with the client in some way).

(books_controller.rb)
  .
  .
  .
  # POST /books
  # POST /books.xml
  def create
    @book = Book.new(params[:book])

    respond_to do |format|
      if @book.save
        format.html { redirect_to(@book, :notice => 'Book was successfully created.') }
        format.xml do
          render :xml => "<result>sucess</result>", :status => :created #, :location => @book
        end

      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @book.errors, :status => :unprocessable_entity }
      end
    end
  end
  .
  .
  .



You can scope out the complete work at it's repo on github.

https://github.com/T...upload-to-rails

0 Comments On This Entry

 

Trackbacks for this entry [ Trackback URL ]

There are no Trackbacks for this entry

November 2014

S M T W T F S
      1
2345678
9101112131415
16171819202122
23 242526272829
30      

Tags

    Search My Blog

    0 user(s) viewing

    0 Guests
    0 member(s)
    0 anonymous member(s)

    Categories