Skip to content

Settings Explained

fonlow edited this page Mar 4, 2022 · 18 revisions

Settings

ApiSelection

ExcludedControllerNames

/// <summary>
/// To exclude some controllers. For example, [My.Namespace.Home, My.Namespace.FileUpload] for My.Namespace.HomeController and My.Namespace.FileUploadController.
/// </summary>
public string[] ExcludedControllerNames { get; set; }

WebApiClientGen is focused on Strong Typed Web API, while some Web APIs not strongly typed. Thus this setting excludes them, otherwise, the generated codes are not usable. For such APIs, it is better to hand craft client codes according to their dynamic behaviors.

DataModelAssemblyNames and CherryPickingMethods

/// <summary>
/// To include assemblies containing data models. Assembly names should be without file extension.
/// </summary>
public string[] DataModelAssemblyNames { get; set; }

/// <summary>
/// Cherry picking methods of POCO classes
/// </summary>
public int? CherryPickingMethods { get; set; }

It is a good practice to put data models into a stand-alone assembly, so multiple domain sepcific assemblies could access the same data models without acknowledging the other domains. And such practice is good to generating client side data models too, since you may want to expose only a subset of data models used on the server side. Such stand-alone assemblies make it easier to cherry-pick what you would expose through grouping by assembly. WebApiClientGen will use the same CherryPickingMethods for all assemblies defined in DataModelAssemblyNames.

Remarks

POCO2TS.exe shares the same CherryPickingMethods setting with WebApiClientGen. POCO2TS.exe uses command line argument to define the setting, while WebApiClientGen uses CodeGen.json.

DataModels

/// <summary>
/// Similar to DataModelAssemblyNames however, each assembly could have a CherryPickingMethods. An assembly should appear in either DataModelAssemblyNames or DataModels, not both.
/// </summary>
public DataModel[] DataModels { get; set; }

public class DataModel
{
	public string AssemblyName { get; set; }

	public int? CherryPickingMethods { get; set; }
}

The server side data models may be used for various purposes and different serialization methods. With DataModels you may define a set cherry picking methods for each data model assembly.

