Visual Studio Prevent Changes to Linked File - c#

In Visual Studio you can add a link to a source file in another project. Is there a way to enforce preventing any changes from being performed on the linked source file (ie: link them into a project as 'read only', so as to prevent accidental modifications by folks who don't realize they are linked, and not local to the project)?
I have two projects, one of which is a DLL, the other is an EXE. The DLL contains a Windows ServiceInstaller and ServiceBase classes. I link these classes into my EXE (there are multiple flavors of the EXE) from the DLL in order for the EXE to be installable as a service and for me to not have to replicate the ServiceBase and ServiceInstaller in all of the EXEs. I do not however want to inadvertently be able to make changes to the linked classes from within the context of the EXE project.

Not via some Visual Studio-supported mechanism, no.
IMHO, as a general rule you should not be using a linked file like that. Yes, the feature exists in VS, but for the very reason you mention as well as others, it's a great way to create code maintenance headaches.
Note that your own scenario could be just as easily solved by exposing shared types in an assembly and referencing that assembly from those that need them. I.e. just reference the DLL from your EXE and use the types as compiled into the DLL rather than having the EXE define new versions of the types using the same source code.

Visual Studio does not have a way to set a "read-only" attribute for a linked file, but in general, linked files cause more problems than they solve.
Generally speaking, the preferred method for code reuse is to put the classes into a DLL and then reference those classes from the EXE - but in your case, the ServiceInstaller and ServiceBase classes have to be present in the EXE in order for the Windows service mechanism to pick them up.
Instead of linking the files, you could create base classes that inherit from ServiceInstaller and ServiceBase and put those in the DLL. Then add new classes into the EXE that inherit from your custom base class (which contains most of the logic). This way, all of the shared code gets pulled in from the shared DLL, but the EXE(s) still contain the classes necessary for the Windows service to start.

Related

How to call tool DLLs in C# when the DLL-path is different on the target PC?

I might be a bit stupid, but I want to create a tool in Visual Studio in C# and want to call third party tools via their API-DLLs. The only topics I found here are dealing with one of the two methods that I already know:
Compilation time: add a reference to "C:\FooTool\foo.dll" in my project + "using fooToolNamespace.fooToolClass" in my code (compilation time) --> I can "naturally" use the classes of the DLL and will even get full IntelliSense support if a suiting XML-file is available with the DLL. Also compilation time checks will be done for my usage of the dll.
Dynamic (run time): calling e.g. Assembly.LoadFile(#"C:\FooTool\foo.dll") and then using reflection on it to find functions, fields and so on --> no IntelliSense, no compilation time checks
So I actually have the DLL at hand and thus option 1) would be nice during development. But if my tool is used on a different PC, the third-party DLL might be in a different path there, e.g. "C:\foo\foo.dll" and "C:\bar\foo.dll".
In my understanding using a copy of "foo.dll" will not work, because "foo.dll" might have dependencies, e.g. requiring other files of the FooTool-directory. Thus in my understanding I have to call the DLL which is "installed" to the target PC and not a local copy of it.
So can I somehow change the path where my tool accesses the "foo.dll" at runtime and still use method 1) during development?
Or is there another way of doing things?
Or am I just dumb and there is a simple solution for all this?
Thanks a lot for the help and have a great day
Janis
To be able to use option 1 (a referenced DLL), you need to put the DLL somewhere "where your EXE (or, more precisely, the Assembly Resolver) can find it" on the customer's PC.
So where does the assembly resolver look for your DLL?
In the directory where the EXE resides (for desktop/console applications) or the bin subdirectory (for web applications). Since you mention that your DLL requires other dependencies as well, you'd need to copy them to that location as well.
The Global Assembly Cache (GAC). If your dependency supports this, installing it to the GAC ensures that it can be found by your application.
These two are the "supported" scenarios. There is also the possibility to tweak the assembly resolver to look into other directories as well, but that should be reserved for special cases where the other two options failed. (We had such a case and solved it with a custom AssemblyResolve handler on the application domain.)

