How to call webmethod from different website - c#

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.

Related

POST JSON Data to web API in SSIS Script task from SQL

I have been searching for an answer to this question, but I keep coming up short so hopefully I can find an answer. Admittedly I am not the best C# programmer and this is born out of necessity and not having a resource to help develop this for me, so I have jumped in feet first.
I have some code that I have successfully posted JSON data to the API IF I hard code the JSON string, but I would like to set the results from a SQL query as an OBJ and then serialize them using NEWTONSOFT.JSON to pass to the API in place of the hard coded data.
public void Main()
{
string url = Dts.Variables["$Package::url"].Value.ToString();
string user = Dts.Variables["$Package::user"].Value.ToString();
string pwd = Dts.Variables["$Package::pwd"].GetSensitiveValue().ToString();
string result = Dts.Variables["User::JSON"].Value.ToString();
var JsonResult = JsonConvert.SerializeObject(result);
var request = (HttpWebRequest)WebRequest.Create(url);
string authHeader = System.Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(user + ":" + pwd));
request.Headers.Add("Authorization", "Basic" + " " + authHeader);
request.ContentType = "application/json";
request.Accept = "application/json";
request.Method = "POST";
request.Headers.Add("Cookie: freedomIdentifyKey=XX");
result.ToString();
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
streamWriter.Write(JsonResult);
streamWriter.Flush();
streamWriter.Close();
var httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result2 = streamReader.ReadToEnd();
}
}
Dts.TaskResult = (int)ScriptResults.Success;
}
I keep getting Error: 0x1 at Script Task: Exception has been thrown by the target of an invocation.
Any thoughts on how I could resolve this?
You don't need to use a StreamWriter.
string url = Dts.Variables["$Package::url"].Value.ToString();
string user = Dts.Variables["$Package::user"].Value.ToString();
string pwd = Dts.Variables["$Package::pwd"].GetSensitiveValue().ToString();
string result = Dts.Variables["User::JSON"].Value.ToString();
var JsonResult = JsonConvert.SerializeObject(result);
var request = (HttpWebRequest)WebRequest.Create(url);
string authHeader = System.Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(user + ":" + pwd));
request.Headers.Add("Authorization", "Basic" + " " + authHeader);
request.ContentType = "application/json";
request.Accept = "application/json";
request.Method = "POST";
request.Headers.Add("Cookie: freedomIdentifyKey=XX");
using (var requestStream = request.GetRequestStream())
{
requestStream.Write(JsonResult);
using (var dataStream = response.GetResponseStream())
{
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader(dataStream);
// Read the content.
string responseFromServer = reader.ReadToEnd();
}
}
And if you want to use HttpClient instead:
string url = Dts.Variables["$Package::url"].Value.ToString();
string user = Dts.Variables["$Package::user"].Value.ToString();
string pwd = Dts.Variables["$Package::pwd"].GetSensitiveValue().ToString();
string result = Dts.Variables["User::JSON"].Value.ToString();
// HttpClient is intended to be instantiated once per application, rather than per-use. See Remarks.
var client = new HttpClient();
// Call asynchronous network methods in a try/catch block to handle exceptions.
try
{
var response = await client.PostAsync(url, result);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
}
catch(HttpRequestException e)
{
// do something
}
Not tested
I was able to get this sorted out. The issue wasn't with the code, but rather with the Newtonsoft.JSON package. It was failing before it even got to the code and I was trying to run it as a SQL 2016 target. When I switched back to a 2019 project it ran fine. To get it to run as a 2016, I installed NEWTONSOFT.JSON using the GACUTIL and it runs great now.
I did make a change and used an SQL query in the code instead of using an execute SQL task and then passing it to a variable.

using OpenTSDB HTTP api in .NET : 400 Bad Request

