.NET Azure Developer Interview Study Guide - Complete Questions & Answers
.NET Azure Developer Interview Study Guide
Complete Questions & Answers with Practical Examples
<div class="intro-section">
<p>This comprehensive study guide provides detailed answers to common .NET Azure developer interview questions. Each answer includes practical examples, code snippets, and the depth of knowledge expected in technical interviews.</p>
</div>
<div class="part-header">Part 1: Core .NET & C# Technical Questions</div>
<div class="question-block">
<h3 class="question-title">Q1: Explain the difference between IEnumerable and IQueryable</h3>
<span class="answer-label">Expected Answer</span>
<p class="content-text"><strong>IEnumerable:</strong></p>
<ul class="content-list">
<li>Represents a forward-only cursor of data in memory</li>
<li>Best for in-memory collections (List, Array, etc.)</li>
<li>LINQ operations are executed in memory using LINQ to Objects</li>
<li>All data is loaded into memory before filtering</li>
<li>Returns data as-is from the data source</li>
</ul>
<p class="content-text"><strong>IQueryable:</strong></p>
<ul class="content-list">
<li>Represents a query that hasn't been executed yet</li>
<li>Best for remote data sources (databases, web services)</li>
<li>LINQ operations are translated to the source query language (SQL for databases)</li>
<li>Filters are applied at the data source before loading into memory</li>
<li>Supports lazy loading and query optimization</li>
</ul>
<p class="practical-example-header">Practical Example:</p>
<div class="code-example">
<pre><code>// IEnumerable - loads ALL products into memory first, then filters
IEnumerable<Product> products = dbContext.Products.ToList(); var expensiveProducts = products.Where(p => p.Price > 100); // Filters in memory
// IQueryable - builds SQL query, only loads filtered results IQueryable<Product> productsQuery = dbContext.Products; var expensiveProducts = productsQuery.Where(p => p.Price > 100); // Translates to SQL WHERE clause
// The SQL generated for IQueryable would be: // SELECT * FROM Products WHERE Price > 100
// Performance difference: // If you have 1 million products but only 10 are > $100: // - IEnumerable loads 1 million records, then filters to 10 // - IQueryable loads only 10 records from the database
<div class="when-to-use">
<p><strong>When to use each:</strong></p>
<p>Use <strong>IEnumerable</strong> when working with small in-memory collections or when you need to apply complex logic that can't be translated to SQL</p>
<p>Use <strong>IQueryable</strong> when working with databases to optimize performance by filtering at the source</p>
</div>
</div>
<div class="question-block">
<h3 class="question-title">Q2: How does Garbage Collection work in .NET?</h3>
<span class="answer-label">Expected Answer</span>
<p class="content-text">.NET uses an automatic memory management system with a generational garbage collector. Here's how it works:</p>
<p class="content-text"><strong>Generational Collection:</strong></p>
<ul class="content-list">
<li><strong>Generation 0:</strong> Newly allocated objects (short-lived)</li>
<li><strong>Generation 1:</strong> Objects that survived one GC (medium-lived)</li>
<li><strong>Generation 2:</strong> Objects that survived multiple GCs (long-lived)</li>
</ul>
<p class="content-text"><strong>The GC Process:</strong></p>
<ul class="content-list">
<li><strong>Allocation:</strong> New objects go to Gen 0</li>
<li><strong>Collection Trigger:</strong> When Gen 0 fills up, GC runs</li>
<li><strong>Mark Phase:</strong> GC identifies reachable objects starting from roots (stack variables, static fields, etc.)</li>
<li><strong>Sweep Phase:</strong> Unreferenced objects are marked for collection</li>
<li><strong>Compact Phase:</strong> Memory is compacted, survivors promoted to next generation</li>
</ul>
<p class="practical-example-header">Code Example:</p>
<div class="code-example">
<pre><code>public class GarbageCollectionExample
{ public void DemonstrateGC() { // Objects created here are in Generation 0 var shortLived = new byte[1000];
// Force garbage collection (don't do this in production!)
GC.Collect(0); // Collect Generation 0
// If shortLived survives, it moves to Generation 1
var longLived = new byte[1000000];
// Check object generation
Console.WriteLine($"Generation: {GC.GetGeneration(longLived)}");
// Large objects (>85KB) go directly to Large Object Heap (LOH)
var largeObject = new byte[90000];
// LOH is collected with Generation 2
}
// Best practices for GC optimization
public void OptimizeForGC()
{
// 1. Use object pooling for frequently created objects
var stringBuilder = StringBuilderPool.Rent();
try
{
// Use the string builder
}
finally
{
StringBuilderPool.Return(stringBuilder);
}
// 2. Implement IDisposable for unmanaged resources
using (var stream = new FileStream("file.txt", FileMode.Open))
{
// Stream is disposed automatically
}
// 3. Avoid finalizers unless necessary
// 4. Use ValueTypes (struct) for small, immutable data
// 5. Minimize allocations in hot paths
}
}
<div class="key-concepts">
<h4>Key Points to Remember:</h4>
<ul>
<li>GC is non-deterministic (you can't predict exactly when it runs)</li>
<li>Finalizers delay garbage collection (objects go through additional cycle)</li>
<li>Use <code>IDisposable</code> pattern for deterministic cleanup</li>
<li>Large Object Heap (LOH) fragmentation can be an issue in long-running applications</li>
</ul>
</div>
</div>
<div class="question-block">
<h3 class="question-title">Q3: What are the different types of caching available in Azure?</h3>
<span class="answer-label">Expected Answer</span>
<p class="content-text">Azure offers multiple caching solutions for different scenarios:</p>
<p class="content-text"><strong>1. Azure Cache for Redis</strong></p>
<ul class="content-list">
<li>In-memory data store based on Redis</li>
<li>Supports complex data structures (strings, hashes, lists, sets)</li>
<li>Use cases: Session state, output caching, distributed caching</li>
</ul>
<div class="code-example">
<pre><code>public class RedisCacheService
{ private readonly IConnectionMultiplexer _redis; private readonly IDatabase _cache;
public RedisCacheService(string connectionString)
{
_redis = ConnectionMultiplexer.Connect(connectionString);
_cache = _redis.GetDatabase();
}
public async Task<T> GetAsync<T>(string key, Func<Task<T>> factory, TimeSpan expiration)
{
var cached = await _cache.StringGetAsync(key);
if (cached.HasValue)
{
return JsonSerializer.Deserialize<T>(cached);
}
var value = await factory();
await _cache.StringSetAsync(key, JsonSerializer.Serialize(value), expiration);
return value;
}
}
<p class="content-text"><strong>2. In-Memory Caching (IMemoryCache)</strong></p>
<ul class="content-list">
<li>Local to application instance</li>
<li>Fastest option but not distributed</li>
<li>Lost on application restart</li>
</ul>
<div class="code-example">
<pre><code>public class InMemoryCacheService
{ private readonly IMemoryCache _cache;
public async Task<T> GetOrCreateAsync<T>(string key, Func<Task<T>> factory)
{
return await _cache.GetOrCreateAsync(key, async entry =>
{
entry.SlidingExpiration = TimeSpan.FromMinutes(5);
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1);
return await factory();
});
}
}
<p class="content-text"><strong>3. Azure CDN (Content Delivery Network)</strong></p>
<ul class="content-list">
<li>Edge caching for static content</li>
<li>Geographic distribution</li>
<li>Reduces latency for global users</li>
</ul>
<p class="content-text"><strong>4. Azure Front Door Caching</strong></p>
<ul class="content-list">
<li>Caches at edge locations</li>
<li>URL-based caching rules</li>
<li>Good for dynamic content with predictable patterns</li>
</ul>
<p class="content-text"><strong>5. Application-Level Response Caching</strong></p>
<div class="code-example">
<pre><code>[ApiController]
public class ProductController : ControllerBase { [HttpGet] [ResponseCache(Duration = 300, VaryByQueryKeys = new[] { "category" })] public async Task<IActionResult> GetProducts([FromQuery] string category) { // Response cached for 5 minutes per category return Ok(await _productService.GetProductsAsync(category)); } }
<p class="practical-example-header">Caching Strategy Decision Matrix:</p>
<table class="comparison-table">
<thead>
<tr>
<th>Cache Type</th>
<th>Use When</th>
<th>Pros</th>
<th>Cons</th>
</tr>
</thead>
<tbody>
<tr>
<td>In-Memory</td>
<td>Single instance, small data</td>
<td>Fastest</td>
<td>Not distributed</td>
</tr>
<tr>
<td>Redis</td>
<td>Distributed, complex data</td>
<td>Scalable, persistent</td>
<td>Network latency</td>
</tr>
<tr>
<td>CDN</td>
<td>Static files, global users</td>
<td>Edge locations</td>
<td>Static content only</td>
</tr>
<tr>
<td>Front Door</td>
<td>Dynamic content, global</td>
<td>Smart routing</td>
<td>More complex setup</td>
</tr>
</tbody>
</table>
</div>
<div class="question-block">
<h3 class="question-title">Q4: How do you handle distributed transactions in microservices?</h3>
<span class="answer-label">Expected Answer</span>
<p class="content-text">Distributed transactions in microservices are challenging because traditional ACID transactions don't work across service boundaries. Here are the main patterns:</p>
<p class="content-text"><strong>1. Saga Pattern</strong></p>
<p class="content-text">Series of local transactions coordinated through events. Two types: Choreography and Orchestration</p>
<p class="practical-example-header">Orchestration Example:</p>
<div class="code-example">
<pre><code>public class OrderSaga
{ private readonly IServiceBus _serviceBus;
public async Task<bool> ProcessOrderAsync(Order order)
{
var sagaId = Guid.NewGuid();
var compensations = new Stack<Func<Task>>();
try
{
// Step 1: Reserve Inventory
var inventoryReserved = await _inventoryService.ReserveItemsAsync(order.Items, sagaId);
compensations.Push(async () => await _inventoryService.ReleaseReservationAsync(sagaId));
// Step 2: Process Payment
var paymentProcessed = await _paymentService.ChargeAsync(order.PaymentInfo, sagaId);
compensations.Push(async () => await _paymentService.RefundAsync(sagaId));
// Step 3: Create Shipment
var shipmentCreated = await _shippingService.CreateShipmentAsync(order, sagaId);
compensations.Push(async () => await _shippingService.CancelShipmentAsync(sagaId));
// All successful - confirm the transaction
await ConfirmSagaAsync(sagaId);
return true;
}
catch (Exception ex)
{
// Compensate in reverse order
while (compensations.Count > 0)
{
var compensation = compensations.Pop();
await compensation();
}
await _logger.LogSagaFailureAsync(sagaId, ex);
return false;
}
}
}
<p class="content-text"><strong>2. Event Sourcing with CQRS</strong></p>
<div class="code-example">
<pre><code>public class OrderAggregate
{ private readonly List<IEvent> _events = new();
public void PlaceOrder(OrderDetails details)
{
// Business logic validation
if (!IsValid(details))
throw new InvalidOrderException();
// Raise domain event
RaiseEvent(new OrderPlacedEvent
{
OrderId = Guid.NewGuid(),
CustomerId = details.CustomerId,
Items = details.Items,
Timestamp = DateTime.UtcNow
});
}
private void RaiseEvent(IEvent @event)
{
_events.Add(@event);
Apply(@event);
}
private void Apply(IEvent @event)
{
// Update aggregate state based on event
switch (@event)
{
case OrderPlacedEvent e:
OrderId = e.OrderId;
Status = OrderStatus.Placed;
break;
}
}
}
<p class="content-text"><strong>3. Outbox Pattern</strong></p>
<div class="code-example">
<pre><code>public class OutboxPattern
{ public async Task SaveOrderWithEventsAsync(Order order) { using var transaction = await _dbContext.Database.BeginTransactionAsync();
try
{
// Save business data
_dbContext.Orders.Add(order);
// Save events to outbox table in same transaction
var outboxEvent = new OutboxEvent
{
Id = Guid.NewGuid(),
EventType = "OrderCreated",
Payload = JsonSerializer.Serialize(order),
CreatedAt = DateTime.UtcNow,
Processed = false
};
_dbContext.OutboxEvents.Add(outboxEvent);
await _dbContext.SaveChangesAsync();
await transaction.CommitAsync();
}
catch
{
await transaction.RollbackAsync();
throw;
}
}
// Background service publishes events
public async Task ProcessOutboxEventsAsync()
{
var unpublishedEvents = await _dbContext.OutboxEvents
.Where(e => !e.Processed)
.OrderBy(e => e.CreatedAt)
.ToListAsync();
foreach (var @event in unpublishedEvents)
{
await _messageBus.PublishAsync(@event.EventType, @event.Payload);
@event.Processed = true;
@event.ProcessedAt = DateTime.UtcNow;
}
await _dbContext.SaveChangesAsync();
}
}
<div class="best-practices">
<h4>Best Practices:</h4>
<ol>
<li>Accept eventual consistency</li>
<li>Design idempotent operations</li>
<li>Implement correlation IDs for tracking</li>
<li>Use compensating transactions for rollbacks</li>
<li>Consider using Azure Service Bus or Event Grid for messaging</li>
</ol>
</div>
</div>
<div class="question-block">
<h3 class="question-title">Q5: Explain the authentication flow using Azure AD in a web application</h3>
<span class="answer-label">Expected Answer</span>
<p class="content-text"><strong>OAuth 2.0 / OpenID Connect Flow with Azure AD:</strong></p>
<p class="practical-example-header">1. Configuration in Startup.cs:</p>
<div class="code-example">
<pre><code>public class Startup
{ public void ConfigureServices(IServiceCollection services) { services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"));
services.AddAuthorization(options =>
{
options.AddPolicy("RequireAdminRole",
policy => policy.RequireRole("Admin"));
options.AddPolicy("RequireEmployeeScope",
policy => policy.RequireClaim("scope", "employee.read"));
});
services.AddMicrosoftIdentityWebApiAuthentication(Configuration, "AzureAd");
}
}
<p class="practical-example-header">2. Authentication Flow Steps:</p>
<div class="code-example">
<pre><code>public class AuthenticationFlow
{ // Step 1: User attempts to access protected resource [Authorize] public class SecureController : Controller { public IActionResult Index() { // User is redirected to Azure AD login if not authenticated return View(); } }
// Step 2: After Azure AD authentication, tokens are received
public class TokenService
{
private readonly ITokenAcquisition _tokenAcquisition;
public async Task<string> GetAccessTokenAsync()
{
// Get token for calling downstream API
var scopes = new[] { "api://your-api/.default" };
var accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes);
// Token structure:
// Header.Payload.Signature (JWT)
// Payload contains: sub (user), aud (audience), exp (expiry), roles, etc.
return accessToken;
}
}
// Step 3: Use token to call protected APIs
public class ApiClient
{
private readonly HttpClient _httpClient;
private readonly ITokenAcquisition _tokenAcquisition;
public async Task<T> CallProtectedApiAsync<T>(string endpoint)
{
var token = await _tokenAcquisition.GetAccessTokenForUserAsync(new[] { "api.scope" });
_httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token);
var response = await _httpClient.GetAsync(endpoint);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<T>();
}
}
}
<p class="practical-example-header">3. Token Validation in API:</p>
<div class="code-example">
<pre><code>[ApiController]
[Authorize] public class ProtectedApiController : ControllerBase { [HttpGet] [RequiredScope("read:data")] public async Task<IActionResult> GetData() { // Azure AD validates: // 1. Token signature // 2. Issuer (Azure AD tenant) // 3. Audience (your API) // 4. Expiration // 5. Scopes/Roles
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
var userName = User.Identity.Name;
return Ok(new { userId, userName });
}
}
<p class="practical-example-header">4. Refresh Token Flow:</p>
<div class="code-example">
<pre><code>public class TokenRefreshService
{ public async Task<AuthenticationResult> RefreshTokenAsync(string refreshToken) { var app = ConfidentialClientApplicationBuilder .Create(clientId) .WithClientSecret(clientSecret) .WithAuthority(authority) .Build();
var accounts = await app.GetAccountsAsync();
try
{
// Silent token acquisition using refresh token
var result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
.ExecuteAsync();
return result;
}
catch (MsalUiRequiredException)
{
// Refresh token expired, user must re-authenticate
throw new UnauthorizedException("Please sign in again");
}
}
}
<div class="key-concepts">
<h4>Key Concepts:</h4>
<ul>
<li><strong>ID Token:</strong> Contains user information (JWT)</li>
<li><strong>Access Token:</strong> Used to access protected resources</li>
<li><strong>Refresh Token:</strong> Used to get new access tokens</li>
<li><strong>Scopes:</strong> Permissions granted to the application</li>
<li><strong>Claims:</strong> User attributes (name, email, roles)</li>
</ul>
</div>
</div>
<div class="part-header">Part 2: Azure Services Deep Dive</div>
<div class="question-block">
<h3 class="question-title">Q6: What's the difference between Azure Functions and Azure WebJobs?</h3>
<span class="answer-label">Expected Answer</span>
<p class="content-text">Both are serverless compute options, but with key differences:</p>
<p class="practical-example-header">Azure Functions:</p>
<div class="code-example">
<pre><code>public static class FunctionExample
{ // HTTP Triggered Function [FunctionName("ProcessOrder")] public static async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequest req, [Queue("orders")] IAsyncCollector<Order> orderQueue, [Table("OrdersTable")] IAsyncCollector<OrderEntity> orderTable, ILogger log) { var order = await req.Content.ReadFromJsonAsync<Order>();
// Multiple outputs from single function
await orderQueue.AddAsync(order);
await orderTable.AddAsync(new OrderEntity(order));
return new OkObjectResult($"Order {order.Id} processed");
}
// Timer Triggered Function
[FunctionName("CleanupOldData")]
public static async Task Cleanup(
[TimerTrigger("0 0 2 * * *")] TimerInfo timer, // Runs at 2 AM daily
ILogger log)
{
log.LogInformation($"Cleanup executed at: {DateTime.Now}");
// Cleanup logic
}
}
<p class="practical-example-header">WebJobs:</p>
<div class="code-example">
<pre><code>public class WebJobExample
{ public static void Main() { var builder = new HostBuilder(); builder.ConfigureWebJobs(b => { b.AddAzureStorageCoreServices(); b.AddAzureStorage(); });
var host = builder.Build();
using (host)
{
host.Run();
}
}
// Continuous WebJob
public static async Task ProcessQueueMessage(
[QueueTrigger("orders")] Order order,
[Blob("invoices/{rand-guid}.pdf")] Stream invoiceOutput,
ILogger logger)
{
logger.LogInformation($"Processing order {order.Id}");
// Long-running process
var invoice = await GenerateInvoiceAsync(order);
await invoice.CopyToAsync(invoiceOutput);
}
}
<p class="practical-example-header">Comparison Table:</p>
<table class="comparison-table">
<thead>
<tr>
<th>Feature</th>
<th>Azure Functions</th>
<th>Azure WebJobs</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Hosting</strong></td>
<td>Standalone or in App Service</td>
<td>Only in App Service</td>
</tr>
<tr>
<td><strong>Scaling</strong></td>
<td>Auto-scales independently</td>
<td>Scales with App Service</td>
</tr>
<tr>
<td><strong>Triggers</strong></td>
<td>HTTP, Timer, Queue, Blob, Event Hub, etc.</td>
<td>Queue, Blob, Manual</td>
</tr>
<tr>
<td><strong>Languages</strong></td>
<td>C#, JavaScript, Python, Java, PowerShell</td>
<td>C#, JavaScript</td>
</tr>
<tr>
<td><strong>Pricing</strong></td>
<td>Consumption or Premium plan</td>
<td>Part of App Service plan</td>
</tr>
<tr>
<td><strong>Development</strong></td>
<td>Portal, VS, VS Code, CLI</td>
<td>Visual Studio</td>
</tr>
<tr>
<td><strong>Use Case</strong></td>
<td>Event-driven, microservices</td>
<td>Background tasks, continuous processing</td>
</tr>
<tr>
<td><strong>Max Execution Time</strong></td>
<td>5 min (Consumption), unlimited (Premium)</td>
<td>Unlimited</td>
</tr>
</tbody>
</table>
<div class="when-to-use">
<p><strong>When to Choose:</strong></p>
<p><strong>Azure Functions:</strong> Event-driven scenarios, microservices, APIs, scheduled tasks</p>
<p><strong>WebJobs:</strong> Long-running processes, complex scheduling, when already using App Service</p>
</div>
</div>
<div class="question-block">
<h3 class="question-title">Q7: How do you ensure thread safety in C#?</h3>
<span class="answer-label">Expected Answer</span>
<p class="content-text">Thread safety prevents race conditions when multiple threads access shared resources:</p>
<p class="practical-example-header">1. Locking Mechanisms:</p>
<div class="code-example">
<pre><code>public class ThreadSafeCounter
{ private int _count; private readonly object _lockObject = new object();
// Basic lock
public void IncrementWithLock()
{
lock (_lockObject)
{
_count++;
}
}
// Monitor (equivalent to lock)
public void IncrementWithMonitor()
{
Monitor.Enter(_lockObject);
try
{
_count++;
}
finally
{
Monitor.Exit(_lockObject);
}
}
// ReaderWriterLockSlim for read-heavy scenarios
private readonly ReaderWriterLockSlim _rwLock = new();
private List<string> _data = new();
public string ReadData(int index)
{
_rwLock.EnterReadLock();
try
{
return _data[index];
}
finally
{
_rwLock.ExitReadLock();
}
}
public void WriteData(string value)
{
_rwLock.EnterWriteLock();
try
{
_data.Add(value);
}
finally
{
_rwLock.ExitWriteLock();
}
}
}
<p class="practical-example-header">2. Concurrent Collections:</p>
<div class="code-example">
<pre><code>public class ConcurrentDataStructures
{ // Thread-safe collections private readonly ConcurrentDictionary<int, string> _cache = new(); private readonly ConcurrentQueue<Task> _taskQueue = new(); private readonly ConcurrentBag<LogEntry> _logs = new();
public async Task ProcessConcurrently()
{
// Thread-safe dictionary operations
_cache.TryAdd(1, "value");
_cache.AddOrUpdate(1, "new", (key, old) => "updated");
// Producer-consumer pattern
var bc = new BlockingCollection<WorkItem>(100);
// Producer
Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
bc.Add(new WorkItem { Id = i });
}
bc.CompleteAdding();
});
// Consumer
Task.Run(() =>
{
foreach (var item in bc.GetConsumingEnumerable())
{
ProcessWorkItem(item);
}
});
}
}
<p class="practical-example-header">3. Atomic Operations:</p>
<div class="code-example">
<pre><code>public class AtomicOperations
{ private int _counter; private long _total;
// Thread-safe increment without locks
public int IncrementAtomic()
{
return Interlocked.Increment(ref _counter);
}
// Thread-safe compare and swap
public bool TryUpdate(int expected, int newValue)
{
return Interlocked.CompareExchange(ref _counter, newValue, expected) == expected;
}
// Thread-safe addition
public void AddToTotal(long value)
{
Interlocked.Add(ref _total, value);
}
}
<p class="practical-example-header">4. Async/Await Patterns:</p>
<div class="code-example">
<pre><code>public class AsyncThreadSafety
{ private readonly SemaphoreSlim _semaphore = new(1, 1);
// Async-safe locking
public async Task<string> GetDataAsync()
{
await _semaphore.WaitAsync();
try
{
// Critical section
return await FetchDataAsync();
}
finally
{
_semaphore.Release();
}
}
// Async local storage
private static readonly AsyncLocal<string> _asyncLocalValue = new();
public async Task ProcessWithContext()
{
_asyncLocalValue.Value = "ContextData";
await Task.Run(() =>
{
// Value is preserved across async boundaries
Console.WriteLine(_asyncLocalValue.Value);
});
}
}
<p class="practical-example-header">5. Immutable Data Structures:</p>
<div class="code-example">
<pre><code>public class ImmutableApproach
{ // Immutable class - inherently thread-safe public class ImmutablePerson { public string Name { get; } public int Age { get; }
public ImmutablePerson(string name, int age)
{
Name = name;
Age = age;
}
// Return new instance instead of modifying
public ImmutablePerson WithAge(int newAge)
{
return new ImmutablePerson(Name, newAge);
}
}
// Using System.Collections.Immutable
private ImmutableList<string> _list = ImmutableList<string>.Empty;
public void AddItem(string item)
{
// Thread-safe: creates new list
_list = _list.Add(item);
}
}
<div class="best-practices">
<h4>Best Practices:</h4>
<ol>
<li>Prefer immutability when possible</li>
<li>Use concurrent collections over manual locking</li>
<li>Keep lock sections small</li>
<li>Avoid nested locks (deadlock risk)</li>
<li>Use <code>volatile</code> keyword for simple flag scenarios</li>
<li>Consider <code>ThreadLocal<T></code> for thread-specific data</li>
</ol>
</div>
</div>
<div class="question-block">
<h3 class="question-title">Q8: Explain async/await and when NOT to use it</h3>
<span class="answer-label">Expected Answer</span>
<p class="practical-example-header">How Async/Await Works:</p>
<div class="code-example">
<pre><code>public class AsyncAwaitExplained
{ // Async/await transforms this method into a state machine public async Task<string> GetDataAsync() { // State 0: Before first await var client = new HttpClient();
// State 1: Awaiting HTTP call
// Thread is released back to thread pool here
var response = await client.GetAsync("https://api.example.com/data");
// State 2: After HTTP call, possibly on different thread
var content = await response.Content.ReadAsStringAsync();
// State 3: Return result
return content;
}
}
<p class="practical-example-header">When TO Use Async/Await:</p>
<div class="code-example">
<pre><code>public class GoodAsyncUsage
{ // I/O Bound Operations public async Task<User> GetUserAsync(int id) { using var connection = new SqlConnection(connectionString); await connection.OpenAsync();
var command = new SqlCommand("SELECT * FROM Users WHERE Id = @id", connection);
command.Parameters.AddWithValue("@id", id);
using var reader = await command.ExecuteReaderAsync();
if (await reader.ReadAsync())
{
return MapToUser(reader);
}
return null;
}
// Multiple concurrent operations
public async Task<Dashboard> GetDashboardAsync()
{
var userTask = GetUserAsync();
var ordersTask = GetOrdersAsync();
var statsTask = GetStatisticsAsync();
await Task.WhenAll(userTask, ordersTask, statsTask);
return new Dashboard
{
User = userTask.Result,
Orders = ordersTask.Result,
Statistics = statsTask.Result
};
}
}
<p class="practical-example-header">When NOT to Use Async/Await:</p>
<div class="bad-example">
<p class="content-text"><strong>1. CPU-Bound Operations:</strong></p>
<div class="code-example">
<pre><code>// ❌ BAD: No actual async operation
public async Task<int> CalculatePrimeAsync(int n) { return await Task.Run(() => { // CPU-intensive calculation // This just moves work to another thread, doesn't save resources return CalculatePrime(n); }); }
<div class="good-example">
<div class="code-example">
<pre><code>// ✅ GOOD: Synchronous for CPU-bound
public int CalculatePrime(int n) { // Direct calculation return CalculatePrime(n); }
<div class="bad-example">
<p class="content-text"><strong>2. Simple, Fast Operations:</strong></p>
<div class="code-example">
<pre><code>// ❌ BAD: Async overhead for simple operation
private readonly Dictionary<int, string> _cache = new();
public async Task<string> GetFromCacheAsync(int key) { return await Task.FromResult(_cache[key]); }
<div class="good-example">
<div class="code-example">
<pre><code>// ✅ GOOD: Synchronous for fast operations
public string GetFromCache(int key) { return _cache[key]; }
<div class="bad-example">
<p class="content-text"><strong>3. Constructor or Property:</strong></p>
<div class="code-example">
<pre><code>// ❌ BAD: Can't make constructor async
public MyClass() { // This blocks and can cause deadlocks InitializeAsync().GetAwaiter().GetResult(); }
<div class="good-example">
<div class="code-example">
<pre><code>// ✅ GOOD: Factory pattern for async initialization
private MyClass() { }
public static async Task<MyClass> CreateAsync() { var instance = new MyClass(); await instance.InitializeAsync(); return instance; }
<div class="bad-example">
<p class="content-text"><strong>4. Avoiding Async All the Way:</strong></p>
<div class="code-example">
<pre><code>// ❌ BAD: Mixing sync and async
public void ProcessData() { var data = GetDataAsync().Result; // Can cause deadlock! Process(data); }
<div class="good-example">
<div class="code-example">
<pre><code>// ✅ GOOD: Async all the way up
public async Task ProcessDataAsync() { var data = await GetDataAsync(); Process(data); }
<div class="bad-example">
<p class="content-text"><strong>5. Short-lived, High-frequency Operations:</strong></p>
<div class="code-example">
<pre><code>// ❌ BAD: Async overhead for frequent calls
public async Task LogAsync(string message) { await Task.Run(() => Console.WriteLine(message)); }
<div class="good-example">
<div class="code-example">
<pre><code>// ✅ GOOD: Use synchronous or batch
private readonly Channel<string> _logChannel = Channel.CreateUnbounded<string>();
public void Log(string message) { _logChannel.Writer.TryWrite(message); }
// Background service processes batches public async Task ProcessLogsAsync() { await foreach (var message in _logChannel.Reader.ReadAllAsync()) { Console.WriteLine(message); } }
<p class="practical-example-header">Common Pitfalls:</p>
<div class="code-example">
<pre><code>public class AsyncPitfalls
{ // ❌ Async void (except event handlers) public async void BadMethod() { await Task.Delay(1000); // Exceptions here crash the application }
// ✅ Return Task
public async Task GoodMethod()
{
await Task.Delay(1000);
}
// ❌ Unnecessary async/await
public async Task<string> UnnecessaryAsync()
{
return await GetStringAsync();
}
// ✅ Direct return
public Task<string> DirectReturn()
{
return GetStringAsync();
}
// ⚠️ ConfigureAwait for libraries
public async Task LibraryMethod()
{
await SomeOperationAsync().ConfigureAwait(false);
// Don't capture SynchronizationContext in libraries
}
}
<div class="part-header">Part 3: System Design & Architecture Questions</div>
<div class="question-block">
<h3 class="question-title">Q9: How would you migrate a monolithic application to Azure?</h3>
<span class="answer-label">Expected Answer</span>
<p class="content-text"><strong>Step-by-Step Migration Strategy:</strong></p>
<p class="practical-example-header">Phase 1: Assessment & Planning</p>
<div class="code-example">
<pre><code>public class ApplicationAssessment
{ public class MigrationReadiness { public Dictionary<string, ComponentAnalysis> Components { get; set; }
public class ComponentAnalysis
{
public string Name { get; set; }
public List<string> Dependencies { get; set; }
public int CouplingScore { get; set; } // 1-10
public bool IsStateless { get; set; }
public string DataStore { get; set; }
public List<string> ExternalIntegrations { get; set; }
}
public MigrationStrategy DetermineStrategy()
{
// Analyze components for:
// 1. Tight coupling (database, shared state)
// 2. Business boundaries
// 3. Scalability requirements
// 4. Technology constraints
return new MigrationStrategy
{
Pattern = "StranglerFig", // or "BigBang", "BranchByAbstraction"
Priority = "CustomerFacing", // Start with edge services
Timeline = "6-12 months"
};
}
}
}
<p class="practical-example-header">Phase 2: Strangler Fig Pattern Implementation</p>
<div class="code-example">
<pre><code>// Step 1: Add API Gateway
public class ApiGatewayConfiguration { public void Configure(IApplicationBuilder app) { app.UseOcelot(async (context, next) => { // Route to monolith or new microservices var path = context.Request.Path.Value;
if (path.StartsWith("/api/users"))
{
// Route to new User microservice
context.Request.Path = "/users" + path.Substring(10);
await next.Invoke();
}
else
{
// Route to monolith
context.Request.Host = new HostString("monolith.app");
await next.Invoke();
}
});
}
}
// Step 2: Extract first microservice public class UserServiceExtraction { // Original monolith code public class MonolithUserService { private readonly AppDbContext _context;
public User GetUser(int id)
{
return _context.Users
.Include(u => u.Orders) // Tight coupling
.FirstOrDefault(u => u.Id == id);
}
}
// New microservice
public class UserMicroservice
{
private readonly UserDbContext _userContext;
private readonly IOrderServiceClient _orderService;
public async Task<UserDto> GetUserAsync(int id)
{
var user = await _userContext.Users.FindAsync(id);
// Call Order service for order data
var orders = await _orderService.GetUserOrdersAsync(id);
return new UserDto
{
Id = user.Id,
Name = user.Name,
Orders = orders
};
}
}
}
<p class="practical-example-header">Phase 3: Data Migration Strategy</p>
<div class="code-example">
<pre><code>public class DataMigrationStrategy
{ // Option 1: Shared Database Anti-pattern (temporary) public class SharedDatabaseApproach { // Both monolith and microservice access same DB // Use for gradual migration public void ConfigureServices(IServiceCollection services) { services.AddDbContext<SharedDbContext>(options => options.UseSqlServer(sharedConnectionString)); } }
// Option 2: Database per Service with Sync
public class DatabasePerService
{
public async Task MigrateDataAsync()
{
// 1. Dual writes during transition
await WriteToMonolithDb(data);
await WriteToMicroserviceDb(data);
// 2. Sync historical data
var batchSize = 1000;
var offset = 0;
while (true)
{
var batch = await GetMonolithData(offset, batchSize);
if (!batch.Any()) break;
await WriteBatchToNewDb(batch);
offset += batchSize;
// Track progress
await UpdateMigrationProgress(offset);
}
}
}
}
<p class="practical-example-header">Phase 4: Azure Service Selection</p>
<div class="yaml-block">
# Azure Architecture for Microservices
## Compute:
- Azure Kubernetes Service (AKS): For containerized microservices
- Azure Container Instances: For simple, stateless services
- Azure App Service: For .NET web apps not yet containerized
## Data:
- Azure SQL Database: For transactional data
- Cosmos DB: For globally distributed data
- Azure Cache for Redis: For session state and caching
## Messaging:
- Azure Service Bus: For reliable messaging between services
- Event Grid: For event-driven architecture
## API Management:
- Azure API Management: For API gateway, rate limiting, authentication
## Monitoring:
- Application Insights: For distributed tracing
- Azure Monitor: For infrastructure monitoring
- Log Analytics: For centralized logging
Phase 5: Deployment Pipeline
// Azure DevOps Pipeline (YAML)public class DeploymentConfiguration { public string GeneratePipeline() { return @" trigger:
- main
stages:
stage: Build jobs:
- job: BuildMicroservices
steps:
- task: Docker@2 inputs: command: 'buildAndPush' repository: '$(containerRegistry)/user-service' dockerfile: 'src/UserService/Dockerfile'
- job: BuildMicroservices
steps:
stage: DeployDev jobs:
- deployment: DeployToAKS environment: 'dev' strategy: runOnce: deploy: steps: - task: Kubernetes@1 inputs: command: 'apply' useConfigurationFile: true configuration: 'k8s/deployment.yaml'
stage: DeployProd condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')) jobs:
- deployment: BlueGreenDeployment environment: 'production' strategy: blueGreen: activeService: 'user-service-active' greenService: 'user-service-green'";
} }
Key Considerations:
- Start Small: Begin with least critical, loosely coupled components
- Maintain Both Systems: Run parallel until confident
- Data Consistency: Implement eventual consistency patterns
- Monitoring: Set up comprehensive monitoring before migration
- Rollback Plan: Always have a way to revert changes
Q10: Design a high-availability e-commerce platform on Azure
Expected AnswerArchitecture Overview:
public class HighAvailabilityArchitecture{ public class AzureComponents { // Multi-region deployment public List<string> Regions = new() { "East US", "West Europe" };
// Traffic Management public string TrafficManager = "Azure Front Door"; // Global load balancing // Compute Layer public ComputeConfiguration Compute = new() { Primary = "Azure Kubernetes Service (AKS)", AutoScaling = true, MinReplicas = 3, MaxReplicas = 100, AvailabilityZones = new[] { "1", "2", "3" } }; // Data Layer public DataConfiguration Data = new() { Database = "Cosmos DB with multi-region writes", Cache = "Azure Cache for Redis Premium", Storage = "Geo-redundant Storage (GRS)", CDN = "Azure CDN for static content" }; }}
<p class="practical-example-header">Implementation Details:</p> <p class="content-text"><strong>1. Frontend Layer (High Availability)</strong></p> <div class="code-example"> <pre><code>// Azure Front Door configurationpublic class FrontDoorConfiguration { public void ConfigureGlobalLoadBalancing() { var frontDoor = new FrontDoorConfig { BackendPools = new[] { new BackendPool { Name = "primary-pool", Backends = new[] { new Backend { Address = "eastus.app.com", Priority = 1, Weight = 50 }, new Backend { Address = "westeu.app.com", Priority = 1, Weight = 50 } }, HealthProbe = new HealthProbe { Path = "/health", Interval = TimeSpan.FromSeconds(30), Timeout = TimeSpan.FromSeconds(10) } } }, RoutingRules = new[] { new RoutingRule { Pattern = "/*", BackendPool = "primary-pool", CacheEnabled = true, CacheDuration = TimeSpan.FromMinutes(5) } } }; } }
<p class="content-text"><strong>2. API Layer (Microservices)</strong></p> <div class="code-example"> <pre><code>// Product Service with resiliencepublic class ProductService { private readonly IHttpClientFactory _httpClientFactory; private readonly IMemoryCache _cache;
public async Task<Product> GetProductAsync(int id) { // Multi-layer caching if (_cache.TryGetValue($"product_{id}", out Product cached)) { return cached; } // Circuit breaker pattern var httpClient = _httpClientFactory.CreateClient("ProductApi"); var policy = Policy .Handle<HttpRequestException>() .OrResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode) .WaitAndRetryAsync( 3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), onRetry: (outcome, timespan, retryCount, context) => { _logger.LogWarning($"Retry {retryCount} after {timespan}"); }); var response = await policy.ExecuteAsync(async () => await httpClient.GetAsync($"/api/products/{id}")); if (response.IsSuccessStatusCode) { var product = await response.Content.ReadFromJsonAsync<Product>(); _cache.Set($"product_{id}", product, TimeSpan.FromMinutes(5)); return product; } // Fallback to Cosmos DB read return await GetFromDatabaseAsync(id); }}
<p class="content-text"><strong>3. Data Layer (Multi-Region Cosmos DB)</strong></p> <div class="code-example"> <pre><code>public class CosmosDbConfiguration{ public void ConfigureHighAvailability() { var cosmosClient = new CosmosClientBuilder(connectionString) .WithApplicationRegion(Regions.EastUS) // Preferred region .WithApplicationPreferredRegions(new[] { Regions.EastUS, Regions.WestEurope, Regions.SoutheastAsia }) .WithConnectionModeDirect() // Better performance .WithBulkExecution(true) // Bulk operations .WithConsistencyLevel(ConsistencyLevel.Session) // Balance consistency/performance .Build(); }
public async Task<Order> CreateOrderWithSagaAsync(Order order) { var container = cosmosClient.GetContainer("ecommerce", "orders"); // Implement idempotency order.Id = order.IdempotencyKey ?? Guid.NewGuid().ToString(); try { // Transactional batch for consistency var batch = container.CreateTransactionalBatch( new PartitionKey(order.CustomerId)) .CreateItem(order) .CreateItem(new Inventory { ProductId = order.ProductId, Quantity = -1 }); var response = await batch.ExecuteAsync(); if (response.IsSuccessStatusCode) { // Publish to Service Bus for order processing await _serviceBus.SendMessageAsync(new ServiceBusMessage( JsonSerializer.Serialize(order)) { Subject = "OrderCreated", SessionId = order.CustomerId // For FIFO processing }); } return order; } catch (CosmosException ex) when (ex.StatusCode == HttpStatusCode.Conflict) { // Idempotent - order already exists return await GetOrderAsync(order.Id); } }}
<p class="content-text"><strong>4. Messaging Layer (Service Bus)</strong></p> <div class="code-example"> <pre><code>public class OrderProcessingService{ public void ConfigureServiceBus() { var client = new ServiceBusClient(connectionString, new ServiceBusClientOptions { TransportType = ServiceBusTransportType.AmqpWebSockets, RetryOptions = new ServiceBusRetryOptions { MaxRetries = 3, Delay = TimeSpan.FromSeconds(1), MaxDelay = TimeSpan.FromSeconds(10), Mode = ServiceBusRetryMode.Exponential } });
// Configure processor with session for ordered processing var processor = client.CreateSessionProcessor("orders", new ServiceBusSessionProcessorOptions { MaxConcurrentSessions = 100, MaxConcurrentCallsPerSession = 1, // Ensure order SessionIdleTimeout = TimeSpan.FromMinutes(5) }); }}
<p class="content-text"><strong>5. Monitoring & Observability</strong></p> <div class="code-example"> <pre><code>public class ObservabilityConfiguration{ public void ConfigureApplicationInsights(IServiceCollection services) { services.AddApplicationInsightsTelemetry(); services.AddSingleton<ITelemetryInitializer, CustomTelemetryInitializer>();
// Custom metrics services.Configure<TelemetryConfiguration>((o) => { o.TelemetryProcessorChainBuilder .Use((next) => new AdaptiveSamplingTelemetryProcessor(next)) .Build(); }); } public class CustomTelemetryInitializer : ITelemetryInitializer { public void Initialize(ITelemetry telemetry) { telemetry.Context.Properties["Environment"] = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); telemetry.Context.Properties["Region"] = Environment.GetEnvironmentVariable("AZURE_REGION"); if (telemetry is RequestTelemetry request) { // Add custom dimensions request.Properties["UserId"] = HttpContext.Current?.User?.Identity?.Name; } } }}
<p class="practical-example-header">Disaster Recovery Strategy:</p> <div class="yaml-block">RTO (Recovery Time Objective): 5 minutes RPO (Recovery Point Objective): 1 minute
Strategies:
- Active-Active: Both regions serve traffic
- Database: Cosmos DB with multi-region writes
- Storage: Geo-redundant storage with RA-GRS
- Backup: Automated backups every hour
- Failover: Automated via Azure Front Door health probes
- Testing: Monthly DR drills
Part 4: Best Practices & Advanced Topics
Q11: How do you optimize LINQ queries for performance?
Expected AnswerCommon LINQ Performance Issues and Solutions:
public class LinqOptimization{ private readonly AppDbContext _context;
// ❌ BAD: N+1 Query Problem public void BadExample() { var orders = _context.Orders.ToList(); foreach (var order in orders) { // Each iteration triggers a database query Console.WriteLine(order.Customer.Name); } } // ✅ GOOD: Eager Loading public void GoodExample() { var orders = _context.Orders .Include(o => o.Customer) .ToList(); } // ❌ BAD: Loading unnecessary data public List<string> GetProductNames() { return _context.Products .ToList() // Loads entire product objects .Select(p => p.Name) .ToList(); } // ✅ GOOD: Project only needed fields public List<string> GetProductNamesOptimized() { return _context.Products .Select(p => p.Name) // SQL: SELECT Name FROM Products .ToList(); } // ❌ BAD: Multiple database round trips public async Task<DashboardData> GetDashboardDataSlow() { var totalOrders = await _context.Orders.CountAsync(); var pendingOrders = await _context.Orders.Where(o => o.Status == "Pending").CountAsync(); var totalRevenue = await _context.Orders.SumAsync(o => o.Total); return new DashboardData { TotalOrders = totalOrders, PendingOrders = pendingOrders, Revenue = totalRevenue }; } // ✅ GOOD: Single query with aggregation public async Task<DashboardData> GetDashboardDataOptimized() { return await _context.Orders .GroupBy(o => 1) // Group all into single group .Select(g => new DashboardData { TotalOrders = g.Count(), PendingOrders = g.Count(o => o.Status == "Pending"), Revenue = g.Sum(o => o.Total) }) .FirstOrDefaultAsync(); } // Compiled Queries for frequently used queries private static readonly Func<AppDbContext, int, Task<Product>> GetProductById = EF.CompileAsyncQuery((AppDbContext context, int id) => context.Products.FirstOrDefault(p => p.Id == id)); public Task<Product> GetProductByIdFast(int id) { return GetProductById(_context, id); } // AsNoTracking for read-only operations public async Task<List<ProductDto>> GetProductsReadOnly() { return await _context.Products .AsNoTracking() // Don't track entities for change detection .Where(p => p.IsActive) .Select(p => new ProductDto { Id = p.Id, Name = p.Name }) .ToListAsync(); }}
<div class="question-block"> <h3 class="question-title">Q12: Implement a real-time notification system using Azure services</h3> <span class="answer-label">Expected Answer</span> <p class="content-text">Complete implementation using SignalR and Azure Services</p> <p class="practical-example-header">1. SignalR Hub</p> <div class="code-example"> <pre><code>public class NotificationHub : Hub{ private readonly IConnectionManager _connectionManager;
public override async Task OnConnectedAsync() { var userId = Context.User.Identity.Name; await _connectionManager.AddConnectionAsync(userId, Context.ConnectionId); await Groups.AddToGroupAsync(Context.ConnectionId, $"user-{userId}"); await base.OnConnectedAsync(); } public async Task SubscribeToCategory(string category) { await Groups.AddToGroupAsync(Context.ConnectionId, $"category-{category}"); }}
<p class="practical-example-header">2. Service Bus Message Handler</p> <div class="code-example"> <pre><code>public class NotificationProcessor : IHostedService{ private readonly ServiceBusProcessor _processor; private readonly IHubContext<NotificationHub> _hubContext;
public async Task StartAsync(CancellationToken cancellationToken) { _processor.ProcessMessageAsync += HandleMessageAsync; _processor.ProcessErrorAsync += HandleErrorAsync; await _processor.StartProcessingAsync(cancellationToken); } private async Task HandleMessageAsync(ProcessMessageEventArgs args) { var notification = JsonSerializer.Deserialize<Notification>(args.Message.Body); switch (notification.Type) { case NotificationType.User: await _hubContext.Clients.Group($"user-{notification.UserId}") .SendAsync("ReceiveNotification", notification); break; case NotificationType.Broadcast: await _hubContext.Clients.All .SendAsync("ReceiveNotification", notification); break; case NotificationType.Category: await _hubContext.Clients.Group($"category-{notification.Category}") .SendAsync("ReceiveNotification", notification); break; } await args.CompleteMessageAsync(args.Message); }}
<p class="practical-example-header">3. Notification Service</p> <div class="code-example"> <pre><code>public class NotificationService{ private readonly ServiceBusSender _sender; private readonly INotificationRepository _repository;
public async Task SendNotificationAsync(Notification notification) { // Save to database for persistence await _repository.SaveAsync(notification); // Send to Service Bus for real-time delivery var message = new ServiceBusMessage(JsonSerializer.Serialize(notification)) { Subject = notification.Type.ToString(), ContentType = "application/json", TimeToLive = TimeSpan.FromHours(1) }; await _sender.SendMessageAsync(message); } // Batch notifications for efficiency public async Task SendBatchNotificationsAsync(List<Notification> notifications) { var messages = notifications.Select(n => new ServiceBusMessage( JsonSerializer.Serialize(n)) { Subject = n.Type.ToString() }).ToList(); await _sender.SendMessagesAsync(messages); }}
<p class="practical-example-header">4. Push Notifications (Mobile)</p> <div class="code-example"> <pre><code>public class PushNotificationService{ private readonly NotificationHubClient _hubClient;
public async Task SendPushNotificationAsync(string userId, string message) { var notification = new Dictionary<string, string> { { "message", message }, { "badge", "1" } }; // Send to specific user's devices await _hubClient.SendTemplateNotificationAsync(notification, $"userId:{userId}"); }}
<p class="practical-example-header">5. Client-side (JavaScript/TypeScript)</p> <div class="code-example"> <pre><code>const connection = new signalR.HubConnectionBuilder() .withUrl('/notificationHub') .withAutomaticReconnect([0, 2000, 10000, 30000]) .build();connection.on('ReceiveNotification', (notification) => { // Handle notification showToast(notification); updateNotificationBadge();
// Store in IndexedDB for offline access await db.notifications.add(notification);});
// Reconnection handling connection.onreconnecting(error => { console.log('Reconnecting...', error); showConnectionStatus('reconnecting'); });
connection.onreconnected(connectionId => { console.log('Reconnected', connectionId); showConnectionStatus('connected');
// Re-subscribe to categories subscribeToCategories();});
await connection.start();
<p class="practical-example-header">6. Scaling Configuration</p> <div class="code-example"> <pre><code>public class ScalingConfiguration{ public void ConfigureServices(IServiceCollection services) { // Use Azure SignalR Service for scaling services.AddSignalR() .AddAzureSignalR(options => { options.ConnectionString = Configuration["Azure:SignalR:ConnectionString"]; options.ServerStickyMode = ServerStickyMode.Required; });
// Redis backplane for multiple servers services.AddStackExchangeRedisCache(options => { options.Configuration = Configuration["Redis:ConnectionString"]; }); }}
<div class="conclusion-section"> <h2>Conclusion</h2> <p class="content-text">This study guide covers the essential topics for .NET Azure developer interviews. Remember:</p> <ol> <li><strong>Understand the concepts deeply</strong> - Don't just memorize answers</li> <li><strong>Practice coding</strong> - Implement these patterns yourself</li> <li><strong>Know the trade-offs</strong> - Every solution has pros and cons</li> <li><strong>Stay current</strong> - Azure services evolve rapidly</li> <li><strong>Think about scale</strong> - Consider performance and cost implications</li> </ol> <p class="content-text" style="margin-top: 25px; font-style: italic;">Focus on understanding the "why" behind each solution, as interviewers value problem-solving approach over memorized answers. Good luck with your interview preparation!</p> </div>