I have the following projects in my solution (the tree structure indicate which projects reference which other projects):
A (.NET Core Web API, C#)
B (.NET Standard class library, C#)
X (.NET 4.0 class library, VB)
Y (.NET 4.0 class library, VB)
Z (.NET 2.0 class library, VB)
The only projects that should be managed from this solution are A and B. B uses some methods from X (which comes from elsewhere in our company), while X depends on Y which again depends on Z. All references are project references. (In reality, the hierarchy below X is wider/deeper, but the above serves to get the point across.)
I don't want to have unnecessary projects in my solution (which slows things down). At the same time, I want to have VS compile all dependencies in the correct order. AFAIK, all necessary information exists in the csproj/vbproj files, so I don't see a technical reason why VS shouldn't be able to do this if I just add X to the solution. But I can only get it to work if I add the entire tree below X.
Is there any (sensible) way to set up compilation of all dependent projects without adding the entire project hierarchy to the solution, or is this the way it's supposed to work?
Related
I created a new .NET Core 1.1 solution and noticed an odd behavior: if I create multiple projects in the solution and chain-reference them, I'm able to freely access types located in a dependency of a dependency, any level down.
This is an example:
We have a Sandbox solution, a Baz class library project, a Bar class library project referencing Baz and a Foo console app project referencing Bar.
From the Foo project I'm able to access and use BazThing, a type defined in the Baz project, even though Foo doesn't have a reference on Baz.
This works with NuGet packages too: if I add Entity Framework to Baz through NuGet I'm able to use the DbContext type in the Foo project.
This is a huge problem when the projects are used to implement layer segregation.
Developers are now allowed to access and use implementation details of the dependencies or bypass layer segregation, both "maliciously" and by mistake (in the above mentioned example, IntelliSense will happily suggests to use BazThings when typing ba without any warning).
Is this how things will work from now on, or are we missing something?
Is it possible to prevent/inhibit this behavior somehow?
Where can I find documentation about this behavior?
That is intended behavior of modern NuGet/msbuild. It is called meta-packages/transitive dependencies and used for example for the NETStandard.Library package to include all libraries of the base class library. I do not think there is a way hiding them. Expect this feature to be added to full .NET Framework projects within the next releases of VS.
Aside of your questions, my personal opinion here is that hiding artifacts behind reference trees is maybe useful at first sight but does not bring any architectural benefit. A loaded assembly can be invoked. One way or the other. Layering, layer bridging and adherence to architecture can be only teached/learned/reviewed/documented. Teach the devs but do not build walls around them. Discipline should not be enforced by the artifacts but by the devs themselves.
I currently have a single Xcode project for a very large code base, I'll call it Project X, which I am dividing into a bunch of sub projects ( Projects A, B, C ).
So far, each of these projects compiles, on their own, just fine. They all produce static libraries. Project B and Project C are dependent on the static library produced by Project A in order to build.
I have another xcode project, Project Z, that requires the static libraries produced by Projects B and C. Herein lies the problem. When Project Z enters the linker phase, things blow up - duplicate symbols are found within the libs for Projects B and C for the code they originally linked against in Project A!
I'm pretty new to the world of static libraries, and I'm unsure of how to move forward with Project Z, or how to modify the other projects so that they are linking against the same Project A lib. I have a feeling it's not possible. What are my options here?
Edit:
I should clarify that Project B and Project C need to build into separate static libs because some clients will only require one or the other.
Also, I'm having this dilemma on both OSX and iOS platforms.
I realize that I could solve this problem on OSX by building the projects as dynamic libraries. However, I'd prefer not to do this, and it still leaves me with same issue on iOS.
Static libraries should never include other static libraries (or third party code in general). A static library is just a bundle of .o files glued together. So if you have multiple copies of the same information, it's going to blow up.
Each static library should just have its own code in it. The final application is responsible for linking all the required libraries together (including libraries required by libraries). This way there is exactly one copy of each thing linked.
This sounds like exactly the sort of problem CoacoaPods was created to solve. If you define pods for each of theses projects then Z should be able to determine and link against all of its dependencies all the way up the chain without introducing duplicate symbols.
I have a function defined in a module called DataAccess like this
module DataAccess
let getData() =
["abc";"def"]
I'm then using an F# MVC controller to pull the data out like this
[<HandleError>]
type FitnessController() =
inherit Controller()
member x.Index() =
let data = DataAccess.getData() |> List.map(fun p -> p) |> List.toArray
x.View(data) :> ActionResult
I get intellisense and all builds well, but when the web page pops up it says that the method does not exist
Method not found: 'Microsoft.FSharp.Collections.FSharpList`1<Models.Entity> DataAccess.getData()'.
When I take a look at the assembly in dotPeek it does show up as a static method that returns an FSharp list. Am I missing something obvious here?
(Ignore the fact that getData and the map function do nothing i've omitted the code for brevity, getData just contains record types that are marked as serializable, but I still get the error even when using strings as in the code example here) I should also say that this is MVC 3 with Razor C# pages.
Do you have DataAccess and FitnessController defined in the same assembly or different assemblies?
If they are defined in different assemblies then this error is almost certainly caused by the assembly that contains FitnessController being compiled against one version of the assembly that contains DataAccess but at runtime a different version is loaded.
This could happen for a number of reasons, the two that I can think of off the top of my head are:
a version of the assembly containing DataAccess is deployed to the gac. The .NET assembly loader always uses the version deployed in the GAC if it exists and it's fairly easy for the version in the GAC to get out of sync with the latest development version.
the version of the assembly containing DataAccess isn't being copied into the bin directory of the asp.net project when your code is compiled.
Is this happen in your development environment or in production? If it's in your development environment it should be fairly easy to debug, simple run the project in debug mode then use the Debug > Windows > Modules window to see where the two assemblies are being loaded from. Once you know that it should be fairly easy to see where the problem comes from.
Alternatively it may just be easier DataAccess and FitnessController into the same assembly.
Our project uses several NuGet packages, a few of which reference LinqBridge, a library that re-implements LINQ to Objects for C# 2.0. The LinqBridge.dll file lives under /packages/PackageName/lib/20/LinqBridge.dll, so it clearly is supposed to only apply to .NET 2.0.
The problem is that, even though every project in the solution is configured to build to .NET 4.0, the LinqBridge.dll binary gets copied over to the final /bin directory and wreaks havoc in Razor views. If I perform .Select() on an IEnumerable, there is an ambiguous call between the built-in LINQ call and the re-implemented one that LinqBridge provides.
I clearly do not need the re-implemented version; if I simply delete LinqBridge.dll from the output /bin directory, everything works just fine. However, that is not an acceptable permanent solution.
Is there any way I can configure something to quit copying that file, which is for an old .NET version, into the /bin output?
Edit: I duct-taped together a solution by adding this to the "Post-build event command line:" commands under "Build Events" in my solution properties:
del $(SolutionDir)\bin\LinqBridge.dll
It's still far from ideal, but at least it lets my project run for now.
NuGet has support for different binaries for different .NET versions so I would suggest that the packages you are using are built badly.
I would contact the authors of the packages and see if they can fix them so that only the net11 or net20 versions include LinqBridge.
Supporting Multiple .NET Framework Versions and Profiles
Many libraries target a specific version of the .NET Framework. For example, you might have one version of your library that's specific to Silverlight, and another version of the same library that takes advantage of .NET Framework 4 features. You do not need to create separate packages for each of these versions. NuGet supports putting multiple versions of the same library in a single package keeping them in separate folders within the package.
(more...)
A useful approach we found was using the LinqBridge.Embedded Nuget package instead of the standard LinqBridge package. This embeds Linqbridge as a C# file within your project, and hence does not get copied over to the bin folder and loaded into the context of the Razor view.
This was useful to us because an assembly we reference still needs to be built in .Net 2.0, as it is also referenced by a 2.0 application. Hence that assembly uses LinqBridge.Embedded, and the LinqBridge assembly does not end up in our 4.0 servers' bin folders.
We upgraded our .net 3.5 projects (c#) to .net 4.0. When you look at the project file there are two tags that I'm trying to make sense out of:
<RequiredTargetFramework>3.5</RequiredTargetFramework>
<TargetFrameworkVersion>4.0</TargetFrameworkVersion>
Why are there two seemingly similar tags with different values?
The <RequiredTargetFramework> element was already present in your 3.5 project. It's associated with the assembly <Reference> and only present on assemblies that are not available in .NET 2.0
I don't buy much stock in the single mention of it in MSDN, I don't see how batch building has anything to do assembly references. Nor is it used in any of the 3.5 MSBuild .target files. I think the IDE simply uses it to put the warning icon next to the reference in the References node when you change the Target Framework to a version less than what's needed to support the assembly.
There are other elements like this in a project file that don't affect MSBuild but have an effect in the IDE. Like <SubType> and <DependentUpon> in the <Compile> element.
Have you found this one link? link text. TargetFrameworkversion is easy, that's the one you can change in the project properties to say which framework to build against. The article says that RequiredTargetFramework is used to batch items (but it's still not clear on it' real purpose other than it's not used a lot)
batches the Reference items by their RequiredTargetFramework metadata. The output of the target looks like this:
Reference: 3.5;3.5
Reference: 4.0
Target batching is seldom used in real builds. Task batching is more common. For more information, see MSBuild Batching.