I'm trying to use .net to put datapoints in OpenTSDB, using the HTTP /api/put API.
I've tried with httpclient, webRequest and HttpWebRequest. The outcome is always 400 - bad request: chunked request not supported.
I've tried my payload with an api tester (DHC) and works well.
I've tried to send a very small payload (even plain wrong, like "x") but the reply is always the same.
Here's one of my code instances:
public async static Task PutAsync(DataPoint dataPoint)
{
try
{
HttpWebRequest http = (HttpWebRequest)WebRequest.Create("http://127.0.0.1:4242/api/put");
http.SendChunked = false;
http.Method = "POST";
http.ContentType = "application/json";
Encoding encoder = Encoding.UTF8;
byte[] data = encoder.GetBytes( dataPoint.ToJson() + Environment.NewLine);
http.Method = "POST";
http.ContentType = "application/json; charset=utf-8";
http.ContentLength = data.Length;
using (Stream stream = http.GetRequestStream())
{
stream.Write(data, 0, data.Length);
stream.Close();
}
WebResponse response = http.GetResponse();
var streamOutput = response.GetResponseStream();
StreamReader sr = new StreamReader(streamOutput);
string content = sr.ReadToEnd();
Console.WriteLine(content);
}
catch (WebException exc)
{
StreamReader reader = new StreamReader(exc.Response.GetResponseStream());
var content = reader.ReadToEnd();
}
return ;
}
where I explicitly set to false the SendChunked property.
note that other requests, like:
public static async Task<bool> Connect(Uri uri)
{
HttpWebRequest http = (HttpWebRequest)WebRequest.Create("http://127.0.0.1:4242/api/version");
http.SendChunked = false;
http.Method = "GET";
// http.Headers.Clear();
//http.Headers.Add("Content-Type", "application/json");
http.ContentType = "application/json";
WebResponse response = http.GetResponse();
var stream = response.GetResponseStream();
StreamReader sr = new StreamReader(stream);
string content = sr.ReadToEnd();
Console.WriteLine(content);
return true;
}
work flawlessly.
I am sure I am doing something really wrong.
I'd like to to reimplement HTTP in Sockets from scratch.
I've found a solution I'd like to share here.
I've used wireshark to sniff my packets, and I've found that this header is added:
Expect: 100-continue\r\n
(see 8.2.3 of https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html)
This is the culprit. I've read the post http://haacked.com/archive/2004/05/15/http-web-request-expect-100-continue.aspx/ by Phil Haack, and found that HttpWebRequest puts that header by default, unless you tell it to stop. In this article I've found that using ServicePointManager I can do just this.
Putting the following code on top of my method, when declaring the http object, makes it work very well, and solves my issue:
var uri = new Uri("http://127.0.0.1:4242/api/put");
var spm = ServicePointManager.FindServicePoint(uri);
spm.Expect100Continue = false;
HttpWebRequest http = (HttpWebRequest)WebRequest.Create(uri);
http.SendChunked = false;

How can I simultaneously pass args and upload a file to a Web API Controller Method?

