We're using Swagger.Net package to help with our documentation.
I'm trying to add request data to be auto-generated into my documentation and was looking at this answer that provides this code block:
[SwaggerExample("id", "123456")]
public IHttpActionResult GetById(int id)
{...}
I'm not sure how I can translate that int into a more complex object. For example:
[Route("SaveCustomThing"), HttpPost]
[SwaggerExample("thing", ???)]
public HttpResponseMessage SaveCustomThing([FromBody] Thing thing)
{...}
How do I pass a pre-configured Thing object in the SwaggerExample attribute?
Looking at the code that attribute (SwaggerExample) takes two parameters:
public SwaggerExampleAttribute(string parameterName, object example)
{
this.ParameterName = parameterName;
this.Example = example;
}
https://github.com/heldersepu/Swagger-Net/blob/6afdb0c1ba611273f27e8a904ec2bb06a630b1b4/Swagger.Net/Swagger/Annotations/SwaggerExampleAttribute.cs#L16
We can see the first one is a string but second is an object...
In theory you should be able to pass anything there.
Another alternative I would recommend, if you have complex models like your Thing you should consider adding the examples on the model, we can do a lot more there... as you can see below we can add description, example values and with some other decorators we can limit the range of values code looks like:
/// <summary>
/// ## Geographic coordinates
/// ___
/// A **geographic coordinate system** is a coordinate system used in geography that enables every location on Earth to be specified by a set of numbers
/// </summary>
public class Location
{
/// <summary>**Latitude**: a geographic coordinate that specifies the north–south position of a point on the Earth's surface.</summary>
/// <example>25.85</example>
[Range(-90, 90)]
public float Lat { get; set; }
/// <summary>**Longitude**: a geographic coordinate that specifies the east-west position of a point on the Earth's surface.</summary>
/// <example>-80.27</example>
[Range(-180, 180)]
public float Lon { get; set; }
}
http://swagger-net-test.azurewebsites.net/swagger/ui/index#/Location/Location_Get2
Related
Suppose the following baseline design: I have a class CarElement which holds properties and methods related to both visual representation and data model/logic representation of a car:
class carElement
{
// UI related properties and methods:
public Size DrawSize { get; set; }
public Point Location { get; set; }
public void Draw()
{
// do something...
}
// data model / logic related properties and methods:
public double weight { get; set; }
public string manufacturer { get; set; }
public double CalculatePrice()
{
// do something...
return 0;
}
}
The usage of this class is as follows: Multiple instances of carElement are drawn to some canvas. Clicking each drawn car shows the properties of that car in a property grid by using propertygrid.SelectedObject = InstanceOfcarElement.
In my opinion, this design is flawed because data model and visual representation are not separated in the class design. I would like to improve the design towards MVC and I am seeking advice on good design decisions.
My current take on this would be to separate above class carElement into something like the following two classes.
class carUIElement // organizes visual representation of a car
{
public Size DrawSize { get; set; }
public Point Location { get; set; }
private carDataElement linkedCarDataElement;
public void Draw()
{
// do something...
}
}
class carDataElement // organizes data model organization of a car
{
public double weight { get; set; }
public string manufacturer { get; set; }
private carUIElement linkedCarUIElement;
public double CalculatePrice()
{
// do something...
return 0;
}
}
With that approach, the following are unclear to me:
carUIElement should know the carDataElement it is linked to, and vice versa. Are there better design approaches to this than the simple linking in above Code?
How would I best show both the UI and data model properties on the property Grid, when the drawn UIElement is clicked?
Is the overall approach viable? What about the above open points? I am missing the experience to judge that, so I would be grateful for your comments. Thank you.
Well while we should always be careful not to over intellectualize stuff, after all we as programmers are more masons than artist and even if Notre Dame church is just a construction and not art, no always will be required exorbitant decoration and acoustic chambers, suppose the next version will be as grand as the previous :)
What do i mean? I propose pragmatism with MVC, so if and if in early infancy of the program, it can have the ui model, also sometimes called the data transfer object, be identical to the logical model, that is not in itself an anti-pattern imo.
Obviously once bulding ui, we begin to have released instances with presumed constructs and when it starts to limit development of the product, how it is presented, typically when you need more info than is relevant to ui, stored on the entity, then you can lock the interface by inventing the DTO model objects and party on with the initial model.
So I get where you're going with what's behind why you might want to separate it.
Then again often we have web frontends, especially with mvc and then mostly it will be no longer a databound view, but a MVVM thingy like like Angular, React, Vue or even Blazor if for some reason you might want that, or the tradition Razor pages, really? in new development??
I try not to put anything in the DTO classes that would be lost if only the serialized JSON version is available to your view engine. So that when modernization happens, your controller/ api doesn't have to principally change.
So seperate classes for seperate concerns an no logic in data access or transfer classes, my suggestion would be something along the lines below, but to end up with your questions:
a) Linking with a navigation property in your data model makes sense if you use it to load for instance using entity framework, it is required.
In Your UI type the frequency is key, typically we like to push all data into the points so that they need nothing else to perform, but this makes sense if the class is being serialized and deserialized and you use a tool like AutoMapper to move to and from, if You're in a windows client like WPF hey your model is already on the client and already loaded up for MVVM, you're in such a much better place that you may not honestly care for front-end types, until they need to vary.
b) the question is do you always want to show both or can you hide the cardata element until they ask for it, that would dictate the choice to either let a DTO include the data from the relation or just the foreign key and have an extra lookup method available imo.
So suggestion brief:
/// <summary>
/// Drawing is a separate concern of the application
/// </summary>
class DrawManager
{
public void DrawCar(CarBase car) { }
}
/// <summary>
/// So is calculating prices
/// </summary>
class PriceManager
{
decimal CalculateCarPrice(CarBase car) { throw new NotImplementedException(); }
}
/// <summary>
/// The 2 classes share properties, invent a base class to abide by the DRY principle
/// </summary>
class CarBase
{
public Size DrawSize { get; set; }
public Point Location { get; set; }
}
/// <summary>
/// Now they are identical
/// </summary>
class carElement : CarBase
{
carDataElement CarData { get; set; }
}
/// <summary>
/// Now they are identical
/// </summary>
class carUIElement : CarBase
{
carDataElement linkedCarDataElement;
}
/// <summary>
/// The data about a car, in RDBMS typically normalized into a seperate entity like you have,
/// does UI really need any of them? Is it always needed when other members are accessed?
/// </summary>
/// <remarks>
/// we could choose to have the data model have a navigation property and then let the ui member not have it and give it a method to ackquire it,
/// but then that shouldn't get done to early and well if it always needs it, it is not yet a seperate datatype justification for the ui aspect
/// </remarks>
class carDataElement
{
public double weight { get; set; }
public string manufacturer { get; set; }
}
We are writing swagger documentation using /// comments in the following way:
/// <summary>
/// Create a new widget
/// </summary>
/// <param name="widget"></param>
[HttpPost("/create")]
[ProducesResponseType(typeof(IPayment), 200)]
[ProducesResponseType(typeof(ErrorResult), 400)]
[ProducesResponseType(typeof(ErrorResult), 404)]
public Task<IActionResult> CreateWidget([FromBody] Widget widget)
{
Now Widget is an implementation of IWidget and the user of the documentation should know in detail what each data member of Widget / IWidget means, what's mandatory, what's optional, and valid values.
We found that the only place to add this description is in
/// <param name="widget">very big multi line description</param>
While this works for the end user, is there a better way? We ask this because it is much more maintainable if the descriptions are provided inline in the class / interface definition.
On the same way you document your actions with the /// comments you can also document your models
Here is an example:
http://swagger-net-test.azurewebsites.net/swagger/ui/index?filter=Location#/Location/Location_Get2
The code for that looks like:
/// <summary>
/// ## Geographic coordinates
/// ___
/// A **geographic coordinate system** is a coordinate system used in geography that enables every location on Earth
/// </summary>
public class Location
{
/// <summary>**Latitude**: a geographic coordinate that specifies the north–south position of a point on the Earth's surface.</summary>
/// <example>25.85</example>
[Range(-90, 90)]
public float Lat { get; set; }
/// <summary>**Longitude**: a geographic coordinate that specifies the east-west position of a point on the Earth's surface.</summary>
/// <example>-80.27</example>
[Range(-180, 180)]
public float Lon { get; set; }
}
This is how it looks like:
On Post or Put requests the documentation can also be seen on the model tab:
https://swagger-net-test.azurewebsites.net/swagger/ui/index?filter=Company
And as usual under the Models:
I have a sample project that gets data from Fitbit but the information comes in metric system not imperial system. Here is the code that pulls a list of Dates and Strings pair using TimeSeriesDataList class, but in kilometers not miles. How can I modify this code to get the data in miles instead of kilometers? Any help is greatly appreciated.
public class TimeSeriesDataList
{
public List<Data> DataList { get; set; }
public class Data
{
public DateTime DateTime { get; set; }
public string Value { get; set; }
}
}
public class FitbitClient : IFitbitClient
{
/// <summary>
/// Get TimeSeries data for another user accessible with this user's credentials
/// </summary>
/// <param name="timeSeriesResourceType"></param>
/// <param name="startDate"></param>
/// <param name="endDate"></param>
/// <param name="userId"></param>
/// <returns></returns>
private TimeSeriesDataList GetTimeSeries(TimeSeriesResourceType timeSeriesResourceType, DateTime baseDate, string endDateOrPeriod, string userId)
{
string userSignifier = "-"; //used for current user
if (!string.IsNullOrWhiteSpace(userId))
userSignifier = userId;
// Here is where I believe I need to make a change, somehow, so that
// data that comes in when this is string is requested, comes in metric units
string requestUrl = string.Format("/1/user/{0}{1}/date/{2}/{3}.xml", userSignifier, StringEnum.GetStringValue(timeSeriesResourceType), baseDate.ToString("yyyy-MM-dd"), endDateOrPeriod);
RestRequest request = new RestRequest(requestUrl);
request.OnBeforeDeserialization = resp => {
XDocument doc = XDocument.Parse(resp.Content);
//IEnumerable<XElement> links = doc.Descendants("result");
var rootElement = doc.Descendants("result").FirstOrDefault().Descendants().FirstOrDefault();
if (rootElement != null && !string.IsNullOrWhiteSpace(rootElement.Name.LocalName))
request.RootElement = rootElement.Name.LocalName;
};
var response = restClient.Execute<TimeSeriesDataList>(request);
HandleResponse(response);
return response.Data;
}
}
EDIT I am looking to get the data already converted by adding something along the lines of "Accept-Language" to the header, but I do not know how to utilize that concept. Using conversion crossed my mind but at this time I would like to see if there is an easier way by adding a simple header rather than creating a conversion class for every scenario, class holding the data, for each distinct region, etc.
I did a quick search and am assuming that RestRequest is the class from the RestSharp library. If so, according to their web site (http://restsharp.org) you would do something like:
request.AddHeader("Accept-Language", "...");
Not sure what the correct value should be, you'll need to figure that out from FitBit's API documentation.
Whatever value this code provides, you can simply divide it by 1.60934 to get the same distance in miles. Hope that helps you solve it.
double kilometers2 = 321.9;
double miles2 = ConvertDistance.ConvertKilometersToMiles
In my mvc application during certain times of the year we want to show one of two links. Basically I have to switch the link when I get a call from management. So, I thought instead of having to recompile the app I would add a custom app setting to the web.config file. Then I created a wrapper so that it is strongly typed. Now, my problem is I don't know where to execute the logic. Should add a property to my view model and set it in the controller based on the configuration setting value? Or should I read it directly in my View and toggle between the two links? I'm pretty sure this only belongs in the view or the controller, and not the service layer, since it is used specifically for UI stuff.
Details.cshtml //current code
#if(Search.App.ParcelDetailDisplayMode == Search.App.DisplayMode.Tax ){
<a id="tax-link" href="#taxlink" title="View Tax Bill on Tax Collectors Website">Tax Bill</a>
}
else if(Search.App.ParcelDetailDisplayMode == Search.App.DisplayMode.Trim ){
<a id="trim-link" href="#trimlink" title="View your TRIM notice online">Trim Notice</a>
}
web.config
<add key="ParcelDetailDisplayMode" value="Tax"/>
config wrapper
namespace Search
{
/// <summary>
/// The app.
/// </summary>
public static class App
{
/// <summary>
/// Gets the tax bill link.
/// </summary>
public static string TaxBillLink
{
get
{
return ConfigurationManager.AppSettings["TaxBillLink"];
}
}
/// <summary>
/// Gets the trim notice link.
/// </summary>
public static string TrimNoticeLink
{
get
{
return ConfigurationManager.AppSettings["TrimLink"];
}
}
/// <summary>
/// Gets the map link.
/// </summary>
public static string MapLink
{
get
{
return ConfigurationManager.AppSettings["MapLink"];
}
}
/// <summary>
/// Gets the update address link.
/// </summary>
public static string UpdateAddressLink
{
get
{
return ConfigurationManager.AppSettings["UpdateAddressLink"];
}
}
/// <summary>
/// Gets the release name.
/// </summary>
public static string ReleaseName
{
get
{
return ConfigurationManager.AppSettings["ReleaseName"];
}
}
/// <summary>
/// Gets the parcel detail display mode.
/// </summary>
public static DisplayMode ParcelDetailDisplayMode
{
get
{
var r = DisplayMode.Tax;
DisplayMode.TryParse(ConfigurationManager.AppSettings["ParcelDetailDisplayMode"], out r);
return r;
}
}
/// <summary>
/// The display mode.
/// </summary>
public enum DisplayMode
{
/// <summary>
/// The trim.
/// </summary>
Trim,
/// <summary>
/// The tax.
/// </summary>
Tax
}
}
}
I would say it does not really matter. Adding it as a property of your model feels to give a little bit more separation.
What does matter though is that your wrapper is static. This will make it really difficult to mock it for the purpose of unit testing (or any other purpose)
There should be no logic in the controller.
Read this for example: Where should I put my controller business logic in MVC3
or this one: https://softwareengineering.stackexchange.com/questions/165444/where-to-put-business-logic-in-mvc-design
I know it's tempting but the less logic you put there the best you will find yourself in the future.
the answer in my opinion is:
You should read your property in a business layer benhead the controller and pass it all the way up to the view in a model object.
I agree with Maurizio in general that all business logic should be in some service/business logic layer. However in this case since you're only fetching a value from web.config whether, in your controller action, you do:
var someValue = App.TaxBillLink;
or you do:
var someValue = _linkService.GetTodaysLink();
really doesn't matter much unless there is some sort of logic there that needs to be unit tested.
I have a view model that represents all the fields available for searching. I'd like to add some logic that would be able to identify if the search values are all the same and determine whether to hit the DB again for their query.
I think I would have to do something like..
after user submits form save form values to some
temporary field.
upon second submission compare temp value to form values collection.
if values are equal set property in view
model IsSameSearch = true
I'd like to use the Post Redirect Get Pattern too. So that My search View doesn't do anything except post the form values to another action that processes and filters the data, which is then "Getted" using Ajax.
The SearchViewModel contains many many search parameters. Here is an abbreviated version.
public bool UseAdvancedSearch { get; set; }
public bool isSameSearch { get; set; }
/// <summary>
/// Gets or sets the page.
/// </summary>
[HiddenInput]
[ScaffoldColumn(false)]
public int Page { get; set; }
[HiddenInput]
[ScaffoldColumn(false)]
public string SortOption { get; set; }
/// <summary>
/// Gets or sets the address keywords.
/// </summary>
[Display(Name="Address")]
public string AddressKeywords { get; set; }
/// <summary>
/// Gets or sets the census.
/// </summary>
public string Census { get; set; }
/// <summary>
/// Gets or sets the lot block sub.
/// </summary>
public string LotBlockSub { get; set; }
/// <summary>
/// Gets or sets the owner keywords.
/// </summary>
[Display(Name="Owner")]
public string OwnerKeywords { get; set; }
/// <summary>
/// Gets or sets the section township range.
/// </summary>
public string SectionTownshipRange { get; set; }
/// <summary>
/// Gets or sets the strap.
/// </summary>
///
[Display(Name="Account Number/Parcel ID")]
public string Strap { get; set; }
/// <summary>
/// Gets or sets the subdivision.
/// </summary>
public string Subdivision { get; set; }
/// <summary>
/// Gets or sets the use code.
/// </summary>
[Display(Name = "Use Code")]
public string UseCode { get; set; }
/// <summary>
/// Gets or sets the zip code.
/// </summary>
[Display(Name="Zip Code")]
public string ZipCode { get; set; }
If you are getting data from Entity Framework you could cache the data at EF level. Look at the package entity framework extended https://github.com/loresoft/EntityFramework.Extended. It is as simple as adding method .FromCache () to the query you use to retrieve and filter the data and it will cache the query result. Make sure you load all the data required using includes etc.
You wouldn't have to worry about same search in model as the caching provider would look at filter settings and determine that it was different. Alternatively cache the data before filtering and then filter the cached results. This is more appropriate if you have lots of filter parameters with significant variance as you will only have to cache 1 large result rather than thousands of smaller results.
You can get more advanced and specify cache period e.g. Cache for 10 minutes
What you are describing is called caching.
One way to accomplish that in your scenario would be to implement GetHashCode() in a way that it would take into account all your fields/properties to compute a unique value. That way you can use your Hash as the key entry in your cache, and store the results with that key.
For that actual caching you could just use the MemoryCache class provided by the .Net Framework if you are not deploying to a web farm.
Also, if you are familiar with IoC and DI (such as using Unity), things like this can be implemented as an Interceptor, and only requiring you to add an attribute to the method you'd like to cache. That way you implement caching only once as a cross-cutting concern and not fill up your application code with things like this.