Migrate from ASP.NET Core to GoFr
Summary
ASP.NET Core teams adopting GoFr keep the same operational shape — opinionated framework, built-in DI, configuration, logging, health checks, OpenTelemetry — but lose the class-and-attribute style. Controllers become handler functions, the IServiceCollection DI container becomes constructor passing, and appsettings.json becomes .env files in configs/.
Migrating with an AI assistant?
Hand https://gofr.dev/AGENTS.md to your coding assistant (Claude Code, Cursor, Codex, Aider). It contains the framework conventions, routing/binding/datasource patterns, and per-framework cheat-sheets so the assistant can translate handlers without you re-explaining GoFr.
Mental model
| ASP.NET Core | GoFr |
|---|---|
[ApiController] + [Route("api/users")] | app.GET("/api/users", handler) |
[HttpGet("{id}")] | app.GET("/api/users/{id}", handler) |
[FromBody] CreateUserDto dto | var dto CreateUser; c.Bind(&dto) |
[FromQuery], [FromRoute] | c.Param("q"), c.PathParam("id") |
IServiceCollection / IServiceProvider | Constructor passing; datasources via *gofr.Context |
appsettings.json + environment overlays | configs/.env + per-environment files |
Configuration.GetSection(...) | app.Config.Get(key) |
Middleware pipeline (app.UseX) | app.UseMiddleware(...) |
IHostedService / BackgroundService | Goroutines started in OnStart, or cron jobs |
IHttpClientFactory + Polly | app.AddHTTPService (circuit breaker + retry + rate limit built-in) |
| Health Checks UI | /.well-known/health (auto) |
Serilog / ILogger<T> | Built-in structured JSON logger |
dotnet ef migrations | GoFr SQL migrations |
| Hangfire / Quartz | app.AddCronJob(...) and Pub/Sub subscribers |
Side-by-side: controller ↔ handler
ASP.NET Core:
[ApiController]
[Route("api/users")]
public class UsersController : ControllerBase {
private readonly IUserService _users;
public UsersController(IUserService users) => _users = users;
[HttpPost]
public async Task<IActionResult> Create([FromBody] CreateUserDto dto) {
var user = await _users.CreateAsync(dto);
return Ok(user);
}
}
GoFr:
type UsersHandler struct {
Users UserService
}
func (h *UsersHandler) Create(c *gofr.Context) (any, error) {
var dto CreateUser
if err := c.Bind(&dto); err != nil {
return nil, err
}
return h.Users.Create(c, dto)
}
func main() {
app := gofr.New()
h := &UsersHandler{Users: NewUserService()}
app.POST("/api/users", h.Create)
app.Run()
}
Configuration: appsettings.json → .env
ASP.NET Core (appsettings.json):
{
"ConnectionStrings": {
"Default": "Server=localhost;Database=app;User Id=root"
},
"Logging": { "LogLevel": { "Default": "Information" } }
}
GoFr (configs/.env):
DB_HOST=localhost
DB_NAME=app
DB_USER=root
LOG_LEVEL=INFO
Environment-specific overrides layer on top: GoFr reads configs/.env first, then overlays configs/.<APP_ENV>.env (so APP_ENV=production overlays configs/.production.env). Note the leading dot and the .env suffix on the override file. This is a natural fit for Kubernetes ConfigMaps and Secrets.
Dependency injection
ASP.NET Core's IServiceCollection (transient/scoped/singleton) is replaced by:
- Constructor passing — pass dependencies into your handler structs at startup. Sufficient for almost all services.
*gofr.Context— datasources (SQL, Redis, Mongo, Pub/Sub clients, HTTP services) are accessed through the request context, so per-request "scoped" services come for free.- Wire / Fx — if you want a generated DI graph, both libraries integrate cleanly.
Middleware pipeline
ASP.NET Core's app.UseAuthentication().UseAuthorization() style maps to:
app.UseMiddleware(authMiddleware)
app.UseMiddleware(rbacMiddleware)
Built-in auth options include Basic, API Key, and OAuth/JWT — see authentication. RBAC is supported on top.
Datasources
Entity Framework Core-style ORM is not built in. GoFr provides connection-pooled SQL clients with observability — pair with sqlc for type-safe queries if you want EF-like ergonomics. SQL (MySQL/Postgres/Oracle/SQLite/SQL Server), MongoDB, Redis, Cassandra, ScyllaDB, Couchbase, ArangoDB, Dgraph, SurrealDB are supported, with migrations for SQL/Mongo/Redis/Dgraph.
Observability
OTLP is the lingua franca on both sides — point GoFr at the same collector you already use for OpenTelemetry.Exporter.OpenTelemetryProtocol. GoFr emits OpenTelemetry traces, Prometheus metrics at /metrics, structured JSON logs with trace IDs, and exposes health at /.well-known/health. Log levels can be changed at runtime via the remote log-level endpoint.
Gradual adoption
Stand up a GoFr microservice next to your ASP.NET Core service. From GoFr, call back into the legacy service through app.AddHTTPService("legacy", baseURL) with built-in circuit breaker, retries, and rate limiting. Move endpoints across at the gateway, one bounded context at a time.

