ASP.NET MVC Questions and Answers

Afroz KaziAfroz Kazi
34 min read
  1. Why OOP is used in C#?

    • OOP is a fundamental pattern used in C# and it allows you to write scalable, modular, maintainable code.

    • Example: - Imagine you're building a school management system.

    • Instead of writing everything in one big program, you can break it down into objects like:

    • Student → has properties like Name, Age, Grade, and methods like Enroll(), Promote().

    • Teacher → has properties like Name, Subject, and methods like AssignGrade().

    • Classroom → has a list of students and a teacher.

  1. What method do you call to add MVC services to the ASP.NET Core pipeline?

    • Use builder.Services.AddMVC() or builder.Services.AddControllersWithViews() to register MVC services.

    • So you can use Controllers, Views, ViewData, ViewBag, etc.

            var builder = WebApplication.CreateBuilder(args);
            builder.Services.AddControllersWithViews();
            // or builder.Services.AddMvc();
            var app = builder.Build();
            app.MapDefaultControllerRoute();
            app.Run();
      
  1. What is Middleware and Why it’s Sequence order important?

    • ASP.NET Core apps use middleware to handle HTTP requests.

    • Middleware processes requests/responses in a pipeline.

    • Because middleware is executed in the order it's added in Startup.cs.

    • If authentication is first, it checks the user. If valid, it passes to the next step like routing, then to your controller.

    • Middleware Sequence in ASP.Net Core should be as follows.

        public void Configure(IApplicationBuilder app) {
          if (env.IsDevelopment()) {
            app.UseDeveloperExceptionPage();
            // Shows detailed error pages with stack traces during development.
          } else {
            app.UseExceptionHandler("/Home/Error");  // Global error page
            app.UseHsts(); 
            // Enforces HTTPS via response header
            //HSTS tells browsers to only use HTTPS. 
            //We avoid it in dev to prevent local redirect issues, 
            //and enable it in production for security compliance.
          }
          app.UseHttpsRedirection();
          // Redirects HTTP requests to HTTPS
          app.UseStaticFiles();
          // When your app needs to serve frontend assets from wwwroot folder. 
          // (e.g,.html, .js, .css, images).
          app.UseRouting();
          // Matches incoming request URLs to route endpoints 
          // (controller actions, Razor pages, minimal APIs).
          app.UseAuthentication();
          // Validates authentication tokens/cookies and sets the HttpContext.User and also
          // used if your app uses JWT tokens, cookies, OAuth, etc.
          app.UseAuthorization();
          // Checks if the authenticated user is allowed to access a route ([Authorize] attributes).
          app.UseCors("AllowAll");
          // Enables Cross-Origin Resource Sharing — allows APIs to be accessed from
          // different domains If needed, must be placed after routing 
          // and before endpoints
          app.UseEndpoints(endpoints => {
            endpoints.MapControllers();
            // Maps attribute-routed Web API controllers
            endpoints.MapDefaultControllerRoute();
            // Enables default MVC route: {controller=Home}/{action=Index}/{id?}
          });
        }
      
  2. How do you create custom middleware using Middleware Class?

    • You create a separate Custom Middleware class with InvokeAsync method that takes the HttpContext as parameter, does some work (like logging or modifying headers), and then calls the next middleware in the pipeline.

    • Call the Custom Middleware inside Configure method in Startup.cs file as follows app.UseMiddleware<CustomHeaderMiddleware>();

    • Clean, reusable, and testable.

    • Great for complex or reusable logic.

        //Define CustomHeaderMiddleware.cs class.
        public class CustomHeaderMiddleware
        {
            private readonly RequestDelegate _next;
      
            public CustomHeaderMiddleware(RequestDelegate next)
            {
                _next = next;
            }
      
            public async Task InvokeAsync(HttpContext context)
            {
                Console.WriteLine("Before next middleware");
      
                context.Response.OnStarting(() =>
                {
                    context.Response.Headers.Add("X-Custom", "Hello from middleware");
                    return Task.CompletedTask;
                });
      
                await _next(context); // Pass to the next middleware
      
                Console.WriteLine("After next middleware");
            }
        }
      
        //How to use in Startup.cs
        public class Startup
        {
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddControllers();
                // Register your middleware’s dependencies if needed
            }
      
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                // Optional: Developer exception page
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
      
                // Your custom middleware goes here
                app.UseMiddleware<CustomHeaderMiddleware>();
      
                // Built-in middleware
                app.UseRouting();
                app.UseAuthentication();   // if any
                app.UseAuthorization();    // if any
      
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllers();
                });
            }
        }
      
  3. What does MVC stand for and what are its responsibilities?

    • By splitting responsibilities in 3 main parts
  • Model: Handles data and business logic.

  • View: Renders UI and displays data.

  • Controller: Processes requests, updates models, returns views.

      //Model
      public class Product
      {
          public int Id { get; set; }
          public string Name { get; set; }
      }
    
      //Controller
      public class ProductController : Controller
      {
          private readonly IProductRepository _repository;
    
          public ProductController(IProductRepository repository)
          {
              _repository = repository;
          }
    
          public IActionResult List()
          {
              var products = _repository.GetAll();
              return View(products);
          }
      }
    
      <!-- File: Views/Product/List.cshtml -->
      @model IEnumerable<Product>
    
      <h2>Product List</h2>
    
      <table class="table">
          <thead>
              <tr>
                  <th>Id</th>
                  <th>Name</th>
              </tr>
          </thead>
          <tbody>
              @foreach (var product in Model)
              {
                  <tr>
                      <td>@product.Id</td>
                      <td>@product.Name</td>
                  </tr>
              }
          </tbody>
      </table>
    
  1. How does routing work in ASP.NET Core?

    • Routing maps URL paths to controller actions using endpoint routing, and there are 2 types of routing as follows:

      1. Attribute routing:

        • Routes are defined directly above controller actions using attributes like [Route], [HttpGet], [HttpPost] etc.

        • Use only when you want fine control over each route.

        • It causes less confusion and more flexibility when different actions don’t follow a strict naming pattern.

        • Route Urls like /get-active-users or /reset-password/token/{id}, which can't be easily mapped by convention-based routing.

        [ApiController]
        [Route("api/products")]
        public class ProductsController : ControllerBase
        {
            [HttpGet("list")]
            public IActionResult GetAll() { ... }

            [HttpGet("{id}")]
            public IActionResult GetById(int id) { ... }
        }

        //In Startup.cs → Configure() method:
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
          app.UseRouting();
          app.UseEndpoints(endpoints =>
          {
             endpoints.MapControllers(); //This enables attribute routing.
          });
        }

        //Also, in ConfigureServices:
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers(); // Or AddControllersWithViews() if you're using views.
        }
  1. Conventional routing:

    • Defines URL patterns in Startup.cs (or Program.cs in minimal hosting model).

    • It relies on naming conventions of controllers and actions.

    • Use only when your routes follow a simple and consistent pattern.

    • It causes less repetition in your code because route URLs like /product/list (mapped to ProductController.List()), /order/details/5 (mapped to OrderController.Details(int id)), and /account/login (mapped to AccountController.Login()) are automatically handled without needing explicit route attributes.

        //In Startup.cs file
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });

        //Example URL
        /*
        - /Home/Index
        - /Home/About/5
        */
  1. What's the difference between Authentication and Authorization?

    1. 🔐Authentication

      • Purpose: Identifies who the user is

      • Sets: HttpContext.User

      • Middleware: app.UseAuthentication()

      • Happens before Authorization

      • 🧾 Example: Validating username & password, token, etc.

    2. 🔒 Authorization

      • Purpose: Determines what the user is allowed to do

      • Uses: Roles, policies, or claims to grant/restrict access

      • Middleware: app.UseAuthorization()

      • Happens after Authentication

      • 🧾 Example: Checking if a user has admin role before accessing a route.

  2. Does an ASP.NET MVC application have to use convention-based routing?

    • No, it's not necessary.

    • MVC apps can use either convention-based routing or attribute routing — or both together.

