BindProperty is not binding to incoming JSON in request body - c#

This the request's body:
{
userId: 382,
serviceName: 'Translation'
}
And this is a property on my API controller:
[BindProperty]
public string ServiceName { get; set; }
But it's null. How should I configure ASP.NET Core to bind from JSON too?
I'm using .NET 6.

Perhaps make FromBody explicit and specify the name, in case it is related to the casing not matching.
[FromBody(Name = "serviceName")]

// Creating a class for the method
public class data{
public int UserId { get; set; }
public string Service { get; set; }
}
// If you wish to do in method
public void getdata([FromBody] data recivedata) {
data d = new data();
d.UserId = recivedata.UserId;
d.Service = recivedata.Service;
// perform any action with the data
}

Related

System.NotSupportedException: ... API HTTPPost with .net and c#

I am an engineering student, doing my final degree project based on xamarin apps, including a connection between the client (xamarin) and API (.net). I am trying to send some encrypted data (in base64 encoding) included on a json object as the Request. On the side of the API, it takes the json request, does some fully homomorphic encryption functions and returns the response within new encrypted information.
The problem is when I am trying to receive the response in API as a self-created class named "Post.cs" which includes the next properties;
public class Post
{
public ulong ? userId { get; set; }
public int ? id { get; set; }
public string? title { get; set; }
public string? body { get; set; }
public string? userIdEncrypted { get; set; }
public string? userIdEncryptedReturned { get; set; }
public string? parmsStr { get; set; }
public Post(ulong? userId, int? id, string? title, string? body, string? userIdEncrypted, string? userIdEncryptedReturned, string? parmsStr)
{
this.userId = userId;
this.id = id;
this.title = title;
this.body = body;
this.userIdEncrypted = userIdEncrypted;
this.userIdEncryptedReturned = userIdEncryptedReturned;
this.parmsStr = parmsStr;
}
So, my API takes the request and deserialize it in order to create a "Post" and do some stuff with it.
I am trying to reproduce HttpPost as follows:
[Route("api/[controller]")]
[ApiController]
public class PostController
{
#region CONSTRUCTOR
public PostController()
{
}
#endregion
//POST ://api/Post
[Route("api/[controller]")]
[HttpPost]
public Post ReceivePost([FromBody] Post post)
{
...
var _post = new Post(post.userId, post.id, post.title, post.body, post.userIdEncrypted
post.userIdEncryptedReturned, post.parmsStr);
... FHE functions...
return _post;
}
}
So, at the time I post the "Post" from the client on xamarin, I am sending a Post as the already mentioned structure, where userIdEncrypted and parmsStr contains a base64 encoded string. When it arrives to the API server, the following issue appears:
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.NotSupportedException: Deserialization of types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with 'JsonConstructorAttribute' is not supported. Type 'System.IO.Stream'. Path: $ | LineNumber: 0 | BytePositionInLine: 1.
---> System.NotSupportedException: Deserialization of types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with 'JsonConstructorAttribute' is not supported. Type 'System.IO.Stream'.
--- End of inner exception stack trace ---
CLIENT ON XAMARIN APP
This is the json string that I post from the client:
PostModel postAux = new PostModel()
{
userId = 2,
id = 1,
title = "Title for post 1",
body = "Body for post 1",
};
/******************************************************
* Encrypt data of the post (userId)
******************************************************/
PostModel newPost = initializeFHE(postAux);
//Here is where I fill the encrypted data (base64 string) included in the Post object
/******************************************************
* POST encrypted data to the server in csharp
******************************************************/
Uri requestUri = new Uri("http://myHost:3000/api/Post");
var client = new HttpClient();
client.DefaultRequestHeaders
.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/json")); // ACCEPT header
var json = JsonConvert.SerializeObject(newPost);
var contentJson = new StringContent(json.ToString(), Encoding.UTF8, "application/json");
//Console.WriteLine(contentJson);
var response = await client.PostAsync(requestUri, contentJson);
...
In which PostModel refers to this self-created Model:
public class PostModel : BaseViewModel
{
public ulong userId { get; set; }
public int id { get; set; }
public string title { get; set; }
public string body { get; set; }
public string userIdEncrypted { get; set; }
public string userIdEncryptedReturned { get; set; }
public string parmsStr { get; set; }
}
I am aware of my inexperience programming on .Net and c#, so any help and explanations are welcome.
Regards,
Raul.
this is one of those rare error messages that tells you exactly what the problem is
Deserialization of types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with 'JsonConstructorAttribute' is not supported.
you need to add a default constructor to Post
public Post() {}

Custom error objects for .Net Core 3 web api

I am currently developing a web api in .NET Core 3. I currently have the following model for my error response object:
public class ErrorRo
{
public string Message { get; set; }
public int StatusCode { get; set; }
public string Endpoint { get; set; }
public string Parameters { get; set; }
public string IpAddress { get; set; }
}
This is a mandated response I need to implement, management has pushed this. It allows more verbose error messages for people hitting our API so that they know what went wrong.
At the moment I am currently populating this object manually in the methods themselves. Is there a way where I can overwrite the response methods. I.e. can I override the BadRequest of IActionResult to automatically populate these fields?
Thanks!
You can use result filters for this purpose. Add a filter which repalces result before sending it back
Model
public class CustomErroModel
{
public string Message { get; set; }
public int StatusCode { get; set; }
public string Endpoint { get; set; }
public string Parameters { get; set; }
public string IpAddress { get; set; }
}
Filter
public class BadRequestCustomErrorFilterAttribute : ResultFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext context)
{
//todo: check for BadRequestObjectResult if anything is returned for bad request
if (context.Result is BadRequestResult)
{
var result = new CustomErroModel
{
StatusCode = 200, //you status code
Endpoint = context.HttpContext.Request.GetDisplayUrl(),
Message = "some message",
IpAddress = context.HttpContext.Connection.RemoteIpAddress.ToString(), //find better implementation in case of proxy
//this returns only parameters that controller expects but not those are not defined in model
Parameters = string.Join(", ", context.ModelState.Select(v => $"{v.Key}={v.Value.AttemptedValue}"))
};
context.Result = new OkObjectResult(result); // or any other ObjectResult
}
}
}
Then apply filter per action or globally
[BadRequestCustomErrorFilter]
public IActionResult SomeAction(SomeModel model)
or
services
.AddMvc(options =>
{
options.Filters.Add<BadRequestCustomErrorFilterAttribute>();
//...
}
Well it depends on the scenario, but one possible approach could be to use a middleware using a similar strategy like the one described in this question, so that you complete the response with extra information.

Asp net core bad model in parameter at post action is not set to null

I have this problem I'm following the Api course on pluralsight and I've been trying to understand why when I pass an invalid Dto in a post request it doesn't get set to null.
Here is my Dto
public class AuthorCreateDto
{
public string Name { get; set; }
public string LastName { get; set; }
public int GenreId { get; set; }
public int CountryId { get; set; }
}
and action
[Route("")]
[HttpPost]
public ActionResult<AuthorDto> CreateAuthor([FromBody]AuthorCreateDto authorCreateDto)
{
if (authorCreateDto == null)
return BadRequest();
var author = Mapper.Map<Author>(authorCreateDto);
if (TryValidateModel(author))
return BadRequest();
var newAuthor = _authorService.CreateAuthor(author);
var newAuthorDto = Mapper.Map<AuthorDto>(newAuthor);
return CreatedAtRoute("GetAuthor", new { id = newAuthor.Id }, newAuthorDto);
}
so when I post an invalid json as
{
"epa": 2,
"wdawd": "awdawd"
}
authorCreateDto does not get set to null while on the course it does. Idk whats going on thank you
For Asp.Net Core, its built-in serializer is Newtonsoft.Json and for FromBody, it will use JsonInputFormatter to bind the request body to model.
By default, SerializerSettings.MissingMemberHandling is Ignore which return default value for the properties which is missing in the request body.
If you prefer null for authorCreateDto, you could configure it with Error by
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.AddJsonOptions(options => {
options.SerializerSettings.MissingMemberHandling = Newtonsoft.Json.MissingMemberHandling.Error;
});
}