ClientApiOutputs (Applied to C# only)

CSClientNamespaceSuffix

/// <summary>
/// The naming of namespace is after the controller's namespace. To distinguish from the server side namespace, it is better to add a suffix like ".Client". The default is ".Client".
/// </summary>
public string CSClientNamespaceSuffix { get; set; } = ".Client";

"Proxy " and "Agent" could be good candidates too.

DataAnnotationsEnabled

/// <summary>
/// System.ComponentModel.DataAnnotations attributes are to be copied over, including Required, Range, MaxLength, MinLength and StringLength.
/// </summary>
public bool DataAnnotationsEnabled { get; set; }

When System.ComponentModel.DataAnnotations attributes are used in the data binding of Web API parameters, .NET runtime may validate the incoming data and throw exceptions with sepecific messages, and the client programs which catch resepctive HTTP errors may display the errors. If the client API generated is used in a service broker, having these attributes copied over will make the broker have the same abilities of error handling, so the broker handles more of user input errors.

DataAnnotationsToComments

/// <summary>
/// System.ComponentModel.DataAnnotations attributes are translated into Doc Comments, 
/// including Required, Range, MaxLength, MinLength, StringLength, DataType and RegularExpression..
/// </summary>
public bool DataAnnotationsToComments { get; set; }

Having these in the doc comments is handy for client UI programming. In C#, some UI components may provide data input constraints through reading these attributes.

DecorateDataModelWithDataContract and DataContractNamespace

/// <summary>
/// Generated data types will be decorated with DataContractAttribute and DataMemberAttribute.
/// </summary>
public bool DecorateDataModelWithDataContract { get; set; }

/// <summary>
/// When DecorateDataModelWithDataContract is true, this is the namespace of DataContractAttribute. For example, "http://mybusiness.com/09/2019
/// </summary>
public string DataContractNamespace { get; set; }

The generated client API codes may be used in a service broker based on .NET Web API, WCF or Biztalk. DataContractAttribute is preferred way of cherry picking and data binding. Another reason why DataContractAttribute is preferred is that DataContractAttbibute supports namespace. This is important in complex business applications, service brokers and Biztalks involving tons of data models for different business domains from different vendors.

DecorateDataModelWithSerializable

Occasionally you may find decorating data models with SerializableAttribute is useful when you client codes really need this attribute.

ClientLibraryProjectFolderName and FileName

/// <summary>
/// Assuming the C# client API project is the sibling of Web API project. Relative path to the running instance of the WebApi project should be fine.
/// </summary>
public string ClientLibraryProjectFolderName { get; set; }

/// <summary>
/// File to be generated under ClientLibraryProjectFolder. The default is WebApiClientAuto.cs.
/// </summary>
public string FileName { get; set; } = "WebApiClientAuto.cs";

Surely you need to create respective CS Project first and use the csproj folder name or relative path. WebApiClientGen supports only 1 CS client project, and if you need to support multiple CS client projects such as .NET Framework, .NET Core, .NET, .NET Standard etc., you may nominate one of the folder in ClientLibraryProjectFolderName, and all the other projects use symbolic links to include the CS file.

GenerateBothAsyncAndSync

/// <summary>
/// For .NET client, generate both async and sync functions for each Web API function, while by default create only async functions.
/// </summary>
public bool GenerateBothAsyncAndSync { get; set; }

Occasionally you may find using block calls may be more convenient, then you may set this to true.

StringAsString

/// <summary>
/// Whether the Web API return string as string, rather than JSON object which is a double quoted string.
/// </summary>
public bool StringAsString { get; set; }

Your Web API should have consistent behavior of serializing strings, text or JSON object.

When StringAsString is true, the generated codes:

C#

var stream = await responseMessage.Content.ReadAsStreamAsync();
using (System.IO.StreamReader streamReader = new System.IO.StreamReader(stream))
{
	return streamReader.ReadToEnd();;
}

TypeScript

getABCDE(headersHandler?: () => HttpHeaders): Observable<string> {
	return this.http.get(this.baseUri + 'api/SuperDemo/String', { headers: headersHandler ? headersHandler() : undefined, responseType: 'text' });
}

When StringAsString is false, the generated codes:

C#

var stream = await responseMessage.Content.ReadAsStreamAsync();
using (JsonReader jsonReader = new JsonTextReader(new System.IO.StreamReader(stream)))
{
	return jsonReader.ReadAsString();
}

TypeScript

getABCDE(headersHandler?: () => HttpHeaders): Observable<string> {
	return this.http.get<string>(this.baseUri + 'api/SuperDemo/String', { headers: headersHandler ? headersHandler() : undefined });
}

CamelCase

/// <summary>
/// Whether to conform to the camel casing convention of javascript and JSON.
/// If not defined, WebApiClientGen will check if GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver is Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver;
/// If CamelCasePropertyNamesContractResolver is presented, camelCasing will be used. If not, no camelCasing transformation will be used.
/// </summary>
public bool? CamelCase { get; set; }

Generally camel casing is preferred.

ContainerNameSuffix

/// <summary>
/// Suffix of container class name if ContainerNameStrategy is not None. The default is "Client".
/// </summary>
public string ContainerNameSuffix { get; set; } = "Client";

"Proxy" could be a good choice too. This improves the readability of generated client API codes in a service broker.

UseEnsureSuccessStatusCodeEx

/// <summary>
/// Replace EnsureSuccessStatusCode with EnsureSuccessStatusCodeEx for specific unsuccessful HTTP status handling, which throws YourClientWebApiRequestException.
/// </summary>
public bool UseEnsureSuccessStatusCodeEx { get; set; }

The standard HttpResponseMessage.EnsureSuccessStatusCode method does expose limited error details and sometimes you may want more details. The this setting will enable generating a block of extension codes:

using System;

namespace Fonlow.Net.Http
{
	using System.Net.Http;

	public class WebApiRequestException : HttpRequestException
	{
		public new System.Net.HttpStatusCode StatusCode { get; private set; }

		public string Response { get; private set; }

		public System.Net.Http.Headers.HttpResponseHeaders Headers { get; private set; }

		public System.Net.Http.Headers.MediaTypeHeaderValue ContentType { get; private set; }

		public WebApiRequestException(string message, System.Net.HttpStatusCode statusCode, string response, System.Net.Http.Headers.HttpResponseHeaders headers, System.Net.Http.Headers.MediaTypeHeaderValue contentType) : base(message)
		{
			StatusCode = statusCode;
			Response = response;
			Headers = headers;
			ContentType = contentType;
		}
	}

	public static class ResponseMessageExtensions
	{
		public static void EnsureSuccessStatusCodeEx(this HttpResponseMessage responseMessage)
		{
			if (!responseMessage.IsSuccessStatusCode)
			{
				var responseText = responseMessage.Content.ReadAsStringAsync().Result;
				var contentType = responseMessage.Content.Headers.ContentType;
				throw new WebApiRequestException(responseMessage.ReasonPhrase, responseMessage.StatusCode, responseText, responseMessage.Headers, contentType);
			}
		}
	}
}

And respective client API function wil run the extended method:

var responseMessage = await client.SendAsync(httpRequestMessage);
try
{
	responseMessage.EnsureSuccessStatusCodeEx();

WebApiRequestException caught will reveal more details which you may want to display or log. And overall this feature is in line with what you get in typical AJAX calls of JavaScript.

IncludeEnsureSuccessStatusCodeExBlock

/// <summary>
/// Default  is true so the code block is included in the generated codes.
/// Defined if UseEnsureSuccessStatusCodeEx is true. Respective code block will be included the code gen output. However, if you have a few client APIs generated to be used in the same application,
/// and you may want these client APIs share the same code block, then put the WebApiRequestException code block to an assembly or a standalone CS file.
/// </summary>
public bool IncludeEnsureSuccessStatusCodeExBlock { get; set; } = true;

Alternatively you may have only one set of generated codes containing the WebApiRequestException code block, through setting this to false for generating other client API sets, if all these client API sets are all contained in one assembly, though generally it is recommended to have one client API set per assembly.

HandleHttpRequestHeaders

/// <summary>
/// Function parameters contain a callback to handle HTTP request headers
/// </summary>
public bool HandleHttpRequestHeaders { get; set; }

Generated codes look like:

public async Task<BulkBillStoreForwardResponseType> BulkBillStoreForwardSpecialistAsync(BulkBillStoreForwardRequestType requestBody, Action<System.Net.Http.Headers.HttpRequestHeaders> handleHeaders = null)
{
	var requestUri = "mcp/bulkbillstoreforward/specialist/v1";
	using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri))
	{
	using (var requestWriter = new System.IO.StringWriter())
	{
	var requestSerializer = JsonSerializer.Create(jsonSerializerSettings);
	requestSerializer.Serialize(requestWriter, requestBody);
	var content = new StringContent(requestWriter.ToString(), System.Text.Encoding.UTF8, "application/json");
	httpRequestMessage.Content = content;
	if (handleHeaders != null)
	{
		handleHeaders(httpRequestMessage.Headers);
	}

	var responseMessage = await client.SendAsync(httpRequestMessage);
Clone this wiki locally