Can API-only controllers use convention-based routing in ASP.NET Core?

  • Technically yes, but it’s not recommended.

  • ASP.NET Core Web API controllers can use convention-based routing, but attribute routing is the default and preferred approach for APIs.

  1. Partial View vs Layout?

    • Partial View: reusable chunk of UI (_Header.cshtml)

    • Layout: template structure (_Layout.cshtml), like a master page.

  2. ViewBag vs ViewData vs TempData

FeatureViewBagViewDataTempData
TypeDynamic objectDictionary (string key, object value)Dictionary (string key, object value)
ScopeSingle requestSingle requestAcross multiple requests (survives redirect)
PurposePass data from controller to viewPass data from controller to viewPass data between requests (e.g., after redirect)
Use CaseSimple data passingStructured key-value pairsSuccess/failure messages after POST-Redirect-GET
// ViewBag (Controller)
ViewBag.Message = "Hello from ViewBag!";
return View();

// View (Razor)
<p>@ViewBag.Message</p>

// ViewData (Controller)
ViewData["Message"] = "Hello using ViewData!";
return View();

// View (Razor)
<p>@ViewData["Message"]</p>

// TempData (Controller)
TempData["Success"] = "Data saved successfully!";
return RedirectToAction("Index");

// View (Razor)
@if (TempData["Success"] != null)
{
    <p>@TempData["Success"]</p>
}
  1. Middleware vs Filters?

    1. ⚙️ Middleware:

      • Runs for every request.

      • Works before routing.

      • Used for logging, auth, CORS, etc.

      • More general/global.

    2. 🔎 Filters:

      • Runs only for controller/action methods.

      • Works after routing.

      • Used for validation, error handling in MVC.

      • More controller-specific.

  2. What are Filters in ASP.NET Core MVC?

    • In ASP.NET Core MVC, filters allow you to run custom code before or after specific stages in the request pipeline.

    • The Filters run after routing has selected the controller and action, and allow logic to validate input, log access, handle errors, or modify results.

  3. Types of Filters?

    • There are five main types of filters, each designed to run at different stages of the request pipeline.

      1. Authorization Filter
  • Runs first, before anything else (even model binding).

  • Determines if the user is authorized to access the resource.

  • Example use: [Authorize], or custom role checks.

        public class MyAuthFilter : IAuthorizationFilter
        {
            public void OnAuthorization(AuthorizationFilterContext context)
            {
                if (!context.HttpContext.User.Identity.IsAuthenticated)
                {
                    context.Result = new UnauthorizedResult();
                }
            }
        }
  1. Resource Filter
  • Runs after authorization, but before model binding.

  • Useful for caching, resource-heavy setups.

  • Can short-circuit the pipeline before action runs.

        public class MyResourceFilter : IResourceFilter
        {
            public void OnResourceExecuting(ResourceExecutingContext context)
            {
                Console.WriteLine("Resource Filter - Before model binding");
            }

            public void OnResourceExecuted(ResourceExecutedContext context)
            {
                Console.WriteLine("Resource Filter - After everything");
            }
        }
  1. Action Filter
  • Runs before and after the action method executes.

  • Best for validation, logging, preprocessing.

        public class MyActionFilter : IActionFilter
        {
            public void OnActionExecuting(ActionExecutingContext context)
            {
                Console.WriteLine("Action Filter - Before action");
            }

            public void OnActionExecuted(ActionExecutedContext context)
            {
                Console.WriteLine("Action Filter - After action");
            }
        }
  1. Exception Filter
  • Catches unhandled exceptions thrown during controller or action execution.

  • Good for logging errors or returning custom error responses.

        public class MyExceptionFilter : IExceptionFilter
        {
            public void OnException(ExceptionContext context)
            {
                Console.WriteLine($"Exception caught: {context.Exception.Message}");
                context.Result = new JsonResult(new { error = "Something went wrong" });
                context.ExceptionHandled = true;
            }
        }
  1. Result Filter
  • Runs before and after the result is executed (e.g., ViewResult, JsonResult).

  • Useful for modifying the response, like formatting or wrapping.

        public class MyResultFilter : IResultFilter
        {
            public void OnResultExecuting(ResultExecutingContext context)
            {
                Console.WriteLine("Result Filter - Before result");
            }

            public void OnResultExecuted(ResultExecutedContext context)
            {
                Console.WriteLine("Result Filter - After result");
            }
        }
  1. Mention Filter Execution Order?

    • HTTP Request → [Authorization Filters][Resource Filters] → Model Binding → [Action Filters] → Controller Action → [Result Filters] → Result Executed (e.g., View rendered) → ([Exception Filter] - if exception occurred at any step) → HTTP Response.
  2. How do you create custom filter class?

    • Create a custom ActionFilterAttribute to run logic before and after a controller action method executes.

    • Use OnActionExecuting to perform validation on input parameters (e.g., checking if id exists).

    • Use OnActionExecuted to log or handle post-action logic after the method completes.

    • Apply the filter via attribute to either the entire controller or specific actions for targeted behavior.

    • Demonstrate real use cases like input validation, logging, and flow control within MVC action execution.

        public class MyActionFilter : ActionFilterAttribute
        {
            public override void OnActionExecuting(ActionExecutingContext context)
            {
                // Before the action executes
                var actionName = context.ActionDescriptor.DisplayName;
                Console.WriteLine($"[Before] Executing action: {actionName}");
      
                // Example: Reject request if no "id" provided
                if (!context.ActionArguments.ContainsKey("id") || context.ActionArguments["id"] == null)
                {
                    context.Result = new BadRequestObjectResult("ID is required");
                }
            }
      
            public override void OnActionExecuted(ActionExecutedContext context)
            {
                // After the action executes
                Console.WriteLine($"[After] Finished executing action: {context.ActionDescriptor.DisplayName}");
            }
        }
      
        //Apply the Filter to a Controller or Action
        [MyActionFilter] // Applies to all actions in this controller
        public class UsersController : Controller
        {
            public IActionResult GetUser(int id)
            {
                // If ID is valid, logic proceeds here
                return Ok($"User ID: {id}");
            }
        }
      
        //Or, apply to just a single action:
        public class UsersController : Controller
        {
            [MyActionFilter] // Applies only to this method
            public IActionResult GetUser(int id)
            {
                return Ok($"User ID: {id}");
            }
        }
      
  3. What is Dependency Injection in ASP.NET Core?

    • It’s a design pattern where objects are provided with their dependencies rather than creating them manually. ASP.NET Core has built-in DI.

    • We used constructor injection to register services like logging, repositories, and config settings.

  4. Difference between AddTransient, AddScoped, and AddSingleton.

    1. AddTransient<TInterface, TImplementation>()

      • A new instance is created every time the service is used.

      • Best for stateless and lightweight services.

      • Use when you don’t need to share state and want a fresh copy every time.

      • Ideal for simple tasks like data transformation, validation, token generation, or sending emails.

          // Sends emails (stateless, no need to retain data)
          services.AddTransient<IEmailSender, EmailSender>();
        
          // Generates secure tokens or OTPs per request
          services.AddTransient<ITokenGenerator, JwtTokenGenerator>();
        
          // Cleans and sanitizes input fields
          services.AddTransient<IInputSanitizer, HtmlInputSanitizer>();
        
          // Formats data for reports — called only when needed
          services.AddTransient<IReportFormatter, PdfReportFormatter>();
        
    2. AddScoped<TInterface, TImplementation>()

      • Creates one instance per HTTP request.

      • All classes in the same request share the same instance.

      • Use when you need to share data across layers in a request (e.g., Controller → Service → Repository).

      • Good for things like request tracking, user info, or per-request caching (e.g., DbContext, UnitOfWork).

          // Tracks and manages the current user's data during a request
          services.AddScoped<IUserService, UserService>();
        
          // Processes an order in checkout flow (data shared across layers)
          services.AddScoped<IOrderProcessor, OrderProcessor>();
        
          // Holds temporary cart data across steps in a request
          services.AddScoped<IShoppingCartService, ShoppingCartService>();
        
          // EF Core DbContext – reused in service & repository during a request
          services.AddScoped<IAppDbContext, AppDbContext>();
        
    3. AddSingleton<TInterface, TImplementation>()

      • Creates a single instance for the entire application.

      • That instance is shared across all users and requests.

      • Created at startup or the first time it's needed.

      • Use for shared global data or heavy services like Logger, Config, Cache, or reading a file.

          // Logs errors and events — shared by entire app
          services.AddSingleton<ILoggerService, FileLoggerService>();
        
          // Reads config file once and exposes settings globally
          services.AddSingleton<IAppConfigurationService, AppConfigurationService>();
        
          // Stores shared in-memory data like tokens or frequent API responses
          services.AddSingleton<ICacheService, MemoryCacheService>();
        
          // Provides a static list of countries — no need to recreate every time
          services.AddSingleton<ICountryListProvider, CountryListProvider>();
        
  5. What is the difference between .NET Framework and .NET Core?

    1. OS Support

      .NET Framework: Works only on Windows

      .NET Core: Cross-platform — runs on Windows, Linux, and macOS

    2. Open Source

      .NET Framework: Not open source.

      .NET Core: Fully open source on GitHub

    3. Application Types

      .NET Framework: Best for Desktop apps (Windows Forms, WPF) and ASP.NET Web Forms/MVC

      .NET Core: Suited for Web APIs, Cloud apps, CLI tools, Microservices, and Cross-platform apps

    4. Performance

      .NET Framework: Global Assembly Cache (GAC)-based.

      .NET Core: App-local DLLs.

  6. What is EF Core?

    • EF Core is an ORM (Object-Relational Mapper) that allows .NET developers to work with databases using .NET objects.
  7. What are DbContext and DbSet in Entity Framework Core?

    • DbContext is the primary class in Entity Framework Core that acts as a bridge between your .NET application and the database.

    • It represents a session with the database that manages database connections, tracks entity states (Added, Modified, Deleted) and is used to query and save data.

    • DbContext in EF Core is used to interact with the database. It tracks the state of entities, so when I call SaveChanges(), only the modified records are updated. I use DbSet<T> to represent tables and query them using LINQ.

        public class AppDbContext : DbContext
        {
            public DbSet<Product> Products { get; set; }
      
            public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
            {
             //code here..
            }
        }
      
    • DbSet<T> represents a table in the database, and each T is a row/entity.

    • DbSet<T> is like a typed table in memory connected to the actual table in SQL.

    • It is used to query, insert, update, and delete entities in the database and acts as a collection of all entities of a given type.

        public class Product
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public decimal Price { get; set; }
        }
      
        // Querying
        var products = _context.Products.ToList();
      
        // Create/Add
        _context.Products.Add(new Product { Name = "Pen", Price = 10 });
        _context.SaveChanges();
      
        // Read
        var product = _context.Products.FirstOrDefault(p => p.Id == 1);
      
        // Update
        product.Price = 20;
        _context.SaveChanges();
      
        // Delete
        _context.Products.Remove(product);
        _context.SaveChanges();
      
  8. Entity Framework Core Methods

    //EF Core methods are built-in functions provided by the Entity Framework Core library 
    //It is used to perform database operations like insert, update, delete, and track entity states.
    
    _context.Products.Add(product); 
    //Add marks a new entity as added to DbSet.
    _context.Products.AddRange(product1, product2); 
    // AddRange marks multiple entities at once to the DbSet.
    
    _context.Products.Update(product);
    //Update marks the entire entity as Modified to the Dbset.
    
    _context.Products.Remove(product);
    //Remove marks an entity as Deleted to the DbSet.
    _context.Products.RemoveRange(products);
    //RemoveRange marks multiple entities as Deleted to the DbSet.
    
    _context.Products.Attach(product);
    //Attach tells EF to start tracking an entity without marking it for changes
    //Used for manual tracking.
    
    _context.Entry(product).State = EntityState.Modified;
    //Manually marks an entity as modified.
    //It Useful when the context isn’t tracking the entity
    
    var product = _context.Products.Find(id);
    //Find() retrieves an entity by primary key.
    //It uses the local cache first before hitting the database.
    
    await _context.Products.AddAsync(product);
    //AddAsync is an asynchronous method in Entity Framework Core that marks a single entity as added.
    await _context.Products.AddRangeAsync(listOfProducts);
    //AddRangeAsync is the async version of AddRange() — it marks a collection of entities as Added so they can be inserted together.
    
    _context.Products.UpdateRange(listOfProducts); 
    //Batch versions of Update() for updating multiple entities at once.
    _context.Products.RemoveRange(listOfProducts);
    //Batch versions of Remove() for deleting multiple entities at once.
    
    var products = _context.Products.AsNoTracking().ToList();
    //Disables tracking for read-only scenarios — improves performance and memory usage.
    
    //ChangeTracker gives you access to all currently tracked entities and lets you inspect or clear their states.
    _context.ChangeTracker.Clear();
    _context.ChangeTracker.Entries();
    
    _context.Entry(product).State = EntityState.Detached; //Stops tracking the entity
    
    _context.SaveChanges();
    //SaveChanges() applies all pending changes (Added, Modified, Deleted) to the database in a single transaction.
    await _context.SaveChangesAsync();
    //SaveChangesAsync is the async version of SaveChanges()
    
  9. LINQ (Method Syntax vs Query Syntax)

    • LINQ (Language Integrated Query) provides query capabilities directly in C# for collections or databases.