C# / MVC Validate model data and call external API based on the results

I have created an WebAPI web app and I would like to validate the data when POST and based on the results to call an external API.
The data will be saved in the database as it is, apart from the validation results.
Validation will be done only for calling the external API.
I have created the logic for posting to the external API but I'm not quite sure how it will be the optimal way to validate the data.
My model includes 10 classes like the below Class1 with multiple properties and I've created a controller for each of them.
The properties can have the true/false values but as strings.
public class Class1
{
public ICollection<Class1Data> Data { get; set; }
}
public class Class1Data
{
public int Id { get; set; }
public string Prop1{ get; set; }
public string Prop2 { get; set; }
..
public string Prop10 { get; set; }
}
WebAPI contoller for POST:
[ResponseType(typeof(Class1))]
public async Task<IHttpActionResult> PostClass1(Class1 class1)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Class1.Add(class1);
await db.SaveChangesAsync();
return CreatedAtRoute("DefaultApi", new { id = Class1.Id }, class1);
}
I've manage somehow to validate one property and POST to external API but not quite sure how I can do that for all my model classes ( I have around 10, 20 props each ).
var notValid = Class1.Data.Where(x => x.Prop1 == "False");
if (notValid != null)
{
foreach ( var fault in notValid )
{
// Call external API using fault.Prop1 / fault.Prop5 / ..
}
}
How could I achieve this?
I hope that my question makes any sense to you.
The simplest way is to use Data Annotations:
Examples:
[StringLength(100)]
public string AccountKey { get; set; }
[Required]
[StringLength(100)]
public string FirstName { get; set; }
Or if you need custom validations you can define them as Custom Validation Attributes and use them like below:
[Required]
[CountryCode]
[StringLength(3)]
public string CountryCode { get; set; }
In this sample [CountryCode] is a Custom validation which you can implement like this:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
public class CountryCodeAttribute : RegularExpressionAttribute
{
public CountryCodeAttribute() :
base("^[A-z]{2,3}([-]{1}[A-z]{2,})?([-]?[A-z]{2})?$")
{
ErrorMessage = "Invalid country code.";
}
}
You will need to import this namespace for this kind of validation:
System.ComponentModel.DataAnnotations

