using code like
using OfficeOpenXml; // namespace for the ExcelPackage assembly
…
FileInfo newFile = new FileInfo(#"C:\mynewfile.xlsx");
using (ExcelPackage xlPackage = new ExcelPackage(newFile)) { … }
I get an exception error of
'IBM437' is not a supported encoding name. For information on defining
a custom encoding, see the documentation for the
Encoding.RegisterProvider method. Parameter name: name
Any ideas as to what the problem could be?
Thanks
Martin
if your project is .net core edit your project file then add
<ItemGroup>
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.3.0" />
</ItemGroup>
and in your startup.cs
add
System.Text.Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
The problem is in the ZIP file reader (ZipInputStream). You need to add the encodings like windows-1252 manually:
dotnet add package System.Text.Encoding.CodePages
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
More info here: .NET Core doesn't know about Windows 1252, how to fix?
Related
I have an issue I can't solve, I have a library with this definition
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0;net6.0;net7.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" />
</ItemGroup>
</Project>
And after a http call with HttpClient I try to do this :
await using var stream = await response.Content.ReadAsStreamAsync();
Which produce this error :
[CS8417] 'Stream': type used in an asynchronous using statement must be implicitly convertible to 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'?
The issue is clearly with NETSANDARD2_0, if I remove it, it works well.
I don't understand why it fails, as I have added the Microsoft.Bcl.AsyncInterfaces.
The problem is that in .NET Standard 2.0, Stream doesn't implement IAsyncDisposable.
It's entirely feasible to use await using within a .NET Standard 2.0 project if you're using types that actually implement IAsyncDisposable - although you also need to specify a LangVersion in the project file, as otherwise the default version of C# is used, which is 7.3 for .NET Standard 2.0. For example:
using System;
using System.IO;
using System.Threading.Tasks;
class Test
{
static async void TestAwaitUsing()
{
// This is fine
await using var working = new Sample();
// This fails, because MemoryStream doesn't implement IAsyncDisposable
await using var failing = new MemoryStream();
}
class Sample : IAsyncDisposable
{
public ValueTask DisposeAsync()
{
throw new NotImplementedException();
}
}
}
Project file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" />
</ItemGroup>
</Project>
Now it's entirely possible that in whatever platform the code is running on, Stream does actually implement IAsyncDisposable - but it's hard to make use of that in an elegant way.
For example, this compiles and will do the right thing if the application platform supports it:
await using var awkward = (IAsyncDisposable) new MemoryStream();
var stream = (MemoryStream) awkward;
// Now use things from stream
This will throw InvalidCastException if you're running on a platform which doesn't support it, however. If you can possibly change your target to .NET Standard 2.1 or a more recent one (e.g. .NET 6) that would be better. If you actually need to run your code with .NET Framework, you just won't be able to use await using with Stream.
await using has been added in C# 8. The default C# version for netstandard2.0 is C# 7.3. In netstandard2.1 it is C# 8.
I am testing a code targeting .NET standard 2.0, in Visual Studio 2022. The code depends on Polly and Microsoft.Extensions.Http.Polly. The program fails to start with error message :
Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'Polly, Version=7.0.0.0, Culture=neutral, PublicKeyToken=c8a3ffc3f8f825cc' or one of its dependencies. The system cannot find the file specified.
I found that the error occurred because the build project process does not copy the Polly.dll to folder NetRetry\bin\Debug\netstandard2.0. But why are these assemblies not copied to output folder? I can find these assemblies in .nuget\packages folder.
To reproduce this error
Program.cs
using Microsoft.Extensions.Http;
using Polly;
using System;
using System.Net.Http;
using System.Threading;
class Program
{
static void Main(string[] args)
{
var h = Policy
.HandleResult<HttpResponseMessage>(r => r.StatusCode != System.Net.HttpStatusCode.OK)
.Or<Exception>()
.RetryAsync(3, (r, count) =>
{
Console.WriteLine($"Log retry {count}");
r.Result.Dispose();
});
var handler = new PolicyHttpMessageHandler(h);
handler.InnerHandler = new HttpClientHandler();
HttpClient c = new HttpClient(handler);
var result = c.GetAsync("https://www.google.com/non-existing", CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult();
}
}
NetRetry.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<AutoGenerateBindingRedirects>True</AutoGenerateBindingRedirects>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="6.0.3" />
<PackageReference Include="Polly" Version="7.2.3" />
</ItemGroup>
</Project>
I tried retargeting project to .NET 5.0 and build the project. This time the assemblies are all copied to folder NetRetry\bin\Debug\net5.0, and the program runs normally.
Manually enable CopyLocalLockFileAssemblies will solve this.
Add to PropertyGroup
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
I am using the following code to dynamically load a Razor Class Library into my ASP.NET Core 3.0 app:
var pluginAssembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(file.FullName);
var partFactory = ApplicationPartFactory.GetApplicationPartFactory(pluginAssembly);
foreach (var part in partFactory.GetApplicationParts(pluginAssembly))
MvcBuilder.PartManager.ApplicationParts.Add(part);
var relatedAssemblies = RelatedAssemblyAttribute.GetRelatedAssemblies(pluginAssembly, throwOnError: true);
foreach (var assembly in relatedAssemblies)
{
partFactory = ApplicationPartFactory.GetApplicationPartFactory(assembly);
foreach (var part in partFactory.GetApplicationParts(assembly))
MvcBuilder.PartManager.ApplicationParts.Add(part);
}
This works fine and controllers and views are initially working. But if I also add the Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation package and the following to the Startup.cs:
services.Configure<MvcRazorRuntimeCompilationOptions>(options =>
{
options.FileProviders.Add(new PhysicalFileProvider(Path.Combine(WebHostEnvironment.ContentRootPath, "..\\AppPlugin")));
});
I get the following exception as soon as I edit a *.cshtml-file:
InvalidOperationException: Cannot find compilation library location
for package 'AppPlugin'
Microsoft.Extensions.DependencyModel.CompilationLibrary.ResolveReferencePaths(ICompilationAssemblyResolver
resolver, List assemblies)
Microsoft.Extensions.DependencyModel.CompilationLibrary.ResolveReferencePaths()
Microsoft.AspNetCore.Mvc.ApplicationParts.AssemblyPartExtensions+<>c.b__0_0(CompilationLibrary
library)
System.Linq.Enumerable+SelectManySingleSelectorIterator.MoveNext()
System.Collections.Generic.List.InsertRange(int index, IEnumerable collection)
Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation.RazorReferenceManager.GetReferencePaths()
Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation.RazorReferenceManager.GetCompilationReferences()
Is there something else I need to load to get this to work?
If I omit the plugin-path from the FileProviders runtime-compilation works for "non-plugin-views".
I was able to get this working by using the following project settings for the razor class library. The key piece was to set PreserveCompilationContext to false.
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
<PreserveCompilationContext>false</PreserveCompilationContext>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
</Project>
In Addition to this, you'll have to add a reference to your main plugin assembly and any additional assemblies used in your views.
services.Configure<MvcRazorRuntimeCompilationOptions>(options =>
{
options.FileProviders.Add(new PhysicalFileProvider(Path.Combine(WebHostEnvironment.ContentRootPath, "..\\AppPlugin")));
opts.AdditionalReferencePaths.Add(pluginAssembly.Location);
});
Issue
In .net6 when you use both:
Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation
Microsoft.VisualStudio.Web.CodeGeneration.Design
you have the error message:
Cannot find compilation library location for package 'Microsoft.Build'`
Solution
Uninstall Microsoft.VisualStudio.Web.CodeGeneration.Design package and you'll be able to use razor runtime compile.
If you are still missing references after defining razor runtime compilation as described in other answers and missing types are located in namespaces referenced as global using e.g. global using MyNamespace.Extensions; try to explicitly add your namespaces to _ViewImports.cshtml or directly into view with #using MyNamespace.Extensions
I am currently building a tool which will support the development of an ASP.NET Core project. This tool uses the Roslyn APIs and other methods for verifying some development requirements (such as project-specific attributes being applied on API Controllers, enforcing naming conventions, and generating some source code for the JavaScript SPA which accesses an API written using the ASP.NET Core Web API template).
In order to do that, I am currently using hardcoded paths to generate code for the SPA app. But in the app's *.csproj file there is actually a "SpaRoot" property specifying where the SPA application is located inside the project:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
<IsPackable>false</IsPackable>
<SpaRoot>ClientApp\</SpaRoot>
...
</PropertyGroup>
...
</Project>
My question is: how can I read the "SpaRoot" property's value using the Roslyn APIs?
I have written a minimum code sample to create a Workspace, open the Solution, and retrieve the Project's reference, which resembles the following:
static async Task Main(string[] args)
{
string solutionFile = #"C:\Test\my-solution.sln";
using (var workspace = MSBuildWorkspace.Create())
{
var solution = await workspace.OpenSolutionAsync(solutionFile);
string projectName = "some-project";
var project = solution.Projects.Single(p => p.Name == projectName);
// How to extract the value of "SpaRoot" from the Project here?
}
I've tried searching on how to extract the "SpaRoot" property from the Project reference, and even went as far as debugging to see if I could spot a way myself. Unfortunately, I came up with no answers to that, and I'm still using hardcoded paths in my original code.
Is it even possible to retrieve the value of .csproj properties of a Project using the current Roslyn APIs?
This is more difficult that you would think :) The Roslyn apis only know what the compiler knows and the compiler is not going to be given anything regarding the SpaRoot property. We can use the MSBuild apis to figure this out though. specifically the Microsoft.Build.Evaluation.Project class.
Some assumptions I am making
You only want to examine .NET Core projects
You will have the .NET Core SDK installed on which ever system runs this tool
So first we want a project file that looks like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<!--NOTE: If the project you are analyzing is .NET Core then the commandline tool must be as well.
.NET Framework console apps cannot load .NET Core MSBuild assemblies which is required
for what we want to do.-->
<TargetFramework>netcoreapp3.1</TargetFramework>
<LangVersion>Latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<!-- NOTE: We put ExcludeAssets="runtime" on all direct MSBuild references so that we pick up whatever
version is being used by the .NET SDK instead. This is accomplished with the Microsoft.Build.Locator
referenced further below. -->
<PackageReference Include="Microsoft.Build" Version="16.4.0" ExcludeAssets="runtime" />
<PackageReference Include="Microsoft.Build.Locator" Version="1.2.6" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="2.9.8" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.4.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.Workspaces" Version="3.4.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="3.4.0" />
<!-- NOTE: A lot of MSBuild tasks that we are going to load in order to analyze a project file will implicitly
load build tasks that will require Newtonsoft.Json version 9. Since there is no way for us to ambiently
pick these dependencies up like with MSBuild assemblies we explicitly reference it here. -->
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
</ItemGroup>
</Project>
and a Program.cs file that looks like this:
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml;
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Locator;
using Microsoft.CodeAnalysis.MSBuild;
// I use this so I don't get confused with the Roslyn Project type
using MSBuildProject = Microsoft.Build.Evaluation.Project;
namespace loadProject {
class Program {
static async Task Main(string[] args) {
MSBuildWorkspaceSetup();
// NOTE: we need to make sure we call MSBuildLocator.RegisterInstance
// before we ask the CLR to load any MSBuild types. Therefore we moved
// the code that uses MSBuild types to its own method (instead of being in
// Main) so the CLR is not forced to load them on startup.
await DoAnalysisAsync(args[0]);
}
private static async Task DoAnalysisAsync(string solutionPath) {
using var workspace = MSBuildWorkspace.Create();
// Print message for WorkspaceFailed event to help diagnosing project load failures.
workspace.WorkspaceFailed += (o, e) => Console.WriteLine(e.Diagnostic.Message);
Console.WriteLine($"Loading solution '{solutionPath}'");
// Attach progress reporter so we print projects as they are loaded.
var solution = await workspace.OpenSolutionAsync(solutionPath, new ConsoleProgressReporter());
Console.WriteLine($"Finished loading solution '{solutionPath}'");
// We just select the first project as a demo
// you will want to use your own logic here
var project = solution.Projects.First();
// Now we use the MSBuild apis to load and evaluate our project file
using var xmlReader = XmlReader.Create(File.OpenRead(project.FilePath));
ProjectRootElement root = ProjectRootElement.Create(xmlReader, new ProjectCollection(), preserveFormatting: true);
MSBuildProject msbuildProject = new MSBuildProject(root);
// We can now ask any question about the properties or items in our project file
// and get the correct answer
string spaRootValue = msbuildProject.GetPropertyValue("SpaRoot");
}
private static void MSBuildWorkspaceSetup() {
// Attempt to set the version of MSBuild.
var visualStudioInstances = MSBuildLocator.QueryVisualStudioInstances().ToArray();
var instance = visualStudioInstances.Length == 1
// If there is only one instance of MSBuild on this machine, set that as the one to use.
? visualStudioInstances[0]
// Handle selecting the version of MSBuild you want to use.
: SelectVisualStudioInstance(visualStudioInstances);
Console.WriteLine($"Using MSBuild at '{instance.MSBuildPath}' to load projects.");
// NOTE: Be sure to register an instance with the MSBuildLocator
// before calling MSBuildWorkspace.Create()
// otherwise, MSBuildWorkspace won't MEF compose.
MSBuildLocator.RegisterInstance(instance);
}
private static VisualStudioInstance SelectVisualStudioInstance(VisualStudioInstance[] visualStudioInstances) {
Console.WriteLine("Multiple installs of MSBuild detected please select one:");
for (int i = 0; i < visualStudioInstances.Length; i++) {
Console.WriteLine($"Instance {i + 1}");
Console.WriteLine($" Name: {visualStudioInstances[i].Name}");
Console.WriteLine($" Version: {visualStudioInstances[i].Version}");
Console.WriteLine($" MSBuild Path: {visualStudioInstances[i].MSBuildPath}");
}
while (true) {
var userResponse = Console.ReadLine();
if (int.TryParse(userResponse, out int instanceNumber) &&
instanceNumber > 0 &&
instanceNumber <= visualStudioInstances.Length) {
return visualStudioInstances[instanceNumber - 1];
}
Console.WriteLine("Input not accepted, try again.");
}
}
private class ConsoleProgressReporter : IProgress<ProjectLoadProgress> {
public void Report(ProjectLoadProgress loadProgress) {
var projectDisplay = Path.GetFileName(loadProgress.FilePath);
if (loadProgress.TargetFramework != null) {
projectDisplay += $" ({loadProgress.TargetFramework})";
}
Console.WriteLine($"{loadProgress.Operation,-15} {loadProgress.ElapsedTime,-15:m\\:ss\\.fffffff} {projectDisplay}");
}
}
}
}
I have a working Mongo and .Net Core app, but still need to access the mongo DB through C#. I am just testing this by trying to make the connection in the program.cs file. At the top I have:
using MongoDB.Driver;
using MongoDB.Driver.Core;
using MongoDB.Bson;
When I run:
var mongo = new MongoClient("mongodb://localhost:27017");
var db = mongo.GetDatabase("cvpz");
mongo.getCollection("people");
I get this error:
Program.cs(16,19): error CS1061: 'MongoClient' does not contain a definition for 'getCollection' and no extension method 'getCollection' accepting a first argument of type 'MongoClient' could be found (are you missing a using directive or an assembly reference?) [/src/src/Identity.api/Identity.api.csproj]
Now, I can access the DB through the commandline through 'mongo localhost/cvpz'. Btw, I am using Ubuntu to run .Net Core.
When I run createCollection() I get a similar error. How do I use C# to interact with Mongo?
One last thing, I should have all the necessary packages, I have these in my .csproj:
<PackageReference Include="MongoDB.Driver" Version="2.3.0" />
<PackageReference Include="MongoDB.Driver.Core" Version="2.3.0" />
<PackageReference Include="MongoDB.Bson" Version="2.3.0" />
Thanks so much guys!
Two things. 'GetCollection' should have an uppercase G. It also requires a generic parameter indicating the document type being stored. For you example:
var mongo = new MongoClient("mongodb://localhost:27017");
var db = mongo.GetDatabase("cvpz");
var coll = mongo.GetCollection<People>("people");
Reference: IMongoDatabase.GetCollection