In C#, is it possible to restrict who can call a method at compile time?
I've looked into directives, but that didn't work since I can't assign values to symbols.
#define WHO VisualStudioUser.Current // does not work
I also looked into Code Access Security (CAS) but that's runtime enforcement, not compile time.
The requirement is to restrict access to a method at compile time for specific developers given the method exists in a pre-compiled assembly.
here's more details...
I'm building a framework or a series or assemblies for a team of developers. Because of our software license restrictions, I can only allow a few developers to write code to make a call to some restricted methods. The developers will not have access to the source code of the framework but they'll have access to the compiled framework assemblies.
The quick answer will be: No this isn't possible, and if you need to do it, you're Doing It Wrong.
How would this even work? Does it depend who who's running the code or who wrote it?
Edit There's kind of a way using InternalsVisibleTo and restricting accessing in source control to the assemblies that InternalsVisibleTo is specified for. See Jordão's answer
The requirement is to restrict access to a method at compile time for specific developers given the method exists in a pre-compiled assembly.
One way is to mark the method private or internal, it won't be callable by anyone outside the assembly. UPDATE: Also take a look at the InternalsVisibleTo attribute, which is used to define which assemblies can "see" internals of your assembly.
Another way is to divide the code you want to distribute from the code you don't want people to call into separate assemblies. Maybe you just share an assembly mostly of interfaces with your users, that they them compile against; and you have a separate assembly with implementations that they shouldn't reference directly. Your internal team would have access to the implementation assembly. This is just a common form of dependency management, the dependency inversion principle.
Draft:
Compile the restricted code into (obfuscated) DLLs: TypeA.dll, TypeB.dll etc.
Define an interface for each type, and compile them into separate DLLs: ITypeA.dll, ITypeB.dll etc.
Create a "guard assembly", and embed all restricted assemblies into it: Guard.dll. This has a ResolveEventHandler, and methods to instantiate different types defined in the embedded restricted DLLs. Instances are returned through their interface.
Developers get the interface DLLs and the Guard.dll. Each developer can get a Guard.dll with special authentication tokens in it. For example, a Guard.dll can be bound to PC, an IP address, a GUID issued to the developer, anything.
The developer can instantiate those types for which she has the proper authentication code, and uses the object instance through an interface.
Sorry this is a bit fuzzy, because it was more than a year ago when I used these techniques. I hope the main idea is clear.
Can you try using Extensible C# developed by ResolveCorp, some of the links for study and implementation are:
http://zef.me/782/extensible-c
http://www.codeproject.com/KB/architecture/DbCwithXCSharp.aspx
http://weblogs.asp.net/nunitaddin/archive/2003/02/14/2412.aspx
http://www.devx.com/dotnet/Article/11579/0/page/5
Related
I want to separate platform-independent logic of my C# program into a shared project. Now I would like to hide repositories, service classes and such from my platform-specific projects. What access modifier can I use? internal doesn't seem to work, as they are compiled into the same executable (I think) and I don't want to go tag all my classes with InternalsVisibleToAttribute.
Is there a way to make classes in my shared project invisible to my platform-specific code?
There's only one place where you need to know the real type you're trying to instance - the platform provider. Everyone else should just use the interfaces that are platform-invariant.
All the platform-specific implementations can then be private or internal for all you care - you just need to ensure the provider has access. Your application will use the platform-specific provider to get the platform-specific instances, while only ever using the platform-invariant interfaces.
As for "being compiled into a single executable", that's not really important. Most likely you care entirely about compile-time checking, and that's still present regardless of how the final executable is packaged. There's some restrictions on reflection in a partial trust environment, but by that point you shouldn't care - you're only in it for the compile checks, not the runtime safety.
No, there is no such feature in C#. If you consider marking every other project with InternalsVisibleToAttribute an option, that would do the trick.
If possible, you could split off those other files (repositories, service files) to another assembly, which is not included in your shared project.
Let me clarify:
I have built a class library to be used in several projects. As part of this DLL I want to add a few different custom providers for Owin Cookies by extending CookieAuthenticationProvider so I need to include a reference to Microsoft.Owin.Security.Cookies. This is safe because the newer projects that will use my library also use Microsoft.Owin.Security.Cookies.
However some of the projects are older and dont use Owin etc... Will they blow up if I include the library for other use? Or will they only blow up if I try to use the provider (which I wouldn't since they cant use it).
I want to put some commonly used things in my library without having to reference every one of it's dependent DLL's to every project that uses them. I'm pretty sure what I'm doing is ok but I was hoping somone could tell me before I waste many hours going forward with this. Also if there is a better way I'm all ears.
The rules:
All types which are visible to a given assembly must be declared in assemblies referenced by that assembly.As long as your class library does not actually expose in its public API the types found in the Microsoft.Owin.Security.Cookies assembly, then other assemblies can safely compile with your DLL without referencing that assembly.
A referenced assembly need not be present at runtime, except when code in that assembly is actually needed, i.e. some other code attempts to call that code.
In general, this means that as long as other assemblies which are referencing your assembly and which don't reference Microsoft.Owin.Security.Cookies also don't call any code in your assembly that would then in turn attempt to call code in Microsoft.Owin.Security.Cookies, that assembly need not be present at runtime.
The tricky part on that second point is that what constitutes "calling code in Microsoft.Owin.Security.Cookies" is not always clear. Typically, as long as you don't access the types in the assembly at all, .NET won't try to execute any code in that assembly. But it's not hard to accidently access the types even when they are not necessarily needed (e.g. in initializers, static or otherwise, code that checks for interface implementations, etc.).
If you really want your clients to be able to use your DLL, which references Microsoft.Owin.Security.Cookies, without necessarily needing that DLL to be present at runtime, you will need to be very careful to ensure you've fully supported that scenario. It is possible to do, but it's also not hard to make a mistake.
(I have to admit, I'm surprised that this useful question hasn't already been addressed on Stack Overflow. Seems like it would have come up before by now. But I was unable to find a duplicate, hence the answer above. If anyone is aware of a duplicate I've overlooked, I welcome any suitable notice of that.)
is it possible to use an interface type, that is defined in a huge external dll, without referencing that dll?
in other words, there will be one core or global dll, that references the external dll, and all the projects reference this global one, so the external dlls are hidden from the other projects.
I want to use the type in my code, while knowing only about the global AllInterfaces project.
can that work? and if so, what needs to be done for such a scenario?
Is it possible to use an interface type that is defined in a huge external dll, without referencing that dll at compile time?
Not really, no. The compiler has the reasonable expectation that the types it needs are available.
Is it possible to use an interface type that is defined in a huge external dll, without referencing that dll at runtime?
Yes. We added that feature to C# 4. The "proper" name for the feature is something like "Type Embedding with Type Equivalence", but everyone just calls it "No PIA".
The motivation for the feature is the one faced most obviously by Visual Studio Tools For Office developers. VSTO developers write C# code that customizes, say, an Excel spreadsheet with some managed code. They communicate with Excel via a managed interface, but of course Excel actually exposes a set of COM interfaces. To bridge that gap, the Office team supplies a Primary Interop Assembly, or PIA. The PIA is a huge external library that contains nothing but metadata that describes how the managed interfaces correspond to the unmanaged interfaces of the COM objects.
The problem is that the Office team does not by default install the PIA when your customer buys Office! Therefore you have to ship the PIA with your customization. And the PIA is so large, it is often many times the size of the customization, which makes your download longer. And so on; it's not an ideal situation by any means.
The No-PIA feature allows the compiler to link only the portions of the PIA you actually use into your library, so that you do not have to ship the PIA with it.
Now, you might ask "what if I have two customizations that communicate with each other, and both use the IFoo interface from a PIA that I am not shipping?" The runtime identifies types by the assembly they came from, and so the two IFoo interfaces would be considered different types, and therefore not compatible.
The "No PIA" feature takes this into account as well. It does the same trick you use in COM to solve this problem: the assembly instructs the runtime to unify all interfaces that have the same GUID into the same logical type even if they come from different assemblies. This thereby explains the requirement that every interface that you use with "no PIA" has to be marked as though it were a COM interop interface with a GUID.
On the command line, use /L instead of /R to reference an assembly as a "no PIA" assembly.
Do a web search on "no PIA" and you'll find more information on this feature.
If you want to use that interface type in your code, that interface should be visible to your code. You code won't compile.
You can write adapter interface in your global dll, for the original interface and use that every where.
It cannot be done statically but you can do it using reflection.
With C# 4 you can use the dynamic keyword.
However, I fail to see how not knowing the interface in advance is going to help you - how are you going to know which methods to call?
You are trying to fool type identity. The CLR identifies a type by these properties:
Assembly display name
[AssemblyVersion]
[AssemblyCulture]
The assembly's PublicKeyToken value
The assembly's processor architecture (implicit)
The type's namespace name
The type's name.
Faking the type namespace name and name isn't difficult, the hard thing to do is faking the assembly properties. You are dead in the water if the assembly is strong-named (non-null PublicKeyToken) or if it is stored in the GAC, you can't get the substitute loaded. Faking the culture and architecture isn't hard to do, you'll have to get the display name and version right.
And of course, you'll have to get the interface declaration exactly right. Intentionally invoking DLL Hell like this is otherwise an Extremely Bad Idea. Not in the least because you now can never get the real assembly loaded.
I know how to branch the code based on Mono (Type.GetType("Mono.Runtime") != null) but even when the Mono code path is taken, Mono is attempting to load assemblies that would be required by the non-Mono code path. This is not all that surprising, but how do I get around the problem? I have tried putting the call to the non-Mono assembly in a different class, but that didn't help.
The only option to do it directly is Reflection all the way, so far as I can see.
I'd suggest a more roundabout approach: refactor all your code that is dependent on Mono or .NET into separate assemblies, one for each platform - let's call them MA and NA. Make sure that the entire API surface of your classes there is covered by common interfaces, which should be in the 3rd assembly, IA. After that, your main application references IA for interfaces, and uses Reflection just once to load either MA or NA depending on whether it's running on Mono or .NET, and obtain the instance of "top-level factory class". Once there, it just uses normal calls via IA interfaces to instantiate all other objects via that factory and work with them.
Expanding on Pavel's answer you can use a plugin framework to help with the conditionality of loading bits of code that are specific to a platform. You can use Mono.Addins or MS' own open sourced Managed Extensibility Framework known as MEF (http://www.codeplex.com/MEF)
Don't add the reference in the command-line compiler options. If you are using a high level IDE tool then you might have to play with its project settings to effect the same thing.
There are other files that come into play too like AssemblyInfo.cs and might contain instructions about assemblies that you are considering. Also the program might be using types from App.Config (Configuration file) or Web.Config (ASP.NET) / dynamic type loading.
Don't rely for your dependencies on the fact that your code is JITted and that only called code is JITted.
Best is always to assume, that whatever is referenced will be loaded and has to be available.
You user might choose to use AOT, which is Mono's counterpart of NGEN.
Or subtle differences in how newer runtime versions handle things like serialization, remoting, security, reflection, etc. can lead to your references being loaded even your code does not use anything directly. (But the serializer might have pulled all types, which then loaded other assemblies)
Use interfaces or classic inheritance, or maybe events or other means of indirection to load the .Net parts only when they are appropriate. And by hat I mean an assembly that you don't reference but load dynamically.
I have got a dll placed in a shared folder over development server. Is there any way to use that dll without adding reference in my application and without installing the same in GAC.
Thanks in advance.
Assembly asm = Assembly.LoadFrom(path);
See MSDN for late binding, reflection etc.
Small edit: A variable with the keyword "as" is asking for trouble. So "Assembly as" changed to "Assembly asm" should be safer.
You may want to look at the Managed Extensibility Framework or at Assembly.Load... in the base framework.
Why would you want to do this, though? You'd need to call any code within the Assembly via reflection (hence the suggestion that the MEF may be what you're really after).
Yes, it is possible...somehow. Have a look at the Assembly-Class. With it you can load assemblies from a file without knowing what you exactly load.
Using Assembly.LoadFrom would be the only way to have zero references, but you'd still need to share contracts.
What's the problem with adding a reference?
What are you going to do when someone wants to work on a laptop and the WiFi goes down?
Yes,
you can call Assembly.Load() and then make use of Reflection to call into the public interface (lowercase "interface" - what I mean is the methods, fields and properties) exposed by the assembbly.
But in order to do that you need to know what methods to call. It helps if you can be certain that the assembly includes classes that do conform to a known .NET interface.
This idea is the basis for "plug-in" architectures in many tools, where the tool loads any assembly in its "plugin" directory, instantiates classes, casts the result to an ISomething, and then invokes methods via that interface.
I also would read Suzanne Cook's .NET CLR Notes.
http://blogs.msdn.com/suzcook/default.aspx
If this assembly is in a shared folder, you may find that .NET security restrictions stop you working with classes in that assembly in quite the way you'd expect.
Rather than storing on a shared folder, you may want to consider checking in the assembly to your source code repository. (I've seen a "/lib" folder used to good effect for this). Then you can reference the assembly directly.
(There are also repository solutions such as Maven that can more properly control this. However, they don't play well with .NET, unfortunately.)