Error using the MSBuild.CodeAnalysis apis to analyze a C# project? - c#

I am attempting to build a tool (using C# and .NET 7.0, Visual Studio 2022) that will analyze another C# project. I added the MSBuild.Locator package and invoked it with MSBuildLocator.RegisterDefaults(). However, when I attempt to actually open the project to be analyzed, I get the following error:
Here is the source code of the tool:
using Microsoft.Build.Locator;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.MSBuild;
using Microsoft.CodeAnalysis.Text;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
namespace AnalysisTool
{
class Program
{
public static async Task DoActualWork()
{
var workspace = MSBuildWorkspace.Create();
workspace.LoadMetadataForReferencedProjects = true;
workspace.WorkspaceFailed += OnWorkspaceFailed;
// Error occurs here
var project = await workspace.OpenProjectAsync(
#"C:\Path\To\OtherProject.csproj");
var compilation = await project.GetCompilationAsync();
}
public static async Task Main(string[] args)
{
var vsAvail = MSBuildLocator.QueryVisualStudioInstances().ToList();
MSBuildLocator.RegisterDefaults();
await DoActualWork();
}
private static void OnWorkspaceFailed(object sender,Microsoft.CodeAnalysis.WorkspaceDiagnosticEventArgs e)
{
if (e.Diagnostic.Kind == Microsoft.CodeAnalysis.WorkspaceDiagnosticKind.Failure)
{
Console.WriteLine(e.Diagnostic.ToString());
}
}
}
}
And the analysis tool's associated project file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<RollForward>Major</RollForward>
<OutDir>..\Bin\</OutDir>
<OutputPath>$(OutDir)</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build.Locator" Version="1.5.5" />
<PackageReference Include="Microsoft.CodeAnalysis" Version="4.4.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Features" Version="4.4.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.Features" Version="4.4.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="4.4.0" />
<PackageReference Include="NuGet.ProjectModel" Version="6.4.0" />
</ItemGroup>
</Project>
I've tried walking it back to .NET 5.0, with the same error. I'd appreciate any help.

Related

OpenXml throws a different exception given identical code and similar build configuration for two distinct solutions. Why?

Suppose I have two separate solutions in Visual Studio 2019:
openxml-exceptions.sln
openxml-exceptions-reference.sln
openxml-exceptions.sln
This solution contains two projects:
basic-example: A class library
call-basic-example: A console app
basic-example
The project file is as follows:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PlatformTarget>AnyCPU</PlatformTarget>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>basic_example</RootNamespace>
<ImplicitUsings>disable</ImplicitUsings>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="2.14.0" />
</ItemGroup>
</Project>
The project also contains SpreadsheetWriterExample.cs:
using System.IO;
using DocumentFormat.OpenXml.Packaging;
using System.Collections.Generic;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Spreadsheet;
using System.Text;
namespace basic_example
{
public class SpreadSheetWriterExample
{
public static void CreateSpreadsheetWorkbook(string filepath)
{
// Create a spreadsheet document by supplying the filepath.
// By default, AutoSave = true, Editable = true, and Type = xlsx.
Console.WriteLine("creating spreadsheet document");
try
{
using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create(filepath, SpreadsheetDocumentType.Workbook))
{
spreadsheetDocument.Close();
}
}
catch (DirectoryNotFoundException e)
{
Console.WriteLine("DirectoryNotFoundException");
}
catch (ArgumentException)
{
Console.WriteLine("ArgumentException");
}
catch (IOException e)
{
Console.WriteLine("IOException");
}
}
public static void Run()
{
CreateSpreadsheetWorkbook("asd\\da*dw.xlsx");
}
}
}
call-basic-example
The project file is as follows:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>call_basic_example</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\basic-example\basic-example.csproj" />
</ItemGroup>
</Project>
The project also contains Program.cs:
using System;
using basic_example;
namespace call_basic_example
{
class Program
{
static void Main(string[] args)
{
SpreadSheetWriterExample.Run();
}
}
}
openxml-exceptions-reference.sln
This solution contains one project:
basic-example: A console app
basic-example
The project file is as follows:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<PlatformTarget>AnyCPU</PlatformTarget>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>basic_example</RootNamespace>
<ImplicitUsings>disable</ImplicitUsings>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="2.14.0" />
</ItemGroup>
</Project>
The project also includes SpreadSheetWriterExample.cs:
using System;
using System.IO;
using DocumentFormat.OpenXml.Packaging;
using System.Collections.Generic;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Spreadsheet;
using System.Text;
namespace basic_example
{
public class SpreadSheetWriterExample
{
public static void CreateSpreadsheetWorkbook(string filepath)
{
// Create a spreadsheet document by supplying the filepath.
// By default, AutoSave = true, Editable = true, and Type = xlsx.
Console.WriteLine("creating spreadsheet document");
try
{
using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create(filepath, SpreadsheetDocumentType.Workbook))
{
spreadsheetDocument.Close();
}
}
catch (DirectoryNotFoundException e)
{
Console.WriteLine("DirectoryNotFoundException");
}
catch (ArgumentException)
{
Console.WriteLine("ArgumentException");
}
catch (IOException e)
{
Console.WriteLine("IOException");
}
}
public static void Main()
{
CreateSpreadsheetWorkbook("asd\\da*dw.xlsx");
}
}
}
Question:
When I build and run openxml-exceptions.sln with call-basic-example as the startup project, I get DirectoryNotFoundException in the output.
When I build and run openxml-exceptions-reference.sln I get ArgumentException in the output.
I am using the following version of Visual Studio:
Given that I am using the exact same framework version in the class library of openxml-exceptions.sln and the console app of openxml-exceptions-reference.sln and the exact same version of OpenXml, I cannot wrap my head around why the thrown and caught error are different for each solution. As far as I can tell they should be exactly the same, but I am apparently overlooking something fundamental.
Why are the errors thrown different for each solution, given the exact same code, framework version and package version?

Roslyn, Could not load file or assembly System.Runtime

I am new with Roslyn and I am trying to compile my first code at runtime.
The code compile(exe) without error but when i run it throught process.Start() in the concole output appers the error
Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'System.Runtime, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
I read that many other people had same problem but the solution here :
https://github.com/dotnet/core/issues/2082
not worked for me
This is the full code of my console app :
using System;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using System.IO;
using System.Diagnostics;
using Microsoft.Extensions.DependencyModel;
using System.Linq;
namespace TestRoslyn
{
class Program
{
static string code = #"
using System;
namespace First
{
public class Program
{
public static void Main()
{" +
"Console.WriteLine(\"Hello, world!\");"
+ #"
}
}
}
";
static void Main(string[] args)
{
MetadataReference[] _ref = DependencyContext.Default.CompileLibraries
.SelectMany(cl => cl.ResolveReferencePaths())
.Select(asm => MetadataReference.CreateFromFile(asm))
.ToArray();
var syntaxTree = SyntaxFactory.ParseSyntaxTree(SourceText.From(code));
var assemblyPath = Path.ChangeExtension(Path.GetTempFileName(), "exe");
var compilation = CSharpCompilation.Create(Path.GetFileName(assemblyPath))
.WithOptions(new CSharpCompilationOptions(OutputKind.ConsoleApplication))
.AddReferences(_ref)
.AddSyntaxTrees(syntaxTree);
var result = compilation.Emit(assemblyPath);
if (result.Success) // Compilation is Success
{
using (Process process = new Process())
{
process.StartInfo.FileName = assemblyPath;
process.Start(); // Here the error appears in the console window
}
}
else
{
System.Diagnostics.Debug.Write(string.Join(
Environment.NewLine,
result.Diagnostics.Select(diagnostic => diagnostic.ToString())
));
}
}
}
}
project file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<PreserveCompilationContext>true</PreserveCompilationContext>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.10.0" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="5.0.0" />
</ItemGroup>
</Project>
Can someone help me ?

How do I replace Database.ExecuteSqlQuery when changing TargetFramework away from.NetCore2.1

I have the following which was working fine in .NetCore2.1 with SDKs
Microsoft.AspNetCore.App(2.1.1)
Microsoft.NetCore.App(2.1.0)
My code is
public static int TransitTime(string postcode, ApiDbContext con)
{
var query = "SELECT top 1 Mins from Transit where postcode = #Postcode order by mins desc;";
var p1 = new SqlParameter("#Postcode",postcode);
var result = 0;
using (var dr = con.Database.ExecuteSqlQuery(query,p1))
{
var reader = dr.DbDataReader;
while (reader.Read()) result = (int)reader[0];
}
return Convert.ToInt32(result);
}
Hovering over the word Database I could see it was in
Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade
I don't see a specific reference to
Microsoft.EntityFrameworkCore.Infrastructure
It is documented as being part of Entity Framework Core 2.1
inside either SDK so I wonder how it is referenced.
However I needed to add a reference to a Framework 4.7.2 dll
So I switched to the following project file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>netstandard2.0</TargetFramework>
<ApplicationIcon />
<StartupObject />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.2.6" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Common\SBD.Common.csproj" />
</ItemGroup>
</Project>
Now I get an error
CS1061 'DatabaseFacade' does not contain a definition for
'ExecuteSqlQuery'
I tried looking form Microsoft.EntityFrameworkCore.Infrastructure in Nuget Manage Packages for Solution but it does not show.
Looking at this question I decided to try using .FromSQl instead.
I found help in the docs but it does not explain how return non entity types.
How do I do that?
After reading the end of this link I am trying
public static int TransitTime(string postcode, ApiDbContext con)
{
var query = "SELECT top 1 Mins from Transit where postcode = #Postcode order by mins desc;";
var p1 = new SqlParameter("#Postcode", postcode);
var result = 0;
using (var command = con.Database.GetDbConnection().CreateCommand())
{
command.CommandText = query;
command.Parameters.Add(p1);
con.Database.OpenConnection();
using (var reader = command.ExecuteReader())
{
while (reader.Read()) result = (int)reader[0];
}
}
return Convert.ToInt32(result);
}
I see that this is using an extension method in Microsoft.EntityFrameworkCore.Infrastructure

How to use 'Microsoft.CognitiveServices.Speech' namespace with Azure Functions?

I'm testing the Microsoft Azure Speech services, specifically trying to use Text-To-Speech. So, I'm using a free layer of Azure, and created a TimeTrigger Azure Function to read an e-mail, traverse through HTML and then call the Speech Service with the SDK Microsoft.CognitiveServices.Speech. I'm using the function.proj to load the nuget packages, loading S22.Imap and HtmlAgilityPack without any issues. But the speech package is triggering an exception:
Unable to load DLL 'Microsoft.CognitiveServices.Speech.core.dll' or one of its dependencies: The specified module could not be found. (Exception from HRESULT: 0x8007007E).
Am I able to use this package in an Azure Function? If so, what am I doing wrong?
I tried to remove the <PackageReference Include="Microsoft.CognitiveServices.Speech" Version="1.6.0" /> line from function.proj and deleted project.assets.json to reload the package but it didn't work.
This is my function.proj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="S22.Imap" Version="3.6.0" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.9" />
<PackageReference Include="Microsoft.CognitiveServices.Speech" Version="1.6.0" />
</ItemGroup>
</Project>
And this is my run.csx:
using System;
using S22.Imap;
using System.Net.Mail;
using HtmlAgilityPack;
using System.Threading.Tasks;
using Microsoft.CognitiveServices.Speech;
using System.Diagnostics;
public static void Run(TimerInfo myTimer, ILogger log)
{
var username = "sample#gmail.com";
var password = "sample";
var subsKey = "sample";
using(ImapClient client = new ImapClient("imap.gmail.com", 993, username, password, AuthMethod.Login, true))
{
IEnumerable<uint> uids = client.Search(SearchCondition.From("sample#sample.com"));
IEnumerable<MailMessage> messages = client.GetMessages(uids);
log.LogInformation($"Count: {messages.Count()}.");
var msg = messages.FirstOrDefault();
if(msg != null)
{
var doc = new HtmlDocument();
doc.LoadHtml(msg.Body);
var paragraphs = doc.DocumentNode.Descendants()
.Where(x => x.Name == "p" && !string.IsNullOrEmpty(x.InnerText.Trim()))
.ToList();
var mailText = string.Empty;
foreach(var par in paragraphs)
mailText += par.InnerText;
if(!string.IsNullOrEmpty(mailText))
{
var config = SpeechConfig.FromSubscription(subsKey, "myregion");
config.SetSpeechSynthesisOutputFormat(SpeechSynthesisOutputFormat.Audio24Khz160KBitRateMonoMp3);
config.SpeechSynthesisLanguage = "pt-BR";
using (var synthesizer = new SpeechSynthesizer(config))
{
using (var result = synthesizer.SpeakTextAsync(mailText).Result)
{
if (result.Reason == ResultReason.SynthesizingAudioCompleted)
{
//Do something with it
}
else if (result.Reason == ResultReason.Canceled)
{
var cancellation = SpeechSynthesisCancellationDetails.FromResult(result);
log.LogError($"CANCELED: Reason={cancellation.Reason}");
if (cancellation.Reason == CancellationReason.Error)
{
log.LogError($"CANCELED: ErrorCode={cancellation.ErrorCode}");
log.LogError($"CANCELED: ErrorDetails=[{cancellation.ErrorDetails}]");
}
}
}
}
}
}
}
}
You could try to delete the function.proj then recreate one and add Microsoft.CognitiveServices.Speech at first.
Make sure the Microsoft.CognitiveServices.Speech.core.dll has been installed in win-x86 and win-x64. Please refer to this issue.
Mark as perquisite
When you publish mark Visual c++ 14 Runtime Libraries as prerequisite

Why does C# code compiled on the fly not work when a debugger is attached?

I have the following C# project targetting .NET 4.0 that takes a source code file, compiles it into an assembly on the fly and then executes a static method of a type contained in that assembly.
This works as expected, as long as I don't start the program with a debugger attached. In that case I get an exception on the call to xmlSerializer.Serialize(sw, family);, more precisely a System.NullReferenceException inside a System.TypeInitializationException inside a System.InvalidOperationException.
If I take the same program, include the source code file in the project and compile it directly into the main program assembly, I will not get an exception regardless of whether or not a debugger is attached.
Please note that I my project references the exact same assemblies as those listed when compiling on the fly.
Why does it matter to the code compiled on the fly whether or not a debugger is attached? What am I missing?
Main file Program.cs:
using System;
using System.CodeDom.Compiler;
using System.IO;
using System.Reflection;
using System.Linq;
namespace DebugSerializeCompiler
{
class Program
{
static void Main()
{
if (!Environment.GetCommandLineArgs().Contains("Compile"))
{
DebugSerializeCompiler.SerializerTest.Run();
}
else
{
Assembly assembly;
if (TryCompile("..\\..\\SerializerTest.cs", new[]{ "Microsoft.CSharp.dll",
"System.dll", "System.Core.dll", "System.Data.dll", "System.Xml.dll" },
out assembly))
{
Type type = assembly.GetType("DebugSerializeCompiler.SerializerTest");
MethodInfo methodInfo = type.GetMethod("Run");
methodInfo.Invoke(null, null);
}
}
Console.ReadKey();
}
static bool TryCompile(string fileName, string[] referencedAssemblies,
out Assembly assembly)
{
bool result;
CodeDomProvider compiler = CodeDomProvider.CreateProvider("CSharp");
var compilerparams = new CompilerParameters
{
GenerateExecutable = false,
GenerateInMemory = true
};
foreach (var referencedAssembly in referencedAssemblies)
{
compilerparams.ReferencedAssemblies.Add(referencedAssembly);
}
using (var reader = new StreamReader(fileName))
{
CompilerResults compilerResults =
compiler.CompileAssemblyFromSource(compilerparams, reader.ReadToEnd());
assembly = compilerResults.CompiledAssembly;
result = !compilerResults.Errors.HasErrors;
if (!result)
{
Console.Out.WriteLine("Compiler Errors:");
foreach (CompilerError error in compilerResults.Errors)
{
Console.Out.WriteLine("Position {0}.{1}: {2}",
error.Line, error.Column, error.ErrorText);
}
}
}
return result;
}
}
}
File compiled into separate assembly SerializerTest.cs:
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
namespace DebugSerializeCompiler
{
public class SerializerTest
{
public static void Run()
{
Console.WriteLine("Executing Run()");
var family = new Family();
var xmlSerializer = new XmlSerializer(typeof(Family));
TextWriter sw = new StringWriter();
try
{
if (sw == null) Console.WriteLine("sw == null");
if (family == null) Console.WriteLine("family == null");
if (xmlSerializer == null) Console.WriteLine("xmlSerializer == null");
xmlSerializer.Serialize(sw, family);
}
catch (Exception e)
{
Console.WriteLine("Exception caught:");
Console.WriteLine(e);
}
Console.WriteLine(sw);
}
}
[Serializable]
public class Family
{
public string LastName { get; set; }
public List<FamilyMember> FamilyMembers { get; set; }
}
[Serializable]
public class FamilyMember
{
public string FirstName { get; set; }
}
}
This is the csproj file used to compile the project using Visual C# 2010 Express on Windows 7:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{7B8D2187-4C58-4310-AC69-9F87107C25AA}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DebugSerializeCompiler</RootNamespace>
<AssemblyName>DebugSerializeCompiler</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SerializerTest.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
It worked fine for me.
But if I had to guess what's going on for you it would be that because you're compiling the class in with your main project and dynamically compiling it the serializer is getting confused about which assembly to use and is failing. You could try attaching an event to AppDomain.CurrentDomain.AssemblyResolve and see if there are any assemblies failing to resolve there.

Categories

Resources