From Java Spring Boot to .NET: What Actually Transfers
When I joined CarWale as a Software Engineer, I was coming from a Java and Spring Boot background — most recently building fintech services at LXME. My new day-to-day was C# and .NET. The first week felt like reading a sentence in a language you almost speak: you recognise the shape of it, but the words keep slipping.
The honest takeaway: the framework changes, the mental model doesn't. Here's what actually transferred.
What transferred immediately
Dependency injection is dependency injection
Spring's @Autowired maps almost one-to-one onto .NET's constructor injection and the built-in IServiceProvider. The concept — invert control, depend on abstractions, let the container wire it up — is identical.
// Spring Boot
@Service
public class ListingService {
private final ListingRepository repository;
public ListingService(ListingRepository repository) {
this.repository = repository;
}
}// .NET
public class ListingService
{
private readonly IListingRepository _repository;
public ListingService(IListingRepository repository)
{
_repository = repository;
}
}Same idea, different punctuation.
Layered architecture, repositories, DTOs
The seams I used in Spring — controllers, services, repositories, DTOs — exist in .NET under different names. A Spring @RestController becomes an ASP.NET Core ControllerBase or a minimal API endpoint. A JPA repository becomes an Entity Framework Core DbContext. The shape of a well-designed service doesn't change.
REST is REST
HTTP is HTTP. Status codes, verbs, idempotency, pagination — all the things I cared about in fintech APIs still matter. Nothing about moving to .NET changed how I think about a clean endpoint.
What I had to relearn
- Async everywhere is the default. In Java I reached for
CompletableFuturewhen I needed it. In .NET,async/awaitis first-class and pervasive —Task<T>instead ofFuture<T>, but the usage pattern is friendlier. - LINQ replaced my stream habits.
stream().map().filter().collect()becomes a LINQ expression. Different syntax, same declarative mindset. - Tooling muscle memory. Maven/Gradle →
dotnetCLI and NuGet. It took a few days to stop typing./mvnw. varvs explicit types and convention. The C# community has its own style conventions; I had to read a lot of existing CarWale code before writing my own.
The lesson I'd give my past self
If you can reason about why a service is structured a certain way — boundaries, coupling, testability — then picking up a new framework is a matter of translation, not reinvention. The people who struggle most when switching stacks are the ones who memorised framework incantations instead of the underlying patterns.
Syntax is cheap. Design taste is what compounds.
Two months in, I'm shipping .NET services and reaching for the same instincts I built with Java and Spring Boot at LXME. The stack changed. The engineer didn't.