Microsoft Web API Help page - how to create annotations for parameters - api

Recently i've start playing with new web api help page functionality, that was recently added to web api project template. And i have a notice that some "Additional information" column is always 'none'.
After some looking at markup i found that this info should arrive from attributes
<td class="parameter-annotations">
#if (parameter.Annotations.Count > 0)
{
foreach (var annotation in parameter.Annotations)
{
<p>#annotation.Documentation</p>
}
}
else
{
<p>None.</p>
}
</td>
But what kind of attribute i should use, to populate additional information?
Thanks

See this site for an example of how to add additional information.
It's basically annotating your model, so in your case it would be something like:-
public class Product
{
/// <summary>
/// The id of the product
/// </summary>
[Required]
public int Id { get; set; }
/// <summary>
/// The name of the product
/// </summary>
[MaxLength(50)]
public string Name { get; set; }
}
Which would give you an output like this:-

Related

In ASP.NET Core webapi how to I add sample requests to swaggerUI when using NSwag.AspNetCore?

Im using
<PackageReference Include="NSwag.AspNetCore" Version="13.8.2" />
In an asp.net core web api 3.1 project, and Im interested in having sample request payloads display within the swaggerUI.
How exactly can I add sample requests when using this framework? Is this even possible with this framework? My best guess is that adding attributes to controller actions. Any insight is appreciated here. Perhaps the answer for this is a simple annotation, which I am hoping for.
Do you mean you want to add sample data to action?If so,you can use:
/// <example>xxx</example>
Here is a demo:
Sample.cs:
public class Sample
{
/// <example>1</example>
public int Id { get; set; }
/// <example>name</example>
public string Name { get; set; }
/// <example>address</example>
public string Address { get; set; }
}
Controller:
[ApiController]
[Route("[controller]")]
public class ApiController : ControllerBase
{
[HttpPost("Index")]
public Sample Index(Sample sample)
{
return sample;
}
}
result:

ASP.NET Core: Mark [FromQuery] Parameter as required

In my controller there is a method take accepts one route and and one query parameter as arguments:
/// <summary>
/// My Method
/// </summary>
/// <param name="routeParameter">Nice description of route parameter.</param>
/// <param name="queryParameter">Nice description of query paramter.</param>
[HttpPost("somePath/{routeParameter}")]
public IActionResult MyMethod([FromRoute] string routeParameter, [FromQuery] DateTime queryParamter)
{
// do something
}
In the OpenApi.json / Swagger generated from this signature via Swashbuckle XML the routeParameter (path) is always required but the queryParameter (query) is marked as optional.
How can I mark the query parameter as required, too?
How can I mark the query parameter as required, too?
Just use [FromQuery, BindRequired] as follow:
[HttpPost("somePath/{routeParameter}")]
public IActionResult MyMethod([FromRoute] string routeParameter, [FromQuery, BindRequired] DateTime queryParamter)
{
// do something
}
Here is the test result:
Here is an alternative with [FromUri] to receive your parameters
[HttpPost("somePath")]
public IActionResult MyMethod([FromUri] Paging paging, [FromUri] QueryParam param)
{
// do something
}
QueryParam.cs
public class QueryParam
{
[Required]
public string routeParameter{ get; set; }
}
Swagger UI

Error message in multiple languages

