Consume ASP.NET WebAPI - c#

Have to consume a web API. The Controller looks like this:
using System;
using System.Collections.Generic;
using System.Web.Http;
using ERPService.Api.Models;
using ERPService.Core.Services;
namespace ERPService.Api.Controllers
{
[RoutePrefix("api/local")]
public class LocalProductController : BaseApiController
{
[Route("product/{productId}/export")]
public ApiResponse<IList<ServiceResponse<object>>> ExportProduct(int productId)
{
return Response(this.ServiceFactory.ProductService.ExportProduct(productId));
}
}
}
Using HttpClient how can I call that ExportProduct function?
I created a console application to consume this:
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:49319/");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.GetAsync("api/local/product/{productId}/export").Result;
The result is an error as following:
Error Code - MethodNotAllowed
Message - Method Not Allowed

string json;
WebRequest req = HttpWebRequest.Create(url);
req.Method = "GET";
using (HttpWebResponse response = (HttpWebResponse)req.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
using (StreamReader responseReader = new StreamReader(responseStream))
{
json = responseReader.ReadToEnd();
}
}
}

Found the solution for the problem: had to add the [HttpGet] attribute so it should look like this:
[Route("product/{productId}/export")]
[HttpGet]
public ApiResponse<IList<ServiceResponse<object>>> ExportProduct(int productId)
{
return Response(this.ServiceFactory.ProductService.ExportProduct(productId));
}

Related

How to call external api with Azure function with POST method with request body data

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Net;
using System.IO;
namespace FunctionRestApi
{
public static class Function1
{
[FunctionName("Function1")]
public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create("URL_with_client_id_authorization_token");
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "GET";
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
log.LogInformation(result);
}
return new OkObjectResult(value: httpWebRequest);
}
}
}
I am new to azure function. This code works when I am just using 'GET' method. But if I want to use 'POST' method with request body data i.e. date range (start_date and end_date) and some other sub_user_id, then how can I do that?
Here is a simple example of a POST request using HttpClient with some comments:
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace AzureFunctionsSandbox.Functions
{
public static class Function1
{
private static readonly HttpClient _httpClient = new HttpClient();
[FunctionName("Function1")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest request,
ILogger log)
{
// create request as an object to easily set values
var myRequest = new MyRequest
{
StartDate = DateTime.Now,
EndDate = DateTime.Now.AddDays(1),
SubUserId = "ABC123"
};
// serialize to JSON string for POST request body
var myRequestJsonBody = JsonConvert.SerializeObject(myRequest);
// .PostAsync() requires a HttpContent object - StringContent is a sub class
var requestContent = new StringContent(myRequestJsonBody, Encoding.UTF8, "application/json");
// make the POST request
var response = await _httpClient.PostAsync("URL_with_client_id_authorization_token", requestContent);
// use response body for further work if needed...
var responseBody = response.Content.ReadAsStringAsync();
return new OkResult();
}
}
public class MyRequest
{
[JsonProperty(PropertyName = "start_date")]
public DateTime StartDate { get; set; }
[JsonProperty(PropertyName = "end_date")]
public DateTime EndDate { get; set; }
[JsonProperty(PropertyName = "sub_user_id")]
public string SubUserId { get; set; }
}
}
https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=net-5.0
See one of the answers in this SO question, it shows how to make a POST call using the HttpClient class, however it is creating new instance of it, it is not the right way. As a best practice use only a static object of HttpClient in your function app.
first check with POSTMAN how you can connect to external API with what authentication configuration BASIC/ BEARER then you can write code using same configuration

Azure DevOps REST API in a Azure Function