Select – Projects data from a collection

    // Method
    var names = employees.Select(e => e.Name);

    // Query
    var names = from e in employees
                select e.Name;

Where – Filters data based on a condition

    // Method
    var highSalaryEmployees = employees.Where(e => e.Salary > 50000);

    // Query
    var highSalaryEmployees = from e in employees
                              where e.Salary > 50000
                              select e;

OrderBy – Sorts data ascending

    // Method
    var sortedEmployees = employees.OrderBy(e => e.Salary);

    // Query
    var sortedEmployees = from e in employees
                          orderby e.Salary
                          select e;

OrderByDescending – Sorts data descending

    // Method
    var sortedEmployees = employees.OrderByDescending(e => e.Salary);

    // Query
    var sortedEmployees = from e in employees
                          orderby e.Salary descending
                          select e;

GroupBy – Groups data based on a key

    // Method
    var groups = employees.GroupBy(e => e.Department);

    // Query
    var groups = from e in employees
                 group e by e.Department;

Join – Joins two collections

    // Method
    var employeeDepartments = employees.Join(departments,
        e => e.DeptId,
        d => d.Id,
        (e, d) => new { e.Name, Department = d.Name });

    // Query
    var employeeDepartments = from e in employees
                              join d in departments on e.DeptId equals d.Id
                              select new { e.Name, Department = d.Name };

