Monday, July 1, 2019

Linking Files in Visual Studio

Linking files in Visual Studio lets us use the same physical file in different projects. I always forget how to do this, so I'm making notes here.

The Short Version
If you already know about linking files and why you want to do it, here's the short version that has the mechanics (details are further down).

To link files, use the "Add Existing Item" dialog. One way of getting to this is to right-click on the project and choose "Add", then "Existing Item...".


When the dialog opens, locate the file you want to link to.


Then DO NOT CLICK THE "Add" BUTTON. Instead, notice that the "Add" button is a drop-down (this is really easy to overlook).


Use the drop-down and select "Add As Link".

That's all there is to it!

If you want details on what linking files really means and why you might want to do it, keep reading.

The Long Version
To show the differences between copying files and linking files, I've set up a solution with 3 class libraries.


The first library, "A-SourceLibrary", is a .NET Core 3.0 class library that contains the file we want to use in the other projects. The file is called "Person.cs".

The file system shows that we have a .csproj file and one .cs file:


The second library, "B-CopiedFiles", is a .NET Standard 2.0 class library that does not currently have any files.

The file system shows that we have a .csproj file only:


The third library, "C-LinkedFiles", is a .NET Framework 4.7.2 class library that does not currently have any files.

The file shows that we have only a .csproj file here as well:


Let's look at the difference between copying and linking.

Copying Files
Copying files from one project to another is out in the open (for the most part).

Copy/Paste
As one option, we can right-click on the source file and choose "Copy" and then right-click on the destination project and choose "Paste".

The keyboard shortcuts Ctrl+C and Ctrl+V also work as long as you have the correct items selected in the Solution Explorer.

Add Existing Item
Another way to copy a file is to Add an Existing Item. We will do this to copy the "Person.cs" file from the "A-SourceLibrary" project to the "B-CopiedFiles" project.

Just like above, you right-click on the project, and select "Add", then "Existing Item..."


When the dialog pops up, just locate the file.


And then click the "Add" button.

This will create a *copy* of the file in the destination project. We see the new file pop up in the Solution Explorer.


But we also see a new file pop up in the File Explorer for the project.


Now we have 2 separate copies of the "Person.cs" file. If we make changes to one file, it will not be reflected in the other.

If we only want 1 physical file that appears to multiple projects, we can use a linked file instead.

Linking Files
The problem I always have with linking files is that I forget how to do it. When I copy files from one project to another, I usually do the "Copy"/"Paste" options that show up in the right-click menu (or with the keyboard shortcuts).

When I want to link a file, I copy the file to my clipboard and the look for a "Paste Special" or something similar on the right-click menu. That doesn't exist. Then I have to try to remember how to do it. So here it is.

This time we will link to the "Person.cs" file in the "A-SourceLibrary" project in the "C-LinkedFiles" project.

As we saw above, we just need to right-click on the destination project ("C-LinkedFiled") and choose "Add" then "Existing Item..."


Then in the dialog, locate the source file in the "A-SourceLibrary" folder.


Then use the drop-down on the "Add" button to choose "Add As Link".


This adds a link to the file in the destination project. We can see that the "Person.cs" file shows up as part of the "C-LinkedFiles" project in Visual Studio.


But if we look at the file system, the "C-LinkedFiles" folder does *not* have a "Person.cs" file.


When we look at the Solution Explorer, we can see that there is a different icon for the linked file compared to the copied file (and the original file):


What we have done is create a reference in one project to a file in a different project. So if we make changes in one location, it is reflected in both.

Why Would We Want to Link Files?
So why would we want to do this? Usually if we want to use an existing class, we would reference that assembly and use it directly. This avoids duplication. And this is what I do when I can.

But in this scenario, we have 3 different class libraries all with different targets. In this case, we may not be able to reference one assembly from another. This example is a bit contrived, so let's explore something a little more realistic.

Transitioning to .NET Core
We are in a bit of a transition period with .NET. As of today, .NET Core 3.0 is still coming (it will be released on September). With .NET Core 3.0, we also get .NET Standard 2.1.

But most people have a lot of applications that are .NET Framework. If I have a .NET Framework 4.7.2 project, I will not be able to use a .NET Standard 2.1 library (only .NET Standard 2.0). While I'm moving my projects from .NET Framework 4.7.2 to .NET Core 3.0, I may want to set up some interim projects to help with the transition.

So I could create a .NET Standard 2.1 class library with the intention that this will be the library referenced by the .NET Core 3.0 project. And then I can create a .NET Standard 2.0 project (that links to the files in the .NET Standard 2.1 project) that I can use today with the .NET Framework project.

For anything that doesn't match up (for example, I might be using additional APIs in the .NET Standard 2.1 project -- like Task.IsCompletedSuccessfully), I can copy files and make custom shivs that will get me through the transition period.

Shared Libraries
Another place where linked files can come in handy is if we create shared libraries (or NuGet packages) that will be used in different environments. We may need code that is a bit different for each environment, but we can use linked files to share what we can.

WPF on .NET Core 3.0
Another place this is useful is when transitioning WPF from .NET Framework to .NET Core. Right now, the WPF designers in Visual Studio are not quite complete for .NET Core. (I'm hoping things will be awesome when it comes to release time.)

To help with the transition, we can have *both* a WPF .NET Framework project and a WPF .NET Core project. We can put our production forms (XAML) in the .NET Core project and link the files to the .NET Framework project.


Then we can use the XAML designer in the .NET Framework project and build/run the .NET Core project.

We only have one set of files to worry about.

Linking Files is Useful
Linking files is really useful. I used to do this quite a bit back in the Silverlight days (boy, I feel old now). Each class library would link to the same source files (sometimes with #if/#endif directives for conditional compilation).

When I got started experimenting with WPF on .NET Core 3.0, someone gave me the advice to link files to get the designers like mentioned above. That was great except that I completely forgot how to link files. So I dropped this here mainly for me to remember later.

Keep learning, and find somewhere to log the things you forget. Then you will have them available to you the next time.

Happy Coding!

5 comments:

  1. All fine and good until you move the folder. Then you have to readd all the files by hand. If there are a thousand files.. might as well use another ide.

    ReplyDelete
  2. Must have used some form of VS for 20 years. And I didn't know you could do that in the UI. I've always just edited the csproj.
    Thanks!

    ReplyDelete
  3. thanks for this I just learnt a heap as a beginner here

    ReplyDelete
  4. This was very helpful, thank you :)

    ReplyDelete
  5. Amazing, thank you! I was completely missing the dropdown on the add button :) In previous versions you could drag and drop while holding alt for the same result but they seem to have removed that for some reason

    ReplyDelete