How to get response data from RestSharp to download for user? - c#

I am using RestSharp to call an HTTP service via a Querystring. The service generates a Word document.
When I call this service, it looks like a Word document is being returned in the "Content" property, but I struggling to work out how to return this content to the user via the traditional download window as a word document for saving.
public ActionResult DocGen(string strReportId)
{
var client = new RestClient("http://localhost:88");
var request = new RestRequest("DocGen/{id}", Method.GET);
request.AddUrlSegment("id", "1060"); // replaces matching token in request.Resource
// execute the request
//RestResponse response = (RestResponse) client.Execute(request);
IRestResponse response = client.Execute(request);
if (response.ErrorException != null)
{
const string message = "Error retrieving response. Check inner details for more info.";
var myException = new ApplicationException(message, response.ErrorException);
throw myException;
}
// Important and simple line. response.rawbytes was what I was missing.
return File(response.RawBytes,response.ContentType,"sample.doc");
}
Should this be an action?
The content type seems correct ie Word.11
So how do I code get this Response.Content back to the user?
Many thanks in advance.
EDIT
I was closer to the solution than I thought. Power to RestSharp I guess !! See above. Now there might be a better way, and I am all ears for any suggestions, but this is where I am at at present.

return File(response.RawBytes,response.ContentType,"sample.doc");
In case anyone may benefit.

Related

RestSharp "Not found" response

I'm trying to use the Youtube Data API v3 with RestSharp. Problem is: I get the response: "Not found" when I try to send a request.
var client = new RestClient("https://www.googleapis.com/youtube/v3/channels?part=statistics");
var request = new RestRequest(Method.POST);
request.AddParameter("key", my api key);
request.AddParameter("id", my channel id);
request.AddParameter("fields", "items/statistics/subscriberCount");
IRestResponse response = client.Execute(request);
var content = response.Content;
Console.WriteLine(response.Content);
this.BeginInvoke((System.Windows.Forms.MethodInvoker)delegate () { label1.Text = response.Content; });
This seems to be a problem with RestSharp or the code because in the Google API explorer thing you can test out the inputs and it works there.
I was trying the same thing today and was stuck on the same step. With an hour of effort I figured out.
In the RestClient(baseUri) constructor, just pass the base url and not the whole path.
While initializing RestClient(resource, Method), pass the path as resource and method will be the second parameter.

Differences between using C# HttpClient API and the postman testing? Client call works on postman, but not C# httpClient getAsync