Take – Takes first n elements

    // Method
    var top3Employees = employees.Take(3);

    // Query
    var top3Employees = (from e in employees
                         select e).Take(3);

Skip – Skips first n elements

    // Method
    var remainingEmployees = employees.Skip(3);

    // Query
    var remainingEmployees = (from e in employees
                              select e).Skip(3);

First – Gets first matching element

    // Method
    var firstHighEarner = employees.First(e => e.Salary > 50000);

    // Query
    var firstHighEarner = (from e in employees
                           where e.Salary > 50000
                           select e).First();

Single – Gets one element (throws if multiple)

    // Method
    var specificEmployee = employees.Single(e => e.Id == 1);

    // Query
    var specificEmployee = (from e in employees
                            where e.Id == 1
                            select e).Single();

🔹 First

  1. Returns the first element in a sequence.

  2. Throws an exception (InvalidOperationException) if the sequence is empty.

  3. Can use a predicate: First(x => x.Age > 18) returns the first match.

🔹 Single

  1. Returns exactly one element from the sequence.

  2. Throws an exception if the sequence is empty or has more than one element.

  3. Use it when only one item is expected to match (like a unique ID).

FirstOrDefault – Gets first match or default

    // Method
    var firstEmployee = employees.FirstOrDefault(e => e.Salary > 100000);

    // Query
    var firstEmployee = (from e in employees
                         where e.Salary > 100000
                         select e).FirstOrDefault();

SingleOrDefault – Gets one or default

    // Method
    var employee = employees.SingleOrDefault(e => e.Id == 100);

    // Query
    var employee = (from e in employees
                    where e.Id == 100
                    select e).SingleOrDefault();

🔹 FirstOrDefault

  1. Similar to First, but returns default value (e.g., null for reference types) if no element is found.

  2. Does not throw if the sequence is empty.

  3. Use when the sequence may or may not have elements, and you want to avoid exceptions.

🔹 SingleOrDefault

  1. Like Single, but returns default value if the sequence is empty.

  2. Throws an exception if the sequence has more than one element.

  3. Use when zero or one element is expected, but not more than one.

Any – Checks if any element matches

    // Method
    var hasHighEarners = employees.Any(e => e.Salary > 80000);

    // Query
    var hasHighEarners = (from e in employees
                          where e.Salary > 80000
                          select e).Any();

All – Checks if all elements match

    // Method only
    var allAboveMinimumWage = employees.All(e => e.Salary > 20000);

Count – Counts matching elements

    // Method
    var highEarnerCount = employees.Count(e => e.Salary > 50000);

    // Query
    var highEarnerCount = (from e in employees
                           where e.Salary > 50000
                           select e).Count();

Sum – Sum of numeric property

    // Method
    var totalSalary = employees.Sum(e => e.Salary);

    // Query
    var totalSalary = (from e in employees
                       select e.Salary).Sum();

Average – Average of numeric property

    // Method
    var averageSalary = employees.Average(e => e.Salary);

    // Query
    var averageSalary = (from e in employees
                         select e.Salary).Average();

Max – Finds max value

    // Method
    var highestSalary = employees.Max(e => e.Salary);

    // Query
    var highestSalary = (from e in employees
                         select e.Salary).Max();

Min – Finds min value

    // Method
    var lowestSalary = employees.Min(e => e.Salary);

    // Query
    var lowestSalary = (from e in employees
                        select e.Salary).Min();

Distinct – Removes duplicates

    // Method
    var uniqueDepartments = employees.Select(e => e.Department).Distinct();

    // Query
    var uniqueDepartments = (from e in employees
                             select e.Department).Distinct();

Concat – Combines collections

    // Method only
    var allEmployees = employees.Concat(contractors);

Union – Combines, removes duplicates

    // Method only
    var uniqueEmployees = employees.Union(contractors);

Intersect – Gets common elements

    // Method only
    var commonEmployees = employees.Intersect(contractors);

Except – Gets difference

    // Method only
    var exclusiveEmployees = employees.Except(contractors);

ToList – Converts to List

    // Method
    var employeeList = employees.ToList();

    // Query
    var employeeList = (from e in employees
                        select e).ToList();

ToDictionary – Converts to Dictionary

    // Method only
    var employeeDict = employees.ToDictionary(e => e.Id, e => e.Name);

SelectMany – Flattens nested collections

    // Method only
    var allTasks = projects.SelectMany(p => p.Tasks);

DefaultIfEmpty – Returns default if empty

    // Method only
    var employeesOrDefault = employees.DefaultIfEmpty(
        new Employee { Name = "No Employee", Salary = 0 }
    );

Zip – Combines two lists

    // Method only
    var pairedList = employees.Zip(managers, (e, m) => 
    new { Employee = e.Name, Manager = m.Name });

Aggregate – Custom accumulation of any logic

    // Method only
    var totalSales = sales.Aggregate((total, next) => total + next);

INNER JOIN - Joins two sequences where keys match.

    // Query Syntax
    var result = from e in employees
                 join d in departments on e.DeptId equals d.Id
                 select new { e.Name, Department = d.Name };

    // Method Syntax
    var result = employees.Join(departments,
                                e => e.DeptId,
                                d => d.Id,
                                (e, d) => new { e.Name, Department = d.Name });

LEFT JOIN (GroupJoin + SelectMany + DefaultIfEmpty) - Includes all from left, even if no match in right.

    // Query Syntax
    var result = from e in employees
                 join d in departments on e.DeptId equals d.Id into deptGroup
                 from d in deptGroup.DefaultIfEmpty()
                 select new { e.Name, Department = d?.Name ?? "No Dept" };

    // Method Syntax
    var result = employees.GroupJoin(departments, e => e.DeptId, d => d.Id,
                                     (e, ds) => new { e, ds }).SelectMany(ed => ed.ds.DefaultIfEmpty(),
                                     (ed, d) => new { ed.e.Name, Department = d?.Name ?? "No Dept" });

RIGHT JOIN - LINQ doesn’t directly support Right Join, but you can swap the collections in Left Join.

    // Query Syntax (simulate Right Join)
    var result = from d in departments
                 join e in employees on d.Id equals e.DeptId into empGroup
                 from e in empGroup.DefaultIfEmpty()
                 select new { Employee = e?.Name ?? "No Employee", Department = d.Name };

    // Method Syntax
    var result = departments.GroupJoin(employees,
                                       d => d.Id,
                                       e => e.DeptId,
                                       (d, es) => new { d, es })
                            .SelectMany(de => de.es.DefaultIfEmpty(),
                                        (de, e) => new { Employee = e?.Name ?? "No Employee", Department = de.d.Name });

CROSS JOIN (Cartesian Product)

    // Query Syntax
    var result = from e in employees
                 from d in departments
                 select new { e.Name, Department = d.Name };

    // Method Syntax
    var result = employees.SelectMany(e => departments,
                                      (e, d) => new { e.Name, Department = d.Name });

CROSS APPLY (like SelectMany with logic) - Used when right sequence depends on the left.

    // Query Syntax
    var result = from e in employees
                 from p in GetProjectsFor(e.Id)
                 select new { e.Name, Project = p.Name };

    // Method Syntax
    var result = employees.SelectMany(e => GetProjectsFor(e.Id),
                                      (e, p) => new { e.Name, Project = p.Name });

OUTER APPLY (like Left Join with a dependent subquery)

    // Query Syntax
    var result = from e in employees
                 let projects = GetProjectsFor(e.Id)
                 from p in projects.DefaultIfEmpty()
                 select new { e.Name, Project = p?.Name ?? "No Project" };

    // Method Syntax
    var result = employees.SelectMany(e => GetProjectsFor(e.Id).DefaultIfEmpty(),
                                      (e, p) => new { e.Name, Project = p?.Name ?? "No Project" });

Group Join (used to simulate One-to-Many + Left Joins) - Returns grouped results per key.

    // Query Syntax
    var result = from d in departments
                 join e in employees on d.Id equals e.DeptId into empGroup
                 select new { Department = d.Name, Employees = empGroup };

    // Method Syntax
    var result = departments.GroupJoin(employees,
                                       d => d.Id,
                                       e => e.DeptId,
                                       (d, empGroup) => new { Department = d.Name, Employees = empGroup });

Multiple Joins (Chain Joins)

    // Query Syntax
    var result = from e in employees
                 join d in departments on e.DeptId equals d.Id
                 join l in locations on d.LocationId equals l.Id
                 select new { e.Name, d.Name, Location = l.City };

    // Method Syntax
    var result = employees.Join(departments,
                                e => e.DeptId,
                                d => d.Id,
                                (e, d) => new { e, d })
                          .Join(locations,
                                ed => ed.d.LocationId,
                                l => l.Id,
                                (ed, l) => new { ed.e.Name, Department = ed.d.Name, Location = l.City });

Self Join (join table with itself)

    // Query Syntax
    var result = from e1 in employees
                 join e2 in employees on e1.ManagerId equals e2.Id
                 select new { Employee = e1.Name, Manager = e2.Name };

    // Method Syntax
    var result = employees.Join(employees,
                                e1 => e1.ManagerId,
                                e2 => e2.Id,
                                (e1, e2) => new { Employee = e1.Name, Manager = e2.Name });

Anti Join (e.g., Get items in one collection not in another) - Using Except, Any, or All.

    // Using Any
    var employeesWithoutDept = employees
        .Where(e => !departments.Any(d => d.Id == e.DeptId));

    // Using Left Join + DefaultIfEmpty (Query Syntax)
    var result = from e in employees
                 join d in departments on e.DeptId equals d.Id into deptGroup
                 from d in deptGroup.DefaultIfEmpty()
                 where d == null
                 select e;

