Embedded resource in .Net Core libraries - c#

I just have started looking into .Net Core, and I don't see classical resources and anything what looks like resources. In classical .Net class libraries I was able to add, for example, text filtes with some script to my project, than I can add these files to project's resources. After that I could easily use that by the following way:
Connection.Execure(Properties.Resources.MySuperScript);
I see that there isn't such feature in .Net Core libraries, at least I don't see.
Is there an alternative in .Net Core to store some statical data as an embedded resource in libraries? And how to use that if it exists?

UPDATE:
.NET Core 1.1 and later have dropped project.json and returned to .csproj files.
This changes Step 2, but not all that much. The necessary lines are very similar:
<ItemGroup>
<Content Remove="_fonts/OpenSans.ttf" />
<Content Remove="_fonts/OpenSans-Bold.ttf" />
<Content Remove="_fonts/OpenSans-Italic.ttf" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="_fonts/OpenSans.ttf" />
<EmbeddedResource Include="_fonts/OpenSans-Bold.ttf" />
<EmbeddedResource Include="_fonts/OpenSans-Italic.ttf" />
</ItemGroup>
There may be a similar *.tff form; unconfirmed.
Steps 1 and 3 are unchanged.
To use embedded resources in .NET Core 1.0 project do the following:
Add your embedded file(s) as usual.
Example: some FONT files on a directory named "_fonts"
Modify "project.json" to include the related resources.
In my case:
"buildOptions": {
"embed": {
"include": [
"_fonts/*.ttf"
]
}
},
Access the embedded resource in code.
var assembly = typeof(MyLibrary.MyClass).GetTypeInfo().Assembly;
Stream resource = assembly.GetManifestResourceStream("MyLibrary._fonts.OpenSans.ttf");
The key point is to use the right name on GetManifestResourceStream call. You have to use [assembly name].[directory].[file name].

Now that project.json is deprecated, you have to specify this in the .csproj file.
<ItemGroup>
<EmbeddedResource Include="_fonts\*.ttf" />
</ItemGroup>
You can use a wildcard as shown, or just list out the files explicitly.

With newer versions of .Net Core - 2.0 or greater - there's a specialized class EmbeddedFileProvider that abstract the embedded file reading. To use it, add Microsoft.Extensions.FileProviders.Embedded package to your application:
dotnet add package Microsoft.Extensions.FileProviders.Embedded
The EmbeddedFileProvider allows you to create a stream reader, and use according to your scenario:
var embeddedProvider = new EmbeddedFileProvider(Assembly.GetExecutingAssembly());
using (var reader = embeddedProvider.GetFileInfo("yourfile.ext").CreateReadStream())
{
// some logic with stream reader
}

People have already generally answered this, so this is a rendering of the answers into something simple.
Before using the following, the file should be added as an embedded resource to the .csproj / project.json
Usage
var myJsonFile = ReadManifestData<Tests>("myJsonFile.json");
Parameter: embedded filename name; Type: any class from the target resource's assembly
looks for an embedded resource with that name
returns the string value
Method
public static string ReadManifestData<TSource>(string embeddedFileName) where TSource : class
{
var assembly = typeof(TSource).GetTypeInfo().Assembly;
var resourceName = assembly.GetManifestResourceNames().First(s => s.EndsWith(embeddedFileName,StringComparison.CurrentCultureIgnoreCase));
using (var stream = assembly.GetManifestResourceStream(resourceName))
{
if (stream == null)
{
throw new InvalidOperationException("Could not load manifest resource stream.");
}
using (var reader = new StreamReader(stream))
{
return reader.ReadToEnd();
}
}
}

I have not confirmed this in documentation, but for me, it would appear the auto-generated Resource code that retrieves embedded files found in Resource.Designer.cs is now functioning again in .NET Core 3.1. I can now retrieve an embedded jpg simply by calling the Properties.Resources.MyImageName which returns a Bitmap object.

Related

How to get a file's content of UNO shared project as string