I'm trying to create a POST Request for Azure DevOps Teams and Repositories and want to create a new team and a new repository through the API method. My Team is created fine but I don't know how to extend the code to create a repository in the same HttpRequest and also how do I have the 'body' to include both the name of the team and the name of the repository as they both have the same 'name' parameter.
I'm quiet new to C# and Azure functions and don't know how to properly implement this in my own project. I would really appreciate it if someone could guide me into the right direction.
I am using Visual Studio with .NET Core 3.0.
Here is the code so far:
using System.IO;
using System;
using System.Net;
using Microsoft.Azure.WebJobs;
using Newtonsoft.Json;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs.Extensions.Http;
namespace TeamsAdd
{
public static class TeamsAdd
{
[FunctionName("Function1")]
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]
HttpRequestMessage req)
{
var personalaccesstoken = "";
var body = new
{
name = "myteamname",
project = new
{
id = "xxxxxxx",
projectname = "myprojectname",
}
};
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(
ASCIIEncoding.ASCII.GetBytes(
string.Format("{0}:{1}", "", personalaccesstoken))));
//Connecting to the DevOps REST API
var requestMessage = new HttpRequestMessage(HttpMethod.Post, $"https://dev.azure.com/{organization}/_apis/projects/{projectId}/teams?api-version=6.0");
requestMessage.Content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json");
//Reading Server Response
using (HttpResponseMessage response = await client.SendAsync(requestMessage))
{
if (!response.IsSuccessStatusCode)
{
response.EnsureSuccessStatusCode();
}
return req.CreateResponse(HttpStatusCode.Created, "Teams created successfully!");
}
}
}
}
}
The API used to create a team and repo are different. For more details, please refer to here and here. So we cannot create the two resources in one request. we need to send two requests to create the two different resources.
For example
public static class Function2
{
public static HttpClient Client = new HttpClient();
public static string PAT = "";
[FunctionName("Function2")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
Object teamBody = new
{
name = "mytest7878orf",
};
Object repoBody = new
{
name = "mytest85698",
project= new {
id = "8d5fa9a0-1061-4891-977b-f91189a0dcbe",
}
};
var teamRes= sendRequest(HttpMethod.Post, "https://dev.azure.com/{organization}/_apis/projects/{projectId}/teams?api-version=6.0", teamBody);
var repoRes= sendRequest(HttpMethod.Post, "https://dev.azure.com/{organization}/{projectId}/_apis/git/repositories?api-version=6.0", repoBody);
var res = new
{
teamRes = JsonConvert.DeserializeObject(teamRes),
repoRes = JsonConvert.DeserializeObject(repoRes)
};
return req.CreateResponse(HttpStatusCode.OK, JsonConvert.SerializeObject(res), "application/json");
}
public static string sendRequest(HttpMethod method, string url, Object body = null) {
Client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(
ASCIIEncoding.ASCII.GetBytes(
string.Format("{0}:{1}", "", PAT))));
//Connecting to the DevOps REST API
var requestMessage = new HttpRequestMessage(method, url);
if (body != null) {
requestMessage.Content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json");
}
using (HttpResponseMessage response = Client.SendAsync(requestMessage).Result)
{
if (!response.IsSuccessStatusCode)
{
try
{
response.EnsureSuccessStatusCode();
}
catch (HttpRequestException ex) {
return ex.Message;
}
}
var content = response.Content.ReadAsStringAsync().Result;
return content;
}
}
}

how to call web api or other restful web services in c#

I can call every webApi methods by ajax request but I can't do it by c#.
this is a simple web api which every body can create it in asp.net mvc web api but I can't find any example about call and get it programmatically by c#.
public class TestController : ApiController
{
// GET: api/Test
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
please some body say me how can I call this web api method in c# and get these 2 values. how can we get value from a web service(RestFull-without reference) in c# ?
To call WEB API in c# you can use the HttpClient class.
public class Client
{
private readonly string baseUri;
private static HttpClient _client;
public Client(string baseUri)
{
this.baseUri = baseUri;
_client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true })
{
BaseAddress = new Uri(baseUri)
};
_client.DefaultRequestHeaders.Accept.Clear();
_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task<SomeResource> GetResourceById(int Id)
{
var path = $"{baseUri}/Resources/{Id}";
var response = await _client.GetAsync(path);
return await response.Content.ReadAsAsync<SomeResource>();
}
the answer is this...all persons who give negative reaction can do this instead of negative reactions:
string GET(string url)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
try
{
WebResponse response = request.GetResponse();
using (Stream responseStream = response.GetResponseStream())
{
StreamReader reader = new StreamReader(responseStream, Encoding.UTF8);
return 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;
}
}
so easier !
Create an HttpClient (https://msdn.microsoft.com/en-us/library/system.net.http.httpclient(v=vs.118).aspx) and call its GetAsync() https://msdn.microsoft.com/en-us/library/hh158912(v=vs.118).aspx method. I'm assuming you have this running locally so your Uri is probably something like http://localhost/test/get depending on how you have Visual Studio configured when you press F5. Here's a complete example: https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client

Get body text from an HttpWebRequest object?

I have a (legacy) method in my codebase which generates and returns a ready-to-send HTTP POST message as a System.Net.HttpWebRequest object:
public HttpWebRequest GetHttpWebRequest(string body, string url, string contentType)
{
HttpWebRequest request = HttpWebRequest.CreateHttp(url);
request.Method = "POST";
// (More setup stuff here...)
using (var writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(body);
}
return request;
}
I'd like to write a unit test which verifies that the HttpWebRequest instance returned by this method actually does have the message body text that was passed in to the method in the body parameter.
Question: How can I get the body text of an HttpWebRequest object (without ever actually sending the HTTP request)?
Stuff I've tried so far:
new StreamReader(myHttpWebRequest.GetRequestStream()).ReadToEnd() - Fails at runtime with ArgumentException: Stream was not readable.
The HttpWebRequest class doesn't seem to have any property that would allow getting/reading the HTTP message body such as Body, Message, Text, etc.
I would write a http listener and make real http requests.
Here is a sample server using WCF + the client code. Just call await TestClient.Test(); (You can also test the server with a browser like http://localhost:8088/TestServer/Dummy)
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Web;
using System.Text;
using System.Threading.Tasks;
namespace SO
{
[ServiceContract]
public class TestServer
{
static WebServiceHost _host = null;
public static Task Start()
{
var tcs = new TaskCompletionSource<object>();
try
{
_host = new WebServiceHost(typeof(TestServer), new Uri("http://0.0.0.0:8088/TestServer"));
_host.Opened += (s, e) => { tcs.TrySetResult(null); };
_host.Open();
}
catch(Exception ex)
{
tcs.TrySetException(ex);
}
return tcs.Task;
}
//A method that accepts anything :)
[OperationContract, WebInvoke(Method = "*", UriTemplate ="*")]
public Message TestMethod(Stream stream )
{
var ctx = WebOperationContext.Current;
var request = ctx.IncomingRequest.UriTemplateMatch.RequestUri.ToString();
var body = new StreamReader(stream).ReadToEnd();
Console.WriteLine($"{ctx.IncomingRequest.Method} {request}{Environment.NewLine}{ctx.IncomingRequest.Headers.ToString()}BODY:{Environment.NewLine}{body}");
return ctx.CreateTextResponse( JsonConvert.SerializeObject( new { status = "OK", data= "anything" }), "application/json", Encoding.UTF8);
}
}
public class TestClient
{
public static async Task Test()
{
await TestServer.Start();
var client = new HttpClient();
var objToSend = new { name = "L", surname = "B" };
var content = new StringContent( JsonConvert.SerializeObject(objToSend) );
var response = await client.PostAsync("http://localhost:8088/TestServer/TestMethod?aaa=1&bbb=2", content);
Console.WriteLine(response.StatusCode);
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
}
}

POST throws HttpRequestMessage does not contain a definition for Form

I am trying to get POST data in C# and everything I have read says to use
Request.Form["parameterNameHere"]
I am trying that, but I get an error saying
System.Net.Http.HttpRequestMessage does not contain a definition for Form and no extension method for Form.'
The method in question is
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.HttpRequest;
namespace TextServer.Controllers
{
public class TextController : ApiController
{
// POST api/<controller>
public HttpResponseMessage Post([FromBody]string value)
{
string val = Request.Form["test"];
HttpResponseMessage response = new HttpResponseMessage();
response.Content = new StringContent("Your message to me was: " + value);
return response;
}
Any help is greatly appreciated.
You should pass your object in the request body and retrieve values from the body:
public HttpResponseMessage Post([FromBody] SomeModel model)
{
var value = model.SomeValue;
...
Or if all you need is the string:
public HttpResponseMessage Post([FromBody] string value)
{
HttpResponseMessage response = new HttpResponseMessage();
response.Content = new StringContent("Your message to me was: " + value);
return response;
}

Categories