C# POST request to webapi using a console program - c#

I have a web api that I can access successfully through a browser :-
https://127.0.0.1:8443/ncrApi
I am trying to create a simple console program in C# using VS2015 to send data and receive a response using http POST.
Here is what I have so far:-
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace WebSample
{
class ApiSendData
{
public string ApiFunction { get; set; }
public string DppName { get; set; }
public string ClearData { get; set; }
public string DppVersion { get; set; }
}
class Program
{
static void Main(string[] args)
{
// The Main function calls an async method named RunAsync
// and then blocks until RunAsyncc completes.
RunAsync().Wait();
}
static async Task RunAsync()
{
using (var client = new HttpClient())
{
// This code sets the base URI for HTTP requests,
// and sets the Accept header to "application/json",
// which tells the server to send data in JSON format.
client.BaseAddress = new Uri("https://localhost:8443/ncrApi");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// HTTP POST
var datatobeSent = new ApiSendData()
{
ApiFunction ="NcrSecureData",
DppName ="CSampleCustomer",
DppVersion ="Latest",
ClearData ="1234567890"
};
HttpResponseMessage response = await client.PostAsJsonAsync("ncrApi", datatobeSent);
if (response.IsSuccessStatusCode)
{
// Get the URI of the created resource.
Uri ncrUrl = response.Headers.Location;
// do whatever you need to do here with the returned data //
}
}
}
}
}
However I am getting an error on the HttpResonseMessage response statement....{"An error occurred while sending the request."}
{"The request was aborted: Could not create SSL/TLS secure channel."}
I suspect it is because I am not correctly understanding the the client.BaseAddress and the HttpResponseMessage response statements.
Here is what I have been following:-
http://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client

You are probably getting an error because the final address is your baseAddress + post address, that is: http://localhost:8443/nrcApi/nrcApi , which doesn't exist
Try changing your client.BaseAddress to:
client.BaseAddress = new Uri("https://localhost:8443/");
For SSL connection errors, try generating a trusted certificate:
Make https call using httpclient

Your code looks ok. However, the issue seems to be the call you are making. Basically in the following call, the first parameter is the method/function to be invoked after your URI.
HttpResponseMessage response = await client.PostAsJsonAsync("ncrApi",
datatobeSent);
In this case ncrApi is your method. Calling it in the base URL will result in it being added to the final call making it give an address to an endpoint that does not exist.

Related

Console app not posting to minimalistic ASP.NET Core API

I have a solution with two projects in Visual Studio 2022:
A console app
A minimalistic API created using ASP.NET Core Web API
The API has a simplistic model as follows:
class Todo // This is the model
{
public int Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
Which ought to represent Todo items in a small database, similar to the tutorial shown in the ASP.NET docs. The API has POST, PUT and DELETE methods.
The POST method looks like this:
// POST
app.MapPost("/todoitems", (Todo todo, TodoDb db) =>
{
db.Todos.Add(todo);
db.SaveChanges();
return Results.Created($"/todoitems/{todo.Id}", todo);
});
I decided to make synchronous calls to simplify this a little bit.
The console application attempts to make use of the POST method exposed by the API to add a Todo item in the database. Here's what I was able to do so far, thanks to the REST client tutorial in the Microsoft docs:
using System;
using System.Threading.Tasks;
using System.Net.Http;
using System.Net.Http.Json;
namespace InteractWithTodoApi
{
class Program
{
private static readonly HttpClient client = new HttpClient();
private static string repoLink = "https://localhost:7157/todoitems";
private static async Task PostData()
{
JsonContent content = JsonContent.Create("{\"id\": 1, \"Name\": \"Wash dishes\", \"IsComplete\": true}", typeof(string));
HttpResponseMessage postTask = await client.PostAsync(repoLink, content);
Console.WriteLine(postTask.Content);
}
static async Task Main(string[] args)
{
await PostData();
}
}
}
I then launch the API with a localhost, and once it is up and running I execute the console app. Then I refresh the API in my browser under https://localhost:PORT/todoitems.
After I refresh my browser, I expect to see a new entry
corresponding to:
{ "Id": 1, "Name": "Wash dishes", "IsComplete": true }"
The console app doesn't crash and runs to completion, however when I refresh that browser, I see that my Todo list is still empty: [].
What am I doing wrong here?
It seems that specifying the header is important while interacting with a JSON-based API. There appear to be two ways of doing this while working with System.Net.Http
Set globally using something like:
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
Set for each POST request as follows:
string JsonString = "{\"name\": \"Wash dishes\", \"isComplete\": true}";
StringContent content = new StringContent(JsonString, Encoding.UTF8, "application/json");
The default is not application/json in System.Net.Http. It appears to be some other kind of text-based value.

Get return value from SignalR client

I have a SignalR method used to send a request to a specific client and then get a return value. I know this isn't possible, but instead the client needs to send the response as a separate message to the hub.
I send the message to the client from outside the hub:
public String GetResponseFromUser(String userId, String request)
{
// Use requestId to be sure the response is on this request
var requestId = Guid.NewGuid().ToString();
var hubContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
hubContext.Clients.User(userId).Request(requestId, request);
// Wait for client to send response to the Hub's Response method
var response = ...?
return response;
}
Hub class
public class MyHub : Hub
{
public void Response(String requestId, String response)
{
// Somehow I want to get the response to the method above
}
}
How can I wait for the client response and use this response in my method outside the hub?
Once your hub is connected you have to wait and listen for the answer:
hubContext.On("Response", (requestId, response) =>
{
// do something
}
);
Of course you have to keep that connection alive.

ASP.NET - GET Web Request API

I'm new to APIs, so I've been trying to use a web request to GET information from Reddit, since the API is unlocked. I've been able to use the right URL to get information using a REST client extension, but I want to implement the body of the data and simply just print it out to a web page.
I know this is easier with python, but they use C#/ASP.NET at my work. I've looked off of tutorials such as:
http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client
I was only able to obtain a header when I used this tutorial and my code is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace API_TESTING
{
class Product
{
public string Name { get; set; }
public double Price { get; set; }
}
class Program
{
static void Main()
{
RunAsync().Wait();
}
static async Task RunAsync()
{
using(var client = new HttpClient())
{
//TODO - send HTTP requests
client.BaseAddress = new Uri("http://www.reddit.com/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//-----
HttpResponseMessage response = await client.GetAsync("r/todayilearned/new.json");
if(response.IsSuccessStatusCode)
{
Console.Write(response);
}
}
}
}
}
Can someone explain how to use ASP.NET for API calls? or link to other up-to-date tutorials? Thank you.
You're almost there. After you get the response, you need to read its content.
var response = await _client.GetAsync(uri);
if (response.IsSuccessStatusCode) {
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
You might want to check out the RedditSharp project to see how others have done this.
Btw, the tutorial you linked to does almost exactly what I answered with under the Getting a Resource (HTTP GET) section. Only difference is they used the generic ReadAsAsync while you can use ReadAsStringAsync if you're just writing the body to the console.

Consuming WebAPI JSON

I'm trying to build some kind of RESTful-like API, I'm aware of that my first draft probably isn't anything near the real RESTful design pattern. However my real question is how should I consume my service using JSON?
In my so called real world example I want my users to sign in via the service so I have this AuthenticationController
namespace RESTfulService.Controllers
{
public class AuthenticationController : ApiController
{
public string Get(string username, string password)
{
// return JSON-object or JSON-status message
return "";
}
public string Get()
{
return "";
}
}
}
Considering the increasing popularity with the technology I assumed that very little code would be needed for consuming the service. Do I really need to serialize the JSON manually with some kind of third party package like json.net? Beneath is my draft for the client
private static bool DoAuthentication(string username, string password)
{
var client = InitializeHttpClient();
HttpResponseMessage response = client.GetAsync("/api/rest/authentication").Result;
if (response.IsSuccessStatusCode)
{
//retrieve JSON-object or JSON-status message
}
else
{
// Error
}
return true;
}
private static HttpClient InitializeHttpClient()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost/");
// Add an Accept header for JSON format.
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
return client;
}
How do I send JSON from service and how do I interpreting it on the client?
Have a look at the System.Net.Http.HttpContentExtensions in System.Net.Http.Formatting.dll. As explained here (and suggested by Mike Wasson in a comment above), you can call ReadAsAsync<T>() on the response content to deserialize from JSON (or XML) to a CLR type:
if (response.IsSuccessStatusCode)
{
var myObject = response.Content.ReadAsAsync<MyObject>();
}
If you need to customize the deserialization, that article links to a further explanation of MediaTypeFormatters.

How to call a WebAPI from Windows Service

I have an application written in Windows Service and this app need to make a call to a WebAPI written in Asp.Net MVC 4 WebAPi. this method in WebAPI return a DTO with primitive type, something like:
class ImportResultDTO {
public bool Success { get; set; }
public string[] Messages { get; set; }
}
and in my webapi
public ImportResultDTO Get(int clientId) {
// process.. and create the dto result.
return dto;
}
My question is, how can I call the webApi from the Windows Service? I have my URL and value of parameter, but I don't know how to call and how to deserialize the xml result to the DTO.
Thank you
You could use System.Net.Http.HttpClient. You will obviously need to edit the fake base address and request URI in the example below but this also shows a basic way to check the response status as well.
// Create an HttpClient instance
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:8888/");
// Usage
HttpResponseMessage response = client.GetAsync("api/importresults/1").Result;
if (response.IsSuccessStatusCode)
{
var dto = response.Content.ReadAsAsync<ImportResultDTO>().Result;
}
else
{
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
}
You can install this NuGet package Microsoft ASP.NET Web API Client Libraries to your Windows Service project.
Here is a simple code snippet demonstrating how to use HttpClient:
var client = new HttpClient();
var response = client.GetAsync(uriOfYourService).Result;
var content = response.Content.ReadAsAsync<ImportResultDTO>().Result;
(I'm calling .Result() here for the sake of simplicity...)
For more sample of HttpClient, please check this out: List of ASP.NET Web API and HttpClient Samples.

Categories