I am testing a REST API post, and it works well when I try it on Postman. However, in some scenario (related to the posting XML data) if I post with HttpClient API, I would receive the following error:
Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
But the same XML content works fine on Postman with status OK and proper response.
What is the differences between using the C# HttpClient API and the postman testing? How can I configure my API call to match with the behavior on postman?
Here I attached the source code, and the Postman screenshot
public void createLoan()
{
string baseCreateLoanUrl = #"https://serverhost/create?key=";
var strUCDExport = XDocument.Load(#"C:\CreateLoan_testcase.xml");
using (var client = new HttpClient())
{
var content = new StringContent(strUCDExport.ToString(), Encoding.UTF8, Mediatype);
string createLoanApi = string.Concat(baseCreateLoanUrl, APIKey);
try
{
var response = client.PostAsync(createLoanApi, content).Result;
}
catch (Exception ex)
{
MessageBox.Show("Error Happened here...");
throw;
}
if (response.IsSuccessStatusCode)
{
// Access variables from the returned JSON object
string responseString = response.Content.ReadAsStringAsync().Result;
JObject jObj = JObject.Parse(responseString);
if (jObj.SelectToken("failure") == null)
{
// First get the authToken
string LoanID = jObj["loanStatus"]["id"].ToString();
MessageBox.Show("Loan ID: " + LoanID);
}
else
{
string getTokenErrorMsg = string.Empty;
JArray errorOjbs = (JArray) jObj["failure"]["errors"];
foreach (var errorObj in errorOjbs)
{
getTokenErrorMsg += errorObj["message"].ToString() + Environment.NewLine;
}
getTokenErrorMsg.Dump();
}
}
}
Thanks for Nard's comment, after comparing the header, I found the issue my client header has this:
Expect: 100-continue
While postman doesn't has.
Once I removed this by using the ServicePointManager:
ServicePointManager.Expect100Continue = false;
Everything seems fine now. Thanks all the input!
My gut tells me it's something simple. First, we know the API works, so I'm thinking it's down to how you are using the HttpClient.
First things first, try as suggested by this SO answer, creating it as a singleton and drop the using statement altogether since the consensus is that HttpClient doesn't need to be disposed:
private static readonly HttpClient HttpClient = new HttpClient();
I would think it would be either there or an issue with your content encoding line that is causing issues with the API. Is there something you are missing that it doesn't like, I bet there is a difference in the requests in Postman vs here. Maybe try sending it as JSON ala:
var json = JsonConvert.SerializeObject(strUCDExport.ToString());
var content = new StringContent(json, Encoding.UTF8, Mediatype);
Maybe the header from Postman vs yours will show something missing, I think the real answer will be there. Have fiddler running in the background, send it via Postman, check it, then run your code and recheck. Pay close attention to all the attribute tags on the header from Postman, the API works so something is missing. Fiddler will tell you.
I was struggling with this for 2 days when I stumbled over Fiddler which lets you record the traffic to the service. After comparing the calls I saw that I had missed a header in my code.

RestSharp - Retrieving Authorization token from POSTed response

I am trying to pass username and password to the following URL :
https://maxcvservices.dnb.com/rest/Authentication
According to the documentation the user_id and password must be passed as headers with the keys: x-dnb-user, x-dnb-pwd respectively.
I thus far have the following code which seems to work but I am unable to retrieve the auth token returned by the response object:
public static void Main (string[] args)
{
var client = new RestClient ("https://maxcvservices.dnb.com/rest/Authentication");
var request = new RestRequest (Method.POST);
request.AddHeader("x-dnb-user", myEmail);
request.AddHeader("x-dnb-pwd", myPassword);
IRestResponse resp = client.Execute(request);
var content = resp.Content;
Console.WriteLine (resp.StatusDescription);
Console.WriteLine (resp.StatusCode);
}
When I try printing the content I get a blank line but what I am actually expecting is the auth token that is returned by the service. A couple of things I think I am doing in the code (but not sure), is passing the userid and password as headers in the POST request which is what is required. The token is returned as the value of the 'Authorization' field in the response object. I was wondering how I might print the token. Also the statusDescription,statusCode both print OK which tells me I have the correct request but am unable to locate the auth token in the response. Any help would be much appreciated in guiding me on how to access the auth token in the Authorization field of the returned POST response.
So you're trying to get the HttpHeader values for Authorization from the IRestResponse object?
You could use e.g. use LINQ for that:
var authroizationHeaderFromResponse = resp.Headers.FirstOrDefault(h => h.Name == "Authorization");
if (authroizationHeaderFromResponse != null)
{
Console.WriteLine(authroizationHeaderFromResponse.Value);
}
Which yields
INVALID CREDENTIALS
You assume that if the response status code is 200 - OK, then there must be a response body accompanying it.
Does the documentation specifically state that you should expect a token in the response body in return?
The D&B developers could send a 200 - OK response with no response body if they want, or they can add their serialized token (JSON, XML etc) elsewhere, e.g. in a header field.
An example of this can be seen in this code from an ASP.NET Web API returning a response from a successful PUT
if (result.Success)
{
var dto = Mapper.Map<TEntity, TDto>(result.Data as TEntity);
var response = Request.CreateResponse(HttpStatusCode.Created, dto);
var uri = Url.Link("DefaultApi", new {id = dto.Id});
response.Headers.Location = new Uri(uri);
return response;
}
This would return a 200 - OK with a serialized object (result.Data) in the response body, but there's nothing wrong with me changing the following
var response = Request.CreateResponse(HttpStatusCode.Created, dto);
To something like
var response = Request.CreateResponse(HttpStatusCode.Created);
That way you would still get a 200 - OK response, but without a response body. This of course is against the recommendations of the HTTP/1.1 Standard for PUT verbs, but it would still work.
I could even do this for giggles
throw new HttpResponseException(HttpStatusCode.Created);
And you would still get a 200 - OK response. Somewhat evil, but possible.
I would suggest trying to fetching data from another resource with the x-dnb-user and x-dnb-pwd header fields set, and check if a response body is returned then. Perhaps D&B was inspired by Basic Authentication when implementing these header fields, and as such require them to be present in every request?
It's worth a try.
Let me know how that works out.
Look in the Headers collection of IRestResponse. It will probably be there rather than the content.
Hth
Oli
It could be that the AUTHTOKEN comes back with the cookies, as this is a common approach.
In this case, you'll need to attach a CookieContanier to your IRestClient, then this container will store the cookies. Provided you use the same client for subsequent requests, that auth cookie will let you in.
private CookieContainer _cookieJar;
...
_cookieJar = new CookieContainer();
_client.CookieContainer = _cookieJar;
You can then inspect the container after a request
_client.PostAsync(MyRequest, (r, h) =>
{
r.Cookies... // inspect em

Trouble with HTTP post in Android

I am fairly new at android development. Here is my problem:
I have this endpoint: http://bdzservice.apphb.com/api/Image which accepts POST requests
The body of the request is a String, example:
/SearchServlet?action=showMap&id1=25&date=09/12/2013&st1=5216000&st2=5229030
Invalid example: {"/SearchServlet?action=showMap&id1=25&date=09/12/2013&st1=5216000&st2=5229030"}
Invalid example2: {mapHref : "/SearchServlet?action=showMap&id1=25&date=09/12/2013&st1=5216000&st2=5229030"}
Invalid example3: {"mapHref" : "/SearchServlet?action=showMap&id1=25&date=09/12/2013&st1=5216000&st2=5229030"}
this is the code I've written so far:
HttpClient client = new DefaultHttpClient();
String message;
HttpPost httpPost = new HttpPost("http://bdzservice.apphb.com/api/Image");
try
{
message = url;
StringEntity se = new StringEntity(message, "UTF8");
se.setContentType("application/json");
httpPost.setEntity(se);
httpPost.setHeader("Content-type", "application/json");
HttpResponse resp = client.execute(httpPost);
if (resp != null)
{
if (resp.getStatusLine().getStatusCode() == 204)
result = true;
}
Log.d("Status line", "" + resp.getStatusLine().getStatusCode());
}
I always get an error when trying to post data, but when I manually (through a REST client) post data I get an OK result.
Can someone help me with this?
EDIT
This is the endpoint, It is written in C# (Web Api)
EDIT 2: Tried modifying the service to return body it recieved (see the comment in the url) and it retruns null, so the problem is it is not getting the body (or just reading it wrong)
I have created a library here for .NET Standard that does POST and PUT. I have tested it thoroughly on Android. There are quick start samples to get going quickly. The sample only has a PUT, but the principle should be the same:
https://bitbucket.org/MelbourneDeveloper/restclient-.net/overview

C# Post XML file using RestSharp

I have written a method to post messages to an uri.
public string RestClientPost(string uri, string message = null)
{
var client = new RestClient(uri);
var request = new RestRequest(Method.POST);
request.AddHeader("Accept", "text/xml");
if (!string.IsNullOrEmpty(message))
request.AddParameter(message, ParameterType.RequestBody);
var result = "";
var response = client.Execute(request);
if (response.StatusCode == HttpStatusCode.OK)
{
result = response.Content;
Console.WriteLine(result);
}
else
{
result = response.StatusCode.ToString();
}
return result;
}
and below code is used above method to post.
public void test123()
{
string uri = "myuri"; //private uri, cannot expose.
var file= System.IO.File.ReadAllText(Path.Combine(Settings.EnvValPath, "RestClientXML", "test.XML"));
var content = new RestClientServices().RestClientPost(uri, file);
}
however, it returns "Unsupported Media type".
my test.XML's content is
<customer>
<customerName>test</customerName >
<customerStatus>OK</customerStatus >
</customer>
And using Advanced Rest Client Plugin for Google Chrome, I'm able to post it and return with string that I wanted. Is there something wrong?? I set "content-type" to "text/xml" in Advanced Rest Client.
The return message is id of the customer. e.g: 2132
im using postman,
if you can call any xml web services with this tools , then you can click on code and select restsharp and copy paste it to your code
This happened because the header "Accept" is to specify a type of return object. In this case a value of a variable content, not the type of content to send. Specify a type of content to send with: "Content-Type: application/xml".
If a return type of POST request is a media file, you can use 'image/png' or 'image/jpeg'. You can use multiple accept header values like: "application/xml, application/xhtml+xml, and image/png".
For example, you can use Fiddler to debug HTTP(s) traffic - it's a good tool for web developers.

Categories

Resources