Full Outer Join (Simulated) - LINQ doesn’t support full outer join directly, but we can combine left join and right join using Union.

    csharpCopyEdit// Query Syntax Simulated
    var left = from e in employees
               join d in departments on e.DeptId equals d.Id into deptGroup
               from d in deptGroup.DefaultIfEmpty()
               select new { e.Name, Department = d?.Name };

    var right = from d in departments
                join e in employees on d.Id equals e.DeptId into empGroup
                from e in empGroup.DefaultIfEmpty()
                select new { Name = e?.Name ?? "No Employee", Department = d.Name };

    var fullOuter = left.Union(right);
  1. What is the difference between [ApiController] and [Controller]?

    1. ApiController
  • [ApiController] is a real attribute used in Web API controllers.

  • It enables automatic model validation.

  • It infers binding sources like [FromBody], [FromQuery].

  • It returns 400 Bad Request automatically for invalid models.

  • It adds consistent behavior for HTTP 204 responses.

  • [ApiController] is optional but strongly recommended for Web API projects.

  1. Controller
  • [Controller] is not an actual attribute in ASP.NET Core.

  • A class is treated as a controller if it inherits from Controller or ControllerBase and ends with Controller.

  1. When would you use Dapper over EF Core?

    • Use Dapper when performance is critical and you want raw SQL control.

    • Use EF Core when productivity, relationships, and migrations are your priority.

  2. How do you protect an endpoint using Auth0 JWT in .NET Core?

    • Use [Authorize] and configure JWT authentication in Program.cs.
    app.UseAuthentication();
    app.UseAuthorization();

    [Authorize]
    [HttpGet("secure-data")]
    public IActionResult GetSecureData() => Ok("This is protected");
  1. How would you implement user authentication and authorization using Auth0 in a .NET Core application?

    • Configure JWT in Startup.cs.

    • Secure endpoints with [Authorize].

    • Use Auth0 to handle token generation.

    csharpCopyEditservices.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.Authority = "https://YOUR_AUTH0_DOMAIN";
            options.Audience = "YOUR_API_IDENTIFIER";
        });
  1. What is SignalR?

    • SignalR is a library in ASP.NET Core that simplifies adding real-time web functionality using WebSockets, Server-Sent Events, or Long Polling.

    • We used SignalR in our Dental Clinics System to broadcast appointment updates in real-time to the receptionist’s dashboard when a patient checks in. It used DynamoDB + SignalR hub to notify Angular frontend using ReceiveNotification().

  1. Real-life example use cases?
  • Live chat systems

  • Stock ticker updates

  • Real-time dashboards

  • Collaborative apps (e.g., Google Docs style)

  1. How does SignalR work under the hood?
  • Client → Hub → Server

  • SignalR auto-negotiates the best transport (WebSocket > SSE > Long Polling)

  • Maintains persistent connection using Hubs

    Basic SignalR Implementation (Code)

    1. Create a Hub

    public class ChatHub : Hub
    {
        public async Task SendMessage(string user, string message)
        {
            await Clients.All.SendAsync("ReceiveMessage", user, message);
        }
    }
  1. Register Hub in Program.cs

    builder.Services.AddSignalR();

    app.MapHub<ChatHub>("/chathub");
  1. Client-side JavaScript (basic)

    <script src="https://cdn.jsdelivr.net/npm/@microsoft/signalr@latest/dist/browser/signalr.min.js"></script>
    <script>
        const connection = new signalR.HubConnectionBuilder()
            .withUrl("/chathub")
            .build();

        connection.on("ReceiveMessage", (user, message) => {
            console.log(`${user}: ${message}`);
        });

        connection.start().then(() => {
            connection.invoke("SendMessage", "Afroz", "Hello from client!");
        });
    </script>
  1. How to send messages to specific clients or groups?
    // Send to specific connection
    await Clients.Client(connectionId).SendAsync("ReceiveMessage", user, msg);

    // To group
    await Groups.AddToGroupAsync(Context.ConnectionId, "Admins");
    await Clients.Group("Admins").SendAsync("ReceiveMessage", "System", "Admin update only.");
  1. WebSocket – Basic Idea

    What is WebSocket?

    • A persistent, full-duplex communication channel between client and server over a single TCP connection.

    • Unlike HTTP (request–response), WebSockets keep the connection open and allow real-time bidirectional data flow.

Use Cases:

  • Chat apps

  • Multiplayer games

  • Live dashboards

  • Notification systems

  1. Difference: WebSocket vs SignalR.

    • SignalR uses WebSocket internally when available but falls back gracefully.
  1. 📡 WebSocket (Raw)

  • Abstraction: Low (manual work required)

  • Ease of Use: Harder

  • Protocol Fallback: No fallback support

  • Built-in Features: None

  1. 🚀 SignalR

  • Abstraction: High (automates fallback and state management)

  • Ease of Use: Easier

  • Protocol Fallback: Yes (supports SSE, Long Polling)

  • Built-in Features: Groups, users, scaling, reconnection

  1. Using Raw WebSocket in ASP.NET Core MVC

    • ASP.NET Core supports WebSockets natively.

✅ 1. Enable WebSockets in Program.cs

    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();

    app.UseWebSockets();

    app.Use(async (context, next) =>
    {
        if (context.Request.Path == "/ws")
        {
            if (context.WebSockets.IsWebSocketRequest)
            {
                WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
                await Echo(context, webSocket);
            }
            else
            {
                context.Response.StatusCode = 400;
            }
        }
        else
        {
            await next();
        }
    });

    async Task Echo(HttpContext context, WebSocket webSocket)
    {
        var buffer = new byte[1024 * 4];
        WebSocketReceiveResult result = await webSocket.ReceiveAsync(
            new ArraySegment<byte>(buffer), CancellationToken.None);

        while (!result.CloseStatus.HasValue)
        {
            await webSocket.SendAsync(
                new ArraySegment<byte>(buffer, 0, result.Count),
                result.MessageType,
                result.EndOfMessage,
                CancellationToken.None);

            result = await webSocket.ReceiveAsync(
                new ArraySegment<byte>(buffer), CancellationToken.None);
        }

        await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
    }

2. Client-Side HTML + JS

    <input type="text" id="msg" />
    <button onclick="send()">Send</button>
    <script>
      const socket = new WebSocket("ws://localhost:5000/ws");

      socket.onopen = () => console.log("Connected");
      socket.onmessage = e => console.log("Server says:", e.data);

      function send() {
        const msg = document.getElementById("msg").value;
        socket.send(msg);
      }
    </script>

🛠️ In Traditional ASP.NET MVC (.NET Framework)?

  • ASP.NET Framework does not natively support WebSockets easily — you'd need:

  • WebSocket support in IIS 8+ and Windows Server 2012+

  • Or use SignalR (recommended) because it works better with MVC out of the box.

  1. If the interviewer asks about WebSockets:

    • Say “We use SignalR in .NET Core which builds on WebSockets when available.”
  2. What is the difference between .NET Framework 4.8 and .NET 8?

    • 🖥️ Platform

      • .NET Framework 4.8: Windows-only

      • .NET 8: Cross-platform

🔓 Open Source

  • .NET Framework 4.8: No

  • .NET 8: Yes

⚙️ Performance

  • .NET Framework 4.8: Slower

  • .NET 8: Much faster

🚀 Deployment

  • .NET Framework 4.8: Requires IIS/Windows

  • .NET 8: Can self-host via Kestrel

