Swashbuckle IOperationFilter for query parameters class doesnt work with nested classes - asp.net-core

I've build custom IOperationFilter based in this article.
It works ok with simple examples like this:
public async Task<IActionResult> GetModels([FromQuery]Parameters parameters)
{
...
}
public class Parameters
{
public int PageSize {get;set;}
public int PageNumber {get;set;}
}
But when I try to set complex parameters like this:
public async Task<IActionResult> GetModels([FromQuery]ComplexParameters parameters)
{
...
}
public class Parameters
{
public int PageSize {get;set;}
public int PageNumber {get;set;}
}
public class ComplexParameters
{
public string Contains {get;set;}
public Parameters Pagination {get;set;}
}
I got problem that swagger creates RequestUrl with brackets for nested class:
https://Url/Path?contains=string&pagination[pageSize]=0&pagination[pageNumber]=0

Related

How to pass FormFile and json object in single model using Asp.net core

I have a model class. That class contains multiple properties , list of custom class and list of formfile data. I need to create post request for this model using Asp.net Core.
Model Class
public class TenoModel
{
[Key]
public int Id { get; set; }
public DateTime Date { get; set; }
public float Salary { get; set; }
[Required]
public string User { get; set; }
public List<IformFile> files {get;set;}
public List<Employee> employees{get;set;}
}
Custom class for employee
public class Employee
{
public int Id {get;set;}
public string Name {get;set;}
public double Salary {get;set;}
}
HttpPost request:
[HttpPost("CreateTeno")]
[Consumes('multipart/form-data']
public async Task<IActionResult> CreateTeno([FormFile] TenoModel model)
{
..... save the model data to teno database
}
When I execute the HttpPost request on swagger Formfile data and some property data come to incoming request on CreateTeno method. I fill the Employee object also in swagger. but that data not coming in my CreateTeno method. List of Employee data count zero. How to pass model class with multiple properties, List of IformFile and multiple list customclass in HTTP post request. Give a sample example.
You'll have to change the signature of your controller method like this:
public async Task<IActionResult> CreateTeno([FromForm] TenoModel model)
Tested with Postman like this
Please note that you have a syntax error here: [Consumes('multipart/form-data'], should be [Consumes("multipart/form-data")]

Asp.Net Core - multiple action methods with the same name and different parameters

I'm looking for a way to have more than one action method with the same name in controller without changing Url (route).
[HTTPPost]
Public ActionResult Method1 (Dto1 param)
{
}
[HTTPPost]
Public ActionResult Method2 (Dto2 param)
{
}
[HTTPPost]
Public ActionResult Method3 (Dto3 param)
{
}
This throws error -
Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints
Dto1, Dto2 and Dto3 derive from a base Dto, each have properties specific to different request methods. I am trying to avoid having a single method with a common Dto which will require multiple validations such as validating mandatory fields based on the value of other fields, etc. If we can have 3 different Post methods with different Dtos, it would makes things much easier
Adding Dtos (Simplified)
public class BaseDto
{
public string CommonProp1 { get; set; }
public string CommonProp2 { get; set; }
}
public class Dto1: BaseDto
{
public enumType Type = enumType.Type1;
public string Property1 { get; set; }
}
public class Dto2 : BaseDto
{
public enumType Type = enumType.Type2;
public string Property2 { get; set; }
}
public class Dto3 : BaseDto
{
public enumType Type = enumType.Type3;
public string Property3 { get; set; }
}
You can use Routes or calling a private method from the three above methods, you shouldn't do this as you want. I think your problem is more deep.
But.... if you still want it, here is a workaround.
Instead of receiving an object, receive a string with json content and parse the object.
But you will have to have a property inside the "json object" or another parameter that defines you wich object it is (Dto1, Dto2 or Dto3). In any case will be the same that use different routes or methods because objects are different.
[HTTPPost]
Public ActionResult Method (string param)
{
//Decode your string called param with JSON with a property inside
}
or
[HTTPPost]
Public ActionResult Method (string param, int type)
{
//Decode your string called param with JSON switching "type" as 1, 2 or 3
}
UPDATE after your update:
I suggest you receive BaseDto and the type in other parameter.
[HTTPPost]
Public ActionResult Method (BaseDto param, int type)
{
}

How does the .net core framework handle model binding on routes using the FromQuery attribute when the type has properties that are also classes?

It seems obvious to me that a method that looks like this:
[HttpGet]
public async Task<IActionResult> Get([FromQuery] SomeType data) {
}
where SomeType is:
public class SomeType {
public int HowMany { get; set; }
public string Why { get; set; }
}
Would be used by a url that looks like domain/controllerName?howMany=5&why=whoknows
But what if SomeType looks like this?
public class SomeLowerType {
public int anotherThing { get; set; }
}
public class SomeType {
public int HowMany { get; set; }
public string Why { get; set; }
public SomeLowerType Anotherhing { get; set;}
}
What would the url look like for that please? Struggling to find docs on this.
You can use . for nested properties, just as you would in code. That makes your example look like this:
domain/controllerName?howMany=5&why=whoknows&anotherhing.anotherThing=whatevs

how to make httppost actionresult bind to only part of the viewModel

I have the following sudo-code
class viewModel
{
public ICollection<modelA> parentModel
public modelC formModel
}
class modelA
{
public int ID {get;set;}
public virtual Icollection<modelB> {get;set;}
}
class modelB
{
public int ID {get;set;}
public string SomeString {get;set;}
public virtual modelA ModelA {get;set;}
}
class modelC
{
public int ModelAID {get;set;}
public string SomeString {get;set;}
}
So. the view model contains a collection of As. Each A contains a collection of Bs and there is a separate model for posting back as a form: the form will be repeated on the page, once in each instance of A with the A.ID passed in to ModelAID as a hidden field. Only one form posting is allowed on the page, The id of the form fields are formModel.ModelAID and .formModel.SomeString as they are derived from the non-parent element of the viewModel.
How do I get the ActionResult to bind only to formModel?
[HttpPost]
Public ActionResult Input(formModel vm)
{
... by default the view model being passed back is full VM, I only want the formModel so the post signature does not match
}
You can try something like
public ActionResult Input([Bind(Prefix = "formModel ")]modelC model)
{
}

EF4 Code Only - Map Columns to Property Complex type

I have a table like this:
Name
Tree
Iron
Clay
Added
I want to map it to a model like this:
Name
Resources
Tree
Iron
Clay
Added
In makes sense to map it like this, when working with it in my program, but doing it that way in the databse would just make it more complex ... not would not add any useful things.
Is it possible with EF4 Code ONly?
public class Sample
{
public int Id { get; set;} // primary key required
public string Name {get;set;}
public DateTime Added{get;set;}
}
public class Resource
{
// no Id defined here
public string Tree{get;set;}
public string Iron { get;set;}
public string Clay { get;set;}
}
public class SampleDB : DbContext
{
//public DbSet<Resource> Resources { get; set; } // should not be there
public DbSet<Sample> Samples { get; set; }
}