File: Shared\Options\WCFCSUpdateOptions.cs
Web Access
Project: src\src\dotnet-svcutil\lib\src\dotnet-svcutil-lib.csproj (dotnet-svcutil-lib)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using Newtonsoft.Json.Linq;
 
using System.Collections.Generic;
using System.Linq;
 
namespace Microsoft.Tools.ServiceModel.Svcutil
{
    /// <summary>
    /// Represents the options as formatted by the WCF Connected Service.
    /// This class maps the WCF CS options into update options.
    /// </summary>
    internal class WCFCSUpdateOptions : UpdateOptions
    {
        #region option keys
        public const string CollectionTypeReferenceKey = "CollectionTypeReference";
        public const string DictionaryCollectionTypeReferenceKey = "DictionaryCollectionTypeReference";
        public const string ReuseTypesinReferencedAssembliesKey = "ReuseTypesinReferencedAssemblies";
        public const string ReuseTypesinAllReferencedAssembliesKey = "ReuseTypesinAllReferencedAssemblies";
        #endregion
 
        #region properties (private deserialization-only properties that resolve to base's properties).
        private ListValue<string> CollectionTypeReference { get { return GetValue<ListValue<string>>(CollectionTypeReferenceKey); } }
        private ListValue<string> DictionaryCollectionTypeReference { get { return GetValue<ListValue<string>>(DictionaryCollectionTypeReferenceKey); } }
        private bool? ReuseTypesinReferencedAssemblies { get { return GetValue<bool?>(ReuseTypesinReferencedAssembliesKey); } }
        private bool? ReuseTypesinAllReferencedAssemblies { get { return GetValue<bool?>(ReuseTypesinAllReferencedAssembliesKey); } }
        #endregion
 
        private List<string> _deserializedCollectionAssemblies = new List<string>();
 
        public WCFCSUpdateOptions()
        {
            RegisterOptions(
                new ListValueOption<string>(CollectionTypeReferenceKey) { CanSerialize = false },
                new ListValueOption<string>(DictionaryCollectionTypeReferenceKey) { CanSerialize = false },
                new SingleValueOption<bool>(ReuseTypesinReferencedAssembliesKey) { CanSerialize = false },
                new SingleValueOption<bool>(ReuseTypesinAllReferencedAssembliesKey) { CanSerialize = false });
 
            GetOption(OptionsKey).SerializationName = "ExtendedData";
            GetOption(InputsKey).Aliases.Add("Uri");
            GetOption(MessageContractKey).Aliases.Add("GenerateMessageContract");
 
            var internalOption = GetOption(InternalTypeAccessKey);
            internalOption.Aliases.Add("SelectedAccessLevelForGeneratedClass");
            internalOption.Deserializing += this.OnSelectedAccessLevelForGeneratedClassDeserializing;
 
            var namespaceOption = GetOption(NamespaceMappingsKey);
            namespaceOption.Deserializing += this.OnNamespaceOptionDeserializing;
 
            var collectionTypeRefOption = GetOption(CollectionTypeReferenceKey);
            collectionTypeRefOption.Deserializing += this.OnCollectionTypeDeserializing;
 
            var dictionaryCollectionTypeRefOption = GetOption(DictionaryCollectionTypeReferenceKey);
            dictionaryCollectionTypeRefOption.Deserializing += this.OnCollectionTypeDeserializing;
        }
 
        public static new WCFCSUpdateOptions FromFile(string filePath, bool throwOnError = true)
        {
            return FromFile<WCFCSUpdateOptions>(filePath, throwOnError);
        }
 
        public static new WCFCSUpdateOptions FromJson(string jsonText, bool throwOnError = true)
        {
            return FromJson<WCFCSUpdateOptions>(jsonText, throwOnError);
        }
 
