Skip to main content

Quickstart

Get your first request captured in under 2 minutes — no database setup, no config file.

Prerequisites

  • .NET 8 or .NET 10 SDK
  • An ASP.NET Core web project (WebAPI, MVC, or minimal API)

Don't have one? Create a throwaway:

dotnet new webapi -n MyApp && cd MyApp

1. Install

dotnet add package Lookout.AspNetCore

If your project uses EF Core, also install the EF integration package in the project that contains your DbContext:

dotnet add package Lookout.EntityFrameworkCore

For Hangfire job capture (optional):

dotnet add package Lookout.Hangfire

2. Wire up

Program.cs — three lines

// 1. Register services — call AFTER AddMemoryCache / AddDistributedMemoryCache
builder.Services.AddLookout();

// 2. Add middleware — call BEFORE UseRouting
app.UseLookout();

// 3. Mount the dashboard as a route on your app at /lookout (no separate process)
app.MapLookout();
Order matters

AddLookout() must come after AddMemoryCache() / AddDistributedMemoryCache() (if used) so the cache decorator can wrap the registered cache. If no cache is registered yet, cache capture is silently skipped.

UseLookout() must come before UseRouting() and any endpoint middleware so it captures the full request lifecycle.

EF Core — one extra step per DbContext

EF Core query capture is not automatic. After installing Lookout.EntityFrameworkCore:

Step 1 — call AddLookoutEntityFrameworkCore() alongside AddLookout():

builder.Services.AddLookout();
builder.Services.AddLookoutEntityFrameworkCore(); // from Lookout.EntityFrameworkCore namespace

Step 2 — add .UseLookout(sp) inside every AddDbContext call you want to instrument:

builder.Services.AddDbContext<AppDbContext>((sp, options) =>
{
options.UseSqlServer(connectionString)
.UseLookout(sp); // <-- adds the Lookout DbCommandInterceptor
});

The sp overload of AddDbContext gives you the service provider so Lookout can resolve its singleton interceptor. If you use AddDbContextFactory, the same .UseLookout(sp) call applies inside the factory delegate.

Multiple DbContexts

Call .UseLookout(sp) in every AddDbContext call you want to instrument. Each context is independent.

3. Run

dotnet run

The dashboard lives at the /lookout route on your app's host and port — there is no separate process. The port is printed by dotnet run:

Now listening on: https://localhost:5001

So navigate to:

https://localhost:5001/lookout

Hit any endpoint in your app. The request row appears in the dashboard within milliseconds.

What you see

The request list shows one row per captured HTTP request:

ColumnWhat it shows
Method + pathGET /api/orders
StatusHTTP response code
DurationEnd-to-end time in ms
db badgeNumber of EF / SQL queries
http badgeNumber of outbound HTTP calls
cache badgeCache hits + misses
log badgeLog entries scoped to this request
exc badgeUnhandled exceptions

Click any row to open the request detail — SQL text with parameters, log output, EF stack traces, N+1 warnings.

Your first N+1

If your code loads a collection then queries each item in a loop, Lookout flags it automatically:

// This produces one query per order — a classic N+1
var orders = await db.Orders.ToListAsync();
foreach (var order in orders)
{
var items = await db.OrderItems
.Where(i => i.OrderId == order.Id)
.ToListAsync();
}

The dashboard shows a warning banner for that request:

N+1 detected — 12 identical queries. Stack trace: OrderService.cs:47

The banner groups all identical SQL shapes, shows a count, and links the stack frame where the repeated query originated.

Next steps

  • Configuration — body capture, retention window, redaction
  • Extensibility — record custom events with ILookoutRecorder or Lookout.Dump()
  • Security model — understand the dev-only default and how to extend it
  • Troubleshooting — ABP, Serilog, Npgsql, and other framework-specific notes