-
Notifications
You must be signed in to change notification settings - Fork 38
Tuple
A tuple is a data structure that contains a number of objects of different types. A tuple is handy for some programming interfaces that allow only 1 parameter while you need to pass multiple parameters of different types. Without tuple, you may have 2 workarounds:
- An array of object. But you will lost the type information.
- A custom container class to contain the objects. However, it is cumbersome to define a contain class every time.
In C#, tuples are represented by 8 predefined generic types. Tuples with more than 7 elements should be represented by octuple, and the last element must be a tuple type.
In TypeScript, tuple types represent JavaScript arrays with individually tracked element types.
In WebApiClientGen, the representation of tuples is in favor of the C#'s constructions, that is, each element is associated with a property name like "Item1", "Item2" and "Item3" etc. Such approach makes the C# codes and TypeScript codes generated look alike for tuples.
And because Tuple is decorated by SerializableAttribute, in the deserialized data the properties has prefix "m_" like "m_Item1", To make the serialization with .NET client codes and TypeScript client codes work with the exact matching between service data models of tuple and client data models,, you may append a line for DefaultContractResolver in function Register of class WebApiConfig in the App_Start folder:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//http://forums.asp.net/t/1821729.aspx?JsonMediaTypeFormatter+does+not+work+with+Tuple+int+List+string+
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new DefaultContractResolver();
//this will support Tuple serialization in JSON
}
}
And this solution will make the serialized data have properties like "Item1" and "Item2" etc., keeping the consistency in both ends.
Examples
C# client API codes:
/// <summary>
///
/// GET api/Tuple/Tuple7
/// </summary>
public async Task<System.Tuple<string, string, string, string, string, long, int>> GetTuple7Async()
{
var template = new System.UriTemplate("api/Tuple/Tuple7");
var uriParameters = new System.Collections.Specialized.NameValueCollection();
var requestUri = template.BindByName(this.baseUri, uriParameters);
var responseMessage = await client.GetAsync(requestUri.ToString());
responseMessage.EnsureSuccessStatusCode();
using (var stream = await responseMessage.Content.ReadAsStreamAsync())
using (System.IO.StreamReader reader = new System.IO.StreamReader(stream))
using (JsonReader jsonReader = new JsonTextReader(reader))
{
var serializer = new JsonSerializer();
return serializer.Deserialize<System.Tuple<string, string, string, string, string, long, int>>(jsonReader);
}
}
/// <summary>
///
/// GET api/Tuple/Tuple7
/// </summary>
public System.Tuple<string, string, string, string, string, long, int> GetTuple7()
{
var template = new System.UriTemplate("api/Tuple/Tuple7");
var uriParameters = new System.Collections.Specialized.NameValueCollection();
var requestUri = template.BindByName(this.baseUri, uriParameters);
var responseMessage = this.client.GetAsync(requestUri.ToString()).Result;
responseMessage.EnsureSuccessStatusCode();
using (var stream = responseMessage.Content.ReadAsStreamAsync().Result)
using (System.IO.StreamReader reader = new System.IO.StreamReader(stream))
using (JsonReader jsonReader = new JsonTextReader(reader))
{
var serializer = new JsonSerializer();
return serializer.Deserialize<System.Tuple<string, string, string, string, string, long, int>>(jsonReader);
}
}
/// <summary>
///
/// POST api/Tuple/Tuple7
/// </summary>
public async Task<string> PostTuple7Async(System.Tuple<string, string, string, string, string, long, int> tuple)
{
using (var requestWriter = new System.IO.StringWriter())
{
var requestSerializer = JsonSerializer.Create();
requestSerializer.Serialize(requestWriter, tuple);
var requestUri = new System.Uri(this.baseUri, "api/Tuple/Tuple7");
var content = new StringContent(requestWriter.ToString(), System.Text.Encoding.UTF8, "application/json");
var responseMessage = await client.PostAsync(requestUri.ToString(), content);
responseMessage.EnsureSuccessStatusCode();
using (var stream = await responseMessage.Content.ReadAsStreamAsync())
using (System.IO.StreamReader reader = new System.IO.StreamReader(stream))
using (JsonReader jsonReader = new JsonTextReader(reader))
{
var serializer = new JsonSerializer();
return serializer.Deserialize<string>(jsonReader);
}
}
}
/// <summary>
///
/// POST api/Tuple/Tuple7
/// </summary>
public string PostTuple7(System.Tuple<string, string, string, string, string, long, int> tuple)
{
using (var requestWriter = new System.IO.StringWriter())
{
var requestSerializer = JsonSerializer.Create();
requestSerializer.Serialize(requestWriter, tuple);
var requestUri = new System.Uri(this.baseUri, "api/Tuple/Tuple7");
var content = new StringContent(requestWriter.ToString(), System.Text.Encoding.UTF8, "application/json");
var responseMessage = this.client.PostAsync(requestUri.ToString(), content).Result;
responseMessage.EnsureSuccessStatusCode();
using (var stream = responseMessage.Content.ReadAsStreamAsync().Result)
using (System.IO.StreamReader reader = new System.IO.StreamReader(stream))
using (JsonReader jsonReader = new JsonTextReader(reader))
{
var serializer = new JsonSerializer();
return serializer.Deserialize<string>(jsonReader);
}
}
}
/// <summary>
///
/// GET api/Tuple/Tuple8
/// </summary>
public async Task<System.Tuple<string, string, string, string, string, string, int, System.Tuple<string, string, string>>> GetTuple8Async()
{
var template = new System.UriTemplate("api/Tuple/Tuple8");
var uriParameters = new System.Collections.Specialized.NameValueCollection();
var requestUri = template.BindByName(this.baseUri, uriParameters);
var responseMessage = await client.GetAsync(requestUri.ToString());
responseMessage.EnsureSuccessStatusCode();
using (var stream = await responseMessage.Content.ReadAsStreamAsync())
using (System.IO.StreamReader reader = new System.IO.StreamReader(stream))
using (JsonReader jsonReader = new JsonTextReader(reader))
{
var serializer = new JsonSerializer();
return serializer.Deserialize<System.Tuple<string, string, string, string, string, string, int, System.Tuple<string, string, string>>>(jsonReader);
}
}
/// <summary>
///
/// GET api/Tuple/Tuple8
/// </summary>
public System.Tuple<string, string, string, string, string, string, int, System.Tuple<string, string, string>> GetTuple8()
{
var template = new System.UriTemplate("api/Tuple/Tuple8");
var uriParameters = new System.Collections.Specialized.NameValueCollection();
var requestUri = template.BindByName(this.baseUri, uriParameters);
var responseMessage = this.client.GetAsync(requestUri.ToString()).Result;
responseMessage.EnsureSuccessStatusCode();
using (var stream = responseMessage.Content.ReadAsStreamAsync().Result)
using (System.IO.StreamReader reader = new System.IO.StreamReader(stream))
using (JsonReader jsonReader = new JsonTextReader(reader))
{
var serializer = new JsonSerializer();
return serializer.Deserialize<System.Tuple<string, string, string, string, string, string, int, System.Tuple<string, string, string>>>(jsonReader);
}
}
/// <summary>
///
/// POST api/Tuple/Tuple8
/// </summary>
public async Task<string> PostTuple8Async(System.Tuple<string, string, string, string, string, string, string, System.Tuple<string, string, string>> tuple)
{
using (var requestWriter = new System.IO.StringWriter())
{
var requestSerializer = JsonSerializer.Create();
requestSerializer.Serialize(requestWriter, tuple);
var requestUri = new System.Uri(this.baseUri, "api/Tuple/Tuple8");
var content = new StringContent(requestWriter.ToString(), System.Text.Encoding.UTF8, "application/json");
var responseMessage = await client.PostAsync(requestUri.ToString(), content);
responseMessage.EnsureSuccessStatusCode();
using (var stream = await responseMessage.Content.ReadAsStreamAsync())
using (System.IO.StreamReader reader = new System.IO.StreamReader(stream))
using (JsonReader jsonReader = new JsonTextReader(reader))
{
var serializer = new JsonSerializer();
return serializer.Deserialize<string>(jsonReader);
}
}
}
/// <summary>
///
/// POST api/Tuple/Tuple8
/// </summary>
public string PostTuple8(System.Tuple<string, string, string, string, string, string, string, System.Tuple<string, string, string>> tuple)
{
using (var requestWriter = new System.IO.StringWriter())
{
var requestSerializer = JsonSerializer.Create();
requestSerializer.Serialize(requestWriter, tuple);
var requestUri = new System.Uri(this.baseUri, "api/Tuple/Tuple8");
var content = new StringContent(requestWriter.ToString(), System.Text.Encoding.UTF8, "application/json");
var responseMessage = this.client.PostAsync(requestUri.ToString(), content).Result;
responseMessage.EnsureSuccessStatusCode();
using (var stream = responseMessage.Content.ReadAsStreamAsync().Result)
using (System.IO.StreamReader reader = new System.IO.StreamReader(stream))
using (JsonReader jsonReader = new JsonTextReader(reader))
{
var serializer = new JsonSerializer();
return serializer.Deserialize<string>(jsonReader);
}
}
}
TypeScript client API codes:
/**
* GET api/Tuple/Tuple7
* @return {{Item1:string, Item2:string, Item3:string, Item4:string, Item5:string, Item6:number, Item7:number}}
*/
GetTuple7(callback: (data : {Item1:string, Item2:string, Item3:string, Item4:string, Item5:string, Item6:number, Item7:number}) => any){
this.httpClient.get(encodeURI(this.baseUri + 'api/Tuple/Tuple7'), callback, this.error, this.statusCode);
}
/**
* POST api/Tuple/Tuple7
* @param {{Item1:string, Item2:string, Item3:string, Item4:string, Item5:string, Item6:number, Item7:number}} tuple
* @return {string}
*/
PostTuple7(tuple: {Item1:string, Item2:string, Item3:string, Item4:string, Item5:string, Item6:number, Item7:number}, callback: (data : string) => any){
this.httpClient.post(encodeURI(this.baseUri + 'api/Tuple/Tuple7'), tuple, callback, this.error, this.statusCode);
}
/**
* GET api/Tuple/Tuple8
* @return {{Item1:string, Item2:string, Item3:string, Item4:string, Item5:string, Item6:string, Item7:number, Rest:{Item1:string, Item2:string, Item3:string}}}
*/
GetTuple8(callback: (data : {Item1:string, Item2:string, Item3:string, Item4:string, Item5:string, Item6:string, Item7:number, Rest:{Item1:string, Item2:string, Item3:string}}) => any){
this.httpClient.get(encodeURI(this.baseUri + 'api/Tuple/Tuple8'), callback, this.error, this.statusCode);
}
/**
* POST api/Tuple/Tuple8
* @param {{Item1:string, Item2:string, Item3:string, Item4:string, Item5:string, Item6:string, Item7:string, Rest:{Item1:string, Item2:string, Item3:string}}} tuple
* @return {string}
*/
PostTuple8(tuple: {Item1:string, Item2:string, Item3:string, Item4:string, Item5:string, Item6:string, Item7:string, Rest:{Item1:string, Item2:string, Item3:string}}, callback: (data : string) => any){
this.httpClient.post(encodeURI(this.baseUri + 'api/Tuple/Tuple8'), tuple, callback, this.error, this.statusCode);
}
Remarks:
{{JsonConvert.DeserializeObject(...)}} and {{ResponseMessage.Content.ReadAsAsync(...)}} could handle well Tuple without injecting DefaultContractResolver in class WebApiConfig. However, because the serialized data has "m_" prefix for each member property of tuple, the TypeScrip codes will have to access each member with the "m_" prefix as well. Since version 1.5, WebApiClientGen uses JsonSerializer and stream to deserialize tuples as well as other data types.