Asp.Net Web Api multiple files with additional data for each - asp.net

I am trying to send multiple files along with some data for every file. This is my model:
public class FileDTO
{
[Required]
public IFormFile File { get; set; }
[Required]
public string CategoryName { get; set; }
[Required]
public string CategoryDescription { get; set; }
public string Detail { get; set; }
}
This is my controller:
[HttpPost("Upload/{id:int}")]
public async Task<IActionResult> Upload(int id, IEnumerable<FileDTO> appFileDTOs)
{
...
}
Is this even a correct way to do so? How do I send such a request in Postman to simulate it?
Thanks in advance!
Edit
I tried it like this in Postman:
Everything submits correctly besides the image. For some reason the image is always null...

[] represents collection/dictionary index while dot(.) represents there's a property.
So you should rename all the field names with the dot representation.
For example, change
appFileDTOs[0][File]
to
appFileDTOs[0].File
Demo

try this it may help you,
send from formData.
in model key send value as
[
{
"CategoryName":"Category1",
"CategoryDescription ":"Category1 Description",
"Detail":"Details "
},
{
"CategoryName":"Category2",
"CategoryDescription ":"Category2 Description",
"Detail":"Details2"
}
]
and for file send first file as file1 and second file as file2;
In server side , remove IEnumerable of FileDTO appFileDTOs from method name.
get value of model as
var data = JsonConvert.DeserializeObject<List<FileDTO>>(Request.Form["model"]);
simillary for file
var fileUpload1 = Request.Form.Files["file1"];
var fileUpload2 = Request.Form.Files["file2"];

Related

Deserializing of untrusted data using C#

I have the following C# code which is getting a "high" error from Checkmarx. I can't see anything wrong with it.
var dataDirectoryPath = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();
var json = File.ReadAllText($"{dataDirectoryPath}{Path.DirectorySeparatorChar}somefile.json");
var settings = new
JsonSerializerSettings{TypeNameHandling=TypeNameHandling.None};
var targetPathSettings = JsonConvert.DeserializeObject<List<TargetPathSetting>>(json, settings);
It gives this error:
The serialized object ReadAllText processed in xxx in the file yyy is deserialized by DeserializeObject in the file zzz
The C# code is as follows:
public class TargetPathSetting
{
public string PathSettingName { get; set; }
public PathSetting PathSetting { get; set; }
}
public class PathSetting
{
public string BaseUrl { get; set; }
public string ApplicationIdUri { get; set; }
}
I can't see that anything that is ever in the file is going to cause any sort of problem, especially with the TypeNameHandling.None setting.
The problem is with the standard Checkmarx query for c #. In this case, Checkmarx does not recognize the correction of this code. To fix it you should use CxAudit and modify this query.

Problems with Full Text Search in Postgresql & .Net Core 2.1

