How to call Post Methode from asp.net Web Api - c#

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; }
}

Related

JSON string will not deserialize into the type specified

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

Deserialize JSON property starting with #

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; }
}

RestSharp StatusCode vs IsSuccessful

I have the following class
public class Customer
{
public Customer()
{
Project = new HashSet<Project>();
}
public uint Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
public HashSet<Project> Project { get; set; }
}
And the following method
protected async Task<IRestResponse> ApplyRequest<T>(string resource,
Method method, T data) where T: class, new()
{
var client = new RestClient(_connectionConfig.BaseUrl);
client.FollowRedirects = false;
var request = new RestRequest(resource, method);
request.RequestFormat = RestSharp.DataFormat.Json;
request.AddParameter("application/json",
JsonConvert.SerializeObject(data), ParameterType.RequestBody);
//request.AddJsonBody(data);
//This also doesn't work
var response2 = await client.ExecuteTaskAsync<T>(request);
return response2;
}
Now if I call this method with Post method, the return statuscode is "created" (and it is actually created). However, the property IsSuccessful gives "false" and the error message is
"Unable to cast object of type 'SimpleJson.JsonArray' to type
'System.Collections.Generic.IDictionary`2[System.String,System.Object]'."
Is this usual, or am I doing something wrong?
Thanks
It's not successful because you had a serialisation error. I also see you logged it on GiTHub and got the same response. https://github.com/restsharp/RestSharp/issues/1064

Posting a complex object with ASP.NET WebAPI

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

Web API Json Response

I am developing Web API for my client. They have suggestion that all response should be a common JSON structure.
{ Data:"", Status:true, Message:"" }
If error means
{ Error:"", Status:false, Message:"" }
Which is the best method to create a common JSON structure as returns.
Now I created a class having these properties. And created 2 classes from IHttpActionResult,Error.cs and Success.cs, From that the response is created and returned from the controller.
The thing is in my controller,
public IHttpActionResult GetNewsAndAnnouncements()
{
var data = newsAndAnnouncementsDataServices.NewsAndAnnouncements();
if (data != null && data.Count() > 0)
{
return new Success(Request, "News and Announcements Retrieved Successfully", data);
}
return new Error(Request, "No News and Announcements Found");
}
Error.cs
public class Error : IHttpActionResult
{
private readonly string _message;
private readonly HttpRequestMessage _request;
private IErrorResponseModel errorResponse;
public Error(HttpRequestMessage request, string message)
{
_message = message;
_request = request;
errorResponse = new ErrorResponseModel();
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
errorResponse.Message = _message;
errorResponse.Status = false;
errorResponse.Error = _message;
var response = new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = new ObjectContent<object>(errorResponse, new JsonMediaTypeFormatter()),
RequestMessage = _request
};
return Task.FromResult(response);
}
}
Success.cs
public class Success : IHttpActionResult
{
private readonly string _message;
private readonly object _data;
private readonly HttpRequestMessage _request;
private IDataResponseModel dataResponse = new DataResponseModel();
public Success(HttpRequestMessage request, string message, object data)
{
_message = message;
_request = request;
_data = data;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
dataResponse.Message = _message;
dataResponse.Status = true;
dataResponse.Data = _data;
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ObjectContent<object>(dataResponse, new JsonMediaTypeFormatter()),
RequestMessage = _request
};
return Task.FromResult(response);
}
}
DataResponseModel.cs
public class DataResponseModel : Mobility.Common.IDataResponseModel
{
public object Data { get; set; }
public string Message { get; set; }
public bool Status { get; set; }
}
ErrorResponseModel.cs
public class ErrorResponseModel : Mobility.Common.IErrorResponseModel
{
public object Error { get; set; }
public string Message { get; set; }
public bool Status { get; set; }
}
Is this a right method. I need suggestion. Is there any other way to achieve this. I heard about delegating handler something. But I don't have much idea on these.
Please help me.
Another solution to this problem is to hook into the ASP.NET pipeline using custom handlers to build a common response object.
For instance:
[DataContract]
public class ApiResponse
{
[DataMember]
public string Version { get { return "1.2.3"; } }
[DataMember]
public int StatusCode { get; set; }
[DataMember(EmitDefaultValue = false)]
public string ErrorMessage { get; set; }
[DataMember(EmitDefaultValue = false)]
public object Result { get; set; }
public ApiResponse(HttpStatusCode statusCode, object result = null, string errorMessage = null)
{
StatusCode = (int)statusCode;
Result = result;
ErrorMessage = errorMessage;
}
}
Have a look at this post for a reference implementation http://www.devtrends.co.uk/blog/wrapping-asp.net-web-api-responses-for-consistency-and-to-provide-additional-information

Categories