Live Dependency Validation in Visual Studio 2017
Last month we announced that Visual Studio “Dev15” Preview 5 now supported Live Dependency Validation. In this blog post,
- I’ll give you an update about:
- an on-demand //connect 2016 video we’ve recorded about Live Dependency Validation
- improvements in the experience in Visual Studio 2017 RC
- known issues: what did not make it for RC, but will be available in RTM
- Then I’ll provide a bit more details on:
- error codes for the dependency validation errors
- differences between Layer validation in Visual Studio 2010-2015 and the live dependency experience in Visual Studio 2017
- Finally, I’ll share a couple of tips in order to author dependency validation diagrams
On demand video about dependency validation
During the connect 2016 event, we’ve proposed an on-demand video which explains in detail why you’d want to use Dependency Validation and how to do so Validate architecture dependencies with Visual Studio. The video contains a quick review of the topic – unwanted dependencies are part of your technical debt. Then I remind you of what the experience was in previous versions of Visual Studio Enterprise, and show how this could be improved, I demo the new-real time dependency validation experience that you, as a developer, will benefit from in Visual Studio 2017. I also demo how easy it is to create a dependency diagram. Finally, I describe how users using the current experience can migrate to the new oneI encourage you to watch this 10 mins video, which will give you a good overview of the scenario and the feature.
Updates on the experience improvements
The demos in the video were done with Visual Studio 2017 RC. We had fixed a number of bugs since “Preview 5” and improved the user experience:
- When upgrading projects to enable live validation, a dialog now expresses progress,
- When updating a project for live dependency validation, the version of the NuGet package is now upgraded to be the same for all projects (and is the highest version in use),
- VB.NET is now fully supported on par with C#,
- The addition of a new Dependency Validation project now triggers a project update,
- The dependency validation Roslyn analyzer is now better:
- It’s less verbose as we no longer report when you declare an implicitly-typed variable (var in C#). Because the type of the variable is guaranteed to be the same as the type on the right-hand side we were effectively reporting the same error twice
- It now reports on delegate invocations.
- You are now advised to enable “full solution analysis” when using live dependency validation: a gold bar appears in the Error List, and opens the options page pointing you at the option to enable or disable the “full solution analysis” (for C#, and VB). You can permanently dismiss this gold bar if you are not interested in seeing all the architectural issues in your solution.If you don’t enable “full solution analysis” the analysis will only be done for the files being edited (this behavior is common to all Roslyn analyzers).
We were not able to fix everything for RC but we are still working on it. The experience will be even better for RTW. In Visual Studio 2017 RC:
- saving a dependency Validation diagram no longer triggers the analysis. This is annoying because if you want to see immediately the effect on the issues in the code, of changing the diagram, the only workaround is to close and reload the solution.
- the experience is not very good when you enable the “Lightweight Solution load” option.
- deleting a dependency validation diagram does not remove the corresponding links from C# and VB projects.
These have all been fixed for RTW.
Real time Dependency Validation error messages
It’s now possible to click on the error code for a dependency validation error message and get an explanation of the issue. The figure below shows the default severity of the rules in the ruleset editor
For your convenience, I’ve summarized, in the table below, in which condition you will have which error.
|Error Code||When is it reported?|
|DV0001||Invalid Dependency. This issue is reported when a code element (namespace, type, member) mapped to a Layer references a code element mapped to another layer, but there is no dependency arrow between these layers in the dependency validation diagram containing this layers. This is a dependency constraint violation|
|DV1001||Invalid namespace name. This issue is reported on a code element associated with a layer which “Allowed Namespace Names” property does not contain the namespace in which this code element is defined. This is a naming constraint violation.|
Note that the syntax of “Allowed Namespace Names” is to be a semi-colon list of namespaces in which code elements associated with are layer are permitted to be defined.
|DV1002||Dependency on unreferenceable namespace. This issue is reported on a code element associated with a layer and referencing another code element defined in a namespace which is defined in the “Unreferenceable Namespace” property of the layer. This is a naming constraint violation.|
Note that the “Unreferenceable Namespaces” property is defined as a Semi-colon separated list of namespaces that should not be referenced in code elements associated with this layer
|DV1003||Disallowed namespace name. This issue is reported on a code element associated with a layer which “Disallowed Namespace Names” property contains the namespace in which this code element is defined. This is a naming constraint violation.|
Note that the “Disallowed namespace name” property is defined as a Semi-colon separated list of namespaces in which code elements associated with this Layer should not be defined.
Differences between Layer validation in Visual Studio 2010-2015 and Live Dependency Validation in Visual Studio 2017
Old layer validation issues vs new Dependency Validation issues
As we have explained last month, the Dependency Validation experience leverages the existing Layer diagram format with some improved terminology for the layer properties. The error messages generated by the Roslyn analyzers are similar, but we have used different error code because the results can be slightly different. The old issues have an error code starting with AV (Architecture Validation errors) whereas the new issues have an error code starting with DV (Dependency Validation errors).
Why can there be differences?
To be fair, you might not notice these differences, however, there is a case where you will. This is the case where you have a Visual Studio 2015 solution where you had enabled the legacy Layer validation. Then you migrate this solution, with Visual Studio 2017 Enterprise, to enable live dependency validation. You commit you changes. Later if you, or someone in your team, opens this solution with Visual Studio 2015, and build it, Visual Studio 2016 will start showing both the old issues (AV) and the new issues (DV). In most cases, they will be the same, but not always, so we thought it would be good to explain a bit more about the differences. The underlying reason for these differences is that the legacy validation (Layer) was being performed against the binary code, whereas the new validation is performed against source code. In the same way that you sometimes must add a reference to an assembly declaring a base interface for a class you use (whereas you don’t yourself reference this base interface), the compiler sometimes generates constructs which are not effectively used, but were drawing a dependency in binary, which is not visible in source code. So, the binary caught legacy validation issues which logically should not be there, whereas the new real time dependency validation won’t. This is a bit subtle, and cases are quite rare. (One case I met is when calling a method passing as a parameter a delegate which had an offending return type).
What dependency issues are caught in Live Dependency Validation?
Live Dependency Validation for assemblies, types, and namespaces is pretty simple: either they are allowed or they are disallowed. The case of generic types is more complex, but makes sense: it’s enough to have at least one unwanted generic type argument to report an issue on the generic type.
As far as members are concerned:
- Method declarations: we check the return type and the parameter types
- Method invocations:
- we check the parent type of the method being called
- we check the return type, even if it is ignored i.e. is not assigned to anything
- we do not check the types of parameters to a method
- However, we do check the values of arguments that are passed to a method. This means that if you pass an object which type is not allowed by at least one of the dependency diagrams in the solution, you will get an error. You won’t, however get an error if you pass null.
- Property reads and writes: we check the containing type and the return type i.e. they are a kind of method invocation
- Fields: we check the field type
For delegates, things get a little more complicated as sometimes we want to validate them as if they were a type, in others we want to validate them as is they were a method invocation.
Tips to author a Dependency Validation diagram
I’ll finish this blog post by sharing a tip on how to author Dependency Validation diagrams. You can, of course, add layers though the toolbox and map them to code elements using the Layer Explorer. But if you have an existing solution, you can do it quicker by Dragging and from Visual Studio explorers and dropping to a Dependency Validation Diagram. You might not know though that this can also be done by Copy/Paste or Drag and Drop from a Code Map
Drag and Drop from explorers
As shown in the video, a recommended way to add layers to a dependency validation diagram is to drag and drop assemblies, references, types and members from the solution explorer, the Class View or the Object Browser. It’s also possible to drag and drop namespaces from the Class View or the Object Browser (they are the only explorers showing namespace).
Drag and Drop or Copy / Paste from a Code Map
You might also be interested in creating a Dependency Validation diagram as corresponds to the solution. To do that you can:
- Generate a Code Map for Solution (from the Architecture menu)
- Personally, I use the Code Map Filter Windows to filter out solution folders and “Test Assets” (as I mostly care so about enforcing dependencies in product code).
- On the generated Code map, you may also remove the “External” node (or expand it to show external assemblies) depending on what you want to do. In the figure below I removed “External”. If you are interested in enforcing namespace dependencies as I did, you can expand the assemblies you care about (delete the other ones from the Code Map)
- Then finally when you are happy that you have the content you care about on Code Map, you can create a new Dependency Diagram (from the Architecture menu) select all the nodes from the Code Map (either by Ctrl+A, or by the rubber band selection, which you trigger by pressing the shift key before you click / drag / release the selection), and do a drag and drop or a copy paste to the new Dependency Validation diagram. You will (in RTM, and after doing a bit of manual layout) get the diagram as in the picture below.
- Note that in Visual Studio 2017 RC, you’ll need to press the Shift key to get one layer per Code Map node when doing the drag and drop. And you won’t see the dependencies. This was fixed for RTM.
- From there you have the current architecture, and you can decide what you want the architecture to be and modify the Dependency Validation diagram accordingly
As usual we’d love to hear your feedback. Don’t hesitate to send feedback directly from Visual Studio (Help | Send Feedback) to report a problem or provide a suggestion.