How can I use WebClient object to send a POST request like this:
public static void SaveOrUpdateEntity(string url, object data)
{
using (var client = new WebClient())
{
// TODO
}
}
where its data is a Person object.
This is controller method
[HttpPost]
public void Post([FromBody]Person person)
{
VeranaWebService.SaveOrUpdatePerson(person);
}
and Person class
public class Person
{
public string Name { get; set; }
public string FirstName { get; set; }
public DateTime? BirthDate { get; set; }
public byte[] Photo { get; set; }
}
You can use Newtonsoft.Json which will help you serialize your data to a json object. It can be used like this
using Newtonsoft.Json;
public static void SaveOrUpdateEntity(string url, object data)
{
var dataString = JsonConvert.SerializeObject(data);
using (var client = new WebClient())
{
client.Headers.Add(HttpRequestHeader.ContentType, "application/json");
response = client.UploadString(new Uri(url), "POST", dataString);
}
}
To learn more about the newtonsoft library, read here
Related
I have the following bit of code whihc sends a Http POST request to the server. The server reurns a 400 Bad request response along with a error object in the form of Json:
namespace MyApp.Shared.Dtos.Response
{
public class ErrorItem
{
public string Message { get; set; }
public string Tag { get; set; }
}
public class ErrorDto
{
public string Title { get; set; }
public List<ErrorItem> Errors { get; set; } = new();
}
}
namespace Accounting.Web.Services
{
public interface IHttpService
{
Task<T> Get<T>(string uri);
Task<T> Post<T>(string uri, object value, bool addBearerToken = false);
public ErrorDto Error { get; set; }
}
public class HttpService: IHttpService
{
private HttpClient _httpClient;
public ErrorDto Error { get; set; }
public HttpService(HttpClient httpClient)
{
_httpClient = httpClient;
_stateService = stateService;
}
public async Task<T> Post<T>(string uri, object value)
{
var request = new HttpRequestMessage(HttpMethod.Post, uri);
request.Content = new StringContent(JsonSerializer.Serialize(value), Encoding.UTF8, "application/json");
return await sendRequest<T>(request, addBearerToken);
}
private async Task<T> sendRequest<T>(HttpRequestMessage request)
{
using var response = await _httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.BadRequest)
{
var result = await response.Content.ReadAsStringAsync();
Error = JsonSerializer.Deserialize<ErrorDto>(result);
//..
}
else
{
//..
}
}
}
}
The result correctly recieves the following response from the server as a JSON string:
{"title":"Username or password is incorrect","errors":[]}
And I can confirm by inspecting var result, it has the above value.
However, It doesn't seem deserialize into the ErrorDto class as one would expect it to:
Error = JsonSerializer.Deserialize(result);
But I simply cannot see any problems with the code, it looks like it should be working.
*** UPDATE ***
My server API code returrns the JSOn using the same DTO class (It's a shared class) using the following code:
[HttpPost("authenticate")]
public ActionResult Authenticate(AuthenticateRequest loginRequest)
{
var auth = _userService.Authenticate(loginRequest);
ErrorDto error = new()
{
Title = "Username or password is incorrect"
};
if (auth.user == null || auth.token == null)
{
return BadRequest(error);
}
return Ok(auth.user.ConvertToDto(auth.token));
}
By default System.Text.Json is case-sensitive. There are multiple options to handle this, for example by providing corresponding JsonSerializerOptions:
var json = #"{""title"":""Username or password is incorrect"",""errors"":[]}";
var errorDto = JsonSerializer.Deserialize<ErrorDto>(json, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
Or marking properties with corresponding JsonPropertyNameAttribute:
public class ErrorItem
{
[JsonPropertyName("message")]
public string Message { get; set; }
[JsonPropertyName("tag")]
public string Tag { get; set; }
}
public class ErrorDto
{
[JsonPropertyName("title")]
public string Title { get; set; }
[JsonPropertyName("errors")]
public List<ErrorItem> Errors { get; set; } = new();
}
UPD
From How to customize property names and values with System.Text.Json doc:
Note
The web default is camel case.
If you want to switch from camel case to the naming policy used for DTOs you can do the following:
builder.Services.AddControllers()
.AddJsonOptions(opts => opts.JsonSerializerOptions.PropertyNamingPolicy = null);
Im writing a c# console app, where i need get som JSON date from a webapi.
For the most part this works fine, however in one of my JSON responses i get a property name staring with #. I cant seem to figure out how to put that JSON property into a C# object.
My code look as follows:
public class AlertResponse
{
public string #class { get; set; }
public string result { get; set; }
public string info { get; set; }
}
public class AuthenticationResponse
{
public string Access_token { get; set; }
}
class Test
{
private static HttpClient client = new HttpClient();
private static string BaseURL = "https://xxxxx.xxxx";
public void Run()
{
client.BaseAddress = new Uri(BaseURL);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
AuthenticationResponse authenticationResponse = Login();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authenticationResponse.Access_token);
AlertResponse OpenAlerts = GetOpenAlerts();
}
internal AlertResponse GetOpenAlerts()
{
var response = client.GetAsync("/api/v2/xxxxxxxxxxxxxxxxxx/alerts/open").Result;
if (response.IsSuccessStatusCode)
{
return response.Content.ReadAsAsync<AlertResponse>().Result;
}
else
{
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
}
return null;
}
private AuthenticationResponse Login()
{
string apiKey = "gdfashsfgjhsgfj";
string apiSecretKey = "sfhsfdjhssdjhsfhsfh";
var byteArray = new UTF8Encoding().GetBytes("public-client:public");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
var form = new FormUrlEncodedContent(new Dictionary<string, string> { { "username", apiKey }, { "password", apiSecretKey }, { "grant_type", "password" } });
HttpResponseMessage tokenMessage = client.PostAsync("/auth/oauth/token", form).Result;
if (tokenMessage.IsSuccessStatusCode)
{
return tokenMessage.Content.ReadAsAsync<AuthenticationResponse>().Result;
}
else
{
Console.WriteLine("{0} ({1})", (int)tokenMessage.StatusCode, tokenMessage.ReasonPhrase);
}
return null;
}
}
And the JSON i get looks like this:
"AlertResponse": {
"#class": "patch_ctx",
"patchUid": "afdhgfhjdajafjajadfjadfjdj",
"policyUid": "dsgafdhasfjafhdafhadfh",
"result": "0x80240022",
"info": "fdgdfhsfgjh"
}
How can i fix this?
Best regards
Glacier
Are you using Newtonsoft.Json or System.Text.Json?
In either cases you should decorate the #class Property with
//System.Text.Json
[JsonPropertyName("#class")]
public string class { get; set; }
or
//Newtonsoft.Json
[JsonProperty("#class")]
public string class { get; set; }
I guess you are looking for DataMemberAttribute and DataContract
using System.Runtime.Serialization;
[DataContract]
public class AlertResponse
{
[DataMember(Name = "#class")]
public string Class { get; set; }
[DataMember(Name = "result")]
public string Result { get; set; }
[DataMember(Name = "info")]
public string Info { get; set; }
}
I try to add data to my API with the HTTP Post method.
Here is my Controller:
[Route("api/[controller]")]
[ApiController]
public class PostAccess : ControllerBase
{
// POST api/<PostAccess>
[HttpPost]
public void Post(UserModel user)
{
}
}
public class UserModel
{
public int UserID { get; set; } = 0;
public string UserName { get; set; } = "";
public string UserPassword { get; set; } = "";
}
And with this code, I try to add data.
var postData = new List<KeyValuePair<string, string>>()
{
new KeyValuePair<string, string>("UserName","Jeremia"),
new KeyValuePair<string, string>("UserPassword","Jeremia")
};
var content = (HttpContent)new FormUrlEncodedContent(postData);
await client.PostAsync("http://localhost:44355/api/PostAccess", content).ContinueWith(
(postTask) =>
{
postTask.Result.EnsureSuccessStatusCode();
}
);
}
I don't know what I'm doing wrong.
I'm very frustrated because I search for 4 hours about this problem.
Sorry for my bad English, hope you have a good day :)
Did you write the code that tries to add data in the Post function?
If yes you have to change the function to async by adding the keyword 'async'
public async void Post(userModel user)
thanks to mabruk for his answer!
Here is my working solution:
The Post Methode:
[HttpPost]
public async Task<ActionResult<RequestModel<UserModel>>> PostUser(UserModel user)
{
}
And with Postman i send the HttpPost
If you want to send it by code, do it like this:
private static readonly HttpClient client = new HttpClient();
static async Task Main(string[] args)
{
var requestObj = JsonConvert.SerializeObject(new UserModel()
{
UserName = "Jeremia1234",
UserPassword = "9364"
});
var client = new HttpClient();
var content = new StringContent(requestObj, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync("https://localhost:44355/api/GetAccess", content);
}
And the RequestModel
public class RequestModel<RequestDataModel>
{
public string JwtToken { get; set; }
public string UserName { get; set; }
public string UserPassword { get; set; }
public RequestDataModel request { get; set; }
}
I want to be able to switch between API providers and achieve the same result.
I have an interface called IApi that I am using for both APIs.
public interface IApi
{
T GetData<T>();
}
I then have my two API classes implementing this interface
public class ApiOne: IApi
{
private IWebClient _client;
public ApiOne(IWebClient client)
{
_client = client;
}
public T GetData<T>()
{
return _client.Get<T>($"{some specific url for this api");
}
}
public class ApiTwo: IApi
{
private IWebClient _client;
public ApiTwo(IWebClient client)
{
_client = client;
}
public T GetData<T>()
{
return _client.Get<T>($"{some specific url for this api");
}
}
Both of these calls obviously return different JSON responses depending on the API. I am using Newtonsoft to deserialze the responses into strong typed classes.
Which means I have 3 data models. 1 for each API response and a 3rd which is what I would like to transform the API responses into so that I can use only one data model as the Generic type.
public class ApiOneResponse
{
public string FieldOne { get; set; }
public string FieldTwo { get; set; }
}
public class ApiTwoResponse
{
public string SomeOtherFieldOne { get; set; }
public string SomeOtherFieldTwo { get; set; }
}
How can I achieve this so that both my API calls can be deserialized down to the same class and I can call it with a simple one liner?
public class CommonResponse
{
public string CommonFieldOne { get; set; }
public string CommonFieldTwo { get; set; }
}
I want to be able to simply call it like the below
static void Main(string[] args)
{
//some additional logic
//call the API
var response = _api.GetData<CommonResponse>();
}
EDIT
The issue is that _webClient.Get will try and deserialise the JSON properties into CommonResonse and each JSON reponse cannot be directly mapped into CommonResponse as the JSON keys would be different on each response.
Below is the WebClient code
public class WebClient : IWebClient
{
public T Get<T>(string endpoint)
{
using (var client = new HttpClient())
{
HttpResponseMessage response = client.GetAsync(endpoint).Result;
response.EnsureSuccessStatusCode();
string result = response.Content.ReadAsStringAsync().Result;
return JsonConvert.DeserializeObject<T>(result);
}
}
}
GetData doesn't need to be generic if you're always returning a CommonResponse:
public interface IApi
{
CommonResponse GetData();
}
Then in each implementation, project the response to your CommonResponse:
public class ApiOne: IApi
{
private IWebClient _client;
public ApiOne(IWebClient client)
{
_client = client;
}
public CommonResponse GetData()
{
var response = _client.Get<ApiOneResponse>($"{some specific url for this api");
return new CommonResponse
{
CommonFieldOne = response.FieldOne,
CommonFieldTwo = response.FieldTwo
}
}
}
I am trying to build a basic text translator in console using Microsoft Azure's Text Translator. However, my subscription keys are simply not working. I have generated them multiple times, as well as inputted them manually. Please assist. I have left in the keys for further clarification. Thank you for reading, and for your help.
The code generates this error:
if (null == subscriptionKey)
{
throw new Exception("Please set/export the environment variable: " + key_var);
// This sample requires C# 7.1 or later for async/await.
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
// Install Newtonsoft.Json with NuGet
using Newtonsoft.Json;
namespace TranslateTextSample
{
/// <summary>
/// The C# classes that represents the JSON returned by the Translator Text API.
/// </summary>
public class TranslationResult
{
public DetectedLanguage DetectedLanguage { get; set; }
public TextResult SourceText { get; set; }
public Translation[] Translations { get; set; }
}
public class DetectedLanguage
{
public string Language { get; set; }
public float Score { get; set; }
}
public class TextResult
{
public string Text { get; set; }
public string Script { get; set; }
}
public class Translation
{
public string Text { get; set; }
public TextResult Transliteration { get; set; }
public string To { get; set; }
public Alignment Alignment { get; set; }
public SentenceLength SentLen { get; set; }
}
public class Alignment
{
public string Proj { get; set; }
}
public class SentenceLength
{
public int[] SrcSentLen { get; set; }
public int[] TransSentLen { get; set; }
}
class Program
{
private const string key_var="b1f43a68dce24b0280360691ad68bc75";
private static readonly string subscriptionKey = Environment.GetEnvironmentVariable(key_var);
private const string endpoint_var = "https://consoletexttranslator.cognitiveservices.azure.com/sts/v1.0/issuetoken";
private static readonly string endpoint = Environment.GetEnvironmentVariable(endpoint_var);
static Program()
{
if (null == subscriptionKey)
{
throw new Exception("Please set/export the environment variable: " + key_var);
}
if (null == endpoint)
{
throw new Exception("Please set/export the environment variable: " + endpoint_var);
}
}
// Async call to the Translator Text API
static public async Task TranslateTextRequest(string subscriptionKey, string endpoint, string route, string inputText)
{
object[] body = new object[] { new { Text = inputText } };
var requestBody = JsonConvert.SerializeObject(body);
using (var client = new HttpClient())
using (var request = new HttpRequestMessage())
{
// Build the request.
request.Method = HttpMethod.Post;
request.RequestUri = new Uri(endpoint + route);
request.Content = new StringContent(requestBody, Encoding.UTF8, "application/json");
request.Headers.Add("Ocp-Apim-Subscription-Key", subscriptionKey);
// Send the request and get response.
HttpResponseMessage response = await client.SendAsync(request).ConfigureAwait(false);
// Read response as a string.
string result = await response.Content.ReadAsStringAsync();
TranslationResult[] deserializedOutput = JsonConvert.DeserializeObject<TranslationResult[]>(result);
// Iterate over the deserialized results.
foreach (TranslationResult o in deserializedOutput)
{
// Print the detected input languge and confidence score.
Console.WriteLine("Detected input language: {0}\nConfidence score: {1}\n", o.DetectedLanguage.Language, o.DetectedLanguage.Score);
// Iterate over the results and print each translation.
foreach (Translation t in o.Translations)
{
Console.WriteLine("Translated to {0}: {1}", t.To, t.Text);
}
}
}
}
static async Task Main(string[] args)
{
// This is our main function.
// Output languages are defined in the route.
// For a complete list of options, see API reference.
// https://learn.microsoft.com/azure/cognitive-services/translator/reference/v3-0-translate
string route = "/translate?api-version=3.0&to=de&to=it&to=ja&to=th";
// Prompts you for text to translate. If you'd prefer, you can
// provide a string as textToTranslate.
Console.Write("Type the phrase you'd like to translate? ");
string textToTranslate = "Hello, Tommy.";
await TranslateTextRequest(subscriptionKey, endpoint, route, textToTranslate);
Console.WriteLine("Press any key to continue.");
Console.ReadKey();
}
}
}
pls try the code below , it works for me :
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
// Install Newtonsoft.Json with NuGet
using Newtonsoft.Json;
namespace TranslateTextSample
{
/// <summary>
/// The C# classes that represents the JSON returned by the Translator Text API.
/// </summary>
public class TranslationResult
{
public DetectedLanguage DetectedLanguage { get; set; }
public TextResult SourceText { get; set; }
public Translation[] Translations { get; set; }
}
public class DetectedLanguage
{
public string Language { get; set; }
public float Score { get; set; }
}
public class TextResult
{
public string Text { get; set; }
public string Script { get; set; }
}
public class Translation
{
public string Text { get; set; }
public TextResult Transliteration { get; set; }
public string To { get; set; }
public Alignment Alignment { get; set; }
public SentenceLength SentLen { get; set; }
}
public class Alignment
{
public string Proj { get; set; }
}
public class SentenceLength
{
public int[] SrcSentLen { get; set; }
public int[] TransSentLen { get; set; }
}
class Program
{
private const string subscriptionKey = "<your translator API key>";
private const string endpoint = "https://api.cognitive.microsofttranslator.com";
static Program()
{
if (null == subscriptionKey)
{
throw new Exception("Please set/export the environment variable: " + subscriptionKey);
}
if (null == endpoint)
{
throw new Exception("Please set/export the environment variable: " + endpoint);
}
}
// Async call to the Translator Text API
static public async Task TranslateTextRequest(string subscriptionKey, string endpoint, string route, string inputText)
{
object[] body = new object[] { new { Text = inputText } };
var requestBody = JsonConvert.SerializeObject(body);
using (var client = new HttpClient())
using (var request = new HttpRequestMessage())
{
// Build the request.
request.Method = HttpMethod.Post;
request.RequestUri = new Uri(endpoint + route);
request.Content = new StringContent(requestBody, Encoding.UTF8, "application/json");
request.Headers.Add("Ocp-Apim-Subscription-Key", subscriptionKey);
// Send the request and get response.
HttpResponseMessage response = await client.SendAsync(request).ConfigureAwait(false);
// Read response as a string.
string result = await response.Content.ReadAsStringAsync();
TranslationResult[] deserializedOutput = JsonConvert.DeserializeObject<TranslationResult[]>(result);
// Iterate over the deserialized results.
foreach (TranslationResult o in deserializedOutput)
{
// Print the detected input languge and confidence score.
Console.WriteLine("Detected input language: {0}\nConfidence score: {1}\n", o.DetectedLanguage.Language, o.DetectedLanguage.Score);
// Iterate over the results and print each translation.
foreach (Translation t in o.Translations)
{
Console.WriteLine("Translated to {0}: {1}", t.To, t.Text);
}
}
}
}
static void Main(string[] args)
{
MainAsync(args).GetAwaiter().GetResult();
Console.ReadKey();
Console.WriteLine("press anykey to exit");
}
static async Task MainAsync(string[] args)
{
string route = "/translate?api-version=3.0&to=de&to=it&to=ja&to=th";
// Prompts you for text to translate. If you'd prefer, you can
// provide a string as textToTranslate.
string textToTranslate = "Hello, Tommy.";
await TranslateTextRequest(subscriptionKey, endpoint, route, textToTranslate);
}
}
}
before you run this console app, pls replace the value of "subscriptionKey" with your own key value here :
Result :
If there is anything unclear , pls feel free to let me know : )