I have a framework which contains several assemblies. Multiple assemblies was created due to logical separation of code. This framework is supposed to be distributed to developer as well as end user. Developer are supposed to use few of framework assemblies to develop their modules. But all other assemblies are required to run the modules. Out of several assemblies, I want only few assemblies could be added to project reference and restrict other from being added to developer project references. In other words, I want developer should not be able to use types contained in assemblies which are not meant for plugin development. What is the best way to do that? I want to avoid passing some object to constructor of each type in those assemblies and verify them.
Can I take advantage of AppDomain or anything similar to that, which identifies type is being created by main app or module. If it is not main app, then throw exception or don't initialize. Any change in architecture is suggested.
One option would be to make the types within the "restricted" assemblies internal instead of public, then add InternalsVisibleToAttribute within those restricted assemblies to allow access to them from the other "framework" assemblies.
That way the end developer can still add a reference to the "restricted" assemblies (and probably should do so, in order to make sure they're copied for deployment) but won't be able to use any of the types within those assemblies.
EDIT: Another alternative might be to use ILMerge to build one assembly at the end - so it's a real unit of deployment, even though you originally split it out for separation reasons.
Yet another alternative would be to merge everything into one project and rely on code review, namespaces and common sense to pick up separation violations.
You can make all of the types in the other assemblies internal to prevent them from being ued outside their defining assembly.
You can use the [InternalsVisibleTo] attribute to make them visible to your other assemblies.
Related
I have two projects:
ProjectMain (class library)
LibraryProject (class library)
ProjectMain is a class library that should only be compiled as a singular library, no referenced libraries. I require a static class reference from LibraryProject BUT I don't want the LibraryProject assembly to be compiled together with the ProjectMain assembly.
I've tried 'link references' in visual studio but this is no solution as the library assembly is always compiled with the main assembly.
There are clear standard solutions to this issue but I am severely limited by the existing implementation requirements. Only one DLL can be compiled without any of the dependent assemblies being in the execution folder, GAC, private path, reflection etc.
The exact limitations are as follows:
Assembly executed in a sandbox from a third party provider, it only supports adding a single assembly with no direct references/reflection etc (it's horrible but my hands are tied)
We would like to handle the code organisation as best possible which means following standard best practices, unfortunately, due to the above limitation that's proving difficult.
What I would like to know is if there is a way to reference a class within another project without also compiling/using that referenced classes assembly. Possibly a method where the compiler 'embeds' the referenced class at compile time.
If your sandbox does not allow loading other dlls in AppDomain, load it yourself by embedding it. You can use Costura.Fody for this purpose, it is easy to use/install, just reference it from nuget.
Of course, embedding it in every scenario is madness and often comes with completely obscure bugs, which often solvable only by enabling traces in regedit.
So, in your case I would create two projects:
MyDll.csproj //it is my original project, with perfect code design and etc. Lovely.
MyDll.Sandbox.csproj //this one is the same as MyDll.csproj, except it is compiled with additional Costura.Fody reference, into single dll (every reference is put inside)
This way you just need to maintenance that MyDll and MyDll.Sandbox files are the same.
I have a project which needs to indirectly use three different versions of a third-party library. These versions are incompatible with each other, so I can't use a binding redirect - it has to be the exact .dll file. (The libraries are Spire.Doc, Spire.XLS & Spire.PDF; the Spire.PDF DLL is referenced by all three)
I have separated the three components into individual wrapper projects, and created classes which wrap direct references to anything in the libraries. However, this doesn't solve my issue: the 'consuming' project still has to copy all of the libraries to the bin folder in order to run. The build process doesn't know which version to copy, and so just copies the latest one. This gives me runtime exceptions due to the wrong DLL being present.
What I've considered/tried:
Adding a binding redirect to a specific version (runtime exception because the exact version of the library is not found)
Using a post-build step to merge the wrapper projects (again a runtime exception complaining about the absence of the library DLL)
Creating separate console applications for each part of the application, then invoking them in a separate - this is a complicated last resort that I'd really rather not do!
I have read that extern alias might be able to help - but as far as I can tell, you can only distinguish between assemblies with different names. The Spire.PDF library has the same name in each project (and the same signed public token).
How can I use these three separate versions of the library independently in the same solution?
Edit:
This issue is slightly different to the suggested duplicate because I don't have the ability to change any code in the dependent libraries. Spire.Doc relies on a different version of Spire.PDF to Spire.XLS
In your consuming project (Project A), create a common interface (ISpiroPdfAlex) that encompasses all the functionality that the 3 versions of your external assembly provides (and you use). You cannot reference anything in Project A from these wrappers in any way, otherwise you'd create a dependency, which is what you're trying to avoid.
Have all 3 wrapper projects import Project A and implement ISpiroPdfAlex. This will give you the ability to call each of the 3 different versions through the same API.
After this, create a subfolder under Project A for each of the versions (so 3 subfolders total) - since Project A has no reference to any of the external assemblies, it cannot load them by itself - you'll have to manually load them when you need the right version. Since your external DLLs may have dependencies with the same name, they cannot all be in the same folder (as you wrote), this is why you need the subfolders.
At run-time when you need one of these versions, you can call Assembly.LoadFile to load a specific version of your assembly from the specified folder and then you can either use Activator.CreateInstance or dependency injection to create an instance of a class that implements your interface. Once you have the instance, you're free to call any of the functions and you'll get version-dependent behavior.
Edit:
OP mentioned in a comment that it's not his code that has the dependency on different versions of the PDF library but the other 3rd-party Spire libraries that his code depends on.
In this case, the 3rd-party code cannot be modified to support dynamic loading of assemblies and they already have a binary dependency. It's not possible to load different versions of the "same" assembly into the same process, especially that you mentioned that these versions are not even backward-compatible with each other.
The only solution I can think of in this situation is to break out all dependent functionality into separate console applications (one for each different version) and call those separate .exe-s through the command-line.
To pass information, you can either pass data directly on the command-line or through stdin. Alternatively, you can just pass the name of a temporary file that has all data necessary to do some processing. To get return data back from the console process, you can either read its stdout or use the same / different file.
This way your main process never loads any of these assemblies and has no dependency on them - each console application has a dependency on just one version so there's no collision.
I have a created a WPF assembly that offers a set of attached behaviors (attached properties with property changed code) that can affect a wide range of third party controls.
Example:
TreeViewBehavior: Requires reference to Windows.Controls
RadTreeViewBehavior: Requires reference to
Telerik.Windows.Controls.Navigation
Some of my users will never use the RadTreeViewBehavior, but they still have to have a reference to Telerik.Windows.Controls.Navigation in their project.
How can I made it so that my users will only need to add references to assemblies that they are actually using?
I hope this makes sense.
You can't, your assembly is dependent on Telerik.Windows.Controls.Navigation and without it your assembly is incomplete. You will either need to remove any use of that assembly in yours, or try merging/embedding the assemblies using something like IlMerge or SmartAssembly.
I would recommend splitting the assembly into one that has behaviours for System.Windows.Controls and one that has behaviours for Telerik.Windows.Controls.Navigation
Our team works on Modules that have dependencies to different assemblies. E.g. We have a EmailClient Module that uses one set to assemblies for one particular build and another set of completely different assemblies for another build. That's because depending on the customer we integrated to different backends.
We want to keep one source tree for the EmailClient and make sure the "Latest" version always works for all customers. Our challenge here, is to not distribute unnecessary assemblies to one set of customers. As they get picky and ask what all these other files are for.
This is causing the following error and is very difficult to catch in one place:
System.IO.FileNotFoundException: Could not load file or assembly.
Does .Net provide such a feature where we can add reference to all sorts of assemblies, but not distribute some of them?
You should look at a plugin architecture like Managed Extensibility Framework (MEF) http://msdn.microsoft.com/en-us/library/dd460648.aspx
This way you can expand your current application without creating dependencies to assemblies.
Even if you're not planning to implement MEF. It will gives ideas and new ways to think, about how to implement it your own.
What are the implications and suggested scenarios to use either?
Assembly.Load is a dynamic reference since you're dynamically loading an external DLL at run-time. You would consider a static reference more like when you're adding a reference to a .NET project and building the project with that reference in place.
EDIT:
From the MSDN Doc:
The compiler records static references
in the assembly manifest's metadata at
build time.
Hmmm, not sure about this one myself. I'll keep my answer here for now, in the hope of getting more correction comments or seeing better answers.
In reference to:
What are the implications and
suggested scenarios to use either?
Usually, if I use Assembly.Load(), it is because I am developing a pluggable system. Dynamic references facilitate inclusion of assemblies that are not necessarily part of my build.
Instantiating types from a dynamically loaded assembly requires at least some reflection. The amount of reflection necessary can be mitigated by ensuring that dynamically-loaded types implement some known interface or base class (from a statically-loaded assembly).
In short, it's a lot of work to use dynamically loaded assemblies; however, doing so can make an application more flexible by allowing users to develop plug-ins. Just weigh the trade-offs of the anticipated flexibility of dynamic references (which may not be a requirement), and design-time support from Visual Studio for static references.
A practice worth consideration if building a plug-in architecture is to load assemblies in their own AppDomains. Doing so permits you to have finer-grained control over the security permissions of assemblies you may not entirely trust, and provides the added benefit that the assemblies can be unloaded at run-time. Personally, I found working with AppDomains to be labor-intensive; however, if the benefits are required, it's good to know that AppDomains are there.
A dyanamic reference as stated in the MSDN(http://msdn.microsoft.com/en-us/library/yx7xezcf(VS.71).aspx) references dynamic referencing as loading a reference with only enough information that the runtime has to search for the assembly being loaded. With static references, the location of assemblies(GAC, application direcotry, etc) are known and can be still accomplished using Assembly.load.