Manage Localized Resources Via Visual Studio In A Plugin Library Project - c#

I am trying to end up being able to include satellite resources with a "Plugin" component, developed in C# and distributed as a DLL. It runs in a "Host" platform, and there are certain restrictions on how I can build and distribute.
I am using Visual Studio, and would like to figure out how to leverage the standard localization features: component-specific resources for my Forms, and other plugin-wide resources. Please bear with some explanation:
The Visual Studio aspect is set up this way: the platform delivers a VS project that is the host project for all of its Plugins. I develop my Plugin by using this project in VS. The Host also has an embedded code editor and other development tools. The Plugin C# code resides in a Host source folder.
Distributing the Plugin requires a compilation from the Host; and then using Host tools to export my plugin files as a DLL. The host compiles the Plugin source against all other default Plugins, then does code obfuscation, and generates stub files for execution, and also manifest-type files. This is all bundled into a Zip file and that's the distribution assembly for the Plugin. When the user installs the Plugin, this is all actually unZipped into the user's Host folder.
I am trying to use Localization features: I cannot simply localize my forms in VS, since the resources are embedded into the VS build output, which is not bundled with the Host Plugin; and is not accessible for me to include at distribution. Also, the Host does not allow me to select the resx files when it does my build for distribution (that might have solved it; but the "Export Plugin" dialog in the Host only allows selecting the C# files that you want to bundle into a distributable Plugin).
I am aware of the ability to bundle resources into a DLL; and I believe that would be my preferred solution if it is possible; and then perhaps I could use the IDE features, then select all my resource files and generate a satellite assembly with the resources. But I cannot figure out how to reference the resources. This would result in satellite resource DLLs placed alongside the MyPlugin.dll (or in culture subfolders) as pictured above. The Host platform allows including dependent DLLs with your Plugin; and they would be unpacked alongside the MyPlugin.dll as pictured.
I have tried simply running AL, and generating a satellite assembly with resources; and placing that file in the Host folder; and also in culture subfolders. However, the resource loading is failing: it does not find the resources.
I have also tried adding the:
[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
in my Plugin source file; and that did not help.
Can anyone figure this out enough to advise me? It may be a namespace problem; which I do not understand well enough to code for. If I have to change the way resources are loaded, I would do that also; but I do not understand enough about the way the resources are managed to know where to begin at this point.
Even given an explanation about what's under the hood with the resources and files, I may figure something out: but I am just looking at the IDE features, and hoping to use them and just find out how to successfully bundle and include the resources along with the Plugin DLL. I don't understand enough about what's under the hood.

... I wound up solving this just by loading resources myself manually ... Explained here:
Building Resource-Only DLL (With al.exe) Is Raising "assembly is built by a runtime newer than the currently loaded runtime"

Related

Resolve 3rd party dll path at runtime

I'm developing an application that depends on some 3rd party dll's (it's actually a plugin to the 3rd party application, and I receive COM objects implementing certain interfaces declared in those dll's). My project contains references to those dll's locally exist on the dev machine, but I want to avoid wraping them inside my installer (for size and legal considerations).
Instead, my installer requires that the dll's are already existing on the target machine, and their path is saved to a text file next to my executable assembly.
How can I use this file to link to the dll's on run time?
Or is it better to add an environment variable during installation and use it instead (how can it be done)?
Using project references, I do not know of a way to have dlls in an arbitrary location. Typically I've handled this issue using an installer, like InstallAware, prompted the user for the 3rd party location, and copied the dlls into my projects folder at the same relative location I chose in my solution file.
If this is improbable for you, you can always load the dlls and create instances of the classes yourself by hand using Assembly.LoadFrom and Activator.CreateInstance.
I hope this helps.

Deploying Custom Pipeline Component BizTalk Server 2010

Though there are many articles to tell about the Pipeline Component deployment. I dont understand how to do it. I build the solution and I have the .dll file. How do I GAC the Pipeline Component Assembly.
Where do I find the assembly, Is the .dll file is the assembly?I am new to .NET or C# I dont understand any of the terminologies. Can anybody help me with the details.
This is a good way of looking at it (taken from Difference Between Assembly and DLL):
An assembly is .NET's "minimum unit of deployment". Usually an
assembly corresponds to a single file, but it doesn't have to - you
can have multiple files, with one of them being the master which knows
where all the other bits are.
Single-file assemblies are usually DLLs or EXE files. If you've got a
normal class library and you just want to send it to the other side,
the DLL is what you want. I'd only worry about more complicated
scenarios as and when you run into them :)
In your case, the DLL is the assembly.
To deploy your custom pipeline component, you would need to
1) Add it to the Global Assembly Cache (use gacutil4)
Check here for more information: http://msdn.microsoft.com/en-us/library/dkkx7f79(v=vs.100).aspx
2) Copy it the Pipeline Components folder (default in C:\Program Files (x86)\Microsoft BizTalk Server 2010\Pipeline Components)
3) Restart the Host Instance (likely BizTalkServerApplication in your case) and deploy your new pipeline which makes use of the pipeline component.