I post this question because I dont found similar issue yet. I'm trying to ensure Full Text Search in .net core app, and according to npgsql documentation I have:
1) Model
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public long License { get; set; }
public NpgsqlTsVector SearchVector { get; set; }
}
2) DatabaseContext:
modelBuilder.Entity<User>()
.HasIndex(p => p.SearchVector)
.ForNpgsqlHasMethod("GIN");
3) Migrations:
migrationBuilder.Sql(
#"CREATE TRIGGER user_search_vector_update BEFORE INSERT OR UPDATE
ON ""Users"" FOR EACH ROW EXECUTE PROCEDURE
ts`enter code here`vector_update_trigger(""SearchVector"", 'pg_catalog.english', ""Name"", ""Surname"");");
Now, I'm trying use FTS in my app, where method Search gets from header 'phase' (string).
[HttpGet]
public async Task<IActionResult> Search([FromHeader] string phase)
{
NpgsqlTsQuery tsVestor = EF.Functions.ToTsQuery("english", phase);
var response = Ok(_context.Users.Where(c => c.SearchVector.Matches(phase)).ToList());
return response;
}
I got:
NotSupportedException: Specified method is not supported.
Microsoft.EntityFrameworkCore.NpgsqlFullTextSearchDbFunctionsExtensions.ToTsQuery(DbFunctions _, string config, string query) in NpgsqlFullTextSearchDbFunctionsExtensions.cs
I also tried send by Header lexeme and comment line:
NpgsqlTsQuery tsVestor = EF.Functions.ToTsQuery("english", phase);
but i got: PostgresException: 42883: operator does not exist: tsvector ## text
Does anyone have any idea what I'm doing wrong?
EDIT ---- :
Ok, I found answer on my question. Converting from string to NpgsqlTsQuery must be inside Matches method:
public async Task<IActionResult> SearchUsers([FromHeader] string phase)
{
return Ok(_context.Users.Where(c => c.SearchVector.Matches(EF.Functions.ToTsQuery(phase))));
}
Placing this convertion outside Matches method threw "NotSupportedException", and putting plain text as function argument threw 42883 Exeception.
Now, it's clear what I was doing wrong.
As #sonofaforester suggests, I put answer on my own question:
Converting from string to NpgsqlTsQuery must be inside Matches method:
public async Task<IActionResult> SearchUsers([FromHeader] string phase)
{
return Ok(_context.Users.Where(c => c.SearchVector.Matches(EF.Functions.ToTsQuery(phase))));
}
Placing this conversation outside Matches method threw "NotSupportedException", and putting plain text as function argument threw 42883 Exception.

Is there a way to change Property Name in JSON data

Is there a way I can change the column/property name I'm returning from a JSON response through a Web API ?
Sample JSON response:
[
{
"ActualPropName1": "Value1", //change ActualPropName1 to something else
"ActualPropName2": "Value2"
}
]
I tried using Data Annotation on the Model, but, it doesn't seem to achieve what I want
[DisplayName("Generic Name")]
public string ActualPropName1{ get; set; }
You could simply have a new property with the desired name that simply returns data from the other property. Then hide/ignore the other:
[JsonIgnore]
public string ActualPropName1 { get; set; }
public string GenericName
{
get
{
return ActualPropName1;
}
}
Although from your example this won't work for property names like 'Generic Name'.
You can use JSON.NET's JsonProperty
[JsonProperty(PropertyName="Your_Name")]
public string ActualPropName1{ get; set; }

Model Validation With Web API and JSON Patch Document

I'm using JsonPatchDocument with ASP.NET 4.5 and Web Api. My controller looks like this:
[HttpPatch]
[Route("MyRoute/{PersonItem1}/{PersonItem2}/")]
public IHttpActionResult ChangePerson([FromHeader]Headers, [FromBody]JsonPatchDocument<PersonDto> person)
{
// Do some stuff with "person"
}
And PersonDto:
public class PersonDto
{
public string Name { get; set; }
public string Email { get; set; }
}
Now, I may send a PATCH request that is something like:
{
"op": "op": "replace", "path": "/email", "value": "new.email#example.org"
}
Now let's say I add some data annotations:
public class PersonDto
{
public string Name { get; set; }
[MaxLength(30)]
public string Email { get; set; }
}
What is the best way to ensure this validation is honored without writing additional validation. Is it even possible?
There is the simple method:
Get your object from your repository.
Deep copy the object so you have object A and B.
Apply the change with person.ApplyUpdatesTo(objB).
Create an extension method to validate the difference between object A and B.
If the validation is good proceede, if not throw an error.
This would catch if the client was attempting to modify immutable fields or if the new information in object B violates your constraints.
Note that this is not a great solution in that you would have to change your code in two places if you happen to change your constraints.

ASP.Net MVC3 conditional validation

I'm having some troubles with validation on my application.
Let's say I've the following models:
public class Company
{
public int id { get; set; }
[Required]
public String Name { get; set; }
public String Location { get; set; }
public List<Contacts> Contacts { get; set; }
}
public class Contact
{
public int id { get; set; }
[Required]
public String Name { get; set; }
[DataType(DataType.EmailAddress)]
public String Email { get; set; }
public String Telephone { get; set; }
public String Mobile { get; set; }
}
Now in my company create view I've two buttons, one to add contacts to the company, and another one to create the new company.
I detected which button was used in my controller like this (both buttons are named "button"):
[HttpPost]
public ActionResult Create(String button, FormCollection collection)
{
if(button == "AddContact")
{
AddContact(collection);
}
else
{
CreateCompany(collection);
}
}
While it's being created the object that represents the company that it's being create is stored in the session (for example HttpContext.Session["company"] = company;)
Now the problem is that if, for example, I try to add a contact without first specifying the company name, i get a validation error because the company name is required, which shouldn't happen because the user might want to add the contacts before adding the company info. Or if I try to save the company, I also get a validation error, because usually when saving the "add contact" form is empty, which means that the contact name (which is required as well) was not specified.
What I want to know is that if it's possible to validate the contact properties only when the addContact button is used, and validate the company properties only when the createCompany button is pressed.
For now i only need to do this serve-side, but if anyone has a solution to do this client-side as well i would appreciate the help.
You could trigger your own validation on the individual objects using
Validator.TryValidateObject(Object, ValidationContext, ICollection)
You can provide conditional validation using the Entity Framework by overriding DbEntityValidationResult in the DbContext. When this validation occurs in the DbContext you can access other entities. When validating a contact you can check the company too. For example:
protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
{
var result = base.ValidateEntity(entityEntry, items);
ValidateContact(result);
return result;
}
private void ValidateContact(DbEntityValidationResult result)
{
var contact= result.Entry.Entity as Contact;
if (contact!= null && contact.ContactId != 0)
{
// Add validation code here, such as:
if(!string.IsNullOrEmpty(contact.Company.Name){
result.ValidationErrors.Add(
new DbValidationError(
"Contact",
"Company name cannot be null or empty when validating contacts.")
);
}
}
}
See Julia Lerman's Programming Entity Framework: DbContext http://www.amazon.com/Programming-Entity-Framework-Julia-Lerman/dp/1449312969 for more details.

Resources