Spring Boot vs .NET Core: Complete Developer Migration Guide

umesh kushwaha - Mar 4 - - Dev Community

Whether you’re moving from Spring Boot to .NET Core or vice versa — your transition guide is here

Supported Languages

Image description

Both frameworks allow development in multiple languages, but Spring Boot is tied to JVM-based languages, while .NET Core is more flexible with multiple language options.

Supported Build Tools

Image description

Spring Boot primarily uses Maven or Gradle, while .NET Core uses MSBuild and dotnet CLI. Dependency management is handled via Maven/Gradle in Spring Boot and NuGet in .NET Core.

Supported IDEs for Development

Image description

You can choose any IDE what ever suits to you. I prefer IntelliJ for Spring Boot and VS Code for .Net Core.

Supported Embedded Servers

Image description

Spring Boot applications typically run on Tomcat by default but can be configured to use Jetty or Undertow. .NET Core applications use Kestrel by default but can be hosted behind IIS, HTTP.sys, or Nginx.

Project Setup & Structure

Spring Boot Project Structure

A typical Spring Boot project structure with multiple environment properties:

Image description

.NET Core Project Structure

A typical .NET Core project structure with multiple environment settings:

Image description

Both frameworks separate concerns using MVC architecture and include configuration files for managing environments. Additionally, both have a dedicated test structure to ensure test-driven development.

Application Initialization

Spring Boot Initialization

Spring Boot applications are initialized using SpringApplication.run() in the main method:

Image description

.NET Core Initialization

.NET Core applications are initialized using CreateDefaultBuilder() in Program.cs:

Image description

Startup Sequence & Main Application Entry Points

Image description

Spring Boot handles configuration automatically using SpringApplication.run(), while .NET Core provides more explicit control via Program.cs and Startup.cs.

Dependency Injection

Both Spring Boot and .NET Core support Dependency Injection (DI) for managing application components.

Image description

Registering Dependencies in Spring Boot

Image description

Registering Dependencies in .NET Core

Image description

Both frameworks support dependency injection, but while Spring Boot uses annotations, .NET Core relies on explicit configuration in Startup.cs.

CRUD Operations with ORM

Spring Boot CRUD Example

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String email;

    // Getters and Setters
}

@Repository
public interface UserRepository extends JpaRepository<User, Long> {}

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    public User createUser(User user) {
        return userRepository.save(user);
    }

    public List<User> getAllUsers() {
        return userRepository.findAll();
    }

    public User updateUser(Long id, User userDetails) {
        User user = userRepository.findById(id).orElseThrow();
        user.setName(userDetails.getName());
        user.setEmail(userDetails.getEmail());
        return userRepository.save(user);
    }

    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }
}

@RestController
@RequestMapping("/users")
public class UserController {
    @Autowired
    private UserService userService;

    @PostMapping
    public User createUser(@RequestBody User user) {
        return userService.createUser(user);
    }

    @GetMapping
    public List<User> getAllUsers() {
        return userService.getAllUsers();
    }

    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User userDetails) {
        return userService.updateUser(id, userDetails);
    }

    @DeleteMapping("/{id}")
    public void deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
    }
}
Enter fullscreen mode Exit fullscreen mode

.NET Core CRUD Example

public class User {
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
}

public class UserService
{
    private readonly AppDbContext _context;
    public UserService(AppDbContext context) {
        _context = context;
    }
    public User CreateUser(User user) {
        _context.Users.Add(user);
        _context.SaveChanges();
        return user;
    }
    public IEnumerable<User> GetAllUsers() {
        return _context.Users.ToList();
    }
    public User UpdateUser(int id, User userDetails) {
        var user = _context.Users.Find(id);
        user.Name = userDetails.Name;
        user.Email = userDetails.Email;
        _context.SaveChanges();
        return user;
    }
    public void DeleteUser(int id) {
        var user = _context.Users.Find(id);
        _context.Users.Remove(user);
        _context.SaveChanges();
    }
}

