/// <summary> /// Serializes this node to DOT graph format. This is generally only done after /// the overall resolve operation is complete. /// </summary> /// <param name="stringBuilder"> /// The <see cref="StringBuilder"/> to which the node content should be written. /// </param> /// <param name="allRequests"> /// A <see cref="RequestDictionary"/> that contains all the other resolve requests /// that occurred in the complete resolve operation. It is used to ensure /// graph edges are drawn to the correct destination service with the proper /// success/failure formatting. /// </param> public void ToString(StringBuilder stringBuilder, RequestDictionary allRequests) { var shape = DecoratorTarget == null ? "component" : "box3d"; var allServiceTypes = Services.Keys.OfType <IServiceWithType>().Select(s => s.ServiceType).ToArray(); var deferred = allServiceTypes.Contains(typeof(ILifetimeScope)) || allServiceTypes.Contains(typeof(IComponentContext)); stringBuilder.StartNode(Id, shape, Success, deferred); foreach (var service in Services.Keys) { stringBuilder.AppendServiceRow(service.GraphDisplayName(), Services[service]); } stringBuilder.AppendTableRow(TracerMessages.ComponentDisplay, Component); if (DecoratorTarget is object) { stringBuilder.AppendTableRow(TracerMessages.TargetDisplay, DecoratorTarget); } // Only write the instance info IF // - There IS an instance AND // - There's more than one service exposed (which means there's at least one service) // not matching the instance type OR // - There's only one service exposed and that one doesn't match the instance type. if (Instance is object && (Services.Count != 1 || !(Services.First().Key is IServiceWithType swt) || swt.ServiceType != Instance.GetType())) { stringBuilder.AppendTableRow(TracerMessages.InstanceDisplay, Instance.GetType().CSharpName()); } if (Exception is object) { stringBuilder.AppendTableErrorRow(Exception.GetType().CSharpName(), Exception.Message); } if (deferred) { stringBuilder.AppendTableRow(TracerMessages.DeferredOperation); } stringBuilder.EndNode(); foreach (var edge in Edges) { // Connect into a table with the ID format "parent:tablerow" var destination = allRequests[edge.Request]; var edgeId = destination.Id.NodeId() + ":" + destination.Services[edge.Service].NodeId(); // Shorter type name for line descriptions where possible. Using // the type name here rather than the C# name because C# will // include the namespace and will be longer than raw type name. // It will still be "pretty printed" in the individual nodes. var description = edge.Service is IServiceWithType edgeSwt ? edgeSwt.ServiceType.Name : edge.Service.Description; stringBuilder.ConnectNodes(Id.NodeId(), edgeId, description, !destination.Success); } }
/// <summary> /// Initializes a new instance of the <see cref="DotGraphBuilder"/> class. /// </summary> public DotGraphBuilder() { Operation = new OperationNode(); Requests = new RequestDictionary(); CurrentRequest = new Stack <Guid>(); }