In regular C#/UWP it is possible without any (bigger) problems to read a file's (or resource's) content to a string variable. How is this done with the UNO platform's WebAssembly build target?
What I already tried: According to the browser's debugging console, my code execution stops (without any exception thrown) as soon as I try to use reflection, for example. Before digging deeper in the JavaScript jungle, I decided to ask the specialists here.
(As a last workaround, I thought about using the HTTP client implementation, but I will do this only if there really is no usable alternative.)
The WebAssembly target for Uno does not support reading content files for now as part of the System.IO.File api (and probably won't in the near future because of its synchronous API).
The easiest way, which works cross platforms, is to use embedded resources:
<ItemGroup>
<EmbeddedResource Include="myfile.txt" />
</ItemGroup>
Then in the code, use something like this:
static string ReadResource(string fileName)
{
var assembly = typeof(Program).Assembly;
var resourceName = assembly.GetManifestResourceNames()
.FirstOrDefault(f => f.Contains(fileName));
if (!string.IsNullOrEmpty(resourceName))
{
using (var s = new StreamReader(assembly .GetManifestResourceStream(resourceName)))
{
return s.ReadToEnd();
}
}
else
{
throw new InvalidOperationException(
$"Unable to find resource {fileName} in {typeof(Program).Assembly}");
}
}

How to read/get a PropertyGroup value from a .csproj file using C# in a .NET Core 2 classlib project?

I want to get the value of the element <Location>SourceFiles/ConnectionStrings.json</Location> that is child of <PropertyGroup /> using C#. This is located at the .csproj file for a .NET Core 2 classlib project. The structure is as follow:
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<Location>SharedSettingsProvider.SourceFiles/ConnectionStrings.json</Location>
</PropertyGroup>
Which class can I use from .NET Core libraries to achieve this? (not .NET framework)
Update 1:
I want to read the value when the application (that this .csproj file builds) runs. Both before and after deployment.
Thanks
As has been discussed in comments, csproj content only controls predefined build tasks and aren't available at run-time.
But msbuild is flexible and other methods could be used to persist some values to be available at run time.
One possible approach is to create a custom assembly attribute:
[System.AttributeUsage(System.AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)]
sealed class ConfigurationLocationAttribute : System.Attribute
{
public string ConfigurationLocation { get; }
public ConfigurationLocationAttribute(string configurationLocation)
{
this.ConfigurationLocation = configurationLocation;
}
}
which can then be used in the auto-generated assembly attributes from inside the csproj file:
<PropertyGroup>
<ConfigurationLocation>https://my-config.service/customer2.json</ConfigurationLocation>
</PropertyGroup>
<ItemGroup>
<AssemblyAttribute Include="An.Example.ConfigurationLocationAttribute">
<_Parameter1>"$(ConfigurationLocation)"</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
And then used at run time in code:
static void Main(string[] args)
{
var configurationLocation = Assembly.GetEntryAssembly()
.GetCustomAttribute<ConfigurationLocationAttribute>()
.ConfigurationLocation;
Console.WriteLine($"Should get config from {configurationLocation}");
}

asp.net core with resource file (resx)

I have a project in ASP.Net Core that need to include a image from a resource file (to generate a PDF).
So, I create a new resource file using Visual Studio (Add > New Item > Resources File), named Resource.resx
Using the Managed Resource Editor (default editor of Visual Studio), I included a new image named logo.png.
A new file named Resource.Designer.cs was created with a method listed below:
public static System.Drawing.Bitmap logo {
get {
object obj = ResourceManager.GetObject("logo", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
Now, only to test, I created the following code:
var logo = Resources.logo;
This threw a new exception, with the following content:
An unhandled exception of type 'System.InvalidCastException' occurred.
Additional Information: Unable to cast object of type 'System.String' to type 'System.Drawing.Bitmap'.
I tried all from this link too:
https://weblogs.asp.net/jeff/beating-localization-into-submission-on-asp-net-5
but the results are the same.
If I make this code on a console application, everything works correctly.
I found another approach that worked good for my problem.
http://codeopinion.com/asp-net-core-embedded-resource/
Just need to create a folder on project (Resources in my case), and then, in project.json, I included the following code:
"buildOptions": {
"embed": ["Resources/**/*"]
}
and then, my code:
var assembly = Assembly.GetExecutingAssembly();
var logoStream = assembly.GetManifestResourceStream("ProjectNamespace.Resources.logo.png");
If you are using .net core 3.1 api, you may-
Add services.AddLocalization(); in ConfigureServices method (Startup.cs)
Add Resource file in the project say Resource.en-US.resx, add TestKey in Name and Hello in Value column for testing purpose.
Add a class file in the same hierarchy with name as Resource.cs
In controller, add a variable-
private readonly IStringLocalizer _localizer;
and inject it in constructor-
public TestController(IStringLocalizer<Resource> localizer)
{
_localizer = localizer;
}
Read the value of resource names as-
_localizer["TestKey"] and you will get Hello (i.e. entered in step#2)
More details at- [https://www.syncfusion.com/blogs/post/how-to-use-localization-in-an-asp-net-core-web-api.aspx]
I'm using Visual Studio 2017 (csproj files) and this solution worked for me:
https://stackoverflow.com/a/39368856/812610
Open Solution Explorer add files you want to embed. Right click on the files then click on Properties. In Properties window and change Build Action to Embedded Resource.
The embedded resource's name is "[DefaultNamespace].[Folder].filename". I saved a cert (cert.pfx) to "Resources" folder so for me it's "MyProjectName.Resources.cert.pfx"
And this was added to my .csproj:
<ItemGroup>
<None Remove="Resources\testcert.pfx" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\testcert.pfx" />
</ItemGroup>

MSBuild custom task depending on another project

I have an odd solution where I need one of the projects to "compile" files in another one.
The compiler (showing here a minimal example) is as follows (MSBuild custom task):
public class MyCompileTask : Task
{
[Required]
public ITaskItem[] InputFiles { get; set; }
[Output]
public ITaskItem[] OutputFiles { get; set; }
public override bool Execute()
{
var generatedFileNames = new List<string>();
foreach (var inputFile in this.InputFiles)
{
var inputFileName = inputFile.ItemSpec;
var outputFileName = Path.ChangeExtension(inputFileName, ".res.txt");
var source = File.ReadAllText(inputFileName);
var compiled = source.ToUpper();
File.WriteAllText(outputFileName, compiled + "\n\n" + DateTime.Now);
generatedFileNames.Add(outputFileName);
}
this.OutputFiles = generatedFileNames.Select(name => new TaskItem(name)).ToArray();
return true;
}
}
As you see, it only uppercases the content of the input files.
This was project A - the "compiler" library.
Project B, for now the main application, has a file "lorem.txt" that needs to be "compiled" into "lorem.res.txt" and put as an EmbeddedResource in B.exe/B.dll.
In B.csproj I added the following:
<PropertyGroup>
<CoreCompileDependsOn>$(CoreCompileDependsOn);InvokeMyCompile</CoreCompileDependsOn>
</PropertyGroup>
<UsingTask TaskName="MyCompiler.MyCompileTask" AssemblyFile="$(MSBuildProjectDirectory)\..\MyCompiler\bin\$(Configuration)\MyCompiler.dll" />
<Target Name="MyCompile" Inputs="lorem.txt" Outputs="lorem.res.txt">
<MyCompileTask InputFiles="lorem.txt">
<Output TaskParameter="OutputFiles" PropertyName="OutputFiles" />
</MyCompileTask>
</Target>
<Target Name="InvokeMyCompile" Inputs="lorem.txt" Outputs="lorem.res.txt">
<Exec Command=""$(MSBuildBinPath)\MSBuild.exe" /t:MyCompile "$(ProjectDir)$(ProjectFileName)"" />
</Target>
(The 2 layers of targets and an explicit msbuild.exe invocation is a workaround to another problem. In fact, much of this example is stolen from that Q.)
The most important part works, i.e. when I change lorem.txt and build, lorem.res.txt gets regenerated.
However:
When lorem.res.txt is physically deleted, a build does nothing (says it's up-to-date) until I actually refresh the project in VS. So, MSBuild does not "know" that lorem.res.txt is actually required to build the project.
More importantly, when I change anything in project A, project B recompiles but does not re-run the compilation lorem.txt -> lorem.res.txt. So MSBuild does not "know" that the transformation is dependent on another project.
How can I declare these dependencies in the csproj file?
Bonus question: how to mark the output file (lorem.res.txt) as a generated EmbeddedResource so I don't have to track it in VS but it's still put into the assembly?
•When lorem.res.txt is physically deleted, a build does nothing (says it's up-to-date) until I actually refresh the project in VS. So, MSBuild does not "know" that lorem.res.txt is actually required to build the project.
I create a demo and reproduce your issue on my side, you could use msbuild command line to avoid it.
•More importantly, when I change anything in project A, project B recompiles but does not re-run the compilation lorem.txt -> lorem.res.txt. So MSBuild does not "know" that the transformation is dependent on another project.
Because the custom task reference the DLL file, when change anything in project A, you need to rebuild project to generate newer DLL file.
Bonus question: how to mark the output file (lorem.res.txt) as a generated EmbeddedResource so I don't have to track it in VS but it's still put into the assembly?
You can add custom ItemGroup in BeforeBuild target to achieve it.
<Target Name="BeforeBuild" DependsOnTargets="MyCompile">
<ItemGroup>
<Content Include="lorem.res.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Target>

How create ProjectExtensions tag with MSBuild for generating .csproj?

From the MS Developer website:
Allows MSBuild project files to contain non-MSBuild information.
Anything inside of a ProjectExtensions element will be ignored by
MSBuild.
See this example :
<ProjectExtensions>
<VisualStudio>
<UserProperties RESOURCE_FILE="projectName.RC" />
</VisualStudio>
</ProjectExtensions>
I want to create something like above
for creating .csproj file programmatically, I use
Namespace: Microsoft.Build.Construction
Assembly: Microsoft.Build (in Microsoft.Build.dll)
for example :
var root = ProjectRootElement.Create();
var group = root.AddPropertyGroup();
group.AddProperty("Configuration", "Debug");
group.AddProperty("Platform", "x64");
// references
AddItems(root, "Reference", "System", "System.Core");
// items to compile
AddItems(root, "Compile", "test.cs");
var target = root.AddTarget("Build");
var task = target.AddTask("Csc");
task.SetParameter("Sources", "#(Compile)");
task.SetParameter("OutputAssembly", "test.dll");
root.Save("test.csproj");
I want to know, How can I use these classes and namespace for creating ProjectExtensions tag
I saw a method with name CreateProjectExtension() but I dont know how use it.
please guide me How create any ProjectExtensions tag

Categories