        protected override void OnAfterDeserialize()
        {
            base.OnAfterDeserialize();
 
            // Synchronize base options (VS2017 format).
 
            if (this.ReuseTypesinReferencedAssemblies == false)
            {
                this.TypeReuseMode = Svcutil.TypeReuseMode.None;
            }
            else if (this.ReuseTypesinAllReferencedAssemblies.HasValue)
            {
                this.TypeReuseMode = this.ReuseTypesinAllReferencedAssemblies == false ?
                    Svcutil.TypeReuseMode.Specified : Svcutil.TypeReuseMode.All;
            }
 
            if (this.CollectionTypeReference.Count > 0)
            {
                this.CollectionTypes.AddRange(this.CollectionTypeReference);
            }
 
            if (this.DictionaryCollectionTypeReference.Count > 0)
            {
                this.CollectionTypes.AddRange(this.DictionaryCollectionTypeReference);
            }
 
            // The collections supported by the WCF CS are all part of .NET Core.
            foreach (var packageName in _deserializedCollectionAssemblies.Select(an => ProjectDependency.FromPackage(an, ProjectDependency.NetCoreAppPackageID, "*")))
            {
                if (!this.References.Contains(packageName))
                {
                    this.References.Add(packageName);
                }
            }
        }
 
        private void OnCollectionTypeDeserializing(object sender, OptionDeserializingEventArgs e)
        {
            // Alias for CollectionTypes option, translate to collection of string ...
 
            var jToken = e.JToken;
            if (jToken.Type == JTokenType.Object)
            {
                // This must be an object with two properties like below: we need separate the collection type and the type assembly.
                // "CollectionTypeReference": {"Item1": "System.Collections.ArrayList", "Item2": "System.Collections.NonGeneric.dll" }
                // "CollectionType": "System.Collections.ArrayList"
                // "Reference": "System.Collections.NonGeneric, {Microsoft.NETCore.App, *}"
 
                var properties = jToken.Value<JObject>().Properties();
                var item1 = properties.FirstOrDefault(p => p.Name == "Item1")?.Value.Value<string>();
                if (item1 != null)
                {
                    e.Value = new List<object> { item1.Trim() };
 
                    var item2 = properties.FirstOrDefault(p => p.Name == "Item2")?.Value.Value<string>();
                    if (item2 != null)
                    {
                        _deserializedCollectionAssemblies.Add(System.IO.Path.GetFileNameWithoutExtension(item2.Trim()));
                    }
                }
            }
        }
 
        private void OnSelectedAccessLevelForGeneratedClassDeserializing(object sender, OptionDeserializingEventArgs e)
        {
            // Alias for InternalTypeAccess option, translate to bool ...
 
            var jToken = e.JToken;
            if (jToken.Type == JTokenType.String)
            {
                var value = jToken.Value<string>();
                switch (value.ToLowerInvariant())
                {
                    case "internal":
                        e.Value = true;
                        break;
                    case "public":
                        e.Value = false;
                        break;
                }
            }
        }
 
        private void OnNamespaceOptionDeserializing(object sender, OptionDeserializingEventArgs e)
        {
            // Alias for NamespaceMappings option, translate to list of strings that can be parsed into a key/value pairs ...
 
            var jToken = e.JToken;
            if (jToken.Type == JTokenType.String)
            {
                e.Value = new List<object> { ParseNamespace(jToken.Value<string>(), sender as OptionBase) };
            }
        }
 
        private object ParseNamespace(string stringValue, OptionBase option)
        {
            // format namespace as a mapping key/value pair:
            // "Namespace": "MyServiceReference1"
            var parts = stringValue.Split(',');
            OptionValueParser.ThrowInvalidValueIf(parts.Length > 2, stringValue, option);
 
            var valueKey = parts.Length == 1 ? "*" : parts[0];
            var valueVal = parts.Length == 1 ? parts[0] : parts[1];
            var value = new KeyValuePair<string, string>(valueKey.Trim(), valueVal.Trim());
            return value;
        }
    }
}