How to register type library file (.tlb) with InstallShield LE in Visual Studio 2012 C#

I've been creating various plugins for an application that requires me to produce a .tlb file. In the past, it has simply been a case of configuring my project's build properties to 'Register for COM interop' thereby producing a .tlb file along with my output dll. Previously, when using the Visual Studio 2010 installer projects template, this would always correctly register .tlb during installation on the target machine.
I've recently attempted to make the switch to Visual Studio 2012 and use the InstallShield LE project to produce my installer, but it doesn't seem to register the type library during the install, nor does the express addition seem to allow me to manually register via the cmd-line regasm route - or at least it's not that obvious to me.
In the InstallShield project options I had to manually add the .tlb application file (from the build's \release folder) to the list of files to be included in the installer as it doesn't seem to get included along with the files produced by the project output or content options. In the .tlb file's 'COM & .Net Settings' properties, I have it configured to Registration Type: 'Extract COM Information' and have enabled 'COM Interop'.
What am I missing?
Try this thread for a good technical description: Are *.tlb files ever used at runtime?
In most cases I believe the *.tlb file is not needed because it is already compiled into most binaries regardless of whether it is an exe file or a dll, but .NET Interop is a lot more complex and as the other thread explains the *.tlb file can be needed to deal with advanced communication issues between threads and processes - something that I incidentially had forgotten.
When implementing a setup I have never had the need to register a *.tlb file by itself, it has been enough to register the corresponding binary (exe/dll), but this all depends on the use cases for the product.
Be aware that the way Installshield is registering for COM Interop is not always the best option as far as I recall. I am not sure exactly what they are doing, but I would check and compare with a normal regasm.exe registration:
http://msdn.microsoft.com/en-us/library/tzat5yw6(v=vs.110).aspx . And read the linked thread (Are *.tlb files ever used at runtime?) carefully on the issues of proxies, stubs and marshalling in case you need these features supported.
Here are some further links with concise information on COM/DCOM:
Contents of a Type Library:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms221355(v=vs.85).aspx
COM, DCOM, and Type Libraries: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366757(v=vs.85).aspx
Files Generated for a COM Interface: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366830(v=vs.85).aspx

How do I relocate assemblies from a deployment project without breaking application references?

I have recently refactored a lot of my applications existing code and I am now looking at tidying up the deployment side of things.
The existing installer application installs everything in the application folder (with the exclusion of a couple of config files which are located in a sub folder). However, I have multiple applications which all use some common assemblies and my goal is to relocate these particular assemblies to the "Common Files" folder in the program files directory.
NB: I have read a lot about the GAC but I have no experience with it and also read a few horror stories, so trying to get a simple solution for the time being.
I managed to get the assemblies installed into the Common Files folder, however, as a result (typical I.T.) I have broken my app! If I copy the assemblies back into the application folder it works fine so the problem is obviously to do with how my app is referencing the assemblies.
To get the installer to install the assemblies into the Common Files folder I just updated the Folder property of each assembly in the Detected Dependencies list. My thoughts were when I did that the installer would somehow update my application to tell it to look in that folder for them but that doens't appear to be the case.
What exactly am I doing wrong here?
There should be no requirements for assemblies to be in the GAC, unless the developer of an application/library designed it so. You have the choice to write you application so that most (if not all) referenced assemblies load from a specified (Common Files) location.
Here's an example architecture that implements the technologies described in the MSDN articles referenced at the bottom of this response.
Example: In an SOA application you might have a couple of different (Windows) services. Services could be load balanced across multiple servers. Within each server, services can be installed under a 'Services' directory. Services living in the 'Services' directory could share assemblies from a (Common Files) 'lib' directory:
\CompanyName
\Services
\Service1
\Service2
\Service3
\lib
Every actual service would derive from a Base Service class that would make use of an Assembly Utility. Your Assembly Utility could be configured to search for assemblies in a systematic way, allowing you to use shared/common assemblies. The neat thing is that your application could run with local assemblies (in local development) but use shared assemblies when deployed.
In my real world example, I had the luxury of having custom build and deployment scripts. Think of the different scenarios you can have deploying 1 of N services. Do you always update the (Common Files) 'lib' directory? Can a service run with local assemblies different than the 'lib' assemblies? Etc.
I hope this was helpful. If your issue is getting a third-party installer to deploy your application correctly, then disregard and name the installer. Otherwise, the given example/solution should help :o)
Read on the subject at MSDN:
Programming With Application Domains and Assemblies
Resolving Assembly Loads
ResolveEventHandler Delegate
PS: I've had challenges resolving assemblies for Microsoft's Unity framework.
If you wish to "reference" some assemblies from common folder, it is possible at development time. However when deploying every application has to have those individual assemblies installed with them.
If at run time, more than one of your applications are sharing some assemblies then "that common folder" is GAC.

