I'm trying to get the format identifier printed on the Swagger UI which is stated on their homepage. In the auto-generated json file it should look like in this example:
The way of how I'd like to achieve that is via xml comments in my view model class. This works well for tags like example, summary etc., but there is no tag like format. It would be important for me to state that the string we are awaiting here in the API must be in a certain format.
A similar question has been asked here, but there hasn't been an answer for the format identifier.
How can I achieve this?
Versions used: .NET 7 and Swashbuckle v 6.4.0.
My view model looks like that:
public class MeasurementViewModel {
/// <example>20.01.2003</example>
/// <format>dd.mm.yyyy</format> <-- this is what I would expect but doesn't have any effect
[JsonProperty("patient_birthdate")] public string? PatientDateOfBirth { get; set; }
}
Found a solution thanks to that answer.
I added the additional package "Swashbuckle.AspNetCore.Annotations" via NuGet and in my Startup.cs where I configure the Swagger generation I enable the annotations:
services.AddSwaggerGen(c =>
...
c.EnableAnnotations();
}
In my ViewModel I can now use the following annotation:
/// <example>20.01.2002</example>
[JsonProperty("patient_birthdate"), SwaggerSchema(Format = "dd.mm.yyyy")] public string? PatientDateOfBirth { get; set; }
.. which results in a beautiful documentation:
Related
We are implementing a .NET Core 3.1 API and we are using Microsoft.AspNetCore.Mvc.NewtonsoftJson according to this doc. We are dealing with enums and we need the string representation instead of the integers. We are doing it using the JsonConverter attribute like this:
[JsonProperty("region")]
[JsonConverter(typeof(StringEnumConverter))]
public Region Region { get; set; }
We are trying to do it globally from the Startup.cs like below :
services.AddControllers().AddNewtonsoftJson(opts => opts.SerializerSettings.Converters.Add(new StringEnumConverter()));
If we do that, the Cosmos DB is complaining with
"PartitionKey extracted from document doesn't match the one specified in the header"
So we tried removing all the attributes except by the region one. All the other enums that don't have the attribute are stored as strings correctly, but the region still needs the attribute to work. Any clue why is this happening and how to solve it?
In netcore 3.1 or higher, you can use JsonStringEnumConverter:
var options = new JsonSerializerOptions
{
Converters = { new JsonStringEnumConverter() },
//other options
};
Try Example online
Just started trying out Breeze today, long time EF user - think I found a bug in Breeze, but I may be doing something wrong - want to know which it is:
I have a simple hierarchy in EF Code First:
// For testimonials about the product line in general
public class Testimonial
{
public int Id { get; set; }
public string Text { get; set; }
}
// For testimonials specific to a single product
[Table("ProductTestimonial")]
public class ProductTestimonial : Testimonial
{
public Product Product { get; set; }
}
So just to be clear there's 2 tables here, Testimonial and ProductTestimonial, both have a PK of Id, and a Text field, and one of them also has an FK off to Product. This is just a simple way of implementing Table Per Type.
So I setup the BreezeController via WebApi:
[BreezeController]
public class EFController : ApiController
{
private readonly EFContextProvider<EfDb> _db = new EFContextProvider<EfDb>();
[HttpGet]
public string Metadata()
{
return _db.Metadata();
}
And I go to load it in breeze.js:
var manager = new breeze.EntityManager('/api/ef');
manager.executeQuery(breeze.EntityQuery.from('Product');
Kablamo. Exception. It says:
Unable to get value of the property 'propertyRef': object is null or undefined
At:
function convertFromODataEntityType(... {
. . .
var keyNamesOnServer = toArray(odataEntityType.key.propertyRef)...
Where odataEntityType.name == 'ProductTestimonial', and .key sure enough is undefined.
Which is true. Picking things apart, when I call executeQuery(), Breeze hits the Metadata call on the WebApi, which I verified calls and returns successfully. The massive JSON string returned from there includes:
{
"name": "ProductTestimonial",
"baseType": "Self.Testimonial",
"navigationProperty": {
"name": "Product",
"relationship": "Self.ProductTestimonial_Product",
"fromRole": "ProductTestimonial_Product_Source",
"toRole": "ProductTestimonial_Product_Target"
}
},
{
"name": "Testimonial",
"key": {
"propertyRef": {
"name": "Id"
}
},
So it would appear the basic issue is that the Metadata is accurately portraying ProductTestimonial as an inherited class, whose key is defined elsewhere, but Breeze.js - if I'm understanding it correctly - is naively just checking the .key property without considering superclasses. But, I could be wrong since I'm so new to Breeze.
Addendum:
I don't think it's relevant here but in case it comes up, yes I do have an IQueryable as well on the WebApi Controller:
[HttpGet]
public IQueryable<Product> Products()
{
return _db.Context.Products;
}
Also, I recognize a potential workaround here is probably to discard TPT and make full classes for every Entity with no inheritance, but I'm really slimming my example down here - there's a lot of inheritance throughout the EF model that has to stay. If it's inheritance or Breeze, Breeze is getting the axe.
Edit: As of v 1.3.1 Breeze now DOES support inheritance.
Inheritance is coming but we don't have a fixed date just yet. Please vote for the feature on the Breeze User Voice. We take these suggestions very seriously.
I don't think manager.fetchEntityByKey works with inheritance - can any of the Breeze guys confirm whether this is correct? It seems to be picking up the inherited fields from my base class, but not the fields from my derived class. I can get the full object by using entityQuery but then I have to name every field. When I do that I'm still getting parse errors on ko bindings.
I am building an ASP.NET Web API application that returns an Atom or an RSS feed. To do this, it builds a System.ServiceModel.Syndication.SyndicationFeed and a custom MediaTypeFormatter is responsible for handling the HTTP Accept Header, converting the SyndicationFeed to either an Atom10FeedFormatter or an Rss20FeedFormatter, and streaming the result to the response stream. So far, so good.
My controller looks something like this:
public class FeedController : ApiController
{
public HttpResponseMessage Get()
{
FeedRepository feedRepository = new FeedRepository();
HttpResponseMessage<SyndicationFeed> successResponseMessage = new HttpResponseMessage<SyndicationFeed>(feedRepository.GetSyndicationFeed());
return successResponseMessage;
}
}
What I would like to do is make use of the built-in OData querying to filter my feed, but changing the return type of the Get() method to IQueryable<SyndicationFeed> obviously will not work since a SyndicationFeed does not implement IQueryable.
Is there a way to use the built in OData querying on the IEnumerable<SyndicationItem> property on the SyndicationFeed?
This question is no longer relevant, since Microsoft remove the rudimentary support for OData querying that was in the Beta build of Web API.
A future version will include more complete OData support. There is an early build of this available via CodePlex and NuGet and there are more details here: http://blogs.msdn.com/b/alexj/archive/2012/08/15/odata-support-in-asp-net-web-api.aspx
The System.Linq namespace provides an extension method named AsQueryable to the IEnumerable interface. Your code would look along the lines of this:
public class FeedController : ApiController
{
public IQueryable<SyndicationFeed> Get()
{
FeedRepository feedRepository = new FeedRepository();
//TODO: Make sure your property handles empty/null results:
return feedRepository.GetSyndicationFeed()
.YourEnumerableProperty.AsQueryable();
}
}
You don't have to return IQuerable from controller when working with OData.
Check "Invoking Query Options Directly" section at https://learn.microsoft.com/en-us/aspnet/web-api/overview/odata-support-in-aspnet-web-api/supporting-odata-query-options
For your case it will looks like:
public SyndicationFeed Get(ODataQueryOptions<SyndicationItem> opts)
{
var settings = new ODataValidationSettings();
opts.Validate(settings);
SyndicationFeed result = feedRepository.GetSyndicationFeed();
result.Items = opts.ApplyTo(result.Items.AsQuerable()).ToArray();
return result;
}
I am wondering if there is a best practice for creating a REST API with ASP.NET MVC 3? At the moment I am thinking of creating a controller for each version of the REST API. For example, so far I have:
public class V1Controller : Controller
{
public V1Controller()
{
}
public ActionResult GetUser(string userId, IUserRepository userRepostory)
{
//code to pull data and convert to JSON string
return View("Results");
}
public ActionResult GetUsersByGroup(string groupId, IUserRepository userRepostory)
{
//code to pull data and convert to JSON string
return View("Results");
}
}
Then for the views I overwrite the _ViewStart.cshtml to remove the layout and then I have Results.cshtml that just outputs the data that is formatted in the controller action, right now JSON. Having every single REST call in one controller seems like a bit too much but it is the best way I can think of so that I can keep clean separate versions of the API so that when it comes to creating version 2 of the API, I can create a V2Controller and not break the existing API to give people time to switch over to the new API.
Is there a better way to create a REST API with ASP.NET MVC 3?
I was able to find a decent solution using MVC's use of Areas.
First, I wanted to have my API follow this URL Definition:
http://[website]/[major_version]_[minor_version]/{controller}/{action}/...
I also wanted to break up the different versions in separate Project files and use the same Controller names in each version:
"../v1_0/Orders/ViewOrders/.." => "../v2_3/Orders/ViewOrders/.."
I searched around and found a workable solution with the use of MVC Areas.
I created a new project in my solution called "Api.Controllers.v1_0" and, as a test, put a SystemController.cs file in there:
using System.Web.Mvc;
namespace Api.Controllers.v1_0
{
public class SystemController : Controller
{
public ActionResult Index()
{
return new ContentResult() {Content = "VERSION 1.0"};
}
}
}
I then added a v1_0AreaRegistration.cs file:
using System.Web.Mvc;
namespace Api.Controllers.v1_0
{
public class v1_0AreaRegistration : AreaRegistration
{
public override string AreaName
{
get{ return "v1_0";}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"v1_0",
"v1_0/{controller}/{action}/{id}",
new { controller = "System", action = "Index", id = UrlParameter.Optional }
);
}
}
}
I walked through the same steps above for a "..v1_1" project with the corresponding files in there, added the projects as references into my "Api.Web" MVC project and was off and running.
If all you are returning is JSON, you do not need a view. Jusr return
new JsonResult(){Data = Data};
Look in here.
Also in terms of versioning, versions can be implemented as different controllers or as extra methods in the same controller. But without knowing why you would need versions and why your clients (which I assume are browsers) would need to know about versioning is not clear from your question.
A controller such as the one you posted in your example code should always keep that methods that you have now for instance GetUsersByGroup() with the same signature. I don't see how there could be a different version of that method.
The inputs are group and repository (which I believe comes from DI). The output is a list of users in JSON format. That's all that matters to the users of the API. What you do inside this method is no one's business.
You should think more of inputs and outputs. You shouldn't be changing the signatures of existing actions unless it is really neccessary to do so.
Think of the controller class in terms of implementing the interface. You have an interface and controller class is it's implementation (I mean you don't need to have it but just think of it in that way). You will rarely change the interface once one or several classes implement it. But you might add the methods to it. And that requires only changes in implementing classes - it does not break the functionality of the API and everyone who's using it will be able to continue using it.
I've learned about custom editor templates for ASP.NET MVC3 and I see now how I can easily implement my own. However for an editor to work it must not only display that data in a textbox, but also somehow transfer the user-edited contents to the server for processing. So how does this binding work for complex models? How does MVC decide where each POST value goes? Are there some magic naming conventions? What about very complex models like dynamic lists or dictionaries or DataTables?
There is a naming convention. So for example if you have the following model:
public class Foo
{
public Bar Bar { get; set; }
}
public class Bar
{
public string Baz { get; set; }
}
and the following action:
public ActionResult Index(Foo foo) { ... }
you could send the following request:
/home/index?Bar.Baz=somevalue
in order to set the Baz value. Of course this will automatically instantiate the Foo model and its Bar property. And obviously this convention also extends for lists and dictionaries.
Whether the values are sent in the query string (GET request), as form values (POST request) or as route values it doesn't really matter for the default model binder. It will look at all those places.
And you should never forget that if this default naming convention doesn't suit your particular requirements you should feel free to write a custom model binder.
Remark: there is also the case for uploading files.