I use some Azure Functions as WebApi. Now I have the following DTO to create a vehicle:
public class CreateVehicleDto
{
public string LicensePlate { get; set; }
public int? Mileage { get; set; }
public string Manufacturer { get; set; }
}
My method header looks like this:
[FunctionName("CreateVehicle")]
public async Task<ActionResult<ReadVehicleDto>> CreateVehicle([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "vehicles")] CreateVehicleDto createVehicleDto){}
The problem is that when my client sends a mileage higher than int.MaxValue all properties of the DTO are null and the method runs without throwing any exception whatsoever.
Is there a way to handle that? In case of a too high mileage I want to return a BadRequestResult.
I've also tried to use the System.ComponentModel.DataAnnotations to set a maximum like this [Range(0, int.MaxValue)] and validate it with the System.ComponentModel.DataAnnotations.Validator. But when the object gets validated it's already too late because all properties of the DTO get passed into the method with a value of null.
Related
I am developing a dashboard in react which calls backend API to fetch all recipes from the database. So the search criteria would be huge. Its required to pass many filter attributes into the backend to get the correct recipes.
As an example below I have defined a class for Search Parameters
public class SearchParams
{
public string TemplateName { get; set; } = "";
public DateTime DateFrom { get; set; }
public DateTime DateTo { get; set; }
public String CreatedBy { get; set; } = "";
public Guid Id { get; set; }
}
So the GET method is required to handle whatever the parameters provided fetch the corresponding recipes from the DB accordingly.
But since GET requests doesnt support accepting parameters as OBJECT (SOrry if I am wrong) I thought about trying with POST. But that feels a little confused to use POST for a search functionality.
So with GET method do I need to define with all the parameters like this
[HttpGet]
public IEnumerable<Recipes> Get(string TemplateName,DateTime DateFrom....)
{
return new string[] { "value1", "value2" };
}
Or any best approach for this?
Please note, my real search criteria include many attributes other than the properties in my class definition above.
nothing prevents you from using SearchParams as an input parameters
[HttpGet]
public IEnumerable<Recipes> Search(SearchParams par)
the only problem is that Get doesn't include a body, so all data should be included in a query string
.../search?TemplateName=TemplateName&CreatedBy=....
I'm using .NET core and EF in my Web API project.
I want to have a Patch end point to update an entity. I found this article which says
Remove Similar to the “Add” operation outlined above, the Remove
Operation typically means you are either removing a property from an
object or removing an item from an array. But because you can’t
actually “remove” a property from an object in C#, what actually
happens is that it will set the value to default(T). In some cases if
the object is nullable (Or a reference type), it will be set to NULL.
But be careful because when used on value types, for example an int,
then the value actually gets reset to “0”.
I don't want the client to send a remove operation which will reset some of his fields or adding a new filed using Add operation
So here I want to create the PATCH end point to update the person FirstName or Age using replace operation only.
I have a Person entity and UpdatePersonDTO like below
public partial class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public int Age { get; set; }
}
public partial class PersonDTO
{
public string FirstName { get; set; }
public int Age { get; set; }
}
This the current code I have
public async Task<Object> UpdatePerson(int id , JsonPatchDocument<PersonRequestDTO> patchDocument) {
var result = _dbContext.persons
.Where(P => P.id == id).FirstOrDefault();
var personToPatch = _mapper.Map<PersonRequestDTO>(result);
patchDocument.ApplyTo(personToPatch);
_mapper.Map(personToPatch, result);
// rest of code and returning updated entitiy dto...
}
Now what is the way to achieve that? and why I couldn't find questions similar to this?
I think the remove operation is very critical , so now I'm feeling that I'm actually missing something here.
As the article says, Add and Remove can't add or remove attributes in C#, only array items. A remove is equivalent to setting the attribute to null, or if it's a value type, to its default.
Validation rules and attributes can detect this. The JSON Patch example in the ASP.NET Core docs shows exactly this scenario. With a slight modification :
[HttpPatch]
public IActionResult JsonPatchWithModelState(
int id,
[FromBody] JsonPatchDocument<Person> patchDoc)
{
if (patchDoc != null)
{
var person = _dbContext.persons
.Find(id)
.FirstOrDefault();
patchDoc.ApplyTo(person, ModelState);
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_dbContext.SaveChanges();
return new ObjectResult(person);
}
else
{
return BadRequest(ModelState);
}
}
Adding validation attributes to the Person class will ensure it can't accept invalid data :
public partial class Person
{
public int Id { get; set; }
[Required]
public string FirstName { get; set; }
[Range(1,199)]
public int Age { get; set; }
}
If we fear the PATCH may modify the ID, and the field is not database-generated, we can check that the person.id is unchanged :
if (!ModelState.IsValid || person.id!=id)
{
if (person.id!=id)
{
ModelState.AddError("id","Not Editable");
}
return BadRequest(ModelState);
}
My azure mobile app backend is presenting a strange behavior.
If my controller action returns an IQueryable<T> and the entity type has a navigation property, it returns 500.
A simple example:
Model
public class ProductHierarchy : EntityData
{
public string Name { get; set; }
public string Description { get; set; }
public DateTime ValidFrom { get; set; }
public DateTime ValidTo { get; set; }
public string BrandId{ get; set; }
[ForeignKey("BrandId")]
public virtual Brand Brand { get; set; }
public ProductStatus Status { get; set; }
public int CreatedBy { get; set; }
public int ModifiedBy { get; set; }
}
Controller Action
[HttpGet]
[Route("api/ProductHierarchies/FromBrand/{brandId}")]
public IQueryable<ProductHierarchy> FromBrand(int brandId)
{
var hierarchies = Query().Where(hi => hi.Brand.OldBrandId ==brandId);
return hierarchies;
}
When I make a request to this action, with the solution running on my local machine, everything works fine, however when I publish the solution to azure, the FromBrand action starts to return 500, with the generic message
"An error has occurred."
In addition, Azure Logs shows me the following exception when I make a request to the action:
Detailed Error Information: Module
__DynamicModule_Microsoft.Owin.Host.SystemWeb.OwinHttpModule,Microsoft.Owin.Host .SystemWeb, Version=3.0.1.0, Culture=neutral,PublicKeyToken=31bf3856ad364e35_19e9f0a3-023d-4d8b-83ef- 180a415e7921 Notification PreExecuteRequestHandler Handler ExtensionlessUrlHandler-Integrated-4.0 Error Code 0x00000000
I've found two changes that can avoid the error:
1) When I decorate the Brand property of the Model with JsonIgnore, the Brand property is ignored and everything works fine
2) When I change the action return type to List<ProductHierarchy>, keeping the Brand property of the model without the JsonIgnore atribute, everything works fine too.
It leads me to conclude that the problem is happening serializing IQueryable<T> when T have a property with another entity as type.
I didn't found anyone having the same issue, so I started to look into my nuget packages looking for wich package Works or Interact with the serialization proccess, and my suspicious are all over Newtonsoft Json and AutoMapper.
Anyone have some clue about how to look under the hood of these packages and determine the origin of the problem?
There are lots of issues and edge cases around relationships. I'm not surprised you have bumped into an issue.
Some resources:
The book - http://aka.ms/zumobook (particularly chapter 3)
Blog on relationships:
https://shellmonger.com/2016/05/27/30-days-of-zumo-v2-azure-mobile-apps-day-26-relationship-advice/
I am very new in dynamodb. I am following http://www.rkconsulting.com/blog/persistence-model-framework-with-aws-dynamodb
step by step tutorial for connecting and CRUD operation in dynamodb and it`s works fine.
In that tutorial they using attribute mapping for map class properties
[DynamoDBTable("Dinosaur")]
public class Dinosaur
{
[DynamoDBHashKey]
public string Id { get; set; }
[DynamoDBProperty(AttributeName = "Name")]
public string Name { get; set; }
[DynamoDBProperty(AttributeName = "HeightMetres")]
public double HeightMetres { get; set; }
[DynamoDBProperty(AttributeName = "WeightKG")]
public double WeightKg { get; set; }
[DynamoDBProperty(AttributeName = "Age")]
public int Age { get; set; }
[DynamoDBProperty(AttributeName = "Characteristics")]
public List<string> Characteristics { get; set; }
[DynamoDBProperty(AttributeName = "Photo", Converter = typeof(ImageConverter))]
public Image Photo { get; set; }
[DynamoDBIgnore]
public int IgnoreMe { get; set; }
}
My question is there any way to map class properties without using attribute ?
like as mongoDb
public class Employee
{
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
}
we can write this in this way in a separate class
BsonClassMap.RegisterClassMap<Employee>(cm => {
cm.AutoMap();
cm.IdMemberMap.SetRepresentation(BsonType.ObjectId);
});
Is it possible in dynamodb ?
In the latest version of the .NET SDK you don't have to put in the attribute tags, it will see all read/write properties and upload the attributes as the same name. You would only have to use the [DynamoDBProperty(...)] if you want the attribute name in DynamoDB to be something other than the .NET object name.
So in your case you could simply remove that attribute for all properties except photo (which needs the converter, you could remove the AttributeName part of it) and WeightKg (because the capitalization is different) and you would get the same result.
I see this is a little bit older question now, so it may not have been that way in older versions (not sure) but I'm using 3.3.0.0 of the SDK and it does work that way. You have probably moved on but answering for others that may come upon this thread as I did...
There is no way, the default "strongly typed" client relies on attributes.
If you have time to do the plumbing yourself - there is nothing stopping your from doing your own implementation of the POC to Dynamo mapping though. Amazon client api (AWSSDK.DynamoDBv2) exposes the raw class AmazonDynamoDBClient which handles all the API calls and the DynamoDBConext is just implementation of IDynamoDBContext interface - which exposes all the "strongly typed" operations. So you can make your own implementation and take different mapping approach in it.
Also you can make a feature request for this:
https://github.com/aws/aws-sdk-net/issues
Is it possible to set an optional [Required] attribute, applicable on PATCH or PUT. I have the following code but no matter what the controller call it will always be required.
public class Car
{
[DataMember(Order = 0)]
public string CarId { get; set; }
[DataMember(Order = 1)]
[Required]
public string IsIncluded { get; set; }
}
Controller;
[HttpPatch]
public HttpResponseMessage PatchCar(Car car)
{
// check if submitted body is valid
if (!ModelState.IsValid)
{
// Something is bad!
}
}
What I want is something like the following;
public class Car
{
[DataMember(Order = 0)]
public string CarId { get; set; }
[DataMember(Order = 1)]
[Required(Patch = True, Put = False]
public string IsIncluded { get; set; }
}
Then my ModelState will take the very into account.
I thought about creating separate derived classes for each action (verb), but the code quickly becomes incredibly verbose.
This is one of the drawbacks of using data annotations for validation unfortunately they cannot be conditionally added.
There are a number of options to you...
Create separate models (or view models) for each verb.
Look into something like this.. http://andrewtwest.com/2011/01/10/conditional-validation-with-data-annotations-in-asp-net-mvc/ which extends required to be IfRequired and adds conditional validation to data annotations. (You would need to roll your own I should think and it may get clumsy!)
Try something like FluentValidation.
http://fluentvalidation.codeplex.com/ (this could be a good option depending on your application requirements).
Hope this helps!