Exception thrown when adding new project into solution - c#

I'm trying to programatically add new project into solution via Roslyn.
var msWorkspace = MSBuildWorkspace.Create();
var solution = msWorkspace.OpenSolutionAsync(Constants.pathToSolution).Result;
var projectId = ProjectId.CreateNewId();
var versionStamp = VersionStamp.Create();
var info = ProjectInfo.Create(
id: projectId,
version: versionStamp,
name: "Redux",
assemblyName: "Redux.dll",
language: LanguageNames.CSharp);
var newSolution = solution.AddProject(info);
msWorkspace.TryApplyChanges(newSolution);
After this, the exception is thrown:
"System.NotSupportedExcpetion: Adding projects is not suported."
When I iterate over changed solution before trying to apply changes, the new project is present there. Adding new documents into projects works without any issues.
Is there a way to add new project into solution and save the changed solution?

Roslyn does not have any code that writes .sln files.
(you can see their solution reader here)
You can't do that.

Related

Strange diagnostics errors, prefedined type System... is not defined or imported

I am getting Roslyn diagnostics errors when parsing a very basic .NET 4.6 application. The solution files can be downloaded from there
https://github.com/dotnet/roslyn/files/2393288/DemoSolution.zip
The dependency tree looks like this:
BLL -> DB
I am getting the following diagnostics errors in the BLL project:
The solution and projects build fine, still Roslyn gives these errors. Maybe the errors are misleading and I need to configure the projects in someway? Any idea how I can resolve these errors?
Here is the code used for parsing the files:
var properties = new Dictionary<string, string>
{
["DesignTimeBuild"] = "true",
["CheckForSystemRuntimeDependency"] = "true"
};
var workspace = MSBuildWorkspace.Create(properties);
workspace.WorkspaceFailed += (sender, args) =>
{
};
workspace.LoadMetadataForReferencedProjects = true;
Solution solution = workspace.OpenSolutionAsync(SolutionFilePath).Result;
foreach (var p in solution.Projects)
{
foreach (var file in p.Documents)
{
var semanticModel = file.GetSemanticModelAsync().Result;
var mscorlib = MetadataReference.CreateFromFile(file.FilePath);
var compilation = CSharpCompilation.Create("MyCompilation",
new[] { semanticModel.SyntaxTree }, new[] { mscorlib });
var model = compilation.GetSemanticModel(semanticModel.SyntaxTree);
var declarationDiagnistics = model.Compilation.GetDeclarationDiagnostics(CancellationToken.None);
var parseDiagnostics = model.Compilation.GetParseDiagnostics(CancellationToken.None);
var allDiagnostics = model.Compilation.GetDiagnostics(CancellationToken.None);
var methodBodyDiagnostics = model.Compilation.GetMethodBodyDiagnostics(CancellationToken.None);
}
}
Subscriping to the workspace.workspaceFailed event results in the following error:
Msbuild failed when processing the file 'MYPATH\BLL.csproj' with
message: C:\Program Files (x86)\Microsoft Visual
Studio\2017\Enterprise\MSBuild\15.0\Bin\Microsoft.Common.CurrentVersion.targets:
(1656, 5): The "GetReferenceNearestTargetFrameworkTask" task could not
be instantiated from the assembly "C:\Program Files (x86)\Microsoft
Visual
Studio\2017\Enterprise\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.Build.Tasks.dll".
Please verify the task assembly has been built using the same version
of the Microsoft.Build.Framework assembly as the one installed on your
computer and that your host application is not missing a binding
redirect for Microsoft.Build.Framework. Unable to cast object of type
'NuGet.Build.Tasks.GetReferenceNearestTargetFrameworkTask' to type
'Microsoft.Build.Framework.ITask'. C:\Program Files (x86)\Microsoft
Visual
Studio\2017\Enterprise\MSBuild\15.0\Bin\Microsoft.Common.CurrentVersion.targets:
(1656, 5): The "GetReferenceNearestTargetFrameworkTask" task has been
declared or used incorrectly, or failed during construction. Check the
spelling of the task name and the assembly name.
So this finally solved it:
Added the microsoft.build redirects as suggested by #GeorgeAlexandria
http://github.com/Microsoft/msbuild/issues/2369#issuecomment-353674937
Cleared the Microsoft.Build.* from the output bin folder
Added the Microsoft.Build.Locator as a reference
Added the line MSBuildLocator.RegisterDefaults() above the workspace code.
Source:
https://github.com/dotnet/roslyn/issues/26029#issuecomment-380164421

Roslyn - determine project excluded from build configuration

I am trying to figure out which project is enabled/disabled in respective build configuration/platform setup. Where could I find this "project.BuildsInCurrentConfiguration" information please?
var properties = new Dictionary<string, string>
{
{ "Configuration", "Debug" },
{ "Platform", "x86"}
};
MSBuildWorkspace workspace = MSBuildWorkspace.Create(properties);
workspace.LoadMetadataForReferencedProjects = true;
Solution solution = workspace.OpenSolutionAsync("someSolution.sln").Result;
foreach (Project project in solution.Projects)
Console.Out.WriteLine($"{project.OutputFilePath} is enabled in this build setup: {project.BuildsInCurrentConfiguration}");
workspace.CloseSolution();
I would have thought I wouldn't be offered the projects that are not part of the picked configuration/platform, but solution.Projects shows me all of them regardless build setup.
I don't think Roslyn really has most of that information right now (I'm not sure if it ever would; but I would hope it would). I don't see anything related to a "configuration" for a project with the Roslyn APIs for example. That seems to be delegated to the DTE interfaces. You can get at platform type in a Roslyn project, so conceptually you could only get projects that would apply to a given type of build:
var rolsynProjects = solution.Projects
.Where(p => p.CompilationOptions.Platform == Platform.X86);
but, things like "DEBUG" configuration seem to only be available via DTE--which isn't that hard to get at. e.g.
var project = DTE.Solution.Projects
.Where(p=>p.FullName == rolsynProjects.First().FilePath).FirstOrDefault();
And from that VS project, you can get at its ConfigurationManager