[Route("api/users")]
[ApiController]
public class UserController : ControllerBase
{
    private readonly UserService _userService;
    public UserController(UserService userService) {
        _userService = userService;
    }
    [HttpPost]
    public ActionResult<User> CreateUser(User user) {
        return Ok(_userService.CreateUser(user));
    }
    [HttpGet]
    public ActionResult<IEnumerable<User>> GetUsers() {
        return Ok(_userService.GetAllUsers());
    }
    [HttpPut("{id}")]
    public ActionResult<User> UpdateUser(int id, User userDetails) {
        return Ok(_userService.UpdateUser(id, userDetails));
    }
    [HttpDelete("{id}")]
    public IActionResult DeleteUser(int id) {
        _userService.DeleteUser(id);
        return NoContent();
    }
}
Enter fullscreen mode Exit fullscreen mode

Here are the key differences between the CRUD approaches in Spring Boot and .NET Core:

![]
Image description

Authentication & Authorization

Spring Boot Security

Dependency

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.11.2</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
Enter fullscreen mode Exit fullscreen mode

Security Configuration & Controller

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserDetailsService userDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
            .antMatchers("/auth/**").permitAll()
            .anyRequest().authenticated()
            .and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
}

@RestController
@RequestMapping("/auth")
public class AuthController {
    @PostMapping("/login")
    public ResponseEntity<String> login(@RequestBody LoginRequest request) {
        // Authenticate and generate JWT token
        return ResponseEntity.ok("JWT-TOKEN");
    }
}
Enter fullscreen mode Exit fullscreen mode

.NET Core Identity Authentication

Install Required Packages

dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
Enter fullscreen mode Exit fullscreen mode

Identity Configuration

public class ApplicationUser : IdentityUser {}

public class ApplicationDbContext : IdentityDbContext<ApplicationUser> {
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options) { }
}
Enter fullscreen mode Exit fullscreen mode

Authentication Middleware in Startup.cs

public void ConfigureServices(IServiceCollection services) {
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options => {
            options.RequireHttpsMetadata = false;
            options.SaveToken = true;
            options.TokenValidationParameters = new TokenValidationParameters {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("YOUR_SECRET_KEY")),
                ValidateIssuer = false,
                ValidateAudience = false
            };
        });
}

public void Configure(IApplicationBuilder app) {
    app.UseAuthentication();
    app.UseAuthorization();
}
Enter fullscreen mode Exit fullscreen mode

Controller for Authentication

[ApiController]
[Route("api/auth")]
public class AuthController : ControllerBase {
    private readonly SignInManager<ApplicationUser> _signInManager;
    private readonly UserManager<ApplicationUser> _userManager;

    public AuthController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager) {
        _userManager = userManager;
        _signInManager = signInManager;
    }

    [HttpPost("login")]
    public async Task<IActionResult> Login([FromBody] LoginRequest request) {
        var result = await _signInManager.PasswordSignInAsync(request.Username, request.Password, false, false);
        if (result.Succeeded) {
            return Ok("JWT-TOKEN");
        }
        return Unauthorized();
    }
}
Enter fullscreen mode Exit fullscreen mode

Key differences between Spring security & .NET core Identity framework

Image description

Writing Unit Tests (TDD Approach)

Unit Testing Frameworks

Image description

Sample Unit Test — Spring Boot

@SpringBootTest
@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {

    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private UserService userService;

    @Test
    public void testGetUserById() {
        User user = new User(1L, "John Doe");
        Mockito.when(userRepository.findById(1L)).thenReturn(Optional.of(user));

        User result = userService.getUserById(1L);
        assertEquals("John Doe", result.getName());
    }
}
Enter fullscreen mode Exit fullscreen mode

Sample Unit Test — .NET Core

public class UserServiceTest {
    private readonly Mock<IUserRepository> _userRepositoryMock;
    private readonly UserService _userService;

    public UserServiceTest() {
        _userRepositoryMock = new Mock<IUserRepository>();
        _userService = new UserService(_userRepositoryMock.Object);
    }

    [Fact]
    public void TestGetUserById() {
        var user = new User { Id = 1, Name = "John Doe" };
        _userRepositoryMock.Setup(repo => repo.GetById(1)).Returns(user);

        var result = _userService.GetUserById(1);
        Assert.Equal("John Doe", result.Name);
    }
}
Enter fullscreen mode Exit fullscreen mode

Running & Testing the Application

Spring Boot

Image description

.NET Core

Image description

References

Spring Boot

.NET Core

.