AWS .NET SDK SimpleEmail SendEmail returning 'Could not load type' error - c#

I'm developing an application using AWS SimpleEmail. I'm getting the error below when I try to test SendEmail function.
Could not load type 'Amazon.Runtime.Internal.InvokeOptions' from
assembly 'AWSSDK.Core, Version=3.3.0.0, Culture=neutral,
PublicKeyToken=885c28607f98e604'.
I have AWSSDK.Core v3.3.31.7 and AWSSDK.SimpleEmail v3.3.7.30 installed.
var credentials = new BasicAWSCredentials("key", "secret");
var client = new Amazon.SimpleEmail.AmazonSimpleEmailServiceClient(credentials, Amazon.RegionEndpoint.EUWest1);
var sesResponse = client.SendEmail(new SendEmailRequest
{
Destination = new Destination
{
BccAddresses = new List<string>
{
},
ToAddresses = new List<string> {
"user#cuchuma.net",
"user2#cuchuma.net"
}
},
Message = new Message
{
Body = new Body
{
Html = new Content
{
Charset = "UTF-8",
Data = "This message body contains HTML formatting. It can, for example, contain links like this one: <a class=\"ulink\" href = \"http://docs.aws.amazon.com/ses/latest/DeveloperGuide\" target = \"_blank\"> Amazon SES Developer Guide </a>."
},
Text = new Content
{
Charset = "UTF-8",
Data = "This is the message body in text format."
}
},
Subject = new Content
{
Charset = "UTF-8",
Data = "Test email"
}
},
ReplyToAddresses = new List<string>
{
},
ReturnPath = "",
ReturnPathArn = "",
Source = "no-reply#cuchuma.net",
SourceArn = ""
});
string messageId = sesResponse.MessageId;

The class it cannot load was only added 2 months ago. So my suspicion is that you have an older version of AWSSDK.Core than you have stated (v3.3.31.7).
Now I'm not sure how this happens, but I have seen instances in the past where Nuget gets messed up and a manual entry in the project file causes an incorrect dll to be loaded.
Open up your project file in notepad and look for the SDK references. They should look like the following:
<Reference Include="AWSSDK.Core, Version=3.3.0.0, Culture=neutral, PublicKeyToken=885c28607f98e604, processorArchitecture=MSIL">
<HintPath>..\packages\AWSSDK.Core.3.3.31.7\lib\net45\AWSSDK.Core.dll</HintPath>
</Reference>
<Reference Include="AWSSDK.SimpleEmail, Version=3.3.0.0, Culture=neutral, PublicKeyToken=885c28607f98e604, processorArchitecture=MSIL">
<HintPath>..\packages\AWSSDK.SimpleEmail.3.3.7.30\lib\net45\AWSSDK.SimpleEmail.dll</HintPath>
</Reference>
Check to see that the package names are indeed AWSSDK.Core.3.3.31.7 and AWSSDK.SimpleEmail.3.3.7.30.
Also check that there are no other random AWSSDK.Core entries.
Lastly... Another issue you might run into, if you don't specify them then don't include the following lines with blank string. It will throw an invalid email address error:
ReturnPath = "",
ReturnPathArn = "",
SourceArn = ""

A variation of #Martin Beeby's answer.
Using the fuslogvw tool I saw that the GAC version of AWSSDK.Core is loaded before attempting to load the local copy. My GAC had an outdated version of the AWSSDK.Core assembly and worse I could not safely uninstall it because there were dependencies. What ended up working was: I navigated to the local copy in my project (something like <solution folder>/packages/AWSSDK.Core.3.5.3.1/) and with an elevated PowerShell prompt I issued:
&"C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.7.2 Tools\gacutil.exe" /i .\AWSSDK.Core.dll
so that the newer version gets installed, and the error went away.
Note: you might have gacutil in a different path and it might even be on the path environment variable so you don't need a path.

Related

System.TypeLoadException: Could not load type 'System.Object' from assembly 'System.Private.CoreLib' because the parent does not exist

We are generating code dynamically to produce a .NET Core console application and then compiling it using:
var csharpParseOptions = new CSharpParseOptions(LanguageVersion.Latest);
csharpParseOptions = csharpParseOptions.WithPreprocessorSymbols(new[] { "TRACE", "DEBUG" });
var syntaxTree = CSharpSyntaxTree.ParseText(code, options: csharpParseOptions);
var compilationUnitSyntax = syntaxTree.GetCompilationUnitRoot();
var options = new CSharpCompilationOptions(OutputKind.ConsoleApplication, optimizationLevel: OptimizationLevel.Debug, platform: Platform.X64)
.WithModuleName("TestConsole")
.WithMetadataImportOptions(MetadataImportOptions.All)
.WithDeterministic(true)
.WithConcurrentBuild(true);
var csharpCompilation = CSharpCompilation.Create(#"TestConsole", syntaxTrees: new[] { syntaxTree }, references: references, options: options);
We can then work without any problems against the generated assembly (in memory) obtained using:
using (var memoryStream = new MemoryStream())
{
var emitResult = csharpCompilation.Emit(memoryStream);
memoryStream.Position = 0;
_assembly = Assembly.Load(memoryStream.ToArray());
}
However, when we write the console.exe to disk using:
csharpCompilation.Emit(fileNameOnDisk, Path.Combine(Path.GetDirectoryName(fileNameOnDisk), Path.GetFileNameWithoutExtension(fileNameOnDisk)) + ".pdb");
and try to run it from there we get the following exception:
System.TypeLoadException: Could not load type 'System.Object' from assembly 'System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e' because the parent does not exist.
Copying the same generated code (Program.cs) into an empty Console project works perfectly but we notice that the size of the executable is significantly larger.
Does anyone have any ideas how to go about fixing this problem? Thanks.
I think your problem is the lack of runtime configuration. From what I read above if you add a file named testconsole.runtimeconfig.json with the following info or similar:
{
"runtimeOptions": {
"tfm": "net6.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "6.0.0"
}
}
}
You'll see that it runs. I'm also attaching a complete example with compilation.Emit that I validated in LINQPad. It does not require an additional file since it generates it in the example. Best of luck and hope it is still useful.
var tree = CSharpSyntaxTree.ParseText (#"class Program
{
static void Main() => System.Console.WriteLine (""Hello"");
}");
string trustedAssemblies = (string)AppContext.GetData ("TRUSTED_PLATFORM_ASSEMBLIES");
var trustedAssemblyPaths = trustedAssemblies.Split (Path.PathSeparator);
var references = trustedAssemblyPaths.Select (path => MetadataReference.CreateFromFile (path));
var compilation = CSharpCompilation
.Create ("test")
.WithOptions (new CSharpCompilationOptions (OutputKind.ConsoleApplication))
.AddSyntaxTrees (tree)
.AddReferences (references);
string outputPath = "test.dll";
Path.GetFullPath (outputPath).Dump();
EmitResult result = compilation.Emit (outputPath);
Console.WriteLine (result.Success);
File.WriteAllText ("test.runtimeconfig.json", #$"{{
""runtimeOptions"": {{
""tfm"": ""net{Environment.Version.Major}.{Environment.Version.Minor}"",
""framework"": {{
""name"": ""Microsoft.NETCore.App"",
""version"": ""{Environment.Version.Major}.{Environment.Version.Minor}.{Environment.Version.Build}""
}}
}}
}}");
// Execute the program we just compiled.
Util.Cmd (#"dotnet.exe", "\"" + Path.GetFullPath (outputPath) + "\"");

Codegeneration at runtime from a string to console exe is not working in C# .NET6

I have some code which must be able to generated a console application at runtime (Codegeneration with System.CodeDom). I did this already a lot, but in NET 6 now I am struggling with that and the new API. In the code below I try to compile simply from a string. See below the static class with method Start() which then should generates the application.
The compilations seems fine, no errors at the end. But when starting the generated AppCodegenerated.exe, it shows some reference exception with System.Runtime.
Please help, any Idea? Already researched a lot but could not find any useful solution..
//-
I used the Visual Studio 2022 / NET 6 and theses Nuget's:
using Basic.Reference.Assemblies;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
using System.Text;
namespace CompilerSimplified
{
public static class Compiler
{
public static bool Start()
{
string FileName = "AppCodegenerated";
string ExePath = AppDomain.CurrentDomain.BaseDirectory + #"\" + FileName + ".exe";
string code = #"using System; Console.WriteLine(""Hello.""); Console.ReadLine(); ";
// ------- References -------------
// .net platform references
List<MetadataReference> References = new List<MetadataReference>();
foreach (var item in ReferenceAssemblies.Net60) // ReferenceAssemblies from Nuget: Basic.Reference.Assemblies;
References.Add(item);
// or tried this: loop manually through system platform
//string[] fileEntries = Directory.GetFiles(#"C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\6.0.0\ref\net6.0\", "*.dll");
//foreach (string fileName in fileEntries)
// references.Add(MetadataReference.CreateFromFile(fileName));MetadataReference.CreateFromFile(fileName));
// ------- References END -------------
// delete existing file
if (File.Exists(ExePath))
File.Delete(ExePath);
// compiler options
CSharpCompilationOptions DefaultCompilationOptions =
new CSharpCompilationOptions(outputKind: OutputKind.ConsoleApplication, platform: Platform.AnyCpu)
.WithOverflowChecks(true).WithOptimizationLevel(OptimizationLevel.Release);
// encode soucre code
string sourceCode = SourceText.From(code, Encoding.UTF8).ToString();
// CSharp options
var parsedSyntaxTree = Parse(sourceCode, "", CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp10));
// compilation
var compilation = CSharpCompilation.Create(FileName, new SyntaxTree[] { parsedSyntaxTree }, references: References, DefaultCompilationOptions);
var result = compilation.Emit(ExePath);
// return
if (result.Success)
return true;
else
return false;
}
private static SyntaxTree Parse(string text, string filename = "", CSharpParseOptions options = null)
{
var stringText = SourceText.From(text, Encoding.UTF8);
return SyntaxFactory.ParseSyntaxTree(stringText, options, filename);
}
}
}
Above code runs fine without error and exports the AppCodegenerated.exe into the project /bin folder.
Execution of this generated AppCodegenerated.exe shows following on the output console:
Unhandled exception: System.IO.FileNotFoundException:
The file or assembly "System.Runtime, Version = 6.0.0.0, Culture = neutral,
PublicKeyToken = b03f5f7f11d50a3a" or a dependency on it was not found.
The system can not find the stated file.
It is not possible to codegenerate directly a console application like the initial approach above. One possible solution is to generate first a dll (what I mentioned above in the example code is working fine), and from there include that .dll into a .exe, from where the functionality can run.

Can't load assembly that isn't explicitly used in my project

I need to load these 4 assemblies on the fly:
"Microsoft.CodeAnalysis",
"Microsoft.CodeAnalysis.CSharp",
"Microsoft.CodeAnalysis.Features",
"Microsoft.CodeAnalysis.CSharp.Features"
They all come from nuget packages referenced in a project separate from the startup project.
But when I try loading them like this:
Assembly.Load("Microsoft.CodeAnalysis"),
Assembly.Load("Microsoft.CodeAnalysis.CSharp"),
Assembly.Load("Microsoft.CodeAnalysis.Features"),
Assembly.Load("Microsoft.CodeAnalysis.CSharp.Features")
// this doesn't work either:
// Assembly.Load("Microsoft.CodeAnalysis.CSharp.Features, Version=3.9.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")
I get a FileNotFoundException on the Assembly.Load(Microsoft.CodeAnalysis.CSharp.Features) call.
However, loading the dll directly from the packages directory like so:
Assembly.LoadFile(#"D:\project\packages\Microsoft.CodeAnalysis.CSharp.Features.3.9.0-2.20525.2\lib\netstandard2.0\Microsoft.CodeAnalysis.CSharp.Features.dll")
works perfectly fine.
I've also noticed that the Microsoft.CodeAnalysis.CSharp.Features.dll isn't copied to the startup project bin directory, while the three other dlls are. I suspect that it's because I'm not explicitly using that assembly in my own code, it's just loaded using reflection and then immediately sent to external code.
My complete intended usage/implementation looks like this
public static Document CreateDocument(string assemblyName, IEnumerable<PortableExecutableReference> referensMetadata, string documentName = "Script",
IEnumerable<Assembly> hostedAssemblies = null)
{
// To prevent "The language 'C#' is not supported." exception
var _ = typeof(Microsoft.CodeAnalysis.CSharp.Formatting.CSharpFormattingOptions);
var mefHostRequiredAssemblies = new List<Assembly>
{
Assembly.Load("Microsoft.CodeAnalysis"),
Assembly.Load("Microsoft.CodeAnalysis.CSharp"),
Assembly.Load("Microsoft.CodeAnalysis.Features"),
Assembly.Load("Microsoft.CodeAnalysis.CSharp.Features")
};
if (hostedAssemblies != null)
{
mefHostRequiredAssemblies.AddRange(hostedAssemblies);
}
var partTypes = MefHostServices.DefaultAssemblies.Concat(mefHostRequiredAssemblies)
.Distinct()
.SelectMany(x => x.GetTypes())
.ToArray();
var compositionContext = new ContainerConfiguration()
.WithParts(partTypes)
.CreateContainer();
var workspace = new AdhocWorkspace(MefHostServices.Create(compositionContext));
var project = ProjectInfo.Create(ProjectId.CreateNewId(), VersionStamp.Create(),
assemblyName, assemblyName, LanguageNames.CSharp)
.WithMetadataReferences(referensMetadata);
var documentId = DocumentId.CreateNewId(project.Id);
var documentInfo = DocumentInfo.Create(documentId, documentName,
loader: TextLoader.From(
TextAndVersion.Create(
SourceText.From(string.Empty), VersionStamp.Create())
)
);
return workspace.CurrentSolution.AddProject(project)
.AddDocument(documentInfo)
.GetDocument(documentId);
}
My question is what am I doing wrong? How come I can't load references I've explicitly added to the project?

How to use BuildManager to build .Net Core project or solution on Visual Studio 2017 (MsBuild 15)

I want to build a simple project or solution (VS 2017, .NET Standard/.Net Core):
ProjectCollection pc = new ProjectCollection();
pc.DefaultToolsVersion = "15.0";
ILogger logger = new ConsoleLogger();
pc.Loggers.Add(logger);
Dictionary<string, string> globalProperty = new Dictionary<string, string>();
BuildRequestData buildRequest = new BuildRequestData(fileName, globalProperty, null, new[] { target }, null);
BuildParameters buildParameters = new BuildParameters(pc)
{
DefaultToolsVersion = "15.0",
OnlyLogCriticalEvents = false,
DetailedSummary = true,
Loggers = new List<Microsoft.Build.Framework.ILogger> { logger }.AsEnumerable()
};
var result = BuildManager.DefaultBuildManager.Build(buildParameters, buildRequest);
return result.OverallResult == BuildResultCode.Success;
But the build fails with the following error
MSBUILD : warning MSB4196: The "*.overridetasks" files could not be successfully loaded from their expected location "C:\Program Files\dotnet". Default tasks will not be overridden.
MSBUILD : warning MSB4010: The "*.tasks" files could not be successfully loaded from their expected location "C:\Program Files\dotnet". Default tasks will not be available.
D:\Build\workspace\Lx\Lx.sln.metaproj : error MSB4036: The "Message" task was not found.
Check the following:
1.) The name of the task in the project file is the same as the name of the task class.
2.) The task class is "public" and implements the Microsoft.Build.Framework.ITask interface.
3.) The task is correctly declared with <UsingTask> in the project file, or in the *.tasks files located in the "C:\Program Files\dotnet" directory.
Seems it is unable to find the right directory or such ...
What should I do to fix this ?
Note: I don't want to copy files from other directories.
It seems in order to use BuildManager with .Net Core/Visual Studio 2017/MsBuild 15, you must set several environment variables:
var msbuildRoot = #"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild";
var msbuildExe = Path.Combine(msbuildRoot, #"15.0\Bin\MsBuild.exe");
var sdkPath = Path.Combine(msbuildRoot, "Sdks");
Environment.SetEnvironmentVariable("MSBUILD_EXE_PATH", msbuildExe);
Environment.SetEnvironmentVariable("MSBUILDSDKSPATH", sdkPath);
Environment.SetEnvironmentVariable("MSBuildExtensionsPath", msbuildRoot);
Note that the first two should be set before any access to MsBuild classes. It's because they are read by BuildEnvironmentHelper in a static initialization (Singleton pattern). Check method TryFromEnvironmentVariable for more details.
However the last one MSBuildExtensionsPath, could be setup by global properties as such :
globalProperties.Add("MSBuildExtensionsPath", msbuildRoot);
Update 28/02/2020:
Have found the Buildalyzer repository.
Doesn't seem to be able to do full build however maybe there are some workarounds to avoid messing with environment.

Compile Assembly on the fly

I have this code:
static void Main(string[] args)
{
CompilerParameters cp = new CompilerParameters
{
GenerateInMemory = true,
IncludeDebugInformation = false,
};
cp.ReferencedAssemblies.AddRange(new string[]{
"System.dll",
"System.Data.dll",
"System.Xml.dll",
"Microsoft.mshtml.dll",
"System.Windows.Forms.dll"
});
Assembly _assembly = Assembly.GetExecutingAssembly();
StreamReader _textStreamReader = new StreamReader(_assembly.GetManifestResourceStream("myprog.restext.txt"));
string src = _textStreamReader.ReadToEnd();
byte[] code = Convert.FromBase64String(src);
src = Encoding.UTF8.GetString(code);
CompilerResults cr = CSharpCodeProvider.CreateProvider("CSharp").
CompileAssemblyFromSource(cp, src);
Assembly asm = cr.CompiledAssembly;
Type typ = asm.GetType("clicker.Program");
MethodInfo method = typ.GetMethod("DoStart");
method.Invoke(null, new[] { (object)args });
}
I thows FileNotFoundException becouse CompileAssemblyFromSource returns the same error. Source using mshtml.
Then I'm trying to compile it using csc.exe, it says:
error CS0006. (no Metadata for "Microsoft.mshtml.dll")
I think it because mshtml is ActiveX library. So The question is how to assemble source usings activeX mshtml.
p.s.
Source has no errors and successfully has compiled from VS but can't be compiled by "on the fly" compilation.
I thows FileNotFoundException
That's normal, Microsoft.mshtml.dll is a primary interop assembly. It is not part of the .NET Framework so cannot be located automatically. It also won't be available on the user's machine, PIAs have to be installed.
The best way to go about it is to ensure that the assembly is present in your build directory so it will be deployed along with your program and can always be found. Project + Add Reference, select Microsoft.mshtml. Select it from the References node and set the Isolated property to False, Copy Local to True. Rebuild and verify that you now have Microsoft.mshtml.dll present in your bin\Debug directory.
And modify your code to pass the full path name to the file. Like this:
var referenceAssemblies = new List<string> {
"System.dll",
"System.Data.dll",
"System.Xml.dll",
"System.Windows.Forms.dll"
};
var homedir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var mshtml = Path.Combine(homedir, "Microsoft.mshtml.dll");
referenceAssemblies.Add(mshtml);
cp.ReferencedAssemblies.AddRange(referenceAssemblies.ToArray());

Categories