I'm using C# 6.0, ASP.NET 4.5 MVC 4.
I'm developing an API that is essentially a wrapper for another API that generates PDFs. A separate server will be implementing it directly, and all other applications will send their data to this server for conversion. The underlying PDF conversion software has specific system requirements so this will free us from the limitation of what machines our applications can run on. It's also somewhat brittle so isolating it is desireable.
To accomplish this I've set up two separate MVC applications, one with the conversion implementation, the other as a simple application that generates data to be converted, which implements the API I'm developing. They're set up to exchange data using POST.
The problem I've run into is that the PDF server isn't receiving the data to be converted. It runs, but its parameter only contains null. I set it up so that it will return a PDF containing the error if this happens. It comes through successfully, containing the resulting error message it generated so that part of it is functioning properly.
Here's the code running on the PDF server:
[HttpPost]
public FileResult MakePdf(string html)
{
byte[] pdf = null;
var converter = new HtmlToPdfConverter();
try
{
pdf = converter.GeneratePdf(html);
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
var errorHtml = errorTop + new Regex("\\s").Replace(e.Message, " ") + errorBottom;
pdf = converter.GeneratePdf(errorHtml);
}
return File(pdf, "application/pdf");
}
Here's the code that's sending the HTML there to be converted:
public byte[] Fetch() {
var webRequest = (HttpWebRequest)WebRequest.Create("http://localhost:60272/PdfServer/MakePdf");
webRequest.Method = "POST";
var encoder = new UTF8Encoding();
byte[] data = encoder.GetBytes(Resource); // Resource contains valid HTML output by ASP.NET
webRequest.ContentLength = data.Length;
webRequest.ContentType = "text/html";
using (var stream = webRequest.GetRequestStream())
{
stream.Write(data, 0, data.Length);
stream.Flush();
}
using (var webResponse = webRequest.GetResponse())
{
using (Stream responseStream = webResponse.GetResponseStream())
{
using (var memoryStream = new MemoryStream())
{
int bufferLength = 1024;
data = new byte[bufferLength];
int responseLength = 0;
do
{
responseLength = responseStream.Read(data, 0, bufferLength);
memoryStream.Write(data, 0, responseLength);
} while (responseLength != 0);
data = memoryStream.ToArray();
}
}
}
return data;
}
I haven't tried sending data to an ASP.NET MVC controller method from a separate application before. The code I wrote here is based on examples I've found of how it's done.
Any ideas about what I'm doing wrong?
Try to form encode it: "application/x-www-form-urlencoded" and name the string-data html. So it would look something like:
var s = "html=" + Resource;
And then send s, instead of sending Resource. And of course set the content type to "application/x-www-form-urlencoded". This should help MVC map the data to the html parameter.
That's the only thing I can think of.
On a side note, I think you also should Close() your stream when you're done, rather than flushing it.
===
A final idea would be to try to change your encoding from text/html to text/plain. I know you're thinking it's HTML, but your method is taking in a string. So to MVC it's expecting a string, not HTML, the fact that it's actually HTML is incidental to the MVC deserializer.
Related
I am working on a website which is old and uses AMF packages to send data to server. I need to send some text data to this website and save that data to this website. In other words I want to automate this website.
I found fluorinefx library but it is no longer supported by owner and there is no documentation on the internet about that. I tried to use fluorinefx's serialize class to serialize my dictionary data and send that to server with content-type header application/x-amf. But httpclient doesnt support AMF bytearrays.
When I tried to use fluorinefx's NetConnection class and use netConnection.Connect(url) method, if url starts with http:// there is no problem, but if url starts with https// it gives an URÄ°Format exception. Since the website I am working on uses https:// I cannot use this Connect method either.
So please help me, how can I prepare a correctly structured AMF object and send this with HttpClient. Or is there any other libraries which I can use for sending AMF packages.(I looked WebOrb and DotAmf too but theese are not working either)
Thanks.
public static object SendAMF(string method, object[] arguments)
{
AMFMessage message = new AMFMessage(3);
message.AddHeader(new AMFHeader("headerKey", false, "headerValue"));
message.AddBody(new AMFBody(method, "/1", arguments));
MemoryStream ms = new MemoryStream();
AMFSerializer serializer = new AMFSerializer(ms);
serializer.WriteMessage(message);
serializer.Flush();
serializer.Dispose();
var request = (HttpWebRequest)WebRequest.Create($"{Endpoint}/Gateway.aspx?method={method}");
byte[] data = Encoding.Default.GetBytes(Encoding.Default.GetString(ms.ToArray()));
request.GetRequestStream().Write(data, 0, data.Length);
try
{
var response = (HttpWebResponse)request.GetResponse();
ms = new MemoryStream();
response.GetResponseStream().CopyTo(ms);
dynamic obj = DecodeAMF(ms.ToArray());
ms.Dispose();
response.Dispose();
return obj;
}
catch(Exception ex)
{
ms.Dispose();
return "ERROR! " + ex.ToString();
}
}
public static dynamic DecodeAMF(byte[] body)
{
MemoryStream memoryStream = new MemoryStream(body);
AMFDeserializer amfdeserializer = new AMFDeserializer(memoryStream);
AMFMessage amfmessage = amfdeserializer.ReadAMFMessage();
dynamic content = amfmessage.Bodies[0].Content;
memoryStream.Dispose();
amfdeserializer.Dispose();
return content;
}
`
I am working on a c# console application where I am making a Http Post request to a web api by using xml file and I'm kind of new to XML and web services but I figured out the following code for the request but failed to pass xml data to the method
static void Main(string[] args)
{
string desturl=#"https://xyz.abcgroup.com/abcapi/";
Program p = new Program();
System.Console.WriteLine(p.WebRequestPostData(desturl, #"C:\Applications\TestService\FixmlSub.xml"));
}
public string WebRequestPostData(string url, string postData)
{
System.Net.WebRequest req = System.Net.WebRequest.Create(url);
req.ContentType = "text/xml";
req.Method = "POST";
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(postData);
req.ContentLength = bytes.Length;
using (Stream os = req.GetRequestStream())
{
os.Write(bytes, 0, bytes.Length);
}
using (System.Net.WebResponse resp = req.GetResponse())
{
if (resp == null) return null;
using (System.IO.StreamReader sr = new System.IO.StreamReader(resp.GetResponseStream()))
{
return sr.ReadToEnd().Trim();
}
}
}
For obvious reasons the above code throws 404 error as I think I am not passing the xml data properly
May I know how I can fix this?
You're not posting xml, your posting the string C:\Applications\TestService\FixmlSub.xml
Change your method call from:
System.Console.WriteLine(p.WebRequestPostData(desturl, #"C:\Applications\TestService\FixmlSub.xml"));
to
var xml = XElement.Load(#"C:\Applications\TestService\FixmlSub.xml");
System.Console.WriteLine(p.WebRequestPostData(desturl, xml.ToString(SaveOptions.DisableFormatting));
If you are trying to learn post / receive, go for it. But there are open source libraries that are already well tested to use if you want to use them.
The non-free version of Servicestack.
And their older free-version. I think the older free version is great. I've never tried the newer one. You deal with objects, like say an Employee and pass that to the library and it does the translation to xml or whatever the web-service wants.
You can post whole strings if you want. They have great extension methods to help you with that too.
I'm using Corona SDK to post data to my C# server:
headers["Content-Type"] = "application/x-www-form-urlencoded"
headers["Accept-Language"] = "en-US"
local body = "color=red&size=small"
local params = {}
params.headers = headers
params.body = body
network.request( host .. "/UpdateHand", "POST", nwListener, params )
I receive a message on the server:
Post["/UpdateHand"] = x =>
{
Console.WriteLine("Received ...");
return "Ok";
};
But when I check the data (when I put a breakpoint on it) I don't see where my data is locaded (i.e. the params.body or params.headers). How can I extract this information?
I should POST it correctly according to the documentation on Corona: http://docs.coronalabs.com/daily/api/library/network/request.html
The post data is in
this.Request.Body
If you have suitable type you can deserialize your data to it using model binding:
var x = this.Bind<YourType>();
There is a Nancy extension for this. You will need to include the namespace for it.
using Nancy.Extensions;
var text = Context.Request.Body.AsString();
I like how concise this is, part of Nancy's super-duper easy path.
But a word of caution! This method leaves the stream at the end, so subsequent calls will return empty string. To fix this, always reset the stream immediately afterwards, like so:
Request.Body.Seek(0, SeekOrigin.Begin);
Nancy 2.0 is supposed to correct this so that the stream position is reset by default.
https://github.com/NancyFx/Nancy/pull/2158
This actually works great:
var body = this.Request.Body;
int length = (int) body.Length; // this is a dynamic variable
byte[] data = new byte[length];
body.Read(data, 0, length);
Console.WriteLine(System.Text.Encoding.Default.GetString(data));
For Nancy 2.0.0, Request.Body is a Stream rather than a RequestStream, so doesn't have an AsString method. However, this seems to work:
using (var reqStream = RequestStream.FromStream(Request.Body))
{
var body = reqStream.AsString();
// ... do stuff with body
}
Ideally getting your post data could be accomplished with a simple Bind() call. However, I've seen inconsistent results when using a Bind in a post call such that I've resorted to using the scheme outlined above.
I've seen various discussions about Nancy Bind() working and not working... I've seen both with Post but cannot explain the inconsistency. Where I saw it function properly was where I could guarantee the body of the request was managed as follows:
var data = Encoding.ASCII.GetBytes (postData);
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream ()) {
stream.Write (data, 0, data.Length);
}
However, when sending data that should have been similarly handled (though I couldn't confirm) through WSO2 infrastructure (data serialized as a JSON event dictionary sent to a service proxy), Bind failed while the method above succeeded.
I have the following MVC method.
[System.Web.Mvc.HttpPost]
public ActionResult Listen(string status)
{
CFStatusMessage statusMessage = new CFStatusMessage();
if (!string.IsNullOrEmpty(status))
{
statusMessage = Newtonsoft.Json.JsonConvert.DeserializeObject<CFStatusMessage>(status);
}
return Content(Server.HtmlEncode(status));// View(statusMessage);
}
I am trying to call the above method from Other application .. (Console). I am using HttpWebRequest to make a call to the MVC Method. Using the below code its able to call the method but the Parameter is always coming as empty string.
string content = "{\"status\":\"success\",\"payload\":\"some information\"}";
string url = "http://myrl.com";
var httpWRequest = (HttpWebRequest) WebRequest.Create(url);
httpWRequest.Method = "POST";
httpWRequest.ContentType = "text/json";
var encoding = new ASCIIEncoding();
byte[] data = encoding.GetBytes(string.Format("status={0}", Uri.EscapeDataString(content)));
httpWRequest.ContentLength = data.Length;
Stream stream = httpWRequest.GetRequestStream();
stream.Write(data, 0, data.Length);
var response = (HttpWebResponse)httpWRequest.GetResponse();
With this its making a call to Listen method but status parameter is always coming blank. whereas I want the json string {status:"success",payload:"some information"} as parameter.
What am I doing wrong?
P.S.: I tried the below statement as well, while sending the actual content.
byte[] data = encoding.GetBytes(content);
Regards,
M
If do you need to provide any kind of service from MVC tryout WebApi instead. You can use HTTP REST to do this easily.
Read more here ASP.NET WebApi
You appear to be saying the request is json, but sending it using wwwencoding.
Remove the status={0} line bit & just send the json as is.
You can try something like this
using (var sw = new StreamWriter(httpWRequest.GetRequestStream()))
{
sw.Write(content);
sw.Flush();
sw.Close();
}
I am new to WCF and Rest services, and tried to do some implementation from posts I found on the web, but I am still getting some problems.
So let me explain my scenario.
I have a WPF application, and in it I have a feedback form, which the client can fill up, attach some screenshots, and send it. Now my idea was to gather all this info inside an XML file, which I am already doing successfully, and then uploading this XML file on my server in a particular folder.
Now as I understand it, the client app has to have a POST method to post the stream to the server, and then I should have an aspx page on the server to decode back the stream I get from the POST, and formulate my XML file, and then save it inside the folder, correct me if I'm wrong.
At the moment I have implemented the code on the client as follows :-
public static void UploadFile()
{
serverPath = "http://localhost:3402/GetResponse.aspx";
filePath = "C:\\Testing\\UploadFile\\UploadFile\\asd_asd_Feedback.xml";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(serverPath);
//request.MediaType = "text/xml";
request.ContentType = "text/xml";
//request.Method = "POST";
request.Method = "POST";
//request.ContentLength = contentLength;
//request.ContentType = "application/x-www-form-urlencoded";
using (FileStream fileStream = File.OpenRead(filePath))
using (Stream requestStream = request.GetRequestStream())
{
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int byteCount = 0;
while ((byteCount = fileStream.Read(buffer, 0, bufferSize)) > 0)
{
requestStream.Write(buffer, 0, byteCount);
}
}
string result = String.Empty;
try
{
using (WebResponse response = request.GetResponse())
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
result = reader.ReadToEnd();
}
}
catch (Exception exc)
{
}
if (result == "OK")
{
}
else
{
// error...
}
}
Now how can I pass the requestStream to the GetResponse.aspx page? And is this the correct way to go?
Thanks for your help and time
I don't understand what your code is trying to do. Have you considered actually using a WCF client and a WCF service for doing the actual upload itself?
There is a sample that does this! This blog post details how to use the programming model on the service side, and this follow-up blog post details how to use it on the client side. I've seen it used quite a bit for file upload and image transfer scenarios, so it might help your situation as well! The example present in those blog posts is a file upload one.
Hope this helps!