Showing posts with label Ndepend. Show all posts
Showing posts with label Ndepend. Show all posts

Sunday, 22 September 2019

Looking into (circular) dependencies of MEF using C# and Ndepend - Migrating from MEF to Autofac

I decided to look into circular dependencies in C# using reflection and NDepend today. A circular dependency is problematic, especially if you are using dependency injection. In fact, if your system injects dependencies through constructors, if part A imports part B and vice versa - you will usually get a crash. To instantiate the part A we need part B, but that holds also for part A instantiating part B. A huge system I have been working on for years uses MEF or Managed Extensibility Framework. This is primarily an extension framework for allowing pluggable applications, such as seen in Silverlight. It also provides Inversion of Control and you can also import through constructors, that is - every type can decorate one constructor with the [ImportingConstructor] attribute. My system however uses property based injection. You can decorate a property with [Import] attribute and the type of the constructor will then create an instance of an object exporting itself as that type. You can import either concrete or interface based types, and it is also possible to specify a key for the import (string identifier). So the bad part about property based injections is that circular injections can creep up on you - the system will not crash - but it allows circular depedendencies to exist in your system. I created the following Unit Test to detect these circular dependencies.
        [Test]
        [Category(TestCategories.IntegrationTest)]
        public void OutputCircularDependencies()
        {
            var compositionParts = new List>CompositionPart<();
          
            foreach (var part in _aggregateCatalog.Parts)
            {
                var importList = new List>string<();
               
                foreach (var import in part.ImportDefinitions)
                {
                    if (import != null)
                    {
                        importList.Add(import.ContractName);
                    }
                }

                foreach (var export in part.ExportDefinitions)
                {
                    string exportType = null;
                    if (export.Metadata.ContainsKey("ExportTypeIdentity"))
                        exportType = export.Metadata["ExportTypeIdentity"].ToString();

                    string creationPolicy = null;
                    if (export.Metadata.ContainsKey("System.ComponentModel.Composition.CreationPolicy"))
                        creationPolicy = export.Metadata["System.ComponentModel.Composition.CreationPolicy"].ToString();
                    compositionParts.Add(new CompositionPart(part.ToString(), exportType, creationPolicy, importList));                   
                }             
            }

            foreach (var part in compositionParts)
            {
                //check each import if it imports this part
                foreach (var importPart in part.Imports)
                {
                    var matchingPart = compositionParts.FirstOrDefault(c =< c.Identity == importPart);
                    if (matchingPart != null)
                    {
                        if (matchingPart.Imports.Any(i =< i == part.Identity))
                        {
                            //Circular reference detected!
                            Console.WriteLine(@"Component {0} is circular dependent of component {1}", part.Name, matchingPart.Name);
                        }
                    }
                }
            }

            
        }
The code loops through the ComposablePart parts of the AggregateCatalog.Each part has ExportDefinitions (usually one export) and ImportDefinitions (often multiple imports). The first pass will then just gather up information for all the parts of the AssemblyCatalog and then loop through each part again and loop though its imports in an inner loop. If the imported part imports the part itself, we have a circular dpeendency. The test just outputs the circular dependencies to the console. I use the class CompositionPart to have a entity to contain some information about each composition part of the AssemblyCatalag instance. It is just a regular AssemblyCatalog in MEF, created like this:

        readonly AggregateCatalog _aggregateCatalog = new AggregateCatalog();
        CompositionContainer _container;

        [SetUp]
        public void CommonInitialize()
        {
            _aggregateCatalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetAssembly(typeof(SomeFeatureModule))));
            _aggregateCatalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetAssembly(typeof(SomeFeatureServiceAgent))));
            _aggregateCatalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetAssembly(typeof(SomeCommonUtil))));
            _aggregateCatalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetAssembly(typeof(SomeProvider))));           
            _container = new CompositionContainer(_aggregateCatalog);
            _container.ComposeParts();
        }

As we can see, the AggregateCatalog just consists of several assemblies in .NET. I rewrite the software to not use MEF and property based imports (i.e. properties decorated with the import attribute of System.ComponentModel.Composition.ImportAttribute) by looping through the parts of the AggregateCatalog and looking at the export definitions. The target is Autofac, which is a DI framework that offers dependency injection IMHO better than MEF ImportingConstructor, so analyzing the export defiitions, I can create a list of statements to migrate from MEF to Autofac.

        [Test]
        [Category(TestCategories.IntegrationTest)]
        public void OutputAutofacRegistrations()
        {

            var sb = new StringBuilder();

            foreach (var part in _aggregateCatalog.Parts)
            {
                string partName = part.ToString();

                if (part.ExportDefinitions != null)
                {
                    foreach (var export in part.ExportDefinitions)
                    {
                        string exportType = null;
                        if (export.Metadata.ContainsKey("ExportTypeIdentity"))
                             exportType = export.Metadata["ExportTypeIdentity"].ToString();                        
                        
                        string creationPolicy = null;
                        if (export.Metadata.ContainsKey("System.ComponentModel.Composition.CreationPolicy"))
                            creationPolicy = export.Metadata["System.ComponentModel.Composition.CreationPolicy"].ToString();
                        
                        string autofacExportDefinition = string.Format("builder.RegisterType>{0}<(){1}{2};", partName, 
                            !string.IsNullOrEmpty(exportType) ? ".As>" + exportType + "<()" : string.Empty,
                            !string.IsNullOrEmpty(creationPolicy) && creationPolicy.ToLower().Contains("nonshared") ? 
                            ".InstancePerDependency()" : ".SingleInstance()");
                        sb.AppendLine(autofacExportDefinition);

                        Console.WriteLine(autofacExportDefinition);
                    }
                    
                }

            }

I also used Ndepend as a supporting tool to look at visualizations of these dependencies. I had trouble detecting ImportingAttribute on properties (properties are methods in C# known as 'property getters' and 'property setters'), but at least I came up with the following CQLinq statements to look for all types that are decorated with the ExportAttribute (exporting parts) and Ndepend then got nice visualization of something called 'View internal dependency cycles on graph'. As Ndepend or my CQLinq skills lacking could not find the importing attribute decorated on properties (Ndepend does not fully support attribute detection on methods in an easy way yet - detecting attributes on types is easier), I ended up with the CQLinq below to at least list up the exporting classes and launching the graphical tool to look if the parts (classes) with circular dependencies was a hotspot in the source base, i.e. a class used by many other classes. The CQLinq below shows how to generate such a graph for revealing class interdepenencies - quite easy using Ndepend.
let exportingTypes = from type in JustMyCode.Types
where type.IsClass && type.HasAttribute("System.ComponentModel.Composition.ExportAttribute")
&& (type.FullNameLike("SomeAcme"))
let f = Types.ChildMethods().Where(m =< m.IsPropertyGetter)
select type
let typesAttributes = Types
from m in exportingTypes.UsingAny(typesAttributes).ChildMethods().Where(x =< x.IsPropertySetter || x.IsPropertyGetter)
let mAttributes = typesAttributes.Where(t =< m.HasAttribute(t)).ToArray()
where mAttributes .Length < 0
select new { m, mAttributes} 
So there you have some tips around how to migrate from MEF to Autofac and detect cyclic dependencies in your source code. Ndepend will be a good tool to have as a companion to the refactoring job when you want to migrate. I will suggest to first rewrite your application using importing constructors instead of property based imports and then fix up the cyclic dependencies. You can use the Lazy initializer for example. It will delay constructing a part of type T specified to fix up such circular dependencies. Or you could of course refactor the code such that part A and part B that imports eachother instead imports some other part C both.. There are different ways to fix it up. Once you have rewritten the software to use importing constructors and there are no circular dependencies, you can switch to Autofac. I showed you in the unit test OutputAutofacRegistrations how to do that. It outputs ContainerBuilder statements to build up a working Autofac IContainer with same kind of mesh of dependencies as in the MEF based application.

Monday, 15 July 2019

Using Ndepend to investigate method cycles

Ndepend is a very powerful Code analysis platform for DotNet and I have created a method cycle detection rule. The method cycle detection also supports property setters and getters. A cycle in a property or method will often cause problems, such as stack overflow exceptions due to too many recursive calls. Spotting such cycles can often be hard in real-world scenarios. A classic error is to actually do a cycle through a property getter, by just calling the getter once more or a property setter for that instance. The following C# attribute invokes a Rules extracted from Source code from Ndepend.

using System;
using NDepend.Attributes;

namespace Hemit.OpPlan.Client.Infrastructure.Aspects
{
    /// Ndepend attribute to enable cyclic loops in methods in the source code 
    [CodeRule(@"// <Name>Avoid methods of a type to be in cycles. Detect also recursive property setter calls</Name>
warnif count > 0

from t in Application.Types
                 .Where(t => t.ContainsMethodDependencyCycle != null && 
                             t.ContainsMethodDependencyCycle.Value)

// Optimization: restreint methods set
// A method involved in a cycle necessarily have a null Level.
let methodsSuspect = t.Methods.Where(m => m.Level == null)

// hashset is used to avoid iterating again on methods already caught in a cycle.
let hashset = new HashSet<IMethod>()


from suspect in methodsSuspect
   // By commenting this line, the query matches all methods involved in a cycle.
   where !hashset.Contains(suspect)

   // Define 2 code metrics
   // - Methods depth of is using indirectly the suspect method.
   // - Methods depth of is used by the suspect method indirectly.
   // Note: for direct usage the depth is equal to 1.
   let methodsUserDepth = methodsSuspect.DepthOfIsUsing(suspect)
   let methodsUsedDepth = methodsSuspect.DepthOfIsUsedBy(suspect)

   // Select methods that are both using and used by methodSuspect
   let usersAndUsed = from n in methodsSuspect where 
                         methodsUserDepth[n] > 0 && 
                         methodsUsedDepth[n] > 0 
                      select n

   where usersAndUsed.Count() > 0

   // Here we've found method(s) both using and used by the suspect method.
   // A cycle involving the suspect method is found!
   let cycle = System.Linq.Enumerable.Append(usersAndUsed,suspect)


   // Fill hashset with methods in the cycle.
   // .ToArray() is needed to force the iterating process.
   let unused1 = (from n in cycle let unused2 = hashset.Add(n) select n).ToArray()

let cycleContainsSetter = (from n1 in cycle where n1.IsPropertySetter select n1).Count()

  
select new { suspect, cycle, cycleContainsSetter }",
        Active = true,
        DisplayStatInReport = true,
        DisplayListInReport = true,
        DisplaySelectionViewInReport = true,
        IsCriticalRule = false)]
    public class MethodCycleDetectionAttribute : Attribute
    {
    }
}


Note that this Ndepend Code rule uses the CQLinq syntax placed into a C# attribute class that inherits from Attribute and itself is attributed with a Ndepend.Attributes.CodeRuleAttribute. I had to adjust the attribute a little bit using the ExtensionMethodsEnumerable fix for .Net 4.6.2 mentioned on Ndepend blog post here: https://blog.ndepend.com/problem-extension-methods/ The following screen shot shows Visual Studio 2019 with Ndepend version 2019.2.5 installed. It shows the method cycle detection code rule I created showing up as a code rule through source code. Selecting that code rule in the menu Ndepend => Rules Explorer that selects Queries and Rules Explorer allows to not only view the code rule but quickly see the code analysis results.
One method cycle I have is shown in the following image, the method ProcessPasRequest of my system. This case shows how advanced Ndepend really is in code analysis. It can detect transitive cycles with multiple function calls. The following two screen shots shows the cycle in question. In this case, it was not a bug, since the cycle will only happend a finite amount of times for a given set of patients, but it still can go into an infinite loop if the external system is not working correct. However in this case, if that external system is not working, the system I have been working with also faults as it relies on that external system. With Ndepend I could spot method cycles with transitive cycles with a breeze! I can also spot property getter and setter cycles, as property getters and setters in C# are methods anyways (compiler generated). I managed to get Ndepend back to the main menu in Visual Studio 2019 using this extension.
https://marketplace.visualstudio.com/items?itemName=Evgeny.RestoreExtensions