Unit 5: ASP.NET Core MVC, Entity Framework Core and Security - Subjective Questions
CSE253 — .Net Programming • Practice Questions with Detailed Answers
20 questions
Define the middleware request pipeline in ASP.NET Core. Explain how an HTTP request and response travel through the pipeline.
The middleware request pipeline is an ordered sequence of software components that process HTTP requests and responses in an ASP.NET Core application.
- An incoming HTTP request is received by the web server and passed to the first middleware component.
- Each middleware can inspect or modify the request.
- A middleware may call the next component by invoking
await next(context). - After the final component processes the request, the response travels backward through the pipeline.
- Middleware components can inspect or modify the response during this reverse flow.
- A middleware can terminate the pipeline by generating a response without calling the next component. This is called short-circuiting.
The pipeline is normally configured in Program.cs using methods such as UseRouting(), UseAuthentication(), UseAuthorization(), and MapControllerRoute(). The order of these components is important because each component operates on the results produced by the preceding middleware.
Explain why the ordering of middleware is important in ASP.NET Core. Illustrate your answer with a typical MVC middleware sequence.
Middleware executes in the order in which it is added to the application. Requests move forward through this order, while responses move backward through it. An incorrect order can cause routing, authentication, authorization, or exception handling to fail.
A typical sequence is:
UseExceptionHandler()handles exceptions generated by later middleware.UseHttpsRedirection()redirects HTTP requests to HTTPS.UseStaticFiles()serves static resources such as CSS and JavaScript.UseRouting()identifies the selected endpoint.UseAuthentication()establishes the identity of the user.UseAuthorization()checks whether that user may access the endpoint.MapControllerRoute()maps requests to MVC controllers and actions.
UseAuthentication() must appear before UseAuthorization() because authorization requires an authenticated identity. Similarly, routing must generally run before authorization so that authorization metadata associated with the selected endpoint is available.
Describe any five commonly used built-in middleware components in ASP.NET Core and state the purpose of each.
Common built-in middleware components include:
- Exception Handler Middleware: Catches unhandled exceptions and produces a controlled error response or redirects to an error page.
- HTTPS Redirection Middleware: Redirects insecure HTTP requests to HTTPS.
- Static File Middleware: Serves files such as images, CSS, JavaScript, and fonts from the web root.
- Routing Middleware: Matches an incoming request to an application endpoint.
- Authentication Middleware: Reads authentication data, such as a cookie or token, and constructs the user's identity.
- Authorization Middleware: Determines whether the current user has permission to access the selected endpoint.
- CORS Middleware: Applies Cross-Origin Resource Sharing rules to requests from other origins.
- Response Compression Middleware: Compresses responses to reduce network transfer size.
These components are registered in Program.cs through methods such as UseStaticFiles(), UseRouting(), and UseAuthorization().
What is custom middleware? Describe how to create, register, and execute custom middleware in ASP.NET Core.
Custom middleware is an application-defined component that performs request or response processing not fully provided by built-in middleware.
A middleware class usually contains:
- A constructor that accepts
RequestDelegate. - An
InvokeAsyncmethod that acceptsHttpContext. - A call to the next middleware when processing should continue.
Example:
public class RequestLoggingMiddleware
{
private readonly RequestDelegate _next;
public RequestLoggingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
Console.WriteLine(context.Request.Path);
await _next(context);
}
}
It can be registered with:
app.UseMiddleware<RequestLoggingMiddleware>();
When a request arrives, InvokeAsync executes. Calling _next(context) passes control to the following component. Omitting that call short-circuits the pipeline. Services can also be injected into the constructor or InvokeAsync, subject to their dependency injection lifetimes.
Define dependency injection in ASP.NET Core. Explain the roles of the service container, service registration, and constructor injection.
Dependency injection (DI) is a design technique in which a class receives the objects it depends on instead of constructing them directly. ASP.NET Core includes a built-in DI container.
- Service registration: Services are registered in
builder.Services, for examplebuilder.Services.AddScoped<IProductService, ProductService>(). - Service container: The framework stores registrations and creates objects while resolving their dependency graphs.
- Constructor injection: A controller or service requests dependencies through its constructor.
Example:
public ProductsController(IProductService service)
{
_service = service;
}
Benefits include:
- Reduced coupling between implementations and consumers.
- Easier unit testing through mock implementations.
- Centralized object creation and lifetime management.
- Better maintainability and adherence to the dependency inversion principle.
ASP.NET Core automatically creates the controller and supplies the registered IProductService implementation.
Distinguish between Transient, Scoped, and Singleton service lifetimes in ASP.NET Core dependency injection. Give a suitable use case for each.
ASP.NET Core supports three principal service lifetimes:
- Transient: A new instance is created every time the service is requested. It is suitable for lightweight, stateless services such as formatters or validators. It is registered with
AddTransient(). - Scoped: One instance is created per HTTP request and shared within that request. It is suitable for request-oriented services and Entity Framework Core
DbContextobjects. It is registered withAddScoped(). - Singleton: One instance is created for the entire application lifetime. It is suitable for thread-safe shared services, configuration caches, or immutable data providers. It is registered with
AddSingleton().
A singleton must not directly depend on a scoped service because the scoped object could effectively be retained beyond its valid request scope. Singleton implementations must also be thread-safe because multiple requests may use the same instance concurrently.
Introduce Entity Framework Core and explain its major advantages and components in a .NET application.
Entity Framework Core (EF Core) is a lightweight, cross-platform Object-Relational Mapper for .NET. It allows applications to work with relational databases through .NET classes and objects.
Major components include:
- Entity classes: Represent database records and normally map to tables.
DbContext: Represents a session with the database and coordinates querying and saving.DbSet<TEntity>: Represents a queryable collection of a particular entity type.- Database provider: Generates database-specific commands for systems such as SQL Server, SQLite, or PostgreSQL.
- Change tracker: Detects changes made to loaded entities.
- LINQ provider: Translates LINQ expressions into database queries.
- Migrations: Incrementally update a database schema as the model changes.
Advantages include reduced data-access boilerplate, strongly typed queries, provider independence, relationship mapping, automatic change tracking, and integrated schema migration support.
Explain the purpose and lifecycle of DbContext and DbSet<TEntity> in Entity Framework Core.
DbContext is the central EF Core class that represents a unit of work with a database. Its responsibilities include:
- Managing database connections.
- Exposing entity collections through
DbSet<TEntity>properties. - Translating LINQ queries into database commands.
- Tracking entity states and relationships.
- Saving changes through
SaveChanges()orSaveChangesAsync().
A DbSet<TEntity> represents all entities of a given type and supports querying, insertion, updating, and deletion.
Example:
public class AppDbContext : DbContext
{
public DbSet<Product> Products => Set<Product>();
}
In ASP.NET Core, DbContext is normally registered with AddDbContext<AppDbContext>(), which gives it a scoped lifetime. Therefore, one context is used during an HTTP request and disposed when that request ends. A context should not normally be shared across requests or concurrent threads.
Compare data annotations and the Fluent API for entity configuration in Entity Framework Core.
Both data annotations and the Fluent API configure how entity classes map to a database.
Data annotations:
- Attributes are placed directly on entity classes and properties.
- Examples include
[Key],[Required],[MaxLength(100)], and[Column("ProductName")]. - They are concise and convenient for simple configurations.
- They couple persistence-related information to the domain class.
- They cannot express every EF Core mapping option.
Fluent API:
- Configuration is written in
OnModelCreating()or separateIEntityTypeConfiguration<TEntity>classes. - Methods such as
HasKey(),Property(),HasOne(), andHasMany()configure the model. - It supports complex keys, indexes, conversions, relationships, delete behavior, and other advanced mappings.
- It keeps entity classes free from persistence attributes.
When both are used for the same setting, Fluent API configuration generally takes precedence. The Fluent API is preferred for complex models and configuration that should remain separate from entity classes.
Describe the Code First approach in Entity Framework Core. Explain the steps for creating a database from entity classes.
In the Code First approach, developers define the application model using C# entity classes and EF Core configuration. EF Core then creates or updates the database schema from that model.
Typical steps are:
- Install the required EF Core provider and tooling packages.
- Create entity classes such as
ProductandCategory. - Create a class derived from
DbContext. - Add
DbSet<TEntity>properties. - Configure keys, constraints, and relationships using annotations or the Fluent API.
- Add a connection string to configuration.
- Register the context using
AddDbContext(). - Create an initial migration with
dotnet ef migrations add InitialCreate. - Apply it using
dotnet ef database update.
Code First is appropriate when the application model drives database design, when the project is new, or when schema changes need to be versioned together with source code.
Describe the Database First approach in Entity Framework Core. How is an existing database reverse-engineered into a model?
In the Database First approach, an existing database is treated as the source of truth. EF Core reverse-engineers its tables, columns, keys, and relationships into entity classes and a DbContext.
A typical command is:
dotnet ef dbcontext scaffold "connection-string" Microsoft.EntityFrameworkCore.SqlServer --output-dir Models
The generated output normally includes:
- Entity classes for selected database tables.
- Properties corresponding to columns.
- Navigation properties representing relationships.
- A derived
DbContextcontainingDbSet<TEntity>properties. - Fluent API configuration representing database constraints.
Useful options include --table to select tables, --context to name the context, and --no-onconfiguring to avoid embedding a connection string in generated code.
Database First is suitable for legacy systems, databases managed by a separate database team, or applications that must use an already established schema. Re-scaffolding may overwrite generated code, so custom logic should be placed in partial classes or separate files.
Compare the Code First and Database First approaches in Entity Framework Core.
Code First and Database First differ mainly in which artifact is treated as the primary design source.
Code First:
- C# entity classes and configuration define the model.
- Migrations generate and evolve the database schema.
- It works well for new applications and developer-controlled databases.
- Model changes are naturally versioned with application code.
Database First:
- An existing database schema defines the model.
- Scaffolding generates entity and context classes.
- It works well for legacy or centrally managed databases.
- Database changes may require the model to be scaffolded again.
Code First gives application developers greater control over schema evolution. Database First preserves compatibility with an existing schema and database-centered workflow. The selection depends on ownership of the schema, project age, deployment process, and collaboration between application and database teams.
What are database migrations in Entity Framework Core? Explain how migrations are created, reviewed, applied, and rolled back.
EF Core migrations are versioned descriptions of model changes that can incrementally update a database schema while preserving existing data.
The normal workflow is:
- Modify entity classes or model configuration.
- Run
dotnet ef migrations add MigrationName. - Review the generated
Up()andDown()methods. - Run
dotnet ef database updateto apply pending migrations.
The Up() method contains operations used to apply a schema change, while Down() contains operations intended to reverse it. EF Core records applied migrations in a migration history table.
To move to an earlier migration, use:
dotnet ef database update PreviousMigration
To remove the latest unapplied migration, use:
dotnet ef migrations remove
Production migrations should be reviewed carefully because operations such as dropping columns may lose data. SQL scripts can be generated with dotnet ef migrations script, allowing controlled review and deployment.
Explain how Create and Read operations are performed using Entity Framework Core in an ASP.NET Core MVC application.
A Create operation constructs an entity, adds it to the context, and saves the changes.
var product = new Product
{
Name = model.Name,
Price = model.Price
};
_context.Products.Add(product);
await _context.SaveChangesAsync();
Add() marks the entity as Added. SaveChangesAsync() generates and executes an INSERT command.
A Read operation normally uses LINQ:
var products = await _context.Products
.AsNoTracking()
.OrderBy(p => p.Name)
.ToListAsync();
A single record can be obtained with FindAsync(id), FirstOrDefaultAsync(), or SingleOrDefaultAsync().
Important practices include:
- Use asynchronous methods in web applications.
- Use
AsNoTracking()for read-only queries. - Project only required columns into view models when practical.
- Validate submitted models before inserting data.
- Avoid exposing entity fields that users should not be allowed to modify.
Explain how Update and Delete operations are performed using Entity Framework Core. Discuss entity state tracking and concurrency considerations.
For an Update, the application commonly loads the existing entity, changes permitted properties, and saves the context:
var product = await _context.Products.FindAsync(id);
if (product == null) return NotFound();
product.Name = model.Name;
product.Price = model.Price;
await _context.SaveChangesAsync();
The change tracker marks modified properties, and EF Core generates an UPDATE command.
For a Delete:
var product = await _context.Products.FindAsync(id);
if (product == null) return NotFound();
_context.Products.Remove(product);
await _context.SaveChangesAsync();
Remove() marks the entity as Deleted, causing a DELETE command when changes are saved.
Loading the existing entity helps prevent overposting because only approved fields are copied. Optimistic concurrency can be implemented with a row-version property. If another user changes the same row, SaveChangesAsync() may throw DbUpdateConcurrencyException, which should be caught and handled by reloading, merging, or asking the user to retry.
Explain how LINQ, eager loading, explicit loading, lazy loading, and AsNoTracking() are used when querying data with Entity Framework Core.
EF Core uses LINQ to construct strongly typed queries. The provider translates supported LINQ expressions into database-specific commands.
- Eager loading: Related data is loaded in the original query using
Include()andThenInclude(). It is useful when the required relationships are known in advance. - Explicit loading: Related data is loaded later through the context entry API, such as
Entry(entity).Collection(...).LoadAsync(). - Lazy loading: Related data is loaded automatically when a navigation property is accessed. It requires configuration and can create many unexpected database queries.
AsNoTracking(): Disables change tracking for returned entities. It reduces memory and processing overhead for read-only operations.- Projection:
Select()retrieves only required fields and is often preferable for MVC view models.
Queries are usually executed only when terminal operations such as ToListAsync(), FirstOrDefaultAsync(), or CountAsync() are called. Developers should inspect generated queries and avoid patterns that produce excessive round trips, especially the N+1 query problem.
Distinguish between authentication and authorization in ASP.NET Core web applications.
Authentication determines who the user is, whereas authorization determines what an identified user is permitted to do.
Authentication:
- Validates credentials or an authentication token.
- Creates a
ClaimsPrincipalrepresenting the user. - May use cookies, bearer tokens, external providers, or ASP.NET Core Identity.
- A failed authentication process commonly results in a login challenge or
401 Unauthorizedresponse.
Authorization:
- Evaluates the authenticated user's roles, claims, policies, or other requirements.
- Protects controllers, actions, Razor Pages, or resources.
- Is commonly applied with the
[Authorize]attribute. - A known user who lacks permission commonly receives
403 Forbidden.
Authentication must normally run before authorization in the middleware pipeline. A user can be authenticated but still not be authorized to perform a particular operation.
Describe the complete working of cookie-based authentication in an ASP.NET Core MVC application.
Cookie-based authentication maintains a signed authentication ticket in a browser cookie.
The process is:
- Cookie authentication is registered with
AddAuthentication().AddCookie(). - Authentication and authorization middleware are added in the correct order.
- The user submits credentials through a login form.
- The application validates the credentials against a secure user store.
- It creates claims and a
ClaimsIdentity. SignInAsync()issues a protected authentication cookie.- On later requests, authentication middleware validates the cookie and reconstructs the user's
ClaimsPrincipal. - Authorization rules use that principal to approve or reject access.
SignOutAsync()removes or invalidates the authentication cookie.
Security measures should include HTTPS, HttpOnly cookies, an appropriate SameSite policy, secure password hashing, anti-forgery validation on forms, controlled expiration, and account lockout where appropriate. Sensitive information should not be stored directly in the cookie.
Explain role-based, claims-based, and policy-based authorization in ASP.NET Core, with suitable examples.
ASP.NET Core provides several authorization models:
- Role-based authorization: Access depends on membership in a role. Example:
[Authorize(Roles = "Administrator")]restricts an action to administrators. - Claims-based authorization: Access depends on facts attached to the user's identity, such as department, country, or permission. A claim contains a type and value.
- Policy-based authorization: One or more requirements are grouped under a named policy. Policies can require claims, roles, authentication schemes, or custom handlers.
Example policy registration:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("CanApproveOrders", policy =>
policy.RequireClaim("permission", "orders.approve"));
});
It can be applied using:
[Authorize(Policy = "CanApproveOrders")]
Policy-based authorization is the most flexible approach because business rules can be expressed as reusable requirements and evaluated by custom authorization handlers. Resource-based authorization can additionally consider the specific object being accessed.
Describe how to design a secure ASP.NET Core MVC CRUD application using Entity Framework Core, authentication, and authorization.
A secure MVC CRUD application should combine data-access controls, identity validation, permission checks, and secure HTTP practices.
Key design measures include:
- Register
DbContextwith a scoped lifetime and keep connection strings in protected configuration. - Use ASP.NET Core Identity or another trusted authentication system instead of implementing password storage manually.
- Place
UseAuthentication()beforeUseAuthorization(). - Protect controllers or actions with
[Authorize], roles, or named policies. - Validate every submitted model with
ModelState.IsValid. - Use dedicated view models and bind only permitted fields to prevent overposting.
- Use anti-forgery tokens on state-changing form requests.
- Check object ownership or resource-specific permission before reading, updating, or deleting a record.
- Use LINQ parameters through EF Core instead of constructing SQL from untrusted input.
- Enforce HTTPS and secure cookie settings.
- Handle missing records, concurrency conflicts, and database exceptions without exposing sensitive details.
- Record security-relevant events using structured logging.
Authentication alone is insufficient. Every protected operation must enforce authorization on the server, even if the corresponding UI button is hidden.
Define the middleware request pipeline in ASP.NET Core. Explain how an HTTP request and response travel through the pipeline.
The middleware request pipeline is an ordered sequence of software components that process HTTP requests and responses in an ASP.NET Core application.
- An incoming HTTP request is received by the web server and passed to the first middleware component.
- Each middleware can inspect or modify the request.
- A middleware may call the next component by invoking
await next(context). - After the final component processes the request, the response travels backward through the pipeline.
- Middleware components can inspect or modify the response during this reverse flow.
- A middleware can terminate the pipeline by generating a response without calling the next component. This is called short-circuiting.
The pipeline is normally configured in Program.cs using methods such as UseRouting(), UseAuthentication(), UseAuthorization(), and MapControllerRoute(). The order of these components is important because each component operates on the results produced by the preceding middleware.
Did this save you a night before the exam?
LPU Notes is free, and it stays free. Ads cover part of the server bill. The rest comes out of a student's own pocket: the domain, the storage, and keeping the site up through the weeks everyone needs it at once.
The payment button didn't load. An ad blocker or a filtered network is the usual reason. to try again.
Nothing here is ever locked, and nothing unlocks. Chip in only if it was worth it. What it pays for →