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;
});
Related
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.
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've been trying to figure this out for about a week now. It's time to ask S.O.
I have 4 overall goals here:
The controller code needs to use ViewModel request inputs for validation reasons. (Controller Snippet)
Client code for my API should use a nice model syntax. (Client Code Snippet)
For the swagger UI page, I would like the "Try me" interface to be usable. Either a bunch of text boxes, or a text area for a json blob to serialize and send over.
GET request
Client Code Snippet:
var response = client.GetUserProductHistory(new Models.UserProductHistoryRequest() {
Locale = "en-US",
UserPuid = "FooBar"
});
Controller Snippet
[HttpGet]
[HasPermission(Permissions.CanViewUserProductHistory)]
public JsonPayload<UserProductHistoryResponse> GetUserProductHistory([FromUri]UserProductHistoryRequest model)
{
JsonPayload<UserProductHistoryResponse> output = new JsonPayload<UserProductHistoryResponse>();
return output;
}
I have tried using [FromBody]. It looks great, but I get an error that says 'GET requests do not support FromBody'.
I tried using [FromUri], but then the generated client gives me like 15 method parameters per call in the generated client.
I tried using [FromUri], and operation filters so that the parameters would be condensed into Ref parameters (complex objects as defined by the spec). This actually worked decently for the client generation and the server side. Problem is, the UI for swagger looks really lame. A single TEXT box that you can't actually use very well. If I can figure out how to get the Swagger UI to change the appearance of the [FromUri] request to more closely match the [FromBody] UI, I will be in good shape here. Any ideas or pre-existing content that would point me in the right direction here?
Swagger is not the limitation - REST itself is. By definition of REST, web servers should ignore the incoming request body on all HTTP GET methods. ASP.NET enforces this convention, which is why you it doesn't allow you to use [FromBody] on the GET method.
When designing a REST API, the better practice is to use POST methods for an actual search. This will allow to use [FromBody], and as a bonus, Swagger will behave the way you want it to. See here for a supporting opinion: https://stackoverflow.com/a/18933902/66101
In our new product we have a few data entry fields that require you to search for the correct value to place in this field.
When you enter this data entry field I would like to provide a search option via something on the view (perhaps an Ajax implementation) and have it allow searching of the database for the value, but when the result returns I want to keep the existing values in place for other fields not affected by the search.
But I have no idea how to do this with MVC. Does anyone have any suggestions on how this should be done?
Write your data entry page in the
usual way for an ASP.NET MVC view.
Get it working without the Ajax
(e.g., submit works correctly when
you just type in the values, without
auto complete).
Write the prototype for a JavaScript method you'll called when the user performs a certain action (e.g. presses a key inside of a certain control). But this inside a script tag in your aspx page. Unfortunately, stack overflow seems to "sanitize" script tags in my example, so I can't demonstrate that part. But you're JavaScript prototype will look something like this:
function startAutoComplete() {
}
Now hook up the event handlers on the user interface control. You need to call the function you've just prototyped an appropriate event handlers for your application. From your description, it sounds like you might want to use onkeydown, but there are lots of events to choose from. You probably need to handle more than one event, as appropriate for your application.
So far, everything that we've done has been standard aspx and JavaScript. In this step, we'll do the only part of the whole process which is really different for ASP.NET MVC. You need to add an action to your controller which will be called (indirectly) by the JavaScript prototype you've just written. The action should accept appropriate input (e.g., a string representing the text from control, or something like that, as appropriate for your application) and return its results in JSON format. I'm going to show a really simple example here; feel free to substitute more complex code in your real application.
public ActionResult GetSuggestions(string searchText)
{
return Json(new {SearchText = searchText});
}
This example just returns a JavaScript object containing one property, which contains the value passed to the function. Like you said, you can write something more useful for your application.
Now you need to call this function in JavaScript. The URI will look something like:
http://localhost/mycontroller/GetSuggestions?searchText=Foo
It is possible to make Ajax calls without a JavaScript library, but much easier if you use jQuery or some other library which handles cross-browser compatibility issues for you. Since I happen to like jQuery, I'll demonstrate that. Let's update the startAutoComplete method we prototyped earlier:
function startAutoComplete() {
var searchText = $("#myeditorid").text();
$.getJSON("/mycontroller/GetSuggestions?searchText=" + searchText,
null,
autoCompleteResponse);
}
The first line uses jQuery to get the text in the control with the ID myeditorid. We'll pass this to the ASP.NET MVC action as the searchText argument, by appending it as a query string parameter.
The next line, which starts with $.getJSON calls a jQuery function which makes an Ajax call to the URI you specify. We pass an argument, autoCompleteResponse, which is the name of a JavaScript method to be called if the response from the Ajax call is successful. Now we have to write autoCompleteResponse.
function autoCompleteResponse(data) {
if (data.SearchText)
{
$("#myeditorid").text(data.SearchText);
}
}
This says, "If the data returned has a SearchText property, set the text of the control to that value." Again, do whatever is appropriate for your application with the data returned.