I have a .NET Core Web API that I have enabled XML comments on in the program.cs file by calling IncludeXmlComments.
I have the following XML comments set on my controller:
But the webpage displays an empty example column:
How do I get the Example column to be populated by the example attribute inside the tag?
The XML on my model does update when I change it so I believe this is correctly configured. I cannot get the Example column to hold a value for the controller parameter.
Related
I want my api to accept a query string array parameter in the form ?id=a,b,c,d as opposed to the standard ?id=a&id=b&id=c. For this I am following this excellent blog article.
Side question: Does ASP.NET Core provide built-in providers/attributes for that yet?
My main question however, is about SwashBuckle.AspNetCore:
In short, I'm trying to get a comma-separated parameter (?p=a,b,c,d) that is typed as an IEnumerable<string>, to show up correctly in the generated Swagger. According to the specs it should get style=form and explode=false. The default here (style=form and explode=true) matches the asp.net core default. How do I achieve this? Is there an annotation attribute that I can place on the parameter?
I'm pretty new to web development and swagger in general so apologies if the question is too naive.
I'll use the Asp.Net Core Web Api template in visual studio 2019 to better explain my problem, so please consider that environment in the case I have omitted some information (or just ask for the missing part that I'll bring it).
There we have the WeatherForecastController class with a simple GET (which I included the names parameter):
[HttpGet]
public IEnumerable<WeatherForecast> Get(IEnumerable<string> names)
{
//...
}
When I try to test this request using the Swagger page, it doesn't recognize the name parameter.
I have ran other tests to find out what's going on and I found the following:
Swagger does work with IEnumerable as it works pretty well if the parameter is of type IEnumerable<IFormFile> (it displays a list of uploaded files, shows the file selection dialog, etc);
I tried encapsulating the parameter(s) in a DTO class and it seems to break even more stuff (even the IEnumerable<IFormFile> doesn't seem to work inside a DTO class; it only works if passed directly in the parameter list of the [HttpVerb] method;
I tried with other similar types as well as ICollection<string>, List<string>, string[]; none of them seem to work;
This same problem happens using primitive types like bool, int, etc as type arguments to IEnumerable<T>;
So what is happening? Should I set some sort of configuration value so it can work with collections of primitive types?
Update with images showing the problem:
... Get(string names, IEnumerable<IFormFile> file):
... Get(IEnumerable<string> names, IFormFile file):
As you can see, when any parameter in the param list is of IEnumerable the swagger UI doesn't properly show the requested fields like in the second image.
You must specify model binding sources in your case. Your action method should be like this:
[HttpPost("test/names")]
public IEnumerable<string> PostNames([FromQuery]IEnumerable<string> names, IEnumerable<IFormFile> files)
{
//...some code
return names;
}
You shouldn't use two or more complex type parameter as an action parameters until you specify the source they are binding from. That's because complex objects are bound to request body by default and only one parameter can be bound to request body.
As of microsoft docs :
Don't apply [FromBody] to more than one parameter per action method. Once the request stream is read by an input formatter, it's no longer available to be read again for binding other [FromBody] parameters.
Complex type means class variables, arrays, and those which are not primary types like int,double, string and etc.
Swagger generates this UI for action above:
As the final word , Note that you can't send something in your request body when you are using GET http request.
I am creating a WebApi and I need to take a key value pairs for my GET endpoint. I found some examples of using dictionary in POST method bus this seems not to work with GET
So far I tried this:
[HttpGet]
public IActionResult Get([FromQuery] Dictionary<string, string> myVar)
{
}
I am using swagger to test the API and if I pass {"key":"value"} I am getting my dictionary with a single pair and value is the entire object I pass in. ({[myVar, {"key":"value"}]})
What is the correct way to pass multiple key value pairs to the WebApi for GET method?
EDIT: The underlying issue was that I was using swagger (swashbuckle) to test my endpoint. And at the moment of this question it doesn't support dynamic query parameters Issue on github. It should support it once OpenApi v3 support is added to swashbucle Issue on github.
You should be able to call the endpoint using the following structure and have the values automatically bound via Web API's built-in binder.
https://example.com/api/values?1=john&2=jane
1 and 2=keys for respective entries in dictionaries.
john and jane=values
I'm using 'swagger UI' with Swagger 2.0 in C#.Net app, and displaying Get, Post, Delete endpoints.
For Post, I'm passing 'model schema' as a body(input parameter).
Its difficult to use one textarea for to input class object.
Is it possible to customize body parameter UI alone... like separate input boxes for all the parameters in class object(model schema)?
SO that, for post method, with model schema parameter, UI will be separate textboxs for all the parameters in the class object(model schema)..
Did you notice that clicking on the Example value on the Data Type column actually fills in the body value with the default entity content? That's a start to avoid typing it all.
Nonetheless, you can also override the current Swagger UI display, changing existing views content to match the text-area to be transformed to a custom-made parser displaying property textboxes instead of a single textarea.
Add the following code to the ConfigureServices in Startup.cs
services.AddControllers()
//Used to Add Input field to the Swagger UI
.ConfigureApiBehaviorOptions(options =>
{
options.SuppressInferBindingSourcesForParameters = true;
});
I have an input, type text, element which is being validated using MVC3 validation on the client and I’d like to not have the input value sent to the server when the post occurs.
I have two entities: A “File” entity and a “Company” entity which share a 1 to 1 relationship. The file entity has a CompanyId foreign key.
This is why if you look at the name and id attributes they appear as: File.Company.Code or File_Company_Code.
The reason I want to avoid sending the input value back to the server is when the request reaches the server I only want to bind the values to my entity of type “File”. As it is also receiving a value for “File.Company.Code” it is also attemting to bind the values to the File’s company object, which is what I want to avoid.
The input element is :
<input name="File.Company.Code" id="File_Company_Code" type="text" data-val-required="Se requiere un código de cliente." data-val="true" value=""/>
And the span element:
<span class="field-validation-valid" data-valmsg-replace="true" data-valmsg-for=" File.Company.Code "/>
I’ve tried:
-Changing the input name and span data-valmsg-for attributes using jquery. But I think that after doing this I may need to rebind the validators??
Any suggestions? (I hope to have explained myself clearly if not let me know.)
Thanks
UPDATE 1 **
Thanks to AFinkelstein sugestion which put me on the right track I updated my domain model such as:
public class FileModel {
public File File {
get {
return this.file;
}
}
*** ADDED this which helped me solve the problem ***
public Company Company {
get {
return this.file.Company;
}
}
}
In my view instead of doing :
#Html.TextboxFor(model => model.File.Company.Code)
#Html.ValidationMessageFor(model => model.File.Company.Code)
I now do:
#Html.TextboxFor(model => model.Company.Code)
#Html.ValidationMessageFor(model => model.Company.Code)
This way the generated name and Id attributes have the value: Company.Code and Company_Code, they dont have the preceding "File". When I receive the post on the server and bind the values to the File object:
FileModel fileModel = new FileModel();
try {
TryUpdateModel(fileModel.File, "File");
as it is not receiving a value for "File.Company.Code" it doesnt attempt to initialize the file's "Company" object, which was causing me other problems.
As it is also receiving a value for “File.Company.Code” it is also attemting to bind the values to the File’s company object, which is what I want to avoid.
I presume this means that File is a domain model within your project. I recommend using a view model in your view.
public class FileViewModel
{
//other stuff contained within the File class
[Required]
public string FileCompanyCode { get; set: }
}
You can use your view model to create or refetch your actual File after posting. Just don't set your actual file company object to the file company code property in the view model. This way it doesn't actually matter if your file company code is binded or not.
I had a similar issue where I wanted the client-side validation but not the field being posted as it was a list of objects and the posting structure didn't support a normal validator.
Still, I was inspired by this question and answer and found out a solution where you add another input field (with all the HTML5 tags that an HTML.HiddenFor would have generated to enable unobtrusive validation) and Html.Validator for the non-existing model property hence the MVC binder in the postback would ignore it.
I also added an Html.ValidatorFor for the real property so that the validation on postback would have somewhere to render as my other validation tags point to a different tag (theoritically)