public int UpdateTargetFramework()

in vsintegration/src/FSharp.ProjectSystem.Base/Project/HierarchyNode.cs [3116:3209]


        public int UpdateTargetFramework(
            IVsHierarchy hier,
            string currentTargetFrameworkMoniker,
            string newTargetFrameworkMoniker
            )
        {
            System.Runtime.Versioning.FrameworkName oldFrameworkName;
            System.Runtime.Versioning.FrameworkName frameworkName = null;

            try
            {
                oldFrameworkName = new System.Runtime.Versioning.FrameworkName(currentTargetFrameworkMoniker);
                frameworkName = new System.Runtime.Versioning.FrameworkName(newTargetFrameworkMoniker);
            }
            catch (ArgumentException)
            {
                return VSConstants.E_INVALIDARG;
            }

            Debug.Assert(oldFrameworkName.Identifier == frameworkName.Identifier);
            
            projectMgr.BuildProject.SetProperty(ProjectFileConstants.TargetFrameworkVersion, HierarchyNode.GetFrameworkVersionString(frameworkName));
            projectMgr.BuildProject.SetProperty(ProjectFileConstants.TargetFrameworkProfile, frameworkName.Profile);

            string targetFSharpCoreVersion = projectMgr.BuildProject.GetPropertyValue(ProjectFileConstants.TargetFSharpCoreVersion);
            bool autoGenerateBindingRedirects;
            bool.TryParse(projectMgr.BuildProject.GetPropertyValue("AutoGenerateBindingRedirects"), out autoGenerateBindingRedirects);

            // In reality for FSharp.Core compatibility with .NetFramework selection looks like this:
            // 2 is incompatible with 4
            // 4.0 is incompatible with 4.5
            // 4.5 is compatible with 4.5.1 and 4.5.2 and 4.6
            var lower = oldFrameworkName.Version < frameworkName.Version ? oldFrameworkName.Version : frameworkName.Version;
            var upper = oldFrameworkName.Version < frameworkName.Version ? frameworkName.Version : oldFrameworkName.Version;
            var hasIncompatibleFsCore = (lower.Major != upper.Major) || (lower.Major == 4 && (lower.Minor < 5 && upper.Minor >= 5));
                
            if (hasIncompatibleFsCore)
            {
                var newVersion =
                    frameworkName.Version.Major >= 4 ?
                    ( frameworkName.Version.Minor < 5 ? new Version(4, 3, 0, 0) : new Version(4, 4, 0, 0) ) : new Version(2, 3, 0, 0);
                targetFSharpCoreVersion = newVersion.ToString();

                if (projectMgr.CanUseTargetFSharpCoreReference)
                {
                    // this project controls version of FSharp.Core with project level property TargetFSharpCoreVersion- set it
                    projectMgr.SetProjectProperty(ProjectFileConstants.TargetFSharpCoreVersion, targetFSharpCoreVersion);
                }
                else
                {
                    // project doesn't use TargetFSharpCoreVersion - fix the reference explicitly
                    var fsCoreName = new System.Reflection.AssemblyName(string.Format("FSharp.Core, Culture=neutral, PublicKeyToken={0}", Utilities.FsCorePublicKeyToken));

                    var vsProj = (VSLangProj.VSProject)projectMgr.Object;

                    var references = vsProj.References;

                    // replace existing fscore with one that has matching version with current target framework
                    var existingFsCore =
                        Microsoft.VisualStudio.FSharp.LanguageService.UIThread.DoOnUIThread(
                            () => references
                                .OfType<Automation.OAAssemblyReference>()
                                .FirstOrDefault(r => r.Name == fsCoreName.Name && r.PublicKeyToken == Utilities.FsCorePublicKeyToken && r.Culture == fsCoreName.CultureName)
                            );

                    if (existingFsCore != null)
                    {
                        Microsoft.VisualStudio.FSharp.LanguageService.UIThread.DoOnUIThread(() =>
                        {
                            // save copyLocal value - after calling existingFsCore.Remove() becomes invalid and can raise exceptions
                            var copyLocal = existingFsCore.CopyLocal;
                            existingFsCore.Remove();
                            fsCoreName.Version = newVersion;

                            // stores assembly FQN
                            var newRef = references.Add(fsCoreName.FullName);
                            newRef.CopyLocal = copyLocal;
                        });
                    }
                }
            }

            try
            {
                this.projectMgr.FixupAppConfigOnTargetFXChange(newTargetFrameworkMoniker, targetFSharpCoreVersion, autoGenerateBindingRedirects);
            }
            catch(Exception e)
            {
                Debug.Assert(false, "Failed with e " + e.ToString());
                return VSConstants.E_FAIL;
            }

            return VSConstants.S_OK;
        }