Consuming REST service with C# code - c#

I am using the following code to get the json result from the service. It works fine for get methods. But when the method type is POST the request address changes to the previous address.
ie;
on the first call to this method the request.address=XXXXX.com:1234/xxx/oldv1.json (method type is get)
and it returns a json string from which I extract another address:XXXXX.com:1234/xxx/newv1.json
and now I call the makerequest method with this endpoint and method type POST, contenttype="application/x-www-form-urlencoded".
When I put breakpint at using (var response = (HttpWebResponse)request.GetResponse()) and checked the request.address value, it was XXXXX.com:1234/xxx/newv1.json
But after that line is executed, the address changes to XXXXX.com:1234/xxx/oldv1.json and the function returns the same response I got with the first Endpoint(XXXXX.com:1234/xxx/oldv1.json).
Can anybody tell what I am doing wrong here?
Is there any better method to consume the service with POST method?
public string MakeRequest(string EndPoint,string Method, string contentType)
{
var request = (HttpWebRequest)WebRequest.Create(EndPoint);
request.Method = Method;
request.ContentLength = 0;
request.ContentType =contentType;
if ( Method == HttpVerb.POST)
{
var encoding = new UTF8Encoding();
var bytes = Encoding.GetEncoding("iso-8859-1").GetBytes("username=123&password=123");
request.ContentLength = bytes.Length;
using (var writeStream = request.GetRequestStream())
{
writeStream.Write(bytes, 0, bytes.Length);
}
}
using (var response = (HttpWebResponse)request.GetResponse())// request.address changes at this line on "POST" method types
{
var responseValue = string.Empty;
if (response.StatusCode != HttpStatusCode.OK)
{
var message = String.Format("Request failed. Received HTTP {0}", response.StatusCode);
throw new ApplicationException(message);
}
// grab the response
using (var responseStream = response.GetResponseStream())
{
if (responseStream != null)
using (var reader = new StreamReader(responseStream))
{
responseValue = reader.ReadToEnd();
}
}
return responseValue;
}
EDIT: Yesterday I asked THIS Question about consuming the service at client side and many suggested it needs to be done at server side as the other domain might not allow accessing the json result at client side.

The issue was about cookies. As I forgot to set the cookies, the request was getting redirected. I had to set cookie container by using
request.CookieContainer = new CookieContainer();

Related

Call a Node Http Triggered azure function inside a .NET core c# console application

I have a Node Http triggered azure function that returns an array in the response body. I want to call this function inside a C# console application and access the array returned by the azure function. My azure function returns the expected response body when I hit it on postman. However this is not the case when I call this endpoint on the c# application as I'm getting a response object with status 200 but content-length is -1. Please note if I do the same call for a normal express application in the c# application, I'm able to get the expected response
Here is my azure function
const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
context.log('HTTP trigger function processed a request.');
const adresses = req.body && req.body.adresses;
if (adresses) {
//make an asyn function call
const locationsPromise = await adresses.map(async (address) => await getLocationCoordinates(address));
const resolvedLocations = await Promise.all(locationsPromise);
context.res = await {
// status: 200, /* Defaults to 200 */
body:{ data: resolvedLocations}
};
}
else {
context.res = await {
status: 400,
body: "Please pass a adresses in the request body"
};
}
};
Here is my C# code I'm using for the call
{
string[] adresses = new string[] { "nairobi", "nakuru", "kericho" };
string apiUrl = "http://localhost:7071/api/Adress-call";
Dictionary<string, string[]> postData1 = new Dictionary<string, string[]>()
{
{ "adresses", adresses },
};
var postData = JsonConvert.SerializeObject(postData1);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(apiUrl);
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = postData.Length;
using (Stream webStream = request.GetRequestStream())
using (StreamWriter requestWriter = new StreamWriter(webStream, Encoding.ASCII))
{
requestWriter.Write(postData);
}
try
{
WebResponse response = request.GetResponse();
using (Stream responseStream = response.GetResponseStream())
{
StreamReader reader = new StreamReader(responseStream, Encoding.UTF8);
DataTable ds = new DataTable();
var pageViewModel = JsonConvert.DeserializeObject<List<LocationModel>>(reader.ReadToEnd());
}
}
catch (WebException ex)
{
WebResponse errorResponse = ex.Response;
using (Stream responseStream = errorResponse.GetResponseStream())
{
StreamReader reader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8"));
String errorText = reader.ReadToEnd();
// log errorText
}
throw;
}
}
The Content-Header may be missing from the response. If you check the HttpWebResponse.ContentLength you'll get a -1. As the docs explain:
If the Content-Length header is not set in the response, ContentLength is set to the value -1.
HttpWebRequest and HttpWebResponse are really old classes that are largely replaced by HttpClient, especially in .NET Core. There were no nullable value types back when these classes were created, so they can only return -1.
All of this should be replaced with HttpClient. The code isn't just simpler, the class itself is thread-safe and can be reused. It caches sockets underneath, which means the app doesn't have to pay the DNS resolution tax each time it tries to call the same endpoint :
var data=new { adresses = new [] { "nairobi", "nakuru", "kericho" }};
var postData = JsonConvert.SerializeObject(data);
var content=new StringContent(data,Encoding.UTF8,"application/json");
var response=await client.PostAsync(content);
At this point you can inspect the status code :
if (response.StatusCode == ...) // Check status code here.
{
...
}
The Content-Length is a Content header. It may be missing, in which case the ContentLength property will be null :
if (response.Content.Headers.ContentLength!=null)
{
long length=response.Content.Headers.ContentLength.Value;
//Use the Content length here
}
Or, using pattern matching :
if (response.Content.Headers.ContentLength is long length)
{
//Use the Content length here
}
Finally, you can read the response as a string with ReadAsStringAsync and deserialize it. That method will take care of decoding the response body :
var json=await response.Content.ReadAsStringAsync();
var models=JsonConvert.DeserializeObject<List<LocationModel>>(json);

Unauthorized error when trying to get Nest Access Token

Everything was working fine until a couple days ago, I started getting an Unauthorized error when trying to get a Nest Access Token. I've double checked and the client ID and client secret code are all correct. Any ideas on what could be causing it?
HttpWebRequest request = WebRequest.CreateHttp("https://api.home.nest.com/oauth2/access_token?");
var token = await request.GetValueFromRequest<NestToken>(string.Format(
"client_id={0}&code={1}&client_secret={2}&grant_type=authorization_code",
CLIENTID,
code.Value,
CLIENTSECRET));
public async static Task<T> GetValueFromRequest<T>(this HttpWebRequest request, string postData = null)
{
T returnValue = default(T);
if (!string.IsNullOrEmpty(postData))
{
byte[] requestBytes = Encoding.UTF8.GetBytes(postData);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
using (var postStream = await request.GetRequestStreamAsync())
{
await postStream.WriteAsync(requestBytes, 0, requestBytes.Length);
}
}
else
{
request.Method = "GET";
}
var response = await request.GetResponseAsync();
if (response != null)
{
using (var receiveStream = response.GetResponseStream())
{
using (var reader = new StreamReader(receiveStream))
{
var json = await reader.ReadToEndAsync();
var serializer = new DataContractJsonSerializer(typeof(T));
using (var tempStream = new MemoryStream(Encoding.UTF8.GetBytes(json)))
{
return (T)serializer.ReadObject(tempStream);
}
}
}
}
return returnValue;
}
While I can't provide an answer I can confirm the same thing is happening to my iOS app in the same timeframe.
Taking my url and post values works fine using postman in chrome. Alamofire is throwing up error 401, as is native swift test code like yours.
Have Nest perhaps changed their https negotiation?
This turned out to be because of a fault on Nest's end which was later fixed.

How to call webmethod from different website

I have website A which is done in ASP.NET and it has in default.aspx
[System.Web.Services.WebMethod]
public string GetCurrentTime(string name)
{
return "Hello " + name + Environment.NewLine + "The Current Time is: "
+ DateTime.Now.ToString();
}
May we call that method somehow from another website B using C#?
Thank you!
May we call that method somehow from another website B using C#?
Yes, you can make REQUESTS to the endpoint using C#. Either GET or POST
Simple GET request
var endPoint = "http://domain.com/default.aspx";
var webReq = (HttpWebRequest)WebRequest.Create(endPoint);
using (var response = webReq.GetResponse()) {
using (var responseStream = response.GetResponseStream()) {
var reader = new StreamReader(responseStream);
var responseString = reader.ReadToEnd();
//Do whatever with responseString
}
}
Simple POST request
var endPoint = "http://domain.com/default.aspx"
var data = "param1=hello&param2=world"
var webReq = (HttpWebRequest)WebRequest.Create(endPoint);
webReq.Method = "POST";
var bytes = Encoding.UTF8.GetBytes(data);
webReq.ContentLength = bytes.Length;
webReq.ContentType = "application/x-www-form-urlencoded";
using (var requestStream = webReq.GetRequestStream()) {
requestStream.Write(bytes, 0, bytes.Length);
}
using (var response = webReq.GetResponse()) {
using (var responseStream = response.GetResponseStream()) {
var reader = new StreamReader(responseStream);
var responseString = reader.ReadToEnd();
//Do whatever with responseString
}
}
This is a simple way of doing it. More info at MSDN.
You can use WebClient or HttpClient on the other hand. You can find example in this post also.
Yes of course, webapi is created intentionally to be called from inside the same website, another website, and from a whatever client (console, winform, wpf, mobile apps, and so on) using c# or another language.
.Net framework has avalaible various classes for calling webapi ex. HttpWebRequest, HttpClient or external libraries ex. RestSharp.

How to set the request body on the client side

Suppose I have the following web method using C# and .NET:
[WebInvoke(UriTemplage="/users", Method="POST")]
[OperationContract]
public User AddNewUser(User u);
It is expected that when you implement POST web method you will accept a request body as part of the incoming HTTP request message. The parameter u is expected to be deserialized from the incoming HTTP message body.
My question is: how do we set this request body on the client side ? It's got to be set somewhere. It really confuses me.
Besides if I added "ResponseFormat = WebMessageFormat.Json" to WebInvoke, how can I deserialize from the returned json string into the User object ?
Thanks.
Your question doesn't reveal what you have tried. If you are using .net on the client then you can use the DataContractSerializer to get the serialized data.
You can then use an HttpWebRequest with the method set to POST.
Add the serialized data to the web request and use the GetResponse() method.
Alternatively you could use Fiddlr to test your web service using requests that you create. It gives you a concise view of exactly what is going up to the server.
To perform a POST request to your WCF Rest method:
private string UseHttpWebApproach<T>(string serviceUrl, string resourceUrl, string method, T requestBody)
{
string responseMessage = null;
var request = WebRequest.Create(string.Concat(serviceUrl, resourceUrl)) as HttpWebRequest;
if (request != null)
{
request.ContentType = "application/json";
request.Method = method;
}
if(method == "POST" && requestBody != null)
{
byte[] requestBodyBytes = ToByteArrayUsingJsonContractSer(requestBody);
request.ContentLength = requestBodyBytes.Length;
using (Stream postStream = request.GetRequestStream())
postStream.Write(requestBodyBytes, 0, requestBodyBytes.Length);
}
if (request != null)
{
var response = request.GetResponse() as HttpWebResponse;
if(response.StatusCode == HttpStatusCode.OK)
{
Stream responseStream = response.GetResponseStream();
if (responseStream != null)
{
var reader = new StreamReader(responseStream);
responseMessage = reader.ReadToEnd();
}
}
else
{
responseMessage = response.StatusDescription;
}
}
return responseMessage;
}
private static byte[] ToByteArrayUsingJsonContractSer<T> (T requestBody)
{
byte[] bytes = null;
var serializer1 = new DataContractJsonSerializer(typeof(T));
var ms1 = new MemoryStream();
serializer1.WriteObject(ms1, requestBody);
ms1.Position = 0;
var reader = new StreamReader(ms1);
bytes = ms1.ToArray();
return bytes;
}
Now Assuming your User object as shown below:
Public Class User
{
Public int UserId {get;set;}
Public string UserName {get;set;}
Public string Password {get;set;}
}
The to call the above method i do:
User objUser = new objUser();
objUser.Username = "Test";
objUser.Password = "Test";
UseHttpWebApproach<User>(serviceBaseUrl, "users", "POST", objUser);

C# - HttpWebRequest - POST

I am trying to make an Http POST to an Apache web server.
I am finding that setting ContentLength seems to be required for the request to work.
I would rather create an XmlWriter directly from GetRequestStream() and set SendChunked to true, but the request hangs indefinitely when doing so.
Here is how my request is created:
private HttpWebRequest MakeRequest(string url, string method)
{
HttpWebRequest request = HttpWebRequest.Create(url) as HttpWebRequest;
request.Method = method;
request.Timeout = Timeout; //Property in my class, assume it's 10000
request.ContentType = "text/xml"; //I am only writing xml with XmlWriter
if (method != WebRequestMethods.Http.Get)
{
request.SendChunked = true;
}
return request;
}
How can I make SendChunked work so I do not have to set ContentLength? I do not see a reason to store the XmlWriter's string somewhere before sending it to the server.
EDIT: Here is my code causing the problem:
using (Stream stream = webRequest.GetRequestStream())
{
using (XmlWriter writer = XmlWriter.Create(stream, XmlTags.Settings))
{
Generator.WriteXml<TRequest>(request, writer);
}
}
Before I did not have a using on the Stream object returned from GetRequestStream(), I assumed XmlWriter closed the stream when disposed, but this is not the case.
One of the answers below, let me to this. I'll mark them as the answer.
As far as HttpWebRequest is concerned, my original code works just fine.
This should work the way you have it written. Can we see the code that actually does the uploading? Are you remembering to close the stream?
Looking at the example at http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.sendchunked.aspx they still set a content length. Really the bottom line is that if you are sending data you need to tell the receiver how much data you will be sending. Why don't you know how much data you are sending before you send the request?
ContentLength:
Property Value
Type: System..::.Int64
The number of bytes of data to send to the Internet resource. The default is -1, which indicates the property has not been set and that there is no request data to send.
Edit for Aaron (I was wrong):
HttpWebRequest httpWebRequest = HttpWebRequest.Create("http://test") as HttpWebRequest;
httpWebRequest.SendChunked = true;
MessageBox.Show("|" + httpWebRequest.TransferEncoding + "|");
From System.Net.HttpWebRequest.SerializeHeaders():
if (this.HttpWriteMode == HttpWriteMode.Chunked)
{
this._HttpRequestHeaders.AddInternal("Transfer-Encoding", "chunked");
}
else if (this.ContentLength >= 0L)
{
this._HttpRequestHeaders.ChangeInternal("Content-Length", this._ContentLength.ToString(NumberFormatInfo.InvariantInfo));
}
I prefer to use a generic method to comply this kind of stuff. Take a look at the XML sender request below. It will serialize your XML and then send it with the appropriate ContentType :
public bool SendXMLRequest<T>(T entity, string url, string method)
{
HttpWebResponse response = null;
bool received = false;
try
{
var request = (HttpWebRequest)WebRequest.Create(url);
var credCache = new CredentialCache();
var netCred = new NetworkCredential(YOUR_LOGIN_HERE, YOUR_PASSWORD_HERE, YOUR_OPTIONAL_DOMAIN_HERE);
credCache.Add(new Uri(url), "Basic", netCred);
request.Credentials = credCache;
request.Method = method;
request.ContentType = "application/xml";
request.SendChunked = "GET" != method.ToUpper();
using (var writer = new StreamWriter(request.GetRequestStream()))
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (StringWriter textWriter = new Utf8StringWriter())
{
serializer.Serialize(textWriter, entity);
var xml = textWriter.ToString();
writer.Write(xml);
}
}
response = (HttpWebResponse)request.GetResponse();
received = response.StatusCode == HttpStatusCode.OK; //YOu can change the status code to check. May be created, etc...
}
catch (Exception ex) { }
finally
{
if(response != null)
response.Close();
}
return received;
}

Categories

Resources