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
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 need to add reference to another assembly in my c# project based on some compiler switch like #ifdirective. For example I want to add reference to logger DLL in my project only when I need it. Is this possible?
As far as I know, a referenced assembly that isn't used AT ALL, isn't a problem. You can even keep it as reference.
As long as your code doesn't trigger the assembly to be loaded, there is no need to have that file available.
I would suggest though to check whether you really need this, and if you can workaround this by creating interfaces and dynamically load the assembly (using Assembly.LoadFrom).
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.
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.
The full error is as follows:
The type
'System.Windows.Forms.Control' is
defined in an assembly that is not
referenced. You must add a reference
to assembly 'System.Windows.Forms,
Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089'.
and it points at the very first statement (an Debug.Assert line) in the very first class in a library project that doesn't need System.Windows.Forms (or so I thought). I know how to solve it: add the mentioned reference. But how do I find out what library is causing this error, or better, what part of the code triggers using the WinForms library?
Normally, you can add libraries that reference others, but you only need to add references to these others when they're actually used.
EDIT: Alternative solution
This or similar problems can also be resolved using the Binding Log Viewer Fuslogvw.exe from Microsoft's Framework Tools. It shows all attempts and successes of assemblies your application binds to.
I suspect there's no line of your code that's causing this, since you say you aren't making use of the System.Windows.Forms types and the compiler error isn't pointing to a (useful) line of your code.
What I think is happening is that you're referencing a library which has a publicly-visible method or property that either returns a System.Windows.Forms.Control or takes one as a parameter. It doesn't matter whether you actually end up calling that method/property, the fact that it's publically visible means that your own code has to be able to resolve all the types that the library is using. If the library only used System.Windows.Forms internally, you wouldn't be experiencing this.
It also means just looking at the dependencies of the assemblies you're depending on may merely narrow down the list of suspects, since there could be some assemblies that depend on System.Windows.Forms internally (no problem) and the one troublemaking assembly that has a public parameter / return value of a type from the S.W.Forms assembly.
My suggestion is you just set up an empty project without a reference to S.W.Forms, then add each of your dependencies in turn and try to compile after each one.
I had the same error.
The problem was that I used a reference to a project, which uses System.Windows.Forms inside.
The solution is to add a reference to System.Windows.Forms also in your project.
Use something like NDepend or Reflector or the Object Browser to check the dependencies of the assemblies you depend on.
I cannot think of any other way given the info above.