This is the DTO C# class:
public class WeatherForecast
{
public string DateFormatted { get; set; }
}
This is what is generated in the swagger definition:
{"WeatherForecast":{"type":"object","properties":{"dateFormatted":{"type":"string"}}}}
The problem is that when I generate an XML example:
<?xml version="1.0" encoding="UTF-8"?>
<WeatherForecast>
<dateFormatted>string</dateFormatted>
</WeatherForecast>
The problem is that when I send that XML back to the API, it does not populate the DateFormatted property. If I change the case so that it is no longer CamelCase (DateFormatted) it works properly, and the property is populated with "string".
How do I switch off CamelCase when generating the swagger definition?
In aspnet the camelcase properties name by default so you change Startup from
services.AddMvc();
to
services
.AddMvc()
.AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());
Reference: aspnet
Related
I am developing a rest application.
Some endpoints require a custom header parameter, not related to authorisation. I created a custom annotation using jax-rs NameBinding. Here is an usage example:
#GET
#RequiresBankHeader
public int get(
#HeaderParam("bank")
#Parameter(ref = "#/components/parameters/banks")
String bank) {
return someService.getSomeInformation();
}
There is a provider that intercepts this call and do some routine using the information in the header parameter.
The problem is that I have to repeat '#HeaderParam("bank") #Parameter(ref = "#/components/parameters/banks") String bank' everywhere, just so it appears in Swagger, even though the service classes do not need it. I was able to at least reuse the parameter definition with ref = "#/components/parameters/banks", and declaring it in the OpenAPI.yml file, that Quarkus merges with generated code very nicely.
But I also want to create and interceptor to dynamically add this do the OpenApi definition whenever RequiresBankHeader annotation is present.
Is there a way to do it?
I dont think you can use interceptors to modify the generated Openapi schema output.
If all methods on a given endpoint require some parameter, you can specify it on class level like so:
#Path("/someendpoint")
public class MyEndpoint {
#HeaderParam("bank")
#Parameter(name = "bank")
String bank;
#GET
public Response getAll() {return Response.ok().build()}
#GET
#Path("{id}")
public Response someMethod(#PathParam("id") String id) {return Response.ok().build();}
}
As mentioned by Roberto Cortez, the MP OpenAPI spec provides a programmatic way to contribute metadata to the openapi.yml file.
It is not possible to detect an annotation in the JAX-RS endpoint definition, but it was good enough to automate what I needed. Since all methods that had the RequiresBankHeader return the same Schema, I was able to hack it like this:
public class OpenApiConfigurator implements OASFilter {
#Override
public Operation filterOperation(Operation operation) {
operation.getResponses().getAPIResponses().values().stream().
map(APIResponse::getContent).
filter(Objects::nonNull).
map(Content::getMediaTypes).
flatMap(mediaTypes -> mediaTypes.values().stream()).
map(MediaType::getSchema).
filter(Objects::nonNull).
map(Schema::getRef).
filter(Objects::nonNull).
filter(ref -> ref.contains("the common response schema")).
findAny().
ifPresent(schema -> {
ParameterImpl parameter = new ParameterImpl();
parameter.setRef("#/components/parameters/banks");
operation.addParameter(parameter);
});
return operation;
}
OpenApiConfigurator should be configure in the application properties, using mp.openapi.filter=com.yourcompany.OpenApiConfigurator
I working on a ASP.NET Core 3.1 web api project. I'm using Swashbuckle.AspNetCore 5.0.0 for documenting my API. Things are working good. However I got stuck with generating response types as my api is using an middleware to wrap every response for consistency. I'm not able to generate correct response type in my swagger ui.
Here is an simple example,
My Action Method:
[HttpGet]
[ProducesResponseType(200, Type = typeof(IEnumerable<WeatherForecast>))]
public IEnumerable<WeatherForecast> Get()
...
As I mentioned, the project has response middleware which will wrap all the response as shown in the below format,
{
"Version": "1.0.0.0",
"StatusCode": 200,
"Message": "Request successful.",
"Result": [
"value1",
"value2"
]
}
Because of this I'm getting mismatch in response value in my swagger ui.
Example of response schema shown in swagger ui as per [ProducesResponseType(200, Type = typeof(IEnumerable<WeatherForecast>))]
But the actual wrapped response looks like,
Is it possible to handle these wrapped response using Swashbuckle.AspNetCore 5.0.0. Please assist me.
After some analysis and research, I found the solution. It's pretty simple using the [ProducesResponseType] attribute.
I created a separate class named ResponseWrapper<T>,
public class ResponseWrapper<T>
{
public int StatusCode { get; set; }
public string Message { get; set; }
public T Result { get; set; }
}
And then decorated my action method as follows,
[HttpGet]
[ProducesResponseType(200, Type = typeof(ResponseWrapper<IEnumerable<WeatherForecast>>))]
public IEnumerable<WeatherForecast> Get()
...
And that works. Hope this helps someone.
I am migrating an application from previous ASP.NET version to ASP.NET 5(vNext, MVC 6). Previously I localized forms with DisplayAttribute attached to ViewModel's properties:
[Required(ErrorMessageResourceName = "FieldIsRequired", ErrorMessageResourceType = typeof(Resources.Validation))]
[Display(Name = "UserName", ResourceType = typeof(Resources.Common))]
public string UserName { get; set; }
I added DataAnnotations service:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.AddViewLocalization(options => options.ResourcesPath = "Resources/Views")
.AddDataAnnotationsLocalization();
}
When I submit an invalid form, an error message gets localized (as specified in the [Required] attribute).
But trying to display the form, I got an exception (No public property "UserName" in the resource class), until I commented out [Display] attribute.
Seems like input labels can't be localized with [DisplayAttribute] anymore?
Thank you!
It is indeed gone. According to the documentation:
The runtime doesn’t look up localized strings for non-validation attributes. In the code above, “Email” (from [Display(Name = "Email")]) will not be localized.
Update 20.03.2017:
Localization of non-validation attributes was re-enabled with the new .NET Core SDK, according to the updated documentation:
DataAnnotations error messages are localized with IStringLocalizer<T>.
Using the option ResourcesPath = "Resources", the error messages in RegisterViewModel can be stored in either of the following paths:
Resources/ViewModels.Account.RegisterViewModel.fr.resx
Resources/ViewModels/Account/RegisterViewModel.fr.resx
I'm using the Kendo AutoComplete client javascript widget, which sends server requests such as the following:
https://domainName/Proto2/api/Goal/Lookup?text=ABC&goalId=8b625c56-7b04-4281-936f-b88d7ca27d76&filter%5Blogic%5D=and&filter%5Bfilters%5D%5B0%5D%5Bvalue%5D=&filter%5Bfilters%5D%5B0%5D%5Boperator%5D=contains&filter%5Bfilters%5D%5B0%5D%5Bfield%5D=Description&filter%5Bfilters%5D%5B0%5D%5BignoreCase%5D=true&_=1423833493290
The MVC server side method to receive this is:
[Route("api/Goal/Lookup")]
[HttpGet] // if the action name doesn't start with "Get", then we need to specify this attribute
public ICollection<IAllegroGoalContract> Lookup(Guid goalId, string text = "")
The problem occurs if the client sends an empty value for the text parameter (ex: text=&goalId=8b625c56-7b04-4281-936f-b88d7ca27d76). In this case .net returns the following error.
"System error - unable to process parameters
(goalId,text,text.String) - invalid data detected"
I've tried various Route attribute values:
[Route("api/Goal/Lookup/{goalId:guid},{text?}")]
[Route("api/Goal/Lookup/{text?}")]
Looks like your parameters are used as a filter, so instead of the GoalId and Text parameters to be part of the route, define a class like this:
public class LookupOptions
{
public Guid GoalId { get; set; } // change this to Guid? if the client can send a nullable goalId.
public string Text { get; set; }
}
So your method signature will be :
[Route("api/Goal/Lookup")]
[HttpGet]
public ICollection<IAllegroGoalContract> Lookup([FromUri]LookupOptions options)
{
// Note that [FromUri] will allow the mapping of the querystring into LookupOptions class.
}
Now, you can pass your options from the client as part of the Query string and it will be assigned to the LookupOptions parameter.
Hope this helps.
Using IE8 (Everything works fine IE9+)
Im using EF to generate the metadata as outlined in the "EF Design Tool" document
I've added ES5 Shim/Sham
Breeze appears to be loading fine
Once I load the meta data I get the following error
"Unable to either parse or import metadata: getters and setters can not be defined on this javascript engine"
Is this something I can work around?
At this stage its just a prototype and Im only using one trivial class (Below)
public class Category
{
private Guid catId;
[Key]
public Guid CatID
{
get { return catId; }
set { catId = value; }
}
private string catDesc;
[Required]
[StringLength(50)]
public string CatDesc
{
get { return catDesc; }
set { catDesc = value; }
}
public Category()
{
}
}
Any ideas?
This behavior is described in the breezeJs documentation here: http://www.breezejs.com/documentation/prerequisites - the relevant section is excerpted below:
Note: Because of IE8 and shim limitations having to do with Object.defineProperty, the breeze
'backingStore' model library is not supported under IE8, however, the 'knockout' and 'backbone'
libraries are supported.
To use breeze and IE8 you have to have knockout or backbone as the backing store. The default breeze backing store uses Object.defineProperty which only works on IE8 DOM objects.