🖼️ UI Support

  • .NET Framework 4.8: WinForms, WPF

  • .NET 8: WinForms (Windows only), MAUI

🔄 Future Updates

  • .NET Framework 4.8: No major future updates

  • .NET 8: Actively developed

  1. Why migrate from .NET Framework to .NET 8?

    • For performance, security, and cross-platform compatibility

    • To take advantage of modern C# features, minimal APIs, containers

    • Because .NET Framework is feature-frozen since 4.8

  2. What features were introduced in C# 7.3 and 8.0?

    • Supported in Both

      • ref, readonly, in parameters

🚫 C# 7.3 Only

  • None beyond the above

C# 8.0 Only

  • Nullable Reference Types

  • Switch Expressions

  • Async Streams (await foreach)

  • Default Interface Methods

  1. What does this return and why?

    string? name = null;
    Console.WriteLine(name.Length);
    
    • In C# 8.0 with nullable reference types enabled, this gives a compile-time warning: possible dereference of null.
      In earlier versions, this compiles but throws a runtime NullReferenceException.
  2. How do you return proper status codes in Web API?

    • Answer: Use built-in methods:

        return Ok(data); // 200
        return NotFound(); // 404
        return BadRequest("Error msg"); // 400
        return StatusCode(500, "Server error"); // custom
      
  3. How do you version APIs in ASP.NET Core?

    • Answer: Use NuGet: Microsoft.AspNetCore.Mvc.Versioning

        [ApiVersion("1.0")]
        [Route("api/v{version:apiVersion}/[controller]")]
        public class ProductsController : ControllerBase
      
    • In Program.cs:

        services.AddApiVersioning(o =>
        {
            o.DefaultApiVersion = new ApiVersion(1, 0);
            o.AssumeDefaultVersionWhenUnspecified = true;
            o.ReportApiVersions = true;
        });
      
  4. What is dependency injection and how is it used in Web API?

    • Answer: Services are registered in Program.cs and injected via constructor.

    •                   // Register
                        builder.Services.AddScoped<IProductService, ProductService>();
      
                        // Use in controller
                        public class ProductController : ControllerBase {
                          private readonly IProductService _service;
                          public ProductController(IProductService service) {
                            _service = service;
                          }
                        }
      
  5. How do you secure a Web API?

    • Use JWT Bearer tokens (e.g., Auth0)

    • Add [Authorize] on controllers

    • Register middleware in Program.cs:

    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
      .AddJwtBearer(...);

    app.UseAuthentication();
    app.UseAuthorization();
  1. How do you enable CORS in Web API?

    builder.Services.AddCors(options =>
    {
        options.AddPolicy("AllowAll", policy =>
            policy.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
    });
    
    app.UseCors("AllowAll");
    
  2. How do you implement file upload in Web API?

    [HttpPost("upload")]
    public async Task<IActionResult> Upload(IFormFile file)
    {
        var path = Path.Combine("Uploads", file.FileName);
        using var stream = new FileStream(path, FileMode.Create);
        await file.CopyToAsync(stream);
        return Ok("Uploaded");
    }
    
  3. What is Model Binding and Validation in Web API?

    • Model binding auto-maps request data to C# objects.

    • Validation via [Required], [StringLength], etc.

    • Use ModelState.IsValid to check before saving.

    public class Product {
        [Required] public string Name { get; set; }
    }
  1. 🔗 What is HATEOAS?

    • HATEOAS stands for: Hypermedia As The Engine Of Application State

    • It's a constraint of REST where the server provides links (URLs) in the response so the client knows what to do next, without needing hardcoded paths.

    • You're using an app and instead of guessing the next screen or button, the app tells you:

“Hey, if you want to update, click this link. If you want to delete, go here.”

  1. 🧪 Simple Example (Without HATEOAS):

     {
       "id": 1,
       "name": "Book",
       "price": 10
     }
    
  2. ✅ With HATEOAS:

     {
       "id": 1,
       "name": "Book",
       "price": 10,
       "links": [
         { "rel": "self", "href": "/api/books/1" },
         { "rel": "update", "href": "/api/books/1", "method": "PUT" },
         { "rel": "delete", "href": "/api/books/1", "method": "DELETE" }
       ]
     }
    
    • rel = relationship (what the link is for)

    • href = where to go

    • method = what HTTP method to use

  3. 💻 .NET Example – Creating a HATEOAS response:

     public class BookWithLinks : Book
     {
         public List<Link> Links { get; set; } = new();
     }
    
     public class Link
     {
         public string Rel { get; set; }
         public string Href { get; set; }
         public string Method { get; set; }
     }
    

    In your controller:

     var book = new BookWithLinks {
         Id = 1,
         Name = "Book",
         Price = 10,
         Links = new List<Link> {
             new Link { Rel = "self", Href = $"/api/books/1", Method = "GET" },
             new Link { Rel = "update", Href = $"/api/books/1", Method = "PUT" },
             new Link { Rel = "delete", Href = $"/api/books/1", Method = "DELETE" }
         }
     };
    
  4. 📦 Real-World Use

    • Makes API self-explaining

    • Useful in hypermedia-driven REST clients

    • Common in HAL, JSON-LD, GraphQL alternatives

  1. Dapper:

    • Dapper is a lightweight, high-performance micro-ORM (Object Relational Mapper) for .NET that simplifies data access by mapping SQL query results to C# objects using extension methods on IDbConnection.

    • Types of Dapper method are as follows:

✅ 1. Query<T>()

  • Synchronously executes a query and maps the result to a list of objects.
    var users = connection.Query<User>("SELECT * FROM Users");

✅ 2. QueryAsync<T>()

  • Asynchronously executes a query and maps results to objects.
    var users = await connection.QueryAsync<User>("SELECT * FROM Users");

✅ 3. QueryFirst<T>()

  • Returns the first row of the result set, throws if none.
    var user = connection.QueryFirst<User>("SELECT * FROM Users WHERE Id = @id", new { id = 1 });

✅ 4. QueryFirstOrDefault<T>()

  • Returns the first row or default (null) if no result.
    var user = connection.QueryFirstOrDefault<User>("SELECT * FROM Users WHERE Id = @id", new { id = 999 });

✅ 5. QuerySingle<T>()

  • Expects exactly one row; throws if zero or more than one.
    var user = connection.QuerySingle<User>("SELECT * FROM Users WHERE Email = @email", new { email = "test@example.com" });

✅ 6. QuerySingleOrDefault<T>()

  • Returns single row or null; throws if more than one row.
    var user = connection.QuerySingleOrDefault<User>("SELECT * FROM Users WHERE Email = @email", new { email = "nonexistent@example.com" });

✅ 7. Execute()

  • Executes an INSERT, UPDATE, or DELETE. Returns affected row count.
    int rows = connection.Execute("DELETE FROM Users WHERE Id = @id", new { id = 5 });

✅ 8. ExecuteAsync()

  • Async version of Execute().
    int rows = await connection.ExecuteAsync("UPDATE Users SET IsActive = 1 WHERE Id = @id", new { id = 3 });

✅ 9. ExecuteScalar<T>()

  • Executes a query and returns a single value (e.g., count).
    int count = connection.ExecuteScalar<int>("SELECT COUNT(*) FROM Users");

✅ 10. ExecuteReader()

  • Returns a raw DbDataReader for manual data reading.
    using var reader = connection.ExecuteReader("SELECT * FROM Users");

11. QueryMultiple()

  • Executes multiple SQL queries in a single call and reads results separately.
    using var multi = connection.QueryMultiple("SELECT * FROM Users; SELECT * FROM Roles");
    var users = multi.Read<User>().ToList();
    var roles = multi.Read<Role>().ToList();

12. QueryAsync<T>(string, CommandType.StoredProcedure)

  • You can also call stored procedures easily.
    var result = await connection.QueryAsync<User>("GetActiveUsers", commandType: CommandType.StoredProcedure);

13. Dynamic Parameters (via DynamicParameters class)

  • Allows passing IN, OUT, and RETURN parameters to stored procs.
    var parameters = new DynamicParameters();
    parameters.Add("@Id", 1);
    var user = connection.QueryFirst<User>("GetUserById", parameters, commandType: CommandType.StoredProcedure);

14. Buffered = false (for streaming large results)

  • Prevents loading entire result set into memory.
    var users = connection.Query<User>("SELECT * FROM BigTable", buffered: false);

15. Type Handlers

  • Lets you map custom types (like enums) to DB types.
    SqlMapper.AddTypeHandler(new MyEnumHandler());

16. Transaction Support

  • You can use IDbTransaction to wrap Dapper calls in transactions.
    using var transaction = connection.BeginTransaction();
    connection.Execute("DELETE FROM Orders WHERE Id = @id", new { id = 10 }, transaction);
    transaction.Commit();

17. Dapper.Contrib (optional extension)

  • Adds methods like Insert, Update, Get, Delete.
    var user = connection.Get<User>(1);   // Needs Dapper.Contrib.Extensions
  1. What are generics?

    • Generics allow reusable, type-safe code. Prevents runtime casting errors and enables compile-time checks.

    • Generics use angle brackets to define type placeholders.

    • Here, T can be any type: int, decimal, string, MyClass, etc.

  2. When to use generics?

    • You want to write reusable code that works with different data types

    • You want type safety at compile time (avoid runtime casting errors)

    • You're working with collections, like List, Dictionary<TKey, TValue>, etc.

        public class Box<T>
        {
            public T Content;
      
            public void PrintContent()
            {
                Console.WriteLine(Content);
            }
        }
      
        Box<string> nameBox = new Box<string>();
        nameBox.Content = "Umar";
        nameBox.PrintContent();  // Output: Umar
      
        Box<int> numberBox = new Box<int>();
        numberBox.Content = 42;
        numberBox.PrintContent();  // Output: 42
      
  3. How to handle exceptions in C#?

    • You use try-catch-finally blocks.

    • It Prevents app crashes, helps recover from errors, improves user experience.

  1. try: Place the code that might throw an error

  2. catch: Handle specific exceptions

  3. finally: (Optional) Runs no matter what—used for cleanup (closing files, releasing resources, etc.)

  • Best Practices:

    • Catch only what you can handle.

    • Use specific exceptions first, then general Exception last.

    • Always log or give meaningful messages to help debugging.

    • Avoid silent catches.

    • Use finally for resource release.

  1. Access modifiers in C#?

    1. public : When you want a member to be accessible from anywhere, including other classes, assemblies, and projects.

    2. internal : When you want to allow access only within the same assembly/project, even by unrelated classes.

    3. protected : When you want to share a member with derived classes, but still keep it hidden from unrelated classes, even within the same assembly.

    4. private : When you want to restrict access to a member strictly within the same class, ensuring that no external class or derived class can access or modify it.

    5. protected internal: When access is needed from derived classes across assemblies, but also from any class within the same assembly, whether related or not.

    6. private protected: When you want access to be restricted to derived classes, but only within the same assembly—not from other assemblies.

  2. async / await / Task in C

    1. What is async?

      • Definition: Marks a method as asynchronous so it can use the await keyword and return control to the caller while waiting.

          public async Task DoWorkAsync() { ... }
        
    2. What is await?

      • Definition: await pauses the method execution until the awaited asynchronous Task completes.
        await SomeAsyncMethod();
  1. What is Task?

    • Definition: Task represents an asynchronous operation.

    • Task is used for methods returning no result (void-like).

    • Task<T> is for methods returning a result (T).

        public async Task<int> GetDataAsync() => 42;
      
  1. Why use Task over void?

    1. ✅ Task:

      • Can be awaited.

      • Exceptions can be caught.

      • Can track completion.

    2. Avoid async void:

      • Can't be awaited.

      • Hard to catch exceptions.

      • Only use for event handlers.

  2. Common Async Methods in C#

    1. Task.Run()
      Executes CPU-bound code on a background thread.

    2. Task.Delay(milliseconds)
      Creates a non-blocking delay for the given time.

    3. ConfigureAwait(false)
      Prevents capturing the current synchronization context (useful in library code to avoid deadlocks).

    4. Task.WhenAll(tasks)
      Waits for all provided tasks to complete; returns when all are done.

    5. Task.WhenAny(tasks)
      Returns the first task that completes out of multiple tasks.

  3. Examples of Common Async Methods in C#

    1. Simple Async Method:
    public async Task<string> GetNameAsync()
    {
        await Task.Delay(1000); // Simulate delay
        return "John";
    }
  1. Using WhenAll:
    await Task.WhenAll(Task1(), Task2());
  1. Using WhenAny:
    1var finishedTask = await Task.WhenAny(Task1(), Task2());
  1. Async with Dapper:
    var user = await connection.QueryFirstOrDefaultAsync<User>(
        "SELECT * FROM Users WHERE Id = @Id", new { Id = 1 });
  1. How do you debug a production issue in .NET Core?

    • Check logs (e.g., Serilog)

    • Reproduce with test data

    • Use try/catch + logging

    • Use tools like Postman for endpoint testing.

    • Use Mordern AI Tools.

    • Contact Seniors before adding any changes.

0
Subscribe to my newsletter

Read articles from Afroz Kazi directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Afroz Kazi
Afroz Kazi