ILMerge Best Practices

Do you use ILMerge? Do you use ILMerge to merge multiple assemblies to ease deployment of dll's? Have you found problems with deployment/versioning in production after ILMerging assemblies together?
I'm looking for some advice in regards to using ILMerge to reduce deployment friction, if that is even possible.
I use ILMerge for almost all of my different applications. I have it integrated right into the release build process so what I end up with is one exe per application with no extra dll's.
You can't ILMerge any C++ assemblies that have native code.
You also can't ILMerge any assemblies that contain XAML for WPF (at least I haven't had any success with that). It complains at runtime that the resources cannot be located.
I did write a wrapper executable for ILMerge where I pass in the startup exe name for the project I want to merge, and an output exe name, and then it reflects the dependent assemblies and calls ILMerge with the appropriate command line parameters. It is much easier now when I add new assemblies to the project, I don't have to remember to update the build script.
Introduction
This post shows how to replace all .exe + .dll files with a single combined .exe. It also keeps the debugging .pdb file intact.
For Console Apps
Here is the basic Post Build String for Visual Studio 2010 SP1, using .NET 4.0. I am building a console .exe with all of the sub-.dll files included in it.
"$(SolutionDir)ILMerge\ILMerge.exe" /out:"$(TargetDir)$(TargetName).all.exe" "$(TargetDir)$(TargetName).exe" "$(TargetDir)*.dll" /target:exe /targetplatform:v4,C:\Windows\Microsoft.NET\Framework64\v4.0.30319 /wildcards
Basic hints
The output is a file "AssemblyName.all.exe" which combines all sub-dlls into one .exe.
Notice the ILMerge\ directory. You need to either copy the ILMerge utility into your solution directory (so you can distribute the source without having to worry about documenting the install of ILMerge), or change the this path to point to where ILMerge.exe resides.
Advanced hints
If you have problems with it not working, turn on Output, and select Show output from: Build. Check the exact command that Visual Studio actually generated, and check for errors.
Sample Build Script
This script replaces all .exe + .dll files with a single combined .exe. It also keeps the debugging .pdb file intact.
To use, paste this into your Post Build step, under the Build Events tab in a C# project, and make sure you adjust the path in the first line to point to ILMerge.exe:
rem Create a single .exe that combines the root .exe and all subassemblies.
"$(SolutionDir)ILMerge\ILMerge.exe" /out:"$(TargetDir)$(TargetName).all.exe" "$(TargetDir)$(TargetName).exe" "$(TargetDir)*.dll" /target:exe /targetplatform:v4,C:\Windows\Microsoft.NET\Framework64\v4.0.30319 /wildcards
rem Remove all subassemblies.
del *.dll
rem Remove all .pdb files (except the new, combined pdb we just created).
ren "$(TargetDir)$(TargetName).all.pdb" "$(TargetName).all.pdb.temp"
del *.pdb
ren "$(TargetDir)$(TargetName).all.pdb.temp" "$(TargetName).all.pdb"
rem Delete the original, non-combined .exe.
del "$(TargetDir)$(TargetName).exe"
rem Rename the combined .exe and .pdb to the original project name we started with.
ren "$(TargetDir)$(TargetName).all.pdb" "$(TargetName).pdb"
ren "$(TargetDir)$(TargetName).all.exe" "$(TargetName).exe"
exit 0
We use ILMerge on the Microsoft application blocks - instead of 12 seperate DLL files, we have a single file that we can upload to our client areas, plus the file system structure is alot neater.
After merging the files, I had to edit the visual studio project list, remove the 12 seperate assmeblies and add the single file as a reference, otherwise it would complain that it couldnt find the specific assembly. Im not too sure how this would work on post deployment though, could be worth giving it a try.
I know this is an old question, but we not only use ILMerge to reduce the number of dependencies but also to internalise the "internal" dependencies (eg automapper, restsharp, etc) that are used by the utility. This means they are completely abstracted away, and the project using the merged utility doesn't need to know about them. This again reduces the required references in the project, and allows it to use / update its own version of the same external library if required.
We use ILMerge on quite a few projects. The Web Service Software Factory, for example produces something like 8 assemblies as its output. We merge all of those DLLs into a single DLL so that the service host will only have to reference one DLL.
It makes life somewhat easier, but it's not a big deal either.
We had the same problem with combining WPF dependencies .... ILMerge doesn't appear to deal with these. Costura.Fody worked perfectly for us however and took about 5 minutes to get going... a very good experience.
Just install with Nuget (selecting the correct default project in the Package Manager Console). It introduces itself into the target project and the default settings worked immediately for us.
It merges the all DLLs marked "Copy Local" = true and produces a merged .EXE (alongside the standard output), which is nicely compressed in size (much less than the total output size).
The license is MIT as so you can modify/distribute as required.
https://github.com/Fody/Costura/
Note that for windows GUI programs (eg WinForms) you'll want to use the /target:winexe switch. The /target:exe switch creates a merged console application.
I'm just starting out using ILMerge as part of my CI build to combine a lot of finely grained WCF contracts into a single library. It works very well, however the new merged lib can't easily co-exist with its component libraries, or other libs that depend on those component libraries.
If, in a new project, you reference both your ILMerged lib and also a legacy library that depends on one of the inputs you gave to ILMerge, you'll find that you can't pass any type from the ILMerged lib to any method in the legacy library without doing some sort of type mapping (e.g. automapper or manual mapping). This is because once everything's compiled, the types are effectively qualified with an assembly name.
The names will also collide but you can fix that using extern alias.
My advice would be to avoid including in your merged assembly any publicly available lib that your merged assembly exposes (e.g. via a return type, method/constructor parameter, field, property, generic...) unless you know for sure that the user of your merged assembly does not and will never depend on the free-standing version of the same library.
We ran into problems when merging DLLs that have resources in the same namespace. In the merging process one of the resource namespaces was renamed and thus the resources couldn't be located. Maybe we're just doing something wrong there, still investigating the issue.
We just started using ILMerge in our solutions that are redistributed and used in our other projects and so far so good. Everything seems to work okay. We even obfuscated the packaged assembly directly.
We are considering doing the same with the MS Enterprise Library assemblies.
The only real issue I see with it is versioning of individual assemblies from the package.
I recently had issue where I had ilmerged assembly in the assembly i had some classes these were being called via reflection in Umbraco opensource CMS.
The information to make the call via reflection was taken from db table that had assembly name and namespace of class that implemented and interface. The issue was that the reflection call would fail when dll was il merged however if dll was separate it all worked fine. I think issue may be similar to the one longeasy is having?
It seems to me like the #1 ILMerge Best Practice is Don't Use ILMerge. Instead, use SmartAssembly. One reason for this is that the #2 ILMerge Best Practice is to always run PEVerify after you do an ILMerge, because ILMerge does not guarantee it will correctly merge assemblies into a valid executable.
Other ILMerge disadvantages:
when merging, it strips XML Comments (if I cared about this, I would use an obfuscation tool)
it doesn't correctly handle creating a corresponding .pdb file
Another tool worth paying attention to is Mono.Cecil and the Mono.Linker [2] tool.
[2]: http:// www.mono-project.com/Linker

Categories