I decided that my question here isn't really what I want to do - the XML I need to send is a lot longer, potentially, than I really want to send in a URI.
It didn't "feel" right doing that, and this unsealed the deal.
I need to send both a couple of args AND a file to my Web API app from a client (handheld/CF) app.
I may have found the code for receiving that, from here [
http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-2]
Specifically, Wasson's Controller code here looks like it very well might work:
public async Task<HttpResponseMessage> PostFile()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
try
{
StringBuilder sb = new StringBuilder(); // Holds the response body
// Read the form data and return an async task.
await Request.Content.ReadAsMultipartAsync(provider);
// This illustrates how to get the form data.
foreach (var key in provider.FormData.AllKeys)
{
foreach (var val in provider.FormData.GetValues(key))
{
sb.Append(string.Format("{0}: {1}\n", key, val));
}
}
// This illustrates how to get the file names for uploaded files.
foreach (var file in provider.FileData)
{
FileInfo fileInfo = new FileInfo(file.LocalFileName);
sb.Append(string.Format("Uploaded file: {0} ({1} bytes)\n", fileInfo.Name, fileInfo.Length));
}
return new HttpResponseMessage()
{
Content = new StringContent(sb.ToString())
};
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
...but now I need to know how to send it; other calls from the client are of the form:
http://<IPAddress>:<portNum>/api/<ControllerName>?arg1=Bla&arg2=Blee
but how does the file I need to send/attach get passed along? It is a XML file, but I don't want to append the whole thing to the URI, as it can be quite large, and doing so would be horrendously weird.
Does anybody know how to accomplish this?
UPDATE
Following the crumbs tvanfosson dropped below, I found code here which I think I can adapt to work on the client:
var message = new HttpRequestMessage();
var content = new MultipartFormDataContent();
foreach (var file in files)
{
var filestream = new FileStream(file, FileMode.Open);
var fileName = System.IO.Path.GetFileName(file);
content.Add(new StreamContent(filestream), "file", fileName);
}
message.Method = HttpMethod.Post;
message.Content = content;
message.RequestUri = new Uri("http://localhost:3128/api/uploading/");
var client = new HttpClient();
client.SendAsync(message).ContinueWith(task =>
{
if (task.Result.IsSuccessStatusCode)
{
//do something with response
}
});
...but that depends on whether the Compact Framework supports MultipartFormDataContent
UPDATE 2
Which it doesn't, according to How can i determine which .Net features the compact framework has?
UPDATE 3
Using the Bing Search Code for C# extension, I mashed "h", chose "How do I", entered "send file via http" and got this:
WebRequest request = WebRequest.Create("http://www.contoso.com/PostAccepter.aspx ");
request.Method = "POST";
string postData = "This is a test that posts this string to a Web server.";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
WebResponse response = request.GetResponse();
Console.WriteLine(((HttpWebResponse)response).StatusDescription);
dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string responseFromServer = reader.ReadToEnd();
Console.WriteLine(responseFromServer);
reader.Close();
dataStream.Close();
response.Close();
As I need to add a couple of string args in addition to the file (which I assume I can add via the postData byte array), can I do that by adding more calls to dataStream.Write()? IOW, is this sensible (first and third lines differ):
WebRequest request = WebRequest.Create("http://MachineName:NNNN/api/Bla?str1=Blee&str2=Bloo");
request.Method = "POST";
string postData = //open the HTML file and assign its contents to this, or make it File postData instead of string postData?
// the rest is the same
?
UPDATE 4
Progress: This, such as it is, is working:
Server code:
public string PostArgsAndFile([FromBody] string value, string serialNum, string siteNum)
{
string s = string.Format("{0}-{1}-{2}", value, serialNum, siteNum);
return s;
}
Client code (from Darin Dimitrov in this post):
private void ProcessRESTPostFileData(string uri)
{
using (var client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
var data = "=Short test...";
var result = client.UploadString(uri, "POST", data);
//try this: var result = client.UploadFile(uri, "bla.txt");
//var result = client.UploadData()
MessageBox.Show(result);
}
}
Now I need to get it sending a file instead of a string in the [FromBody] arg.
You should look into using multipart/form-data with a custom media type formatter that will extract both the string properties and the uploaded XML file.
http://lonetechie.com/2012/09/23/web-api-generic-mediatypeformatter-for-file-upload/

How to receive data on asp website from c#?

Im sending data to local website using c# console application. Function that sends data is:
public static HttpWebRequest GetRequest(String url, NameValueCollection nameValueCollection)
{
// Here we convert the nameValueCollection to POST data.
// This will only work if nameValueCollection contains some items.
var parameters = new StringBuilder();
foreach (string key in nameValueCollection.Keys)
{
parameters.AppendFormat("{0}={1}&",
HttpUtility.UrlEncode(key),
HttpUtility.UrlEncode(nameValueCollection[key]));
}
parameters.Length -= 1;
// Here we create the request and write the POST data to it.
var request = (HttpWebRequest)HttpWebRequest.Create(url);
request.Method = "POST";
using (var writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(parameters.ToString());
}
return request;
}
url and NameValueCollection are correct.
but I cant receive anything on the website.
website code is:
System.IO.StreamReader reader = new System.IO.StreamReader(HttpContext.Current.Request.InputStream);
string requestFromPost = reader.ReadToEnd();
Response.Write(requestFromPost);
I'm new to asp.net. What am I missing?
Try this.
var parameters = new StringBuilder();
foreach (string key in nameValueCollection.Keys)
{
parameters.AppendFormat("{0}={1}&",
HttpUtility.UrlEncode(key),
HttpUtility.UrlEncode(nameValueCollection[key]));
}
parameters.Length -= 1;
var request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
// Every so often I've seen weird issues if the user agent isn't set
request.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
// encode the data for transmission
byte[] bytedata = Encoding.UTF8.GetBytes(parameters.ToString());
// tell the other side how much data is coming
request.ContentLength = bytedata.Length;
using (Stream writer = request.GetRequestStream())
{
writer.Write(bytedata, 0, bytedata.Length);
}
String result = String.Empty;
using (var response = (HttpWebResponse)request.GetResponse()) {
using(StreamReader reader = new StreamReader(response.GetResponseStream())) {
result = reader.ReadToEnd(); // gets the response from the server
// output this or at least look at it.
// generally you want to send a success or failure message back.
}
}
// not sure why you were returning the request object.
// you really just want to pass the result back from your method
return result;
You probably want to wrap most of the above in a try..catch. If the post fails then it's going to throw an exception.
On the receiving end, it's a little easier. You can do things like:
String val = Request.QueryString["myparam"];
or just iterate through the query string collection.

Consuming REST service with C# code

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();

Categories

Resources