programmatically extract interface using roslyn

I am looking for a way to extract an interface from a document (c# class declaration) using Roslyn.
going from the reformatter example.
MSBuildWorkspace workspace = MSBuildWorkspace.Create();
// Open the solution within the workspace.
Solution originalSolution = workspace.OpenSolutionAsync(project).Result;
// Declare a variable to store the intermediate solution snapshot at each step.
MSBuildWorkspace workspace = MSBuildWorkspace.Create();
Solution originalSolution = workspace.OpenSolutionAsync(project).Result;
Solution newSolution = originalSolution;
foreach (ProjectId projectId in originalSolution.ProjectIds)
{
// Look up the snapshot for the original project in the latest forked solution.
Project proj = newSolution.GetProject(projectId);
var comp = proj.GetCompilationAsync().Result;
///var bind = comp.
if (proj.Name.EndsWith("Core.DataLayer"))
{
foreach (DocumentId documentId in proj.DocumentIds)
{
Document document = newSolution.GetDocument(documentId);
if (IsRepositoryDocument(document))
{
//How to implement this?
var newinterface = GetInterfaceFromRespository(document);
}
}
}
}
I started out using the sample "reformat solution" that the Roslyn team provided. However I am unable to find a public API to extract an interface from a given class file.
When trying to find this functionality in the Roslyn source code I can only find internal classes. I found the relevant classes in
"src\Features\Core\Portable\ExtractInterface" of the roslyn source code, i could copy these into my project and get it working, but i would rather not.
TLDR; is there a public API that I can use from C# to extract an interface from a class programatically?
Note that this is done in a "regular" C# project and not in a visual studio extension or analyzer.
You can get all the interfaces from a C# file using the below code statements.
string code = new StreamReader(filePath).ReadToEnd();
var syntaxTree = CSharpSyntaxTree.ParseText(code);
var syntaxRoot = syntaxTree.GetRoot();
IEnumerable<InterfaceDeclarationSyntax> interfaceDeclarations = syntaxRoot.DescendantNodes().OfType<InterfaceDeclarationSyntax>();
Then you can iterate the available interfaces in the file.

Including an embedded resource in a compilation made by Roslyn

I'm attempting to include an embedded resource into a dll that I am compiling using Roslyn. I've found something that helped put me on the right track here.
However, when I create the dll using the following code:
const string resourcePath = #"C:\Projects\...\Properties\Resources.resources";
var resourceDescription = new ResourceDescription(
"Resources.resources",
() => File.OpenRead(resourcePath),
true);
var result = mutantCompilation.Emit(file, manifestResources: new [] {resourceDescription});
I find that it will pass all of the unit tests that I have created for the project except for those that rely on the Resources file.
The error I'm getting looks like the following:
System.Resources.MissingManifestResourceException ... Make sure "[Project].Properties.Resources.resources" was correctly embedded or linked into
assembly "[Project]" at compile time, or that all the satellite assemblies required are loadable and fully signed.
The dll is supposed to be signed, and when it is emitted by roslyn it comes out with the correct public key. Also, the Resource.resx is included in my project directly in the Properties folder.
I would appreciate any help anyone could provide.
Ok, so while I was looking for answers, I came across this web page where it was commented that the resource stream was null until the he added the namespace.
So after adding the namespace I got somehting like this
const string resourcePath = #"C:\Projects\...\Properties\Resources.resources";
var resourceDescription = new ResourceDescription(
"[namespace].Resources.resources",
() => File.OpenRead(resourcePath),
true);
var result = mutantCompilation.Emit(file, manifestResources: new [] {resourceDescription});
which runs exactly like you'd expect.

Roslyn Add a document to a project

I'm running roslyn ctp2
I am attempting to add a new html file to a project
IWorkspace workspace = Workspace.LoadSolution("MySolution.sln");
var originalSolution = workspace.CurrentSolution;
ISolution newSolution = originalSolution;
newSolution.GetProject(newSolution.ProjectIds.First())
.AddDocument("index.html", "<html></html>");
workspace.ApplyChanges(originalSolution, newSolution);
This results in no changes being written. I am trying to get the new html file to appear in VS
There are two issues here:
Roslyn ISolution, IProject, and IDocument objects are immutable, so in order to see changes you would need to create a new ISolution with the changes, then call Workspace.ApplyChanges().
In Roslyn, IDocument objects are only created for files that are passed to the compiler. Another way of saying this is things that are part of the Compile ItemGroup in the project file. For other files (including html files), you should use the normal Visual Studio interfaces like IVsSolution.
Workspaces are immutable. That means that any method that sounds like it's going to modify the workspace will instead be returning a new instance with the changes applied.
So you want something like:
IWorkspace workspace = Workspace.LoadSolution("MySolution.sln");
var originalSolution = workspace.CurrentSolution;
var project = originalSolution.GetProject(originalSolution.ProjectIds.First());
IDocument doc = project.AddDocument("index.html", "<html></html>");
workspace.ApplyChanges(originalSolution, doc.Project.Solution);
However, I'm not near a machine with Roslyn installed at the moment, so I can't guarantee this 100%.

Categories