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>
Related
I have a VS 2017 extension and have tried using my own custom Project Template, by adding it programmatically, but things aren't going so well.
In my endeavour to find the mistake, I would like to see whether it is my custom Project Template causing the problem or not. Therefore I want to programmatically add any other existing built-in VS project such as a ClassLibrary type project template.
It seems to be located here:
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\ProjectTemplates\CSharp\Windows\1033\
But there isn't a zip folder and I can't create one in that directory according to Windows.
I will be using something similar to the following code:
Solution2 soln = (Solution2)visualStudioInstance.Solution;
string templatePath = soln.GetProjectTemplate("ClassLibrary.zip", "CSharp");
soln.AddFromTemplate(templatePath, projPath, "MyProjectName", false);
Am I on the right track?
I've tried it and I got an exception, but perhaps it was just because the zip folder doesn't exist.
UPDATE
The exception I get is:
"Object reference not set to an instance of an object."
I get it in the last line of the following code, when I try to add a reference to calcEngineProject. calcEngineProject is null even though it enters the if-statement and should be assigned the value of projCS.Object as VSProject2.
The code is as follows:
templatePath = soln.GetProjectTemplate("ClassLibrary.zip", "CSharp");
soln.AddFromTemplate(templatePath, prjPath, "ClassLibrary1", false);
foreach (Project p in soln.Projects)
{
if (String.Compare(p.Name, "ClassLibrary1") == 0)
{
projCS = p;
break;
}
}
if (projCS != null)
{
calcEngineProject = projCS.Object as VSProject2;
}
calcEngineProject.References.Add(Path.Combine(Config.Engine.EngineBinPath, "Engines.Calculation.dll"));
Also, I saw that templatePath is this:
"C:\PROGRAM FILES (X86)\MICROSOFT VISUAL
STUDIO\2017\PROFESSIONAL\COMMON7\IDE\EXTENSIONS\EYXTAMKA.FB4\ProjectTemplates\CSharp\.NET
Standard\1033\ClassLibrary\ClassLibrary.vstemplate"
and not
\%USERPROFILE%\Documents\My Exported Templates\
as mentioned in Upgrading custom project template
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.
I created a new VSIX extension project in Visual Studio 2012, and wrote a MEF classifier (as a test) that should simply highlight all text in a .mylang file. Here are the relevant parts of my .NET 4.5 code:
internal static class MyLangLanguage
{
public const string ContentType = "mylang";
public const string FileExtension = ".mylang";
[Export(typeof(ClassificationTypeDefinition))]
[Name(ContentType)]
[BaseDefinition("code")]
internal static ContentTypeDefinition MyLangSyntaxContentTypeDefinition = null;
[Export]
[FileExtension(FileExtension)]
[ContentType(ContentType)]
internal static FileExtensionToContentTypeDefinition MyLangSyntaxFileExtensionDefinition = null;
}
[Export(typeof(IClassifierProvider))]
[ContentType(MyLangLanguage.ContentType)]
[Name("MyLangSyntaxProvider")]
internal sealed class MyLangSyntaxProvider : IClassifierProvider
{
[Import]
internal IClassificationTypeRegistryService ClassificationRegistry = null;
public IClassifier GetClassifier(ITextBuffer buffer)
{
return buffer.Properties.GetOrCreateSingletonProperty(() => new MyLangSyntax(ClassificationRegistry, buffer));
}
}
internal sealed class MyLangSyntax : IClassifier { }
Here is the full code.
These are the relevant parts from my source.extension.vsixmanifest file. Based on suggestions and similar files I found across the web, I added the dependency on MPF and the two assets.
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<!-- ... -->
<Dependencies>
<Dependency Id="Microsoft.Framework.NDP" DisplayName="Microsoft .NET Framework" d:Source="Manual" Version="4.5" />
<Dependency d:Source="Installed" Id="Microsoft.VisualStudio.MPF.11.0" DisplayName="Visual Studio MPF 11.0" Version="[11.0,12.0)" />
</Dependencies>
<Assets>
<Asset Type="Microsoft.VisualStudio.VsPackage" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%;PkgdefProjectOutputGroup|" />
<Asset Type="Microsoft.VisualStudio.MefComponent" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%|" />
</Assets>
</PackageManifest>
I also tried a version 1.0 manifest:
<?xml version="1.0" encoding="utf-8"?>
<Vsix Version="1.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2010">
<!-- ... -->
<References />
<Content>
<MefComponent>|%CurrentProject%|</MefComponent>
</Content>
</Vsix>
When I run it, it starts an experimental instance of Visual Studio 2012, and the Extensions and Updates window shows that my extension is active. However, it does not do anything when I load or create a .mylang file. Any exceptions I throw (as a test) from my extension are never thrown. Breakpoints are never hit, and get an exclamation mark with the following warning:
The breakpoint will not currently be hit. No symbols have been loaded for this document.
It feels as if my extension is never really loaded at all. My problem is similar to this problem and this problem, but I'm using Visual Studio 2012 which uses a new VSIX manifest format.
What I know:
I can find my DLL and VSIX file in the %localappdata%\Microsoft\VisualStudio\11.0Exp\Extensions\MyLang\VSIXProject1\1.0 folder, so I know they are copied.
Their timestamp corresponds to when I last built the project, so I know they are up-to-date.
Project Properties > Debug > Start external program: is already automatically set to C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\devenv.exe, and the Command line arguments were automatically set to /rootsuffix Exp.
The Visual Studio log (created with the /log option) has two entries related to my extension: Successfully loaded extension... and Extension is enabled....
My DLL does not appear on the Modules tab (list of all loaded DLLs) of the debugging Visual Studio, while some (not all) other extensions do appear.
It doesn't get loaded in Visual Studio 2012 or 2010 both on my laptop and my desktop PC.
What I've tried:
Set <IncludeAssemblyInVSIXContainer> to true in the .csproj file, per this suggestion, but it did not make any difference.
I can't add the line <MefComponent>|%CurrentProject%|</MefComponent> to the source.extension.vsixmanifest file as it uses a different format (2.0) than VSIX projects for previous versions of Visual Studio (1.0).
This suggestion (setting IncludeAssemblyInVSIXContainer and friends in my .csproj to true) but it does not make a difference. And my breakpoints are still showing the warning and not being hit.
Reset the VS Experimental instance using the Reset the Visual Studio 2012 Experimental Instance shortcut in the Start Menu, as per this suggestion. It didn't make a difference.
How can I at the very least be sure my VSIX MEF extension is loaded and works? And if possible, how can I make by breakpoint work and debug it?
Edit: The problem is you've improperly exported your ContentTypeDefinition as a ClassificationTypeDefinition. You should use the following instead:
[Export] // <-- don't specify the type here
[Name(ContentType)]
[BaseDefinition("code")]
internal static ContentTypeDefinition MyLangSyntaxContentTypeDefinition = null;
Here's my two guesses right now:
Try removing the following line from your vsixmanifest. I assume you do not have a class in your project that extends Package, in which case Visual Studio might be refusing to load your package due to the following Asset line (your extension does not actually provide this asset).
<Asset Type="Microsoft.VisualStudio.VsPackage" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%;PkgdefProjectOutputGroup|" />
If that fails, try replacing your current source.extension.vsixmanifest with one written to the old schema (version 1.0). I know this form still works in Visual Studio 2012 because all ~20 extensions I work on (with >10 public releases) use the old schema.
280Z28 solved the problem! For completeness, this is the full tried and tested code that will create a super simple VSIX Visual Studio MEF extension that colors all text in a .mylang file blue (or whatever the current keyword color is).
How to create a simple coloring MEF VSIX extension
Make sure you have the Visual Studio SDK installed. (VS2010 SP1 SDK, VS2012 SDK)
Create a new VSIX Project(From the template under Installed → Templates → Visual C# → Extensibility.)
Enter something in the Author field of the VSIX manifest editor, then save and close it.
Add references to the following libraries,version 10.0.0.0 for VS2010, or 11.0.0.0 for VS2012:
Microsoft.VisualStudio.CoreUtility.dll
Microsoft.VisualStudio.Language.StandardClassification.dll
Microsoft.VisualStudio.Text.Data.dll
Microsoft.VisualStudio.Text.Logic.dll
Microsoft.VisualStudio.Text.UI.dll
Microsoft.VisualStudio.Text.UI.Wpf.dll
Add a reference to the following library:
System.ComponentModel.Composition.dll version 4.0.0.0
Create and add a new code file MyLang.cs, and copy-and-paste the code below in it.
Edit source.extension.vsixmanifest as XML.
For Visual Studio 2010, add the following XML just before the closing tag </Vsix>, and save:
<Content>
<MefComponent>|%CurrentProject%|</MefComponent>
</Content>
(If there is already an empty <Content/>, remove it.)
For Visual Stuio 2012, add the following XML just before the closing tag </PackageManifest>, and save:
<Assets>
<Asset Type="Microsoft.VisualStudio.MefComponent" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%|" />
</Assets>
(If there is already an empty <Assets/>, remove it.)
Only for Visual Studio 2010:
Unload the VSIX project (right-click the project → Unload project).
Edit the .csproj project file (right-click the project → Edit MyProject.csproj).
Change the value at <IncludeAssemblyInVSIXContainer> to true.
Save and close the file.
Reload the VSIX project (right-click the project → Reload project).
Now build and run it. When you load a .mylang file, all text should be colored blue (or whatever the default keyword color is).
MyLang.cs
using Microsoft.VisualStudio.Language.StandardClassification;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Utilities;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
namespace VSIXProject1
{
internal static class MyLangLanguage
{
public const string ContentType = "mylang";
public const string FileExtension = ".mylang";
[Export]
[Name(ContentType)]
[BaseDefinition("code")]
internal static ContentTypeDefinition MyLangSyntaxContentTypeDefinition = null;
[Export]
[FileExtension(FileExtension)]
[ContentType(ContentType)]
internal static FileExtensionToContentTypeDefinition MyLangSyntaxFileExtensionDefinition = null;
}
[Export(typeof(IClassifierProvider))]
[ContentType(MyLangLanguage.ContentType)]
[Name("MyLangSyntaxProvider")]
internal sealed class MyLangSyntaxProvider : IClassifierProvider
{
[Import]
internal IClassificationTypeRegistryService ClassificationRegistry = null;
public IClassifier GetClassifier(ITextBuffer buffer)
{
return buffer.Properties.GetOrCreateSingletonProperty(() => new MyLangSyntax(ClassificationRegistry, buffer));
}
}
internal sealed class MyLangSyntax : IClassifier
{
private ITextBuffer buffer;
private IClassificationType identifierType;
private IClassificationType keywordType;
public event EventHandler<ClassificationChangedEventArgs> ClassificationChanged;
internal MyLangSyntax(IClassificationTypeRegistryService registry, ITextBuffer buffer)
{
this.identifierType = registry.GetClassificationType(PredefinedClassificationTypeNames.Identifier);
this.keywordType = registry.GetClassificationType(PredefinedClassificationTypeNames.Keyword);
this.buffer = buffer;
this.buffer.Changed += OnBufferChanged;
}
public IList<ClassificationSpan> GetClassificationSpans(SnapshotSpan snapshotSpan)
{
var classifications = new List<ClassificationSpan>();
string text = snapshotSpan.GetText();
var span = new SnapshotSpan(snapshotSpan.Snapshot, snapshotSpan.Start.Position, text.Length);
classifications.Add(new ClassificationSpan(span, keywordType));
return classifications;
}
private void OnBufferChanged(object sender, TextContentChangedEventArgs e)
{
foreach (var change in e.Changes)
ClassificationChanged(this, new ClassificationChangedEventArgs(new SnapshotSpan(e.After, change.NewSpan)));
}
}
}
Set <IncludeAssemblyInVSIXContainer> to true in the .csproj file, per
this suggestion.
I had exactly the same problem and this solved it. Do a full rebuild.
I have defined a Visual Studio template called classDB.cs. I would like the default name for the class to appear as [projectname]DB.cs, where [projectname] is the name of the current project (as entered in the Create Project dialog). Is there a way to achieve this? I tried setting the name of the class to $safeprojectname$DB.cs, but that didn't work.
UPDATE
I modified my project template but give's this error when it's generating the project
here's the template class
namespace $safeprojectname$.Models
{
public class $safeprojectname$DB : DbContext
{
}
}
I have been battling with a similar error to this for days, and I finally figured it out. Visual Studio escapes the $ in the .csproj file. So you will have a node that looks like this:
<Compile Include="Models\%24safeprojectname%24DB.cs" />
Open up the .csproj file in a text editor, and change it to:
<Compile Include="Models\$safeprojectname$DB.cs" />
And save the file. Your project will reload, but it won't try to escape the filename again! Export your template, and you should find that the parameter now gets replaced.
Try a template like this:
using System;
//...
namespace $rootnamespace$ {
class $safeitemname$DB {
}
}
Works for me.
Make sure you update the correct template (should be located under C:\Users\[user]\Documents\Visual Studio 2010\Templates\ItemTemplates on Windows 7) and restart Visual Studio.
EDIT
The above code is for an Item Template, but that shouldn't differ from a Project Template. According to MSDN, the $safeitemname$ and $safeprojectname$ parameters behaves the same:
safeitemname
The name provided by the user in the Add New Item dialog box, with all unsafe characters and spaces removed.
safeprojectname
The name provided by the user in the New Project dialog box, with all unsafe characters and spaces removed.
I would like two how to do to share Resources files between 2 (or more) projects?
So, to resume, I've three project :
the development project (CF.NET) that include the resource file (with all definition).
I've two other projects that are empty BUT linking to the development projects, it's just a different build each time, so when I modify the development project, all three projects are updated too. (Modification of the csproj file.)
Question is, what about Resources files? When I try to access from the development project I get all resources but when I try from the 2 others, it throws an "MissingManifestResourceException".
Any idea how to solve this issue?
Thanks.
[EDIT]
Here is what I've done :
Create a project named "RealProject" which contains all code (including resources files)
Create a project named "LinkedProject" which contains nothing (I deleted all files into it and modify the csproj file as the following :
<ItemGroup>
<Compile Include="..\RealProject\**\*.cs" />
</ItemGroup>
So in LinkedProject directory I've only :
[Directory] bin
[Directory] obj
[File ] LinkedProject.csproj
The whole LinkedProject uses the RealProject files, it's just a different configuration build (see here to know why : C# - Code compiler for .NET & CF.NET )
Once in that configuration, I've no access to the resources files from the RealProject ...
If you need screens or more detailed explanation, just ask.
[EDIT]
With this code, it works, Resource manager isn't loaded on the good Assembly name, but it should exists a better solution !!!
Assembly ass = Assembly.ReflectionOnlyLoadFrom(#"..\..\..\RealProject\bin\Debug\RealProject.dll");
ResourceManager manager = new ResourceManager("RealProject.Properties.Resources", ass);
[Solution]
Things to check :
The LinkedProject as the same
namespace as the RealProject
Add Resources as links
Clean up all your solution
Rebuild it
Test !
Try to add the resource file as a link to the other two projects and make sure the namespaces as defined in the project file is the same.
Try adding existing file in other projects as a link.
The problem with sharing resources files between different projects is that the root namespace has to be the same in all the projects you use the same file in.
Or not.
You can get the root namespace at runtime in the *Resources.designer.cs file. Note the links in the comments to related answers. Make sure you commit this and keep an eye on it, the code-generator has a habit of overwriting it which would break its universality. I used the xml doc comments to remind me what's going on, if the code-gen obliterates it I'll see it in the commit diff.
/// <summary> Returns the cached ResourceManager instance used by this class. </summary>
/// <remarks> DO NOT commit any version of this file the tool overwrites, it will break it for other projects</remarks>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null))
{
// https://stackoverflow.com/a/1329631/492 https://stackoverflow.com/a/51978052/492
Assembly thisAssembly = typeof(/*thisClassName*/).Assembly;
// you need a class called "App", or just change the name on the next line to one you have in the root namespace
var apps = thisAssembly?.GetTypes().Where(t => t.Name == "App");
if (apps.Count() != 1)
throw new InvalidOperationException($"Too Many App classes. Count: {apps.Count()}, Apps: {apps}");
Type appType = apps.FirstOrDefault();
string ns = appType.Namespace;
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager($"{ns}.OtherNames.Spaces.thisClassName", typeof(thisClassName).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}