Skip to content

Opt in or Opt out

fonlow edited this page Nov 26, 2023 · 3 revisions

By default, the cherry-picking of data types is opt-in, so custom data types implemented in assemblies declared in "DataModelAssemblyNames" and decorated by DataContractAttribute will be exposed to client programs.

By default, the cherry-picking of Web API functions is opt-out, so all public functions of ApiController derived classes will be processed, except those declared in "ExcludedControllerNames".

{
    "ClientLibraryProjectFolderName": "DemoWebApi.ClientApi",
    "ExcludedControllerNames": [
        "DemoWebApi.Controllers.Account"
    ],
    "GenerateBothAsyncAndSync": true,
    "TypeScriptFolder": "ClientApi",
    "DataModelAssemblyNames": [
        "DemoWebApi.DemoData", "DemoWebApi"
    ],
    "CherryPickingMethods": 1
}

WebApiClientGen encourages opt-in for cherry-picking data types. However, if you have large amount of data types to be exposed to the client side and you prefer opt-out, you may choose "NewtonsoftJson", "Serializable" (4), "AspNet" (8) or "All" (0) of CherryPickingMethods. Please note, overall only custom data types implemented in assemblies declared by "DataModelAssemblyNames" are included, and this is opt-in.

When "Serializable" is selected, data members decorated by NonSerializedAttribute will be excluded.

When "AspNet" or "All" is selected, all data members will be exposed to the client sides.

Please refer to examples of cherry picking.

Remarks:

ASP.NET MVC / Web API Help Page has such logic as illustrated in the code snippet below.

        private static bool ShouldDisplayMember(MemberInfo member, bool hasDataContractAttribute)
        {
            JsonIgnoreAttribute jsonIgnore = member.GetCustomAttribute<JsonIgnoreAttribute>();
            XmlIgnoreAttribute xmlIgnore = member.GetCustomAttribute<XmlIgnoreAttribute>();
            IgnoreDataMemberAttribute ignoreDataMember = member.GetCustomAttribute<IgnoreDataMemberAttribute>();
            NonSerializedAttribute nonSerialized = member.GetCustomAttribute<NonSerializedAttribute>();
            ApiExplorerSettingsAttribute apiExplorerSetting = member.GetCustomAttribute<ApiExplorerSettingsAttribute>();

            bool hasMemberAttribute = member.DeclaringType.IsEnum ?
                member.GetCustomAttribute<EnumMemberAttribute>() != null :
                member.GetCustomAttribute<DataMemberAttribute>() != null;

            // Display member only if all the followings are true:
            // no JsonIgnoreAttribute
            // no XmlIgnoreAttribute
            // no IgnoreDataMemberAttribute
            // no NonSerializedAttribute
            // no ApiExplorerSettingsAttribute with IgnoreApi set to true
            // no DataContractAttribute without DataMemberAttribute or EnumMemberAttribute
            return jsonIgnore == null &&
                xmlIgnore == null &&
                ignoreDataMember == null &&
                nonSerialized == null &&
                (apiExplorerSetting == null || !apiExplorerSetting.IgnoreApi) &&
                (!hasDataContractAttribute || hasMemberAttribute);
        }

WebApiClientGen does not deal with XmlIgnoreAttribute since NoeSerializedAttribute is more appropriate in Web API designs.

WebApiClientGenCore

For .NET Core, in addition to cherry picking mentioned above with the JSON codegen payload, you could have the following codes to opt-out all API controllers.

    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc( // or AddControllers, or AddControllersWithViews, 
                options =>
                {
#if DEBUG
                    options.Conventions.Add
                     (new Fonlow.CodeDom.Web.ApiExplorerVisibilityEnabledConvention());//To make ApiExplorer be visible to WebApiClientGen
#endif
                }
                );

This includes all controllers except those decorated by ApiExplorerSettingsAttribute or ApiControllerAttribute.

Alternatively, if you prefer opt-in approach, you may use ApiExplorerSettingsAttribute to decorate a Web API controller, like this one:

[ApiExplorerSettings(IgnoreApi = false)] // or [ApiController]
[Route("api/[controller]")]
public class HeroesController : ControllerBase
{

Then there's no need to add ApiExplorerVisibilityEnabledConvention.

In the .NET Core Landscape

WebApiClientGen was initially developed for .NET Framework in 2015. DataContractAttribute and DataMemberAttribute etc. were chosen for opt-in cherry-picking of data types because:

  1. These attributes are looking cleaner and more universal than the other XML/JSON related attributes.
  2. If you want to publish JSON based Web API and SOAP Web services, the same data models could be reused easily.

In the .NET Core landscape, WCF service is no longer officially supported by Microsoft in favour of gPRC, however, DataContractAttribute is more semantically conforming to "Design by Contract".

Clone this wiki locally