4

I am creating an app that will add some files and folders to an existing project which is loaded in Visual studio. That works but it will always pop up a message telling the user (me) to refresh the project to show the new files.

enter image description here

When using Entity Framework and adding a migration it will add a file to a project that is currently loaded and it doesn't ask the user. I would like to be able to do the same thing.

Is this possible? If someone doesn't know the answer do they know how I might delve into EF and add migration to see how they do it?

Here is the code that I am using to edit the project file:

using Microsoft.Build.Evaluation;

 internal class ProjectFileHandler
    {
        private void AddMigrationFolder(Project project, string     projectFileLocation, string name)
        {
            var loc = Path.Combine(projectFileLocation.Substring(0, projectFileLocation.LastIndexOf("\\")), name);
            project.AddItem("Folder", loc);            
        }

        internal void AddMigrationFile(string projectfileLocation, string migrationFolderName, string fileLocation)
        {
            var project = new Project(projectfileLocation);
            AddMigrationFolder(project, projectfileLocation, migrationFolderName);

            project.AddItem("Compile", fileLocation);

            project.Save();
        }
    }
Jon
  • 15,110
  • 28
  • 92
  • 132

2 Answers2

0

Pretty old, but I'll leave a comment. Maybe it helps someone else.

The problem is the "project.Save();"

The solution recognizes this as an "external" change. Try your code without this line.

  • Even I am also facing this issue. If you don't use project.Save(), then it will prompt you to overwrite the project file. Also, I want this change to be included before build is called. Has anyone got a solution? – Ven Sep 10 '19 at 07:35
0

Even older, but I had to solve this problem today, so for what it's worth, here's what I did.

Firstly, as far as I can tell, you can't update a project using Microsoft.Build.Evaluation without Visual Studio prompting the user to reload it. You have to call project.Save() to write your updates to the project XML, and Visual Studio 'sees' the file change and displays the prompt.

What you can do - and this looks to be what Entity Framework does, albeit with Powershell - is use EnvDTE instead of Microsoft.Build.Evaluation. EnvDTE is available on NuGet and the latest version supports .NET Framework 4.5 and .NET Standard 2, so it should be pretty widely compatible.

With EnvDTE you get a reference to a Project object and call AddFromFile(absoluteFilePath) - there are also other Add() methods if needed.

If you have the full file path to your project, you can get a project file using:

using System.Linq;
using System.Runtime.InteropServices;
using EnvDTE;

var dte = (DTE)Marshal.GetActiveObject("VisualStudio.DTE");

var project = dte
    .Solution
    .EnumerateProjects()
    .First(p => p.FullName == fullPathToProject);

...where EnumerateProjects() is the following extension method:

using EnvDTE;
using System.Collections;
using System.Collections.Generic;

internal static class EnvDteExtensions
{
    public static IEnumerable<Project> EnumerateProjects(
        this Solution solution)
    {
        return Enumerate(solution.Projects);
    }

    private static IEnumerable<Project> Enumerate(IEnumerable items)
    {
        foreach (var item in items)
        {
            var candidateProject = item;

            if (candidateProject is ProjectItem projectItem &&
                projectItem.SubProject != null)
            {
                candidateProject = projectItem.SubProject;
            }

            if (!(candidateProject is Project project))
            {
                continue;
            }

            yield return project;

            try
            {
                if (project.ProjectItems == null)
                {
                    continue;
                }
            }
            catch
            {
                continue;
            }

            foreach (var subProject in Enumerate(project.ProjectItems))
            {
                yield return subProject;
            }
        }
    }
}

A Project in EnvDTE might actually be a project, or it might be a solution folder containing projects - the candidateProject is ProjectItem projectItem && projectItem.SubProject != null check handles the latter scenario.

EnvDTE's Project.AddFromFile() pops the file into Solution Explorer with no project reload prompt.

Finally, AddFromFile() seems to be idempotent, so you can spam the same file into the project without worrying if it already exists.

Steve Wilkes
  • 7,085
  • 3
  • 29
  • 32