使用JSON请求和RestSharp通过c#上传文件

在管理通过c#将数据加载到我的Rails服务器之后(请点击此处了解我在说什么),我现在正尝试将文件上传到同一台服务器以及其他数据。

在Ruby中,我可以使用代码执行此操作:

require 'HTTMultiParty' class ReceiptCreate include HTTMultiParty # Log to file # debug_output File.new("httparty1.log", "w+") base_uri "localhost:3000" format :json headers "Accept" => "application/json" def initialize end def post(machine_serial,filepath,tag_number,token) options = { body: {receipt: {tag_number:tag_number, receipt_file: File.new(filepath), ispaperduplicate:0 }, machine: {serial_number: machine_serial, safe_token: token } } } self.class.post('/receipts', options) end end receipt = ReceiptCreate.new() filename1 = "C:\\filename1.pdf" filename2 = "C:\\filename2.pdf" response=receipt.post("2803433",filename2,"p94tt7w","123") puts response 

当我检查rails服务器上的参数时,我看到了

 Parameters: {"receipt"=>{"tag_number"=>"p94tt7w", "receipt_file"=>#<ActionDispatch::Http::UploadedFile:0x4183ea8 @original_filename="Invoice.pdf", @content_type="application/octet-stream", @headers="Content-Disposition: form-data; name=\"receipt[receipt_file]\"; filename=\"Invoice.pdf\"\r\nContent-Length: 11653\r\nContent-Type: application/octet-stream\r\nContent-Transfer-Encoding: binary\r\n", @tempfile=#>, "ispaperduplicate"=>"0"}, "machine"=>{"serial_number"=>"2803433", "safe_token"=>"123"}} 

但是如果我尝试用下面的c#代码做同样的事情

 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using RestSharp; using System.Web.Script.Serialization; using System.IO; namespace RonRestClient { class templateRequest { public Receipt receipt; public class Receipt { public float total; public String tag_number; public bool ispaperduplicate = true; public byte[] receipt_file; public Receipt(float total, String tagnr, string filepath) { this.total = total; this.tag_number = tagnr; this.receipt_file = File.ReadAllBytes(filepath); } }; public Machine machine; public class Machine { public String serial_number; public String safe_token; public Machine(String machinenr, String safe_token) { this.serial_number = machinenr; this.safe_token = safe_token; } }; } public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { string path = @"C:\filename2.pdf"; string tagnr = "p94tt7w"; string machinenr = "2803433"; string safe_token = "123"; float total = 100; templateRequest req = new templateRequest(); req.receipt = new templateRequest.Receipt(total, tagnr, path); req.machine = new templateRequest.Machine(machinenr, safe_token); //string json_body = JsonConvert.SerializeObject(req); //string json_body = new JavaScriptSerializer().Serialize(req); //var json_body = "{\"receipt\" : {\"total\":"+total+", \"tag_number\":\""+tagnr+"\",\"ispaperduplicate\":true},\"machine\":{\"serial_number\": \""+machinenr+"\",\"safe_token\": \""+safe_token+"\"}}"; var client = new RestClient("http://localhost:3000/receipts"); var request = new RestRequest(Method.POST); //set request Body request.AddHeader("Content-type", "application/json"); request.AddHeader("Accept", "application/json"); request.RequestFormat = DataFormat.Json; request.AddBody(req); //request.AddParameter("application/json", json_body, ParameterType.RequestBody); // easily add HTTP Headers // add files to upload (works with compatible verbs) //request.AddFile("receipt/receipt_file",path); // execute the request IRestResponse response = client.Execute(request); var content = response.Content; // raw content as string if(response.ErrorMessage !="") content += response.ErrorMessage; response_box.Text = content; } } } 

我明白了

 Parameters: {"receipt"=>{"total"=>100, "tag_number"=>"p94tt7w", "ispaperduplicate"=>true, "receipt_file"=>[37, 80, [n3...nX], 10]}, "machine"=>{"serial_number"=>"2803433", "safe_token"=>"123"}} 

这似乎基本上意味着Restsharp认为我的文件只是另一个字段。

RestSharp似乎有一个方法来添加文件request.AddFile("receipt/receipt_file",path); ,我相信这可能是要走的路……但是当我尝试添加文件时,我收到一条错误消息:

写入开始后无法设置此属性。

我是否需要单独设置文件的每个属性?

编辑

同时我发现这篇文章 ,将我的代码更改为:

 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using RestSharp; using System.Web.Script.Serialization; using System.IO; using System.Net; namespace RonRestClient { class templateRequest { public Receipt receipt; public class Receipt { //public float total; public String tag_number; public bool ispaperduplicate = true; //public byte[] receipt_file; public Receipt(String tagnr) { //this.total = total; this.tag_number = tagnr; // this.receipt_file = File.ReadAllBytes(filepath); } }; public Machine machine; public class Machine { public String serial_number; public String safe_token; public Machine(String machinenr, String safe_token) { this.serial_number = machinenr; this.safe_token = safe_token; } }; } public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { string path = @"C:\filename2.pdf"; string tagnr = "p94tt7w"; string machinenr = "2803433"; string safe_token = "123"; float total = 100; templateRequest req = new templateRequest(); req.receipt = new templateRequest.Receipt(tagnr); req.machine = new templateRequest.Machine(machinenr, safe_token); var request = new RestRequest("/receipts",Method.POST); request.AddParameter("receipt[total]", total); request.AddParameter("receipt[tag_number]", tagnr); request.AddParameter("machine[serial_number]", machinenr); request.AddParameter("machine[safe_token]", safe_token); request.AddFile("receipt[receipt_file]", File.ReadAllBytes(path), "Invoice.pdf", "application/octet-stream"); // Add HTTP Headers request.AddHeader("Content-type", "application/json"); request.AddHeader("Accept", "application/json"); request.RequestFormat = DataFormat.Json; //set request Body //request.AddBody(req); // execute the request //calling server with restClient RestClient restClient = new RestClient("http://localhost:3000"); restClient.ExecuteAsync(request, (response) => { if (response.StatusCode == HttpStatusCode.OK) { //upload successfull MessageBox.Show("Upload completed succesfully...\n" + response.Content); } else { //error ocured during upload MessageBox.Show(response.StatusCode + "\n" + response.StatusDescription); } }); } } } 

现在我得到的参数:

 Parameters: {"receipt"=>{"total"=>"100", "tag_number"=>"p94tt7w", "receipt_file"=>#<ActionDispatch::Http::UploadedFile:0x3db42d8 @original_filename="Invoice.pdf", @content_type="application/octet-stream", @headers="Content-Disposition: form-data; name=\"receipt[receipt_file]\"; filename=\"Invoice.pdf\"\r\nContent-Type: application/octet-stream\r\n", @tempfile=#>}, "machine"=>{"serial_number"=>"2803433", "safe_token"=>"123"}} 

连同HTTP 422 – 不可处理的实体错误。

如果我要将这些参数与我使用ruby代码的那些参数进行比较,那么现在唯一的区别似乎是这最后一条消息没有Content-length和Content-Transfer-Encoding字段……

你对我如何添加属性有任何想法吗?

这是一场战斗……最后我发现了解决这个问题的两种不同方法。 具有讽刺意味的是,正如许多编码问题一样,我所要做的就是首先设置正确的参数……只有一个缺失的参数花费我超过4小时..

两者详述如下:

1 – 使用RestSharp (总字段不应该在那里,并且缺少ispaperduplicate字段)

 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using RestSharp; using System.Web.Script.Serialization; using System.IO; using System.Net; namespace RonRestClient { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { string path = @"C:\filename2.pdf"; //localhost settings string requestHost = @"http://localhost:3000/receipts"; string tagnr = "p94tt7w"; string machinenr = "2803433"; string safe_token = "123"; // Do it with RestSharp templateRequest req = new templateRequest(); req.receipt = new templateRequest.Receipt(tagnr); req.machine = new templateRequest.Machine(machinenr, safe_token); var request = new RestRequest("/receipts", Method.POST); request.AddParameter("receipt[tag_number]", tagnr); request.AddParameter("receipt[ispaperduplicate]", 0); request.AddParameter("machine[serial_number]", machinenr); request.AddParameter("machine[safe_token]", safe_token); request.AddFile("receipt[receipt_file]", File.ReadAllBytes(path), Path.GetFileName(path), "application/octet-stream"); // Add HTTP Headers request.AddHeader("Content-type", "application/json"); request.AddHeader("Accept", "application/json"); request.RequestFormat = DataFormat.Json; //set request Body //request.AddBody(req); // execute the request //calling server with restClient RestClient restClient = new RestClient("http://localhost:3000"); restClient.ExecuteAsync(request, (response) => { if (response.StatusCode == HttpStatusCode.OK) { //upload successfull MessageBox.Show("Upload completed succesfully...\n" + response.Content); } else { //error ocured during upload MessageBox.Show(response.StatusCode + "\n" + response.StatusDescription); } }); } } } 

2 – 使用FileStream和HttpWebRequest (谢谢Clivant )

 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using RestSharp; using System.Web.Script.Serialization; using System.IO; using System.Net; namespace RonRestClient { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { string path = @"C:\Projectos\My Training Samples\Adobe Sample\RBO1574.pdf"; //localhost settings string requestHost = @"http://localhost:3000/receipts"; string tagnr = "p94tt7w"; string machinenr = "2803433"; string safe_token = "123"; FileStream fs1 = File.OpenRead(path); long filesize = fs1.Length; fs1.Close(); // Create a http request to the server endpoint that will pick up the // file and file description. HttpWebRequest requestToServerEndpoint = (HttpWebRequest)WebRequest.Create(requestHost); string boundaryString = "FFF3F395A90B452BB8BEDC878DDBD152"; string fileUrl = path; // Set the http request header \\ requestToServerEndpoint.Method = WebRequestMethods.Http.Post; requestToServerEndpoint.ContentType = "multipart/form-data; boundary=" + boundaryString; requestToServerEndpoint.KeepAlive = true; requestToServerEndpoint.Credentials = System.Net.CredentialCache.DefaultCredentials; requestToServerEndpoint.Accept = "application/json"; // Use a MemoryStream to form the post data request, // so that we can get the content-length attribute. MemoryStream postDataStream = new MemoryStream(); StreamWriter postDataWriter = new StreamWriter(postDataStream); // Include value from the tag_number text area in the post data postDataWriter.Write("\r\n--" + boundaryString + "\r\n"); postDataWriter.Write("Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}", "receipt[tag_number]", tagnr); // Include ispaperduplicate text area in the post data postDataWriter.Write("\r\n--" + boundaryString + "\r\n"); postDataWriter.Write("Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}", "receipt[ispaperduplicate]", 0); // Include value from the machine number in the post data postDataWriter.Write("\r\n--" + boundaryString + "\r\n"); postDataWriter.Write("Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}", "machine[serial_number]", machinenr); // Include value from the machine token in the post data postDataWriter.Write("\r\n--" + boundaryString + "\r\n"); postDataWriter.Write("Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}", "machine[safe_token]", safe_token); // Include the file in the post data postDataWriter.Write("\r\n--" + boundaryString + "\r\n"); postDataWriter.Write("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n" + "Content-Length: \"{2}\"\r\n" + "Content-Type: application/octet-stream\r\n" + "Content-Transfer-Encoding: binary\r\n\r\n", "receipt[receipt_file]", Path.GetFileName(fileUrl), filesize); postDataWriter.Flush(); // Read the file FileStream fileStream = new FileStream(fileUrl, FileMode.Open, FileAccess.Read); byte[] buffer = new byte[1024]; int bytesRead = 0; while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0) { postDataStream.Write(buffer, 0, bytesRead); } fileStream.Close(); postDataWriter.Write("\r\n--" + boundaryString + "--\r\n"); postDataWriter.Flush(); // Set the http request body content length requestToServerEndpoint.ContentLength = postDataStream.Length; // Dump the post data from the memory stream to the request stream Stream s = requestToServerEndpoint.GetRequestStream(); postDataStream.WriteTo(s); postDataStream.Close(); } } }