I have a project that I publish as MyNuget package in a local feed. The project references a ThirdPartyNuget that has ThirdPartyExtensions public static class with public extension methods over IQueryable.
Now, in my main solution I reference MyNuget and DO NOT reference ThirdPartyNuget. Still, Visual Studio 2022 shows the extensions methods from ThirdPartyExtensions. Why?
I do not expect this as I consider ThirdPartyNuget the implementation detail of MyNuget.
The assemblies in ThirdPartyNuget are obfuscated and ThirdPartyExtensions class looks weird as it has no namespace. Here is what I see in the debugger:
typeof(ThirdPartyExtensions).Name == typeof(ThirdPartyExtensions).FullName == "ThirdPartyExtensions"
typeof(ThirdPartyExtensions).Namespace == null
typeof(ThirdPartyExtensions).GUID == {00000000-0000-0000-0000-000000000000}
What's the mechanics of this behavior?
How do I hide the visibility of ThirdPartyExtensions in my main solution?
If you use PackageReference format for your package dependencies,
PrivateAsset tag in your MyNuget .csproj may do the trick.
https://learn.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#controlling-dependency-assets
You might be using a dependency purely as a development harness and might not want to expose that to projects that will consume your package. In this scenario, you can use the PrivateAssets metadata to control this behavior.
<PackageReference Include="ThirdPartyNuget" Version="1.0.0">
<PrivateAssets>compile</PrivateAssets>
</PackageReference>
Or you can use developmentDependency in packages.config as described in this question:
Don't include dependencies from packages.config file when creating NuGet package
In terms of question: "why public dependencies is the default way?", I would say: It makes life easier.
It's easier to consume packages with public dependencies. And it's easier to make them public if it's default behavior.
For example, many packages for web development depended on Newtonsoft.json. And to configure serialization, it was needed to expose it. Another opinion about that.
Probably guys from MS have some statistics about it. But I didn't see any articles about that. They only recommend it as the default way.
In terms of your case, I'am not sure that I correctly reproduced it.
In my test I've created three projects:
One subPackage with empty default namespace.
One package with reference to SubPackage with PrivateAssets attribute.
And project, which references Package, but not references SubPackage.
It doesn't compile if I try to use extensions.
But prints '2' in runtime, if I use GetNumber method.
And if I've understood question correctly it's the desired result.
But I'm not sure, will it work for your patched ThirdPartyNuget package or not.
If you don't declare a namespace for your class, then the default global namespace is used.The global namespace is the namespace that contains namespaces and types that are not declared inside a named namespace. See here.
You can see classes which are not have namespace using global keyword. The global keyword is the global namespace alias only when it's the left-hand identifier of the :: qualifier.For more information read here
In my main solution I reference MyNuget and DO NOT reference ThirdPartyNuget. BUT your MyNuget referenced to ThirdPartyNuget. It means, your project will be referenced to ThirdPartyNuget as well.
It is not possible to hide the visibility of extensions, BUT...
Your expectation and goal is looks strange. Hovewer, you can do something like this:
If your goal is: do not allowing to use that extensions method in your projects that uses MyNuget you can create the same extensions classes with empty namespace. For example, ThirdPartyNuget project has this extension (without namespace):
public static class ThirdPartyExtensions
{
public static void DoSome(this string value)
{
//Do some
}
}
Just create the same class in MyNuget and try to use this in your project. You will get ambiguous error from compiler :).
So, it will not hide it, but it will not allow to use this extension
Related
I am currently playing around with the latest Visual Studio 2017 Release Candidate by creating a .NET Standard 1.6 library. I am using xUnit to unit test my code and was wondering if you can still test internal methods in VS2017.
I remember that you could add a line in AssemblyInfo.cs class in VS2015 that would enable specified projects to see internal methods:
[assembly:InternalsVisibleTo("MyTests")]
As there is no AssemblyInfo.cs class in VS2017 .NET Standard projects, I was wondering if you can still unit test internal methods?
According to .NET docs for the InternalsVisibleToAttribute:
The attribute is applied at the assembly level. This means that it can be included at the beginning of a source code file, or it can be included in the AssemblyInfo file in a Visual Studio project.
In other words, you can simply place it in your own arbitrarily named .cs file, and it should work fine:
// some .cs file included in your project
using System.Runtime.CompilerServices;
[assembly:InternalsVisibleTo("MyTests")]
As described here:
https://blog.sanderaernouts.com/make-internals-visible-with-new-csproj-format
It is possible to add the internal visible attribute within the project file by adding another ItemGroup:
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>$(AssemblyName).Tests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
or even:
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>$(MSBuildProjectName).Tests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
I like that solution because the project file seems to be the right place for defining such concerns.
While the first answer is perfectly fine. If you feel you still want to do this in the original AssemblyInfo you can always choose to not auto generate the file and add it manually.
<PropertyGroup>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
For more information:
https://stackoverflow.com/a/47075759/869033
The "InternalsVisibleTo" attribute is key to any sort of "white-box" (the term of the decade, I guess) testing for .Net. It can be placed in any c# file with the "assembly" attribute on the front. Note that MS DOCs say that the assembly name must be qualified by the public key token, if it is signed. Sometimes that does not work and one must use the full public key in it's place. Access to internals is key to testing concurrent systems and in many other situations. See https://www.amazon.com/xUnit-Test-Patterns-Refactoring-Code/dp/0131495054. In this book, Meszaros describes a variety of coding styles that basically constitute a "Design For Test" approach to program development. At least that's the way I've used it over the years.
ADDED:
Sorry, I haven't been on here for a while. One approach is called the "testing subclass" approach by Meszaros. Again, one has to use "internalsvisableto" to access the base class's internals. This is a great solution, but it doesn't work for sealed classes. When I teach "Design For Test", I suggest that it's one of the things that are required to be "pre-engineered" into the base classes in order to provide testability. It has to become almost a cultural thing. Design a "base" base class that is unsealed. Call it UnsealedBaseClass or something uniformly recognizable. This is the class to be subclassed for testing. It is also subclassed to build the production sealed class, which often only differs in the constructors it exposes. I work in the nuclear industry and the testing requirements are taken VERY seriously. So, I have to think about these things all the time. By the way, leaving testing hooks in production code is not considered a problem in our field, as long as they are "internal" in a .Net implementation. The ramifications of NOT testing something can be quite profound.
Another way is to use a 'wrapper' TestMyFoo public class inside the target project that has public methods and inherits from the class you need to test (e.g. MyFoo). These public methods simply call through onto the base class you want to test.
It is not 'ideal' as you end up shipping a test hook in your target project. But consider modern reliable cars ship with diagnostic ports and modern reliable electronics ship with a JTAG connection. But nobody is silly enough to drive their car using the diagnostic port.
I have been implementing this solution explained here to make an outlinedTextbox.
I have created a test project and added directly in the main namespace and it works.
Now I want to add it to a library (HelperLib) and want to use it in whatever program of mine I want. For example here the program is called pcdLoggerS2.
but when I add it to my xaml it says that
so it's a matter of namespaces.
Therefore I have add this
xmlns:local="clr-HelperLib"
in my definition of my Base:WindowViewBase but nothing has changed but it's really in that namespace!
--ADD FOR DAVID---
You need to make sure that you've added the HelperLib project as a reference to your test project.
Open PcdLogger and right click on References, and add that project as a reference. Until you do this, the XAML in your test project will not be able to find the correct assembly.
Additionally, when you reference a namespace, from another assembly, you need to add that information to the namespace declaration in your XAML.
(See: https://msdn.microsoft.com/en-us/library/bb514546%28v=vs.90%29.aspx)
As an example:
(I would suggest leaving local for your local namespaces)
xmlns:helper="clr-namespace:HelperLib;assembly=HelperLib"
EDIT:
Additionally, Visual Studio's intellisense is fond of telling you that the namespace, or class, does not exist until you have built the project. You may have to rebuild and/or close/reopen the xaml file for intellisense to cooperate again.
check Namespace of you class.
HelperLib its name of a class, but not namespace.
Try to write this:
xmlns:local="clr-namespace:HelperLib"
I'm building a class library with some utility functions that any of my projects can access. I need to be able to use some classes within the System.Net namespace, like WebHeaderCollection. Unfortunately, Visual Studio doesn't find them, and doesn't give me the option to resolve them by adding the correct using directive.
Not even after explicitly having added System.Net does it find the reference. What am I doing wrong?
UPDATE:
I solved the problem. I had created a Class Library (Package) (used
for NuGet, where you edit the references in project.json instead of
going the Add Reference... route). This time I created a regular Class Library (in the Windows category) instead and references now work like a charm.
Check the documentation. That object is in the System.Net.Requests assembly:
I want to flag one of my methods with the StringFormatMethod attribute so Resharper syntax highlights it.
I was able to do this by referencing the JerBrains.Annotations assembly and adding the attribute.
However I find this to be a very invasive way to do this. Not everybody here uses JetBrains and it will require committing the .dll to subversion, adding the dependency and littering the code with something that is specific to a particular IDE, which I hate.
I read about the "external annotations" feature, but I wasn't able to do it. I'm not sure if I did it wrong or if it's simply not supported for a project inside the solution (i.e not a compiled assembly reference).
So is there a way to add a code annotation to a method in the project in a non-invasive way?
P.S this is the method:
using System;
namespace MyLib
{
public static class Assert
{
public static void That(bool condition, string format, params object[] #params)
{
if (!condition)
throw new Exception(string.Format(format, #params));
}
}
}
And this is the contents of
C:\Program Files (x86)\JetBrains\ReSharper\v7.1\Bin\ExternalAnnotations\MyLib.xml:
<assembley name="MyLib">
<member name="MyLib.Assert.That(System.Boolean,System.String,System.Object[])">
<attribute ctor="M:JetBrains.Annotations.StringFormatMethodAttribute.#ctor">
<argument>format</argument>
</attribute>
</member>
</assembley>
Just to sum up possibilities:
You reference nuget Jetbrains.Annotations, and DO NOT define JETBRAINS_ANNOTATIONS:
Such annotations are useful only for developers working with source code, they are not compiled in your binary (Conditional statement is used) and they are not visible when referencing your dll. You can even add developmentOnly="true" attribute to Jetbrains.Annotations in packages.config, so by default it would not be treated as dependency.
You reference as above but define JETBRAINS_ANNOTATIONS:
now you have real binary dependency and Jetbrains.Annotations.dll must be either distributed with your library or it must be downloaded as nuget dependency.
You copy annotations with internal checked (so client code would not use them), into "YourLib.Annotations": They then embedded into your lib and available for other developers even when they use only binary version.
You provide external annotations: for bigger libraries/more attributes this can also consume 40k, it is separate file, and generally it is less trivial to create/consume.
I personally went with third option (for shared libraries, projects usually just use nugets)
You don't have to reference the assembly to add annotation attributes. As per the documentation, you can go to ReSharper/Options/Code Annotations, copy the attribute implementations to the clipboard, and paste them into your own source, where ReSharper will use them. You can even change the namespace they're in if you'd prefer not to have JetBrains in your assembly.
I don't know whether you'll have any luck using external (XML) annotations for source code, though. I get the impression they're only for existing binaries. That said, I think that decorating your source with attributes is quite valuable as a source of documentation for yourself and other developers.
Don't know if it helps, but the element name <assembley> is misspelled (unless they actually used that in the schema). Should be <assembly>.
(Yet another question from my "Clearly I'm the only idiot out here" series.)
When I need to use a class from the .NET Framework, I dutifully look up the documentation to determine the corresponding namespace and then add a "using" directive to my source code:
using System.Text.RegularExpressions;
Usually I'm good to go at this point, but sometimes Intellisense doesn't recognize the new class and the project won't build. A quick check in the Object Browser confirms that I have the right namespace. Frustration ensues.
Using HttpUtility.UrlEncode() involved adding the appropriate directive:
using System.Web;
But it also required adding a reference to .NET Framework Component for System.Web, i.e. right-click the project in Solution Explorer, select Add Reference and add System.Web from the .NET tab.
How might I discern from the documentation whether a .NET namespace is implemented by a .NET Framework Component that must be referenced? I'd rather not hunt through the available components every time I use a namespace on the off chance that a reference is needed.
(For those who like to stay after class and clean the erasers: Will Organize Usings > Remove and Sort also remove references to componenents that are not used elsewhere in the project? How do you clean up unnecessary references?)
Check out this link for UrlEncode:
Namespace: System.Web
Assembly: System.Web (in System.Web.dll)
The Assembly line tells you which dll to reference.
You'll note that the documentation (e.g. http://msdn.microsoft.com/en-us/library/system.web.httputility.aspx) tells you the name of the assembly/DLL that the class should be found in, along with the class's namespace.
Namespace: System.Web
Assembly: System.Web (in System.Web.dll)
On a side note, I know it can be a little dear, but Resharper makes things like this so much easier. If you're a serious developer, you may want to consider investing in a license. For the eraser-cleaners, Resharper adds a handy little "Find Code Dependent on Module" item to the right-click menu on references in the Solution Explorer. It's not quite an automatic cleanup, but it makes it a lot easier to see whether something's still being used by your project.
The documentation specifies two things for any type:
The namespace of the type (for the using directive)
The assembly containing the type (this is what you add a reference to)
To take an example where the two are different, look at the documentation for Enumerable:
Namespace: System.Linq
Assembly: System.Core (in System.Core.dll)
If you look at the MSDN docs, e.g.
http://msdn.microsoft.com/en-us/library/system.web.httputility.aspx
It tells you the namespace and the assembly that is required.
First, a correction to your terminology: What you are referencing is called an "assembly". An assembly contains classes that belong to a namespace. A namespace can span across multiple assemblies.
Most assemblies are named the same as the main namespace that is contained in them. For example, System.Web exists in System.Web.dll. The documentation also usually tells you which assembly needs to be referenced.
I think that you are running into a difference between c# and C here. To compare: In C, all you need to do to include a new library is to include it in the header.
It .net, you need to be aware of 2 things:
A namespace can span more than one assembly/dll (that means that you might not get a compiler error on the using clause, because some of the dlls that support that namespace are referenced -- just not the one that you need)
To "see" the contents of a given assembly, you have to add a reference to it. The using clause alone just gives you some short-cut syntax so that you can write HttpUtility.Encode(), instead of System.Web.HttpUtility.UrlEncode(), you have to add the reference in order for the compiler to "know" about the class.
To avoid your problem:
In the MSDN documents, pay attention to the assembly that the class is in, and make sure that you have a reference to the assembly.
If you browse to the MSDN for the class you're trying to use. It typically tells you the assembly that the class is in. For example the Regex class is in Assembly System (in System.dll) or the HttpUtility class is in Assembly System.Web (in System.Web.dll).
I believe tools such as ReSharper help with this, as well, and automatically references the assemblies you need.
I'm pretty sure you have to manually remove the unused references in C# projects. In VB.NET projects there's a button to list the unused references when you're in the project properties page. I don't see this in C# projects, though.