Good day everyone,
I have a doubt on my currently development, the thing is i've created a project using ntier and data application block for my data access layer so, i have a package named Entities where i create all my classes and i was trying to use error messages mapped to a resource file the problem is when i write the following code it marks up with error:
(Entity-Base-Clients)
public partial class Clients {
public Int32 Id {get;set;}
[Display(Name="Name",
ResourceType=typeof(Resources.Language))]
[Required(AllowEmptyStrings=false,
ErrorMessageResourceName="Id",
ErrorMessageResourceType=typeof(Resources.Language))]
public string Name {get;set;}
}
In the following code it marks up error in "Resources" (which is the folder where i put my resource files) and "Language" is the resource file.
But when i do the exactly the same thing on the "Model" folder didn't marks up any error
(Model-Clients)
public Int32 Id {get;set;}
[Display(Name="Name",
ResourceType=typeof(Resources.Language))]
[Required(AllowEmptyStrings=false,
ErrorMessageResourceName="Id",
ErrorMessageResourceType=typeof(Resources.Language))]
public string Name {get;set;}
}
Do i have doing something wrong? am i missing a reference or configuration of the RF?
Thanks in advance
[Display(Name = "Name"), Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName ="nameHasToBeGiven")]
public string name { get; set; }
this one is way easier
This is an old problem. To solve it I deactivated the EDMX Code generation and I created external TT files to generate :
DomainLayer : Contains EF EDMX classes (with navigation)
DataLayer : Contains stuff to query data
[Serializable]
public partial class Contact : _DomainLayer_Base
{
#region Primitive Properties
/// <summary>
/// Gets or sets Id.
/// </summary>
/// <value>The Id.</value>
public virtual int Id
{
get;
set;
}
/// <summary>
/// Gets or sets FK_Language.
/// </summary>
/// <value>The FK_Language.</value>
/// <remarks>
/// Foregn key of Contact
///
/// </remarks>
public virtual int FK_Language
{
get { return _fK_Language; }
set
{
try
{
_settingFK = true;
if (_fK_Language != value)
{
if (Language != null && Language.Id != value)
{
Language = null;
}
_fK_Language = value;
}
}
finally
{
_settingFK = false;
}
}
}
}
MetaDataLayer : Contains EF Independant classes with data annotations linked to resources (without navigation)
[Serializable]
public partial class Contact_MetaData : _MetaDataLayer_Base
{
[Display(Name = "Ety_Contact_Id" , ResourceType = typeof(InnovaApp.Layers.ResourcesLayer.Properties.MetaDataResources))]
[Required(ErrorMessageResourceName = "ErrMsgRequired",ErrorMessageResourceType = typeof(InnovaApp.Layers.ResourcesLayer.Properties.Resources))]
public virtual int Id
{
get;
set;
}
[Display(Name = "Ety_Contact_FK_Language" , ResourceType = typeof(InnovaApp.Layers.ResourcesLayer.Properties.MetaDataResources))]
[Required(ErrorMessageResourceName = "ErrMsgRequired",ErrorMessageResourceType = typeof(InnovaApp.Layers.ResourcesLayer.Properties.Resources))]
public virtual int FK_Language
{
get;
set;
}
MetaModels : Inside the portal, MetaModels are MetaData members containers. They contains data required by portal. Example :If you have a foreign key, the ForeignKey value will be in the MetaData but ListItems used to fill the lookup will be in the MetaModel.
EntityLayer : Contains EF EDMX
When I create a EF Query I prefix result with db :
When I use the data in the view, I use my MetaDataLayer :
public class ContactViewer_MetaModel : Contact_MetaData
To transfert data from DomainLayer to MetaDataLayer I Use Emit Mapper because My TT files guaranty same signature between Domain and MetaData.
toReturn = ObjectMapperManager.DefaultInstance.GetMapper<Contact, ContactViewer_MetaModel>().Map(dbContact);
and in the view :
#model InnovaApp.Layers.SecurityLayer.Models.MetaModels.Contact_MetaModel
#Html.HiddenFor(m => m.Id)
<ol class="olMainForm">
<li>
#Html.LabelFor(m => m.FK_Genre)
#Html.DropDownListFor(m => m.FK_Genre, Model.Genres)
#Html.ValidationMessageFor(m => m.FK_Genre)
</li>
</ol>
You can find the full source here :
https://myprettycms.codeplex.com

ASP.NET Web API help page - how to show generic return type in documentation

I'm using a generic return type for all my api responses:
public HttpStatusCode statusCode { get; set; }
public string error { get; set; }
public IDictionary<string, string> errorfor { get; set; }
public T result { get; set; }
and in API:
/// <summary>
/// GET Order API
/// </summary>
/// <returns> return list of orders {Order} </returns>
public HttpResponseMessage Get(){
var response = new BaseResponseMessage<IList<Order>>();
//some more codes
response.result = orders;
return Request.CreateResponse(HttpStatusCode.OK, response);
}
Now of course my API Help page don't show Order in sample Response body. Is it possible to configure Help Page generator to show generic type? Thanks!
Web API 2.1 Help Pages now do this: http://www.asp.net/web-api/overview/releases/whats-new-in-aspnet-web-api-21#help-page
You might also check out returning the standard HttpResponseMessage with the new ResponseTypeAttribute:
/// <summary>
/// GET Order API
/// </summary>
[ResponseType(typeof(List<Order>))]
public HttpResponseMessage Get()
{
var orders = new List<Order>();
return Request.CreateResponse(HttpStatusCode.OK, orders);
}
It would not be possible for HelpPage to guess what would be the return type of an action with just the signature that you have. As you know HelpPage generation does not happen during normal request, but is something which depends on static information.
There is a workaround for this though. You can look at the following commented code in Areas\HelpPage\App_Start\HelpPageConfig.cs which lets you specify a specific return type for an action.
//// Uncomment the following to correct the sample response when the action returns an HttpResponseMessage with ObjectContent<string>.
//// The sample will be generated as if the controller named "Values" and action named "Post" were returning a string.
//config.SetActualResponseType(typeof(string), "Values", "Post");
I understand that this workaround would be too cumbersome for you since you mentioned about having this kind of signature for all your actions.
You could probably extend HelpPage by creating a custom attribute which informs about the return type and decorate it on the actions. You can then modify installed HelpPage code to look for these attributes.

How can I keep track of a shopping cart across multiple projects?

First some background, we are creating a new "eGov" application. Eventually, a citizen can request permits and pay for licenses along with pay their utility bills and parking tickets online. Our vision has a shopping cart so a person can pay for multiple items in one transaction. To keep things organized better, we are going to break each section into a different project. This also allows me to work on one project while the other developer works another. The person making a payment could be a registered user or could remain unregistered. We feel a person from out of our jurisdiction probably doesn't want to register just to pay their parking ticket or pay for a one-time business license.
This project will be on Windows Server 2008 and IIS7 and using ASP.NET MVC 3. We will probably use a single domain (maybe egov.domain.gov) and in multiple sub directories (/cart, /permit, /billing, etc) though that is not 100% decided yet.
Now the problem. How do we track a shopping cart across multiple projects? There was talk of using a cookie that expires at a certain point or using a state machine. We are uncertain if using a session id would work. If we use a state machine, I have never used that and only understand it in concept (it works across multiple machines and SO uses it).
One other note, we are going to be building this on a VMWare server, so the possibility of having this run across multiple servers is a possibility in the future.
What would you use and why?
Update: It appears like many seem to recommend storing the cart in HttpContext. Is this the same across multiple applications?
First you need to setup your SQL Server to accept session state connections.
Article 1
Article 2
Then add the following to your Web.config file:
<sessionState mode="SQLServer" sqlConnectionString="Server=.\SQLEXPRESS;Integrated Security=SSPI;Initial Catalog=ASPState;Application Name=name" timeout="20" allowCustomSqlDatabase="true" />` within `<system.web>
I then created a class library that has two classes: Cart and CartItem.
CartItem defined to hold each individual shopping cart item
[Serializable]
public class CartItem
{
[Key]
public int RecordId { set; get; }
public string ItemNumber { set; get; }
public string Description { set; get; }
public DateTime DateTimeCreated { set; get; }
public decimal Cost { get; set; }
}
Cart works with your shopping cart
public class Cart
{
HttpContextBase httpContextBase = null;
public const string CartSessionKey = "shoppingCart";
/// <summary>
/// Initializes a new instance of the <see cref="ShoppingCart"/> class.
/// </summary>
/// <param name="context">The context.</param>
public Cart(HttpContextBase context)
{
httpContextBase = context;
}
/// <summary>
/// Gets the cart items.
/// </summary>
/// <returns></returns>
public List<CartItem> GetCartItems()
{
return (List<CartItem>)httpContextBase.Session[CartSessionKey];
}
/// <summary>
/// Adds to cart.
/// </summary>
/// <param name="cartItem">The cart item.</param>
public void AddToCart(CartItem cartItem)
{
var shoppingCart = GetCartItems();
if (shoppingCart == null)
{
shoppingCart = new List<CartItem>();
}
cartItem.RecordId = shoppingCart.Count + 1;
cartItem.DateTimeCreated = DateTime.Now;
shoppingCart.Add(cartItem);
httpContextBase.Session[CartSessionKey] = shoppingCart;
}
/// <summary>
/// Removes from cart.
/// </summary>
/// <param name="id">The id.</param>
public void RemoveFromCart(int id)
{
var shoppingCart = GetCartItems();
var cartItem = shoppingCart.Single(cart => cart.RecordId == id);
shoppingCart.Remove(cartItem);
httpContextBase.Session[CartSessionKey] = shoppingCart;
}
/// <summary>
/// Empties the cart.
/// </summary>
public void EmptyCart()
{
httpContextBase.Session[CartSessionKey] = null;
}
/// <summary>
/// Gets the count.
/// </summary>
/// <returns></returns>
public int GetCount()
{
return GetCartItems().Count;
}
/// <summary>
/// Gets the total.
/// </summary>
/// <returns></returns>
public decimal GetTotal()
{
return GetCartItems().Sum(items => items.Cost);
}
}
To test this, first in my shopping cart project in my home controller I did the following:
public ActionResult Index()
{
var shoppingCart = new Cart(this.HttpContext);
var cartItem = new CartItem
{
Description = "Item 1",
ItemNumber = "123"
Cost = 20,
DateTimeCreated = DateTime.Now
};
shoppingCart.AddToCart(cartItem);
cartItem = new CartItem
{
Description = "Item 2",
ItemNumber = "234"
Cost = 15,
DateTimeCreated = DateTime.Now
};
shoppingCart.AddToCart(cartItem);
var viewModel = new ShoppingCartViewModel
{
CartItems = shoppingCart.GetCartItems(),
CartTotal = shoppingCart.GetTotal()
};
return View(viewModel);
}
In my second project's home controller, I added the following:
public ActionResult Index()
{
var shoppingCart = new Cart(this.HttpContext);
var cartItem = new CartItem
{
Description = "Item 3",
ItemNumber = "345"
Cost = 55,
DateTimeCreated = DateTime.Now
};
shoppingCart.AddToCart(cartItem);
return View();
}
This seemed to work for me great.