Whether you’re moving from Spring Boot to .NET Core or vice versa — your transition guide is here
Supported Languages
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
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
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
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:
.NET Core Project Structure
A typical .NET Core project structure with multiple environment settings:
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:
.NET Core Initialization
.NET Core applications are initialized using CreateDefaultBuilder()
in Program.cs
:
Startup Sequence & Main Application Entry Points
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.
Registering Dependencies in Spring Boot
Registering Dependencies in .NET Core
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);
}
}
.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();
}
}
Here are the key differences between the CRUD approaches in Spring Boot and .NET Core:
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>
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");
}
}
.NET Core Identity Authentication
Install Required Packages
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
Identity Configuration
public class ApplicationUser : IdentityUser {}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser> {
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options) { }
}
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();
}
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();
}
}
Key differences between Spring security & .NET core Identity framework
Writing Unit Tests (TDD Approach)
Unit Testing Frameworks
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());
}
}
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);
}
}
Running & Testing the Application
Spring Boot
.NET Core
References
Spring Boot
.NET Core