The problem is that there are 3 different agents that need these types - and they are all configured differently. Microsoft did a lot of work so that they all worked with the same files - but they didn’t provide reference files.
You have to explain everything to them yourself. And so, in order.
1. Visual Studio Editor
Visual Studio Editor simply cannot edit files outside the project folder. You need to make a separate project for shared files - and open these files only in it.
2. Local server
The local server hosts files directly from the project folder without reading the project file. Since there is really no file in this place, an error occurs.
To "train" the server to give files based on their presence in the project, and not on the disk - you can use the following class:
class ProjectFileProvider : VirtualPathProvider { private readonly string applicationVirtualPath = HostingEnvironment.ApplicationVirtualPath; private readonly string applicationPhysicalPath = HostingEnvironment.ApplicationPhysicalPath; private readonly Dictionary<string, ProjectFile> projectFiles; public ProjectFileProvider(string projectFile) { if (!applicationVirtualPath.EndsWith("/")) applicationVirtualPath = applicationVirtualPath + "/"; var project = XDocument.Load(Path.Combine(applicationPhysicalPath, projectFile)); var ns = project.Root.Name.Namespace; projectFiles = (from item in project.Root.Elements(ns + "ItemGroup").Elements() where item.Name.LocalName == "None" || item.Name.LocalName == "Content" let virtualPath = (string)item.Element(ns + "Link") ?? (string)item.Attribute("Include") let physicalPath = (string)item.Attribute("Include") select new ProjectFile(applicationVirtualPath + virtualPath, Path.Combine(applicationPhysicalPath, physicalPath))) .ToDictionary(file => file.VirtualPath, StringComparer.InvariantCultureIgnoreCase); } public override VirtualFile GetFile(string virtualPath) { if (virtualPath.StartsWith("~/")) virtualPath = applicationVirtualPath + virtualPath.Substring(2); ProjectFile file; projectFiles.TryGetValue(virtualPath, out file); return file; } public override bool FileExists(string virtualPath) { if (virtualPath.StartsWith("~/")) virtualPath = applicationVirtualPath + virtualPath.Substring(2); return projectFiles.ContainsKey(virtualPath); } public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies) { long hash = 0; foreach (string filepath in virtualPathDependencies) unchecked { hash = hash * 31 + filepath.GetHashCode(); var file = GetFile(filepath) as ProjectFile; if (file != null) { hash = hash * 31 + file.GetFileInfo().LastWriteTimeUtc.GetHashCode(); } } return hash.ToString("x"); } public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart) { var files = virtualPathDependencies.Cast<string>().Select(GetFile).Cast<ProjectFile>().Where(file => file != null).Select(file => file.PhysicalPath).ToArray(); return new CacheDependency(files, utcStart); } } private class ProjectFile : VirtualFile { public ProjectFile(string virtualPath, string physicalPath) : base(virtualPath) { PhysicalPath = physicalPath; } public string PhysicalPath { get; } public override Stream Open() => File.OpenRead(PhysicalPath); public FileInfo GetFileInfo() => new FileInfo(PhysicalPath); }
It simply connects:
if (HostingEnvironment.VirtualPathProvider.FileExists("~/Foo.csproj")) HostingEnvironment.RegisterVirtualPathProvider(new ProjectFileProvider("Foo.csproj"));
Important note This method works only for those files that are needed by ASP.NET. That is, all sorts of .aspx, .cshtml, .svc and other similar files fall here.
But the scripts and pictures are given to IIS directly, so this trick is not applicable to them.
3. Publication
When publishing your application, the build system collects all the files together to transfer them to the server. Here I wanted to write how to manually edit the csproj file for embedding in the publication pipeline - but suddenly it turned out that the publication system already supports links.
But there is a subtlety associated with the previous item. The fact is that the project file is not published. That is why in the last paragraph, I put a check on its availability.