How to create a dll that includes all the others?

At the moment of creating a project of type "Library of Classes, usually one can generate a dll when compiling, but how could I generate a dll without losing others that I already have included?
I explain with an example: It turns out that Nuget downloaded an S22.Imap dll with the one I worked with, later I generated the dll in the traditional way that I explained in the beginning, but when I wanted to work with dll in another computer, I got errors that were not I found functions that contained the S22.IMAP dll. So to solve this problem, I had to copy the dll of my project, S22.IMAP in an additional way in a specific path of the other computer.
My question is:
How could you generate a dll that includes the ones included in the project you were working with?
All the referred 3rd party dlls (S22.Imap.dll in your example) will be copied to the output folder together with your own dll file (let's say a.dll) when you build your project. That means you should always copy them together (S22 + a.dll) to the place you want to refer them, on another computer/folder/place.
If you really want to make them only one file (although it is not recommended), you can set the S22 one as some "nested resource". Then you will get only one a.dll file and the S22 one is inside the a.dll. See below page for some reference:
Embedding one dll inside another as an embedded resource and then calling it from my code
AND, ILMerge is some tool that can help you do so.
In general, you don't. A DLL is a dynamic linked library, and you would normally only combine static libraries during a build. Here is an answer on the difference between static and dynamic linking.
Typically you would include all the DLLs you need in the installer package. If you use Visual Studio to create the installer, it can detect the dependencies for you. When you run the installer, all of the necessary DLLs are deployed. Nearly all commercial .NET software follows this pattern.
It is possible to merge an assembly into another assembly using a tool called ILMerge. This would be a very unusual thing to do, and could cause issues with intellectual property and code signing, so it is not recommended.

Dependency injection for a visual studio add-in

I'm working on a visual studio add-in that takes SQL queries in your project, plays the request and generates a C# wrapper class for the results. I want to do a simplest possible dependency injection, where projects using my add-in supply a class that can provide the project's db connection string, among other things.
This interface is defined in my add-in...
[Serializable]
public interface IDesignTimeQueryProcessing
{
public string ConnectionString { get; }
...
}
And the question : How do I define and instantiate the concrete implementation, then use it from the add-in?
Progress?
The interface above is defined in the add-in. I've created a reference in the target project to the add-in, written the concrete implementation, and put the name of this class in the target project web.config. Now I need to load the target project from the add-in to use my concrete class.
If I use Assembly.Load()...
var userAssembly = Assembly.LoadFrom(GetAssemblyPath(userProject));
IQueryFirst_TargetProject iqftp = (IQueryFirst_TargetProject)Activator.CreateInstance(userAssembly.GetType(typeName.Value));
I can successfully load my class, but I lock the target assembly and can no longer compile the target project.
If I create a temporary app domain...
AppDomain ad = AppDomain.CreateDomain("tmpDomain", null, new AppDomainSetup { ApplicationBase = Path.GetDirectoryName(targetAssembly) });
byte[] assemblyBytes = File.ReadAllBytes(targetAssembly);
var userAssembly = ad.Load(assemblyBytes);
I get a file not found exception on the call ad.Load(), even though the bytes of my dll are in memory.
If I use CreateInstanceFromAndUnwrap()...
AppDomain ad = AppDomain.CreateDomain("tmpDomain", null, new AppDomainSetup { ApplicationBase = Path.GetDirectoryName(targetAssembly) });
IQueryFirst_TargetProject iqftp = (IQueryFirst_TargetProject)ad.CreateInstanceFromAndUnwrap(targetAssembly, typeName.Value);
I get an
InvalidCastException. "Unable to cast transparent proxy to type QueryFirst.IQueryFirst_TargetProject"
This makes me think I'm very close? Why would an explicit cast work fine with Assembly.Load(), but fail when the same assembly is loaded in a newly created AppDomain?
I'm assuming that your add-in is going to be triggered in someway in order to start working with SQL Queries.
I'd recommend that you bundle a separate .exe file with your add-in and do the processing in there.
Here's why:
Personally, I've had a lot of issues with AppDomains similar to what you're running into with file locking and the head ache of Temp Domains. The other issue you'd likely run into is once you load an Assembly into an AppDomain, you can't unload. By using a separate process (that dies when it's finished) you don't have to worry about the problem.
Depending on the type of Projects you want to support, those Projects will have dependencies. Managing references to dependent dlls will be a lot easier if you can just point your standalone .exe at a directory (ie the bin directory).
If you hook into Visual Studio's Build Events (DTE.Events.BuildEvents.OnBuildBegin) you can kill your process and release the locks on the dll files. Or you could have your process first make copies.
Testing/debugging is a lot easier with a stand alone file. You don't need to worry about trying to debug by attaching to Visual Studio (How to debug a Vsix project).
You can use the following methods to start/kill processes:
Process.Start
Process.Kill
I think you can reference the output of a Console Project directly from your VSIX Add In Project via the References Anatomy of a VSIX Package. Otherewise, you might need to do some custom MSBuild to get the .exe included within the VSIX file.
Once it's included, you can find the .exe because it should be in the same path as your executing VSIX (Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) and I would pass it the Path to the loaded Project's bin directory.
As an aside, this isn't Dependency Injection. If you want to use DI inside a VS Extension, you can use whatever framework you'd like, but I think MEF is natively supported. Personally, I prefer Ninject. Define your Kernel inside the Package class and the use it to load your top level class.

How do I compile C# code as a library instead of an executable?

I have a C# console application in Visual Studio 2010. It has a Main() method as well as a bunch of utility classes. I'd like those utility classes to be available to other solutions. From reading online it seems that I need to compile it as a Class Library (DLL). So here's what I did:
Went in Visual Studio to "Project > [ProjectName] Properties > Application" and changed "Output type" from "Console Application" to "Class Library"
Rebuilt; ProjectName.dll was created in bin/Debug.
Created a new Console Application
Solution Explorer > Add Reference > browse to ProjectName.DLL, select it.
However, neither IntelliSense nor the Object Browser could find the classes inside that DLL.
I tried recompiling several different Console Applications as Class Libraries and got the same result. I also noticed that it works if I initially create the solution as a Class Library, but not if I convert it to one later.
Any tips?
You do not need to build it as a dll. VS 2010 (and IIRC 2008) allow referencing exe assemblies. All you need is for they relevant types to be declared public - top-level classes defualt to internal if you don't add a specifier.
You can switch output type to Class library in project properties as well - then you will have an output as dll instead exe file
What I've always done (since this is what you do with C++ static libraries, which is what I normally use - though I think it has some advantages for C# too) is add the class library's project to the solution, then add a reference to it in the project (or projects) that uses it.
When you go to add a reference, the list of potential references includes items from the solution, so it should be fairly obvious what to do. You should then get intellisense for your library.
One advantage of doing things this way is that if you need to edit files in the library project, it's very straightforward because they are close to hand, and the project then gets rebuilt automatically when you compile the solution.
Make sure that the classes in your dll project are public.
At first, from the point of view of managed libraries it does not matter what kind of Output type is your managed library. I mean that you can successfully reference ConsoleApplication1.exe from ConsoleApplication2.exe project (so you have no reason to convert ConsoleApplication1.exe to ConsoleApplication1.dll).
At second, I've tried to reproduce your situation, but... without effect. My VS displays types/methods from ConsoleApplication1.dll. One reason I can suppose is that you have forgotten to set visibility modifier (public keyword) for your utility classes.

What is a .NET managed module?

I know it's a Windows PE32, but I also know that the unit of deployment in .NET is an assembly which in turn has a manifest and can be made up of multiple managed modules.
My questions are :
1) How would you create multiple managed modules when building a project such as a class lib or a console app etc.
2) Is there a way to specify this to the compiler(via the project properties for example) to partition your source code files into multiple managed modules.
If so what is the benefit of doing so?
3)Can managed modules span assemblies?
4)Are separate file created on disk when the source code is compiled or are these created in memory and directly embedded in an assembly?
EDIT:
#Jon:
For 2):So, does compiling/building source in visual studio always create a single managed module? If so then I fail to understand as to why VS doesn't provide a mechanism to do so in spite of the fact that .NET supports doing so.
I agree that it would be unmanageable to create an assembly with modules from different languages. Is that the only reason why .NET allows creating multi module assemblies?
I read in Richter's CLR via C# that modules can also span assemblies, and this can help keep assembly sizes down, and reduce memory footprint by downloading assembles on demand when certain functionality is invoked for the first time, but I'm not quite sure as to why would one want to span a module across assemblies, why not just create a new assembly which implicity creates a new module in the process. You would still gain the same benefits.
Item 4) was in regards to ".netmodule" files.
As part of the VS build process I haven't seen any ".netmodule" files created in the obj directory. I've typically noticed .pdb, .dll/.exe and a *FileListAbsolute file and hence the question on whether any separate files are created for managed modules.
EDIT:
#Jon: Here is the excerpt from CLR via C#(3rd edition) Pg 43:
Maybe I'm misreading this but it sounds to me that a module (which is a file belonging to an assembly) can be downloaded on demand.
"For example, an assembly can consist of several types.
You could put the frequently used types in one file and the less frequently used types in
another file. If your assembly is deployed by downloading it via the Internet, the file with
the infrequently used types might not ever have to be downloaded to the client if the client
never accesses the types. For example, an independent software vendor (ISV) specializing in
UI controls might choose to implement Active Accessibility types in a separate module (to
satisfy Microsoft’s Logo requirements). Only users who require the additional accessibility
features would require this module to be downloaded.
You configure an application to download assembly files by specifying a codeBase element
(discussed in Chapter 3) in the application’s configuration file. The codeBase element identifies
a URL pointing to where all of an assembly’s files can be found."
1) You can't do this in Visual Studio. You can do it from the command line using:
csc /target:module Foo.cs Bar.cs
In this case you'd end up with a fle called Foo.netmodule
2) See question 1 - you can't do this from Visual Studio, but you can do it from the command line. I don't know of any benefits. EDIT: I agree with Andrew's statement that you could create an assembly from multiple languages this way - but I believe it would be impractical. You'd have to work out an appropriate dependency chain so that you could build one complete module first, then the next etc... at that point, why not just build separate assemblies in the first place? It would effectively be an extra accessibility domain, admittedly... but that's about all. I believe the disadvantages of this are likely to outweigh the advantages in almost all scenarios. If you really want to build a single assembly, you can always use ilmerge after building separate assemblies.
3) Well, in theory a single module could be included in multiple assemblies, but there'd be no point in doing so - it would create a very confusing system.
4) I'm not really sure what you mean. Visual Studio creates some intermediate files in the obj directory, if that's what you mean. The command line compiler doesn't leave any extra files lying around, but it may create intermediate files which it deletes on completion - I don't really know.
EDIT: I don't believe VS builds modules as an intermediate step. Compiling in Visual Studio always creates a single assembly per project, and that assembly has a single module. When you say that CLR via C# says that "modules can span assemblies" are you sure you don't mean that assemblies can span multiple modules? You can download modules of an assembly on demand, but not the other way round. If you have a specific reference, I could look it up...
You cannot create modules using VS, but you can do it using compiler. Modules are separate files on the file system, it is possible to have several modules in one assembly written in different languages.
EDIT: Also you can put rarely used classes in the separate modules. Such modules will be loaded only when classes are needed.

Categories

Resources