In my action I have Request property. I want to use this request to get response from another URL (from another website). Is it possible?
To request a external webpage from C# code and retrieve it as a string. You can use the following snippet of code:
try
{
var request = WebRequest.Create("http://www.steelcm.com/");
var response = request.GetResponse();
var responseStream = response.GetResponseStream();
using(var reader = new StreamReader(responseStream))
{
// Convert stream object to string
string myWebPage = reader.ReadToEnd();
}
}catch(Exception e)
{
// TODO: Handle error exception
}
This will return the HTML in the string variable myWebPage. Also you will need to include the following 2 libraries:
using System.Net;
using System.IO;
Of course you can manipulate the request URL dependant on a users input.
Related
I am trying to do webservice async so ui can respond and websevice call is done in background, but since i am little inexpirienced with async stuff i need little help.
Here is my code:
Inside my action result i have call to method which have asyinc stuff in it
public ActionResult SavePackage(string ParcelNumber)
{
/////some other stuff
SaveAsync(ParcelNumber);
}
And
then i have async method :
public async Task SaveAsync(string ParcelNumber)
{
await api.RegisterPackage(ParcelNumber);
}
Which calls api:
public async Task RegisterPackage(string ParcelNumber)
{
var rk = "some api http";
HttpWebRequest request = WebRequest.Create(rk) as HttpWebRequest;
request.Headers.Add("cache-control", "no-cache");
request.Method = "POST";
request.ContentType = "application/json";
string data = "{\n \"ParcelNumber\": \"" + ParcelNumber+ "\"}";
byte[] dataStream = Encoding.UTF8.GetBytes(data);
Stream newStream = request.GetRequestStream();
// Send the data.
newStream.Write(dataStream, 0, dataStream.Length);
newStream.Close();
Task<WebResponse> getResponseTask = Task<WebResponse>.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, null);
await getResponseTask.ContinueWith(getResponseAntecedent =>
{
WebResponse webResponse = getResponseAntecedent.Result;
using (var reader = new StreamReader(webResponse.GetResponseStream()))
{
string error = reader.ReadToEnd();
//TODO: use JSON.net to parse this string and look at the error message
var myDeserializedObjList3 = Newtonsoft.Json.JsonConvert.DeserializeObject<RootObjectAtt>(error);
var isValid = myDeserializedObjList3.IsValid;
var ModelErrors = myDeserializedObjList3.ModelErrors;
var ValidationErrors = myDeserializedObjList3.ValidationErrors;
}
});
}
My problem is that the above code is still waiting for response to finish (and that can take about 20 second), and i would like if possible when i call the api i could go back to my ui and let ppl do their stuff while api is proccessed in background.
Anybody have any suggestion?
As I describe on my blog, async does not change the HTTP protocol.
First, the best solution to your problem is to not change your ASP.NET action method at all. Instead, have the actual UI application issue the call asynchronously. If your UI app is a .NET app, then it can use async/await; if it's a web app (i.e., JavaScript), then it can use an AJAX call. Another good option is to introduce SignalR, which allows the server to signal when the work is done.
If you really want to run ASP.NET code outside of a request (which is never recommended), then you can use one of the techniques I describe on my blog for ASP.NET fire-and-forget.
I have some strange problem. I am using Microsoft.AspNet.WebApi.Client.5.2.3 for simple .NET client for API. I want to post some data to API. I am using PostAsJsonAsync method for it.
using (var client = new HttpClient())
{
var adress = new Uri("http://localhost:28906/v1/things?access_token=SOMETOKEN");
var result = await client.PostAsJsonAsync(adress, new ThingModel() { Name = "test"});
}
When I am sending request, my uri is transformed from "http://localhost:28906/v1/things?access_token=SOMETOKEN" to "http://localhost:28906/v1/things/?access_token=SOMETOKEN" ( '/' is inserted before '?'). And request becomes wrong. How can I overcome this? In fact, how can I pass query string and json body?
Something is going to call my web server with the url http://testserver.fake.com/responses/123 with a POST.
What I want to do is save the body of the POST to a file such as "\fileserver\response\123.response".
What should the signature look like on the controller?
Here you go:
public ActionResult SavePostAction(int responseId)
{
// read post data straight from the request.
string postData = new StreamReader(HttpContext.Request.InputStream).ReadToEnd();
// create a json file
string json = JsonConvert.SerializeObject(new
{
postData = postData
});
// Save the file to your filesystem\db etc..
System.IO.File.WriteAllText(#"c:\temp\" + responseId + ".reponse", json);
return new EmptyResult(); // or whatever
}
I could really use some help understanding why this unit test is failing. I suspect it's due to the way I'm handling the streams. I have a number of other tests that successfully use this self-hosting server setup, but they all read services that return primitives like strings.
Here's the test in question:
using System.Net.Http;
using System.Threading;
using System.Web.Http.SelfHost;
using AttributeRouting.Web.Http.SelfHost;
using NUnit.Framework;
[TestFixture]
public class StreamControllerTests
{
[Test]
public void Can_get_simple_streaming_service_to_respond()
{
using (var config = new HttpSelfHostConfiguration("http://in-memory"))
{
config.Routes.MapHttpAttributeRoutes();
using (var server = new HttpSelfHostServer(config))
{
// I get the same behavior if I use HttpClient
using (var client = new HttpMessageInvoker(server))
{
using (var request = new HttpRequestMessage(HttpMethod.Get, "http://in-memory/stream/notepad"))
{
using (HttpResponseMessage response = client.SendAsync(request, CancellationToken.None).Result)
{
Assert.IsNotNull(response.Content);
// FAILS, content length is 0
Assert.Greater(response.Content.Headers.ContentLength, 0);
}
}
}
}
}
And here is the controller that feeds the test:
using System;
using System.Drawing.Imaging;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using AttributeRouting.Web.Mvc;
using MyUnitTests.Properties;
[GET("stream/notepad")]
public HttpResponseMessage StreamAnImageFromResources()
{
var imageStream = new MemoryStream(); // closed when stream content is read
Resources.a_jpeg_in_resources.Save(imageStream, ImageFormat.Jpeg);
try
{
HttpResponseMessage response = Request.CreateResponse();
// at this point, imageStream contains about 120K bytes
response.Content = new StreamContent(imageStream);
return response;
}
catch (Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.ServiceUnavailable, e);
}
}
I don't see anything really wrong but your test is more complicated than it needs to be.
Try this,
[Test]
public void Can_get_simple_streaming_service_to_respond2()
{
var config = new HttpConfiguration();
config.Routes.MapHttpAttributeRoutes();
var server = new HttpServer(config);
var client = new HttpClient(server);
var request = new HttpRequestMessage(HttpMethod.Get, "http://in-memory/stream/notepad");
HttpResponseMessage response = client.SendAsync(request, CancellationToken.None).Result;
Assert.IsNotNull(response.Content);
// FAILS, content length is 0
Assert.Greater(response.Content.Headers.ContentLength, 0);
}
EDIT: In the comments, Darrel gave me the true answer, which I'm moving to the answer body for visibility:
Check the position of your image stream after doing Save. You need to reset it back to 0 before passing to StreamContent. Also, you might want to consider doing GetManifestResourceStream instead, it will save copying the bytes into managed memory.
I'm building an application in ASP.NET MVC (using C#) and I would like to know how I can perform calls like curl http://www.mywebsite.com/clients_list.xml inside my controller
Basically I would like to build a kind of REST API to perform actions such as show edit and delete, such as Twitter API.
But unfortunately until now I didn't find anything besides that cURL for windows on this website: http://curl.haxx.se/
So I don't know if is there any traditional way to retrieve this kind of call from URL with methods like post delete and put on the requests, etc...
I just would like to know an easy way to perform commands like curl inside my controller on my ASP.NET MVC Application.
UPDATE:
Hi so I managed to make GET Requests but now I'm having a serious problem in retrieve POST Request for example, I'm using the update status API from Twitter that in curl would work like this:
curl -u user:password -d "status=playing with cURL and the Twitter API" http://twitter.com/statuses/update.xml
but on my ASP.NET MVC application I'm doing like this inside my custom function:
string responseText = String.Empty;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://twitter.com/statuses/update.xml");
request.Method = "POST";
request.Credentials = new NetworkCredential("username", "password");
request.Headers.Add("status", "Tweeting from ASP.NET MVC C#");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
responseText = sr.ReadToEnd();
}
return responseText;
Now the problem is that this request is returning 403 Forbidden,
I really don't know why if it works perfectly on curl
:\
UPDATE:
I finally manage to get it working, but probably there's a way to make it cleaner and beautiful, as I'm new on C# I'll need more knowledge to do it, the way the POST params are passed makes me very confused because is a lot of code to just pass params.
Well, I've created a Gist - http://gist.github.com/215900 , so everybody feel free to revise it as you will. Thanks for your help çağdaş
also follow the code here:
public string TwitterCurl()
{
//PREVENT RESPONSE 417 - EXPECTATION FAILED
System.Net.ServicePointManager.Expect100Continue = false;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://twitter.com/statuses/update.xml");
request.Method = "POST";
request.Credentials = new NetworkCredential("twitterUsername", "twitterPassword");
//DECLARE POST PARAMS
string headerVars = String.Format("status={0}", "Tweeting from ASP.NET MVC C#");
request.ContentLength = headerVars.Length;
//SEND INFORMATION
using (StreamWriter streamWriter = new StreamWriter(request.GetRequestStream(), ASCIIEncoding.ASCII))
{
streamWriter.Write(headerVars);
streamWriter.Close();
}
//RETRIEVE RESPONSE
string responseText = String.Empty;
using (StreamReader sr = new StreamReader(request.GetResponse().GetResponseStream()))
{
responseText = sr.ReadToEnd();
}
return responseText;
/*
//I'M NOT SURE WHAT THIS IS FOR
request.Timeout = 500000;
request.ContentType = "application/x-www-form-urlencoded";
request.UserAgent = "Custom Twitter Agent";
#if USE_PROXY
request.Proxy = new WebProxy("http://localhost:3000", false);
#endif
*/
}
Try using Microsoft.Http.HttpClient. This is what your request would look like
var client = new HttpClient();
client.DefaultHeaders.Authorization = Credential.CreateBasic("username","password");
var form = new HttpUrlEncodedForm();
form.Add("status","Test tweet using Microsoft.Http.HttpClient");
var content = form.CreateHttpContent();
var resp = client.Post("http://www.twitter.com/statuses/update.xml", content);
string result = resp.Content.ReadAsString();
You can find this library and its source included in the WCF REST Starter kit Preview 2, however it can be used independently of the rest of the stuff in there.
P.S. I tested this code on my twitter account and it works.
Example code using HttpWebRequest and HttpWebResponse :
public string GetResponseText(string url) {
string responseText = String.Empty;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (StreamReader sr = new StreamReader(response.GetResponseStream())) {
responseText = sr.ReadToEnd();
}
return responseText;
}
To POST data :
public string GetResponseText(string url, string postData) {
string responseText = String.Empty;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentLength = postData.Length;
using (StreamWriter sw = new StreamWriter(request.GetRequestStream())) {
sw.Write(postData);
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (StreamReader sr = new StreamReader(response.GetResponseStream())) {
responseText = sr.ReadToEnd();
}
return responseText;
}
This is the single line of code I use for calls to a RESTful API that returns JSON.
return ((dynamic) JsonConvert.DeserializeObject<ExpandoObject>(
new WebClient().DownloadString(
GetUri(surveyId))
)).data;
Notes
The Uri is generated off stage using the surveyId and credentials
The 'data' property is part of the de-serialized JSON object returned
by the SurveyGizmo API
The Complete Service
public static class SurveyGizmoService
{
public static string UserName { get { return WebConfigurationManager.AppSettings["SurveyGizmo.UserName"]; } }
public static string Password { get { return WebConfigurationManager.AppSettings["SurveyGizmo.Password"]; } }
public static string ApiUri { get { return WebConfigurationManager.AppSettings["SurveyGizmo.ApiUri"]; } }
public static string SurveyId { get { return WebConfigurationManager.AppSettings["SurveyGizmo.Survey"]; } }
public static dynamic GetSurvey(string surveyId = null)
{
return ((dynamic) JsonConvert.DeserializeObject<ExpandoObject>(
new WebClient().DownloadString(
GetUri(surveyId))
)).data;
}
private static Uri GetUri(string surveyId = null)
{
if (surveyId == null) surveyId = SurveyId;
return new UriBuilder(ApiUri)
{
Path = "/head/survey/" + surveyId,
Query = String.Format("user:pass={0}:{1}", UserName, Password)
}.Uri;
}
}
Look into the System.Net.WebClient class. It should offer the functionality you require. For finer grained control, you might find WebRequest to be more useful, but WebClient seems the best fit for your needs.