Automapper from SOAP Web Service to View Model

I want to use Automapper for mapping SOAP Web Service Response to a Model which will be used to return the result through a Web API.
Mostly of the attributes returned in the object by the web service are codes, we want to show in the response of our api the descriptions related to those codes.
For example:
The web service response with a list of:
<charge>
<type>ABC</type>
<qualifier>3</qualifier>
<periodCode>004</periodCode>
<code>STE</code>
</charge>
<charge> ... </charge>
Which will be encapsulated in a class like this:
class Charge {
string type { get; set; }
string qualifier { get; set; }
string periodCode { get; set; }
string code { get; set; }
decimal rate { get; set; }
}
Our model is:
public class RCharge {
public string Description { get; set; }
public bool? IncludedInRate { get; set; }
public decimal? AmountValue { get; set; }
public string Period { get; set; }
}
I have stored in a database the information related to the codes and descriptions, as all codes have their own description.
The problem is how to map from the code returned in the web service, to the description. I have this code, and I could make a call to the database in search of the code and get the description, but is it ok? I guess the ConstructUsing is executed for every item in the response, so make a query here would result in a bunch of requests to DB.
AutoMapper.Mapper.Initialize(config => {
config
.CreateMap<Charge, RCharge>()
.ConstructUsing(s => RChargeConstructor.Construct(s));
});
public class RChargeConstructor {
public static RCharge Construct(ResolutionContext context) {
if (context == null || context.IsSourceValueNull)
return null;
var src = (Charge)context.SourceValue;
return new RCharge() {
Description = src.type, // want description from DB
IncludedInRate = src.qualifier == "3",
AmountValue = src.rate,
Period = src.periodCode // want description from DB
};
}
}
Is there a good approach for doing this kind of mapping?

Categories