Skip to content

KitKeen/EasyFinder

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 

Repository files navigation

EasyFinder

Roslyn-based static analysis tool for .NET microservice architectures. Scans source code to find entry points, trace message flows between services, and resolve DI dependency chains — without building or running the projects.

Problem

In a microservice architecture with dozens of repositories, answering simple questions becomes painful:

  • "Where is this request handled?" — grep across 100+ repos, hope the naming is consistent
  • "Who listens to this message?" — search every repo for the message type, miss half of them
  • "What does this handler depend on?" — open the file, trace each injected service manually, repeat 3 levels deep
  • "Which messages have no consumers?" — nobody knows until something breaks in production

EntryFinder answers all of these by parsing C# source code with Roslyn and building a structured index of entry points, message flows, and dependency trees.

Installation

dotnet tool install -g EntryFinder

Or clone and build:

git clone <repo-url>
cd EntryFinder
dotnet build

Quick Start

# List all entry points (handlers, controllers, message handlers) in a repo
easyfinder scan ~/src/orders

# Search for entry points by name, request/response type, or attribute
easyfinder find CreateOrder ~/src/orders

# Build a cross-service message flow graph
easyfinder graph ~/src

# Trace who produces and consumes a specific message
easyfinder trace OrderCreatedMessage ~/src

# Show the DI dependency tree of a class (default depth: 3)
easyfinder deps CreateOrderHandler ~/src/orders

# Any command with --mermaid outputs a Mermaid diagram
easyfinder graph ~/src --mermaid
easyfinder trace OrderCreatedMessage ~/src --mermaid
easyfinder deps CreateOrderHandler ~/src/orders --mermaid

Example Output

easyfinder scan

Found 48 entry points in ~/src/orders

  [Handler] (18)
    CreateOrderHandler  <CreateOrderRequest, CreateOrderResponse>
      API/Orders/CreateOrderHandler.cs:14
    GetOrderHandler  <GetOrderRequest, GetOrderResponse>
      API/Orders/GetOrderHandler.cs:11
    ...

  [MessageHandler] (22)
    PaymentCompletedHandler  <PaymentCompletedMessage>  [MessageHandler(Queue.Payments, RetryCount = 5)]
      MessageHandlers/PaymentCompletedHandler.cs:16
    ...

  [Controller] (8)
    HealthController
      Controllers/HealthController.cs:7
    ...

easyfinder trace

  OrderCreatedMessage
    Producers:
      orders/CreateOrderHandler  API/Orders/CreateOrderHandler.cs:42
    Consumers:
      notifications/SendOrderConfirmationHandler  queue=Queue.Orders
        MessageHandlers/SendOrderConfirmationHandler.cs:11
      warehouse/ReserveStockHandler  queue=Queue.Orders
        MessageHandlers/ReserveStockHandler.cs:18

easyfinder deps

  [Handler] CreateOrderHandler
  API/Orders/CreateOrderHandler.cs:14

  + IOrderRepository  orderRepository  -> DAL/OrderRepository.cs
    - IDbMapper  dbMapper
  + IPricingService  pricingService  -> Logic/PricingService.cs
    + IDiscountEngine  discountEngine  -> Logic/DiscountEngine.cs
    - ICache  cache
  + IPaymentGateway  paymentGateway  -> Logic/PaymentGateway.cs
    - IHttpClientFactory  httpClientFactory
  - ILogger  logger
  - IPublisher  publisher

easyfinder graph --mermaid

Output can be pasted into any Markdown renderer that supports Mermaid (GitHub, Confluence, Notion):

graph LR
    S0["<b>orders</b><br/>48 entries"]
    S1["<b>notifications</b><br/>12 entries"]
    S2["<b>warehouse</b><br/>31 entries"]
    S3["<b>payments</b><br/>24 entries"]

    S0 -->|"OrderCreatedMessage"| S1
    S0 -->|"OrderCreatedMessage"| S2
    S3 -->|"PaymentCompletedMessage"| S0
    S0 -->|"StockReservedMessage"| S2
Loading

Features

1. Entry Point Scanner

Finds classes that inherit from configurable base types. Default patterns:

Kind Base Types Description
Handler RequestHandler, InternalRequestHandler CQRS-style request handlers
MessageHandler MessageHandler Async message/event handlers
Controller Controller, ControllerBase, ApiController ASP.NET MVC/API controllers
GrpcService GrpcService gRPC service implementations

For each entry point, extracts:

  • Class name and generic type arguments (request/response types)
  • Attributes (e.g., [MessageHandler(Queue.Orders, RetryCount = 5)])
  • File path and line number

2. Message Flow Scanner

Builds a cross-service message graph by detecting:

  • Producers — calls to PublishAsync(new SomeMessage { ... }) or Publish<T>(...)
  • Consumers — classes inheriting from MessageHandler<T> or similar base types
  • Orphan messages — messages with no producers or no consumers in the scanned codebase

3. Dependency Scanner

Resolves constructor injection chains using Roslyn syntax analysis:

  • Primary constructors (C# 12): class MyHandler(IFoo foo) : BaseHandler
  • Classic constructors: public MyHandler(IFoo foo) { _foo = foo; }
  • Interface resolution: IFoo → finds Foo class, or any class implementing IFoo
  • Configurable depth: default 3 levels, avoids infinite recursion

4. Mermaid Export

All graph-producing commands support --mermaid flag:

  • graph --mermaid — service-to-service message flow diagram
  • trace --mermaid — producer/consumer diagram for a specific message (colored: green=producer, yellow=message, purple=consumer)
  • deps --mermaid — DI dependency tree (colored: blue=root, green=resolved, gray=infrastructure)

Configuration

Create a config.json next to the executable or in the working directory:

{
  "defaultRoot": "~/src",
  "patterns": [
    {
      "kind": "Handler",
      "baseTypes": ["RequestHandler", "InternalRequestHandler"]
    },
    {
      "kind": "MessageHandler",
      "baseTypes": ["MessageHandler"]
    },
    {
      "kind": "Controller",
      "baseTypes": ["Controller", "ControllerBase"]
    },
    {
      "kind": "Job",
      "baseTypes": ["BackgroundJob", "RecurringJob"]
    }
  ]
}

Patterns are fully configurable — add your own base types for any framework (MediatR, MassTransit, NServiceBus, custom handlers).

How It Works

  1. No build required — parses source code with CSharpSyntaxTree.ParseText(), no need to compile or resolve NuGet packages
  2. No reflection — everything is syntax-level analysis
  3. Service detection — each subdirectory containing .csproj files is treated as a service
  4. Interface resolution — tries IFooFoo convention first, then scans for classes implementing the interface
  5. File filtering — skips bin/, obj/, .git/, and test projects by default

Limitations

  • Syntax-only analysis — does not resolve namespaces or NuGet packages. Two classes with the same name in different namespaces will collide (first one wins)
  • Interface resolution is heuristic — relies on naming conventions and base list scanning. DI registration modules are not parsed
  • Message detection — only detects PublishAsync(new T { }) and Publish<T>() patterns. Dynamic dispatch is not detected
  • No incremental scanning — every run parses all files from scratch

Roadmap

  • Index caching — save scan results to disk, only re-parse changed files
  • HTTP route mapping — link handlers to their actual URL endpoints
  • SQL table detection — trace from handler → repository → SQL queries → table names
  • Watch mode — file watcher that incrementally updates the index
  • JSON export — machine-readable output for CI/CD integration

License

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages