아래는 MCP를 활용한 ASP.NET Core 애플리케이션을 설치부터 실행까지 단계별로 진행하는 시나리오와 실행 가능한 샘플 코드를 제공합니다.
dotnet --version
명령어로 버전을 확인합니다.dotnet new web -n MCPExample
cd MCPExample
프로젝트의 Program.cs
파일에 아래의 코드를 작성합니다. 이 코드는 MCP를 구현하는 핵심 클래스들과 미들웨어를 포함하며, 간단한 GET 엔드포인트에서 컨텍스트 정보를 출력합니다.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
using System;
using System.Linq;
using System.Threading;
// 애플리케이션 시작: minimal hosting model (.NET 6 이상)
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// MCP 미들웨어 등록: 모든 요청에 대해 RequestContext를 자동 설정
app.UseMiddleware<RequestContextMiddleware>();
// 간단한 엔드포인트: 현재 RequestContext 정보를 반환
app.MapGet("/", (HttpContext context) =>
{
var reqContext = RequestContextProvider.Current;
return $"Hello, {reqContext.UserId} from tenant {reqContext.TenantId}! (CorrelationId: {reqContext.CorrelationId})";
});
// 애플리케이션 실행
app.Run();
// =============================
// MCP 구현 관련 클래스들
// =============================
/// <summary>
/// 요청과 관련된 정보를 담는 모델 (MCP 컨텍스트)
/// C# 11의 required 키워드를 사용하여 필수 초기화를 강제
/// </summary>
public class RequestContext
{
public required string CorrelationId { get; set; } = Guid.NewGuid().ToString();
public required string UserId { get; set; }
public required string TenantId { get; set; }
}
/// <summary>
/// AsyncLocal을 사용하여 스레드 및 비동기 환경에서도 안전하게 RequestContext를 관리하는 제공자 클래스
/// </summary>
public static class RequestContextProvider
{
private static readonly AsyncLocal<RequestContext?> _context = new();
public static RequestContext Current => _context.Value ??= new RequestContext { UserId = "Anonymous", TenantId = "default" };
public static void Set(RequestContext context) => _context.Value = context;
}
/// <summary>
/// HTTP 요청마다 RequestContext를 생성 및 설정해주는 미들웨어
/// </summary>
public class RequestContextMiddleware
{
private readonly RequestDelegate _next;
public RequestContextMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
// HttpContext의 User.Identity 정보나 헤더를 통해 사용자/테넌트 정보를 추출
var userId = context.User.Identity?.Name ?? "Anonymous";
var tenantId = context.Request.Headers["X-Tenant-ID"].FirstOrDefault() ?? "default";
// 새로운 RequestContext 인스턴스 생성
var requestContext = new RequestContext
{
UserId = userId,
TenantId = tenantId
};
// RequestContextProvider에 설정하여 이후 어디서든 접근 가능하도록 함
RequestContextProvider.Set(requestContext);
// 다음 미들웨어로 요청 전달
await _next(context);
}
}
dotnet run
http://localhost:5000
(또는 출력되는 URL)을 입력하면, 다음과 같은 결과를 확인할 수 있습니다.Hello, Anonymous from tenant default! (CorrelationId: {랜덤GUID})
X-Tenant-ID
헤더를 포함한 요청을 보내면, 응답 메시지에 반영되는 것을 확인할 수 있습니다.Hello, Anonymous from tenant MyTenant! (CorrelationId: {랜덤GUID})
curl -H "X-Tenant-ID: MyTenant" http://localhost:5000
위 예제는 MCP(Model Context Protocol)를 활용하여 비동기 환경에서도 안전하게 요청 컨텍스트를 관리하는 방법을 보여줍니다.
MCP(Model Context Protocol)는 단순히 HttpContext
대체 용도로만 사용되는 것이 아니라, 다양한 비동기 및 분산 환경에서도 활용할 수 있습니다. 여기서는 다음과 같은 대표적인 활용 사례를 예제 코드와 함께 소개하겠습니다.
백그라운드 작업을 수행하는 동안에도 RequestContext
를 유지하여, 요청과 관련된 데이터를 안전하게 전달할 수 있습니다.
using System;
using System.Threading;
using System.Threading.Tasks;
public class BackgroundWorker
{
public async Task ProcessAsync()
{
Console.WriteLine($"[Background Task] User: {RequestContextProvider.Current.UserId}, Tenant: {RequestContextProvider.Current.TenantId}");
await Task.Delay(1000); // 비동기 작업 시뮬레이션
}
}
// 실행 코드 예제
public class Program
{
public static async Task Main()
{
// MCP 컨텍스트 설정
var context = new RequestContext
{
UserId = "User123",
TenantId = "TenantA"
};
RequestContextProvider.Set(context);
Console.WriteLine($"[Main] User: {RequestContextProvider.Current.UserId}, Tenant: {RequestContextProvider.Current.TenantId}");
// 백그라운드 작업 실행
var worker = new BackgroundWorker();
await worker.ProcessAsync();
}
}
[Main] User: User123, Tenant: TenantA
[Background Task] User: User123, Tenant: TenantA
ThreadLocal
을 사용하면 백그라운드 작업에서 컨텍스트를 유지하기 어려운데, MCP를 사용하면 비동기 작업에서도 컨텍스트가 올바르게 유지됩니다.비동기 메시지 큐를 사용할 때, 메시지 컨텍스트(예: CorrelationId
)를 유지하면서 안전한 로깅과 트레이싱이 가능합니다.
using System;
using System.Threading.Tasks;
public class MessageQueueProcessor
{
public async Task ProcessMessageAsync(string message)
{
// 현재 컨텍스트 정보를 이용하여 메시지 처리
Console.WriteLine($"[Processing] CorrelationId: {RequestContextProvider.Current.CorrelationId}, Message: {message}");
await Task.Delay(500);
}
}
// 실행 코드 예제
public class Program
{
public static async Task Main()
{
var context = new RequestContext
{
UserId = "User123",
TenantId = "TenantB",
CorrelationId = Guid.NewGuid().ToString()
};
RequestContextProvider.Set(context);
Console.WriteLine($"[Main] CorrelationId: {RequestContextProvider.Current.CorrelationId}");
// 메시지 큐에서 메시지 수신 후 처리
var processor = new MessageQueueProcessor();
await processor.ProcessMessageAsync("Hello from queue");
}
}
[Main] CorrelationId: 123e4567-e89b-12d3-a456-426614174000
[Processing] CorrelationId: 123e4567-e89b-12d3-a456-426614174000, Message: Hello from queue
CorrelationId
를 자동으로 유지하면서 로깅과 디버깅을 쉽게 할 수 있습니다.MCP를 사용하면 분산 시스템에서 요청을 추적하는 CorrelationId
를 자동으로 유지할 수 있습니다.
using System;
using System.Diagnostics;
using System.Threading.Tasks;
public class TracingExample
{
private static readonly ActivitySource ActivitySource = new("MCPTracing");
public async Task ProcessWithTracingAsync()
{
using var activity = ActivitySource.StartActivity("ProcessWithTracing");
activity?.SetTag("UserId", RequestContextProvider.Current.UserId);
activity?.SetTag("TenantId", RequestContextProvider.Current.TenantId);
activity?.SetTag("CorrelationId", RequestContextProvider.Current.CorrelationId);
Console.WriteLine($"[Tracing] CorrelationId: {RequestContextProvider.Current.CorrelationId}");
await Task.Delay(500);
}
}
// 실행 코드 예제
public class Program
{
public static async Task Main()
{
var context = new RequestContext
{
UserId = "UserXYZ",
TenantId = "TenantC",
CorrelationId = Guid.NewGuid().ToString()
};
RequestContextProvider.Set(context);
var tracer = new TracingExample();
await tracer.ProcessWithTracingAsync();
}
}
[Tracing] CorrelationId: 7f3b4a29-cc3d-4b5d-913c-9d531df23e99
MCP를 활용하면 다중 테넌트 SaaS 애플리케이션에서 각 테넌트의 데이터를 분리하여 관리할 수 있습니다.
using System;
public class MultiTenantService
{
public void ProcessTenantData()
{
Console.WriteLine($"[Multi-Tenant] Processing data for Tenant: {RequestContextProvider.Current.TenantId}");
}
}
// 실행 코드 예제
public class Program
{
public static void Main()
{
// 테넌트 A의 컨텍스트 설정
var tenantAContext = new RequestContext { UserId = "UserA", TenantId = "TenantA" };
RequestContextProvider.Set(tenantAContext);
var serviceA = new MultiTenantService();
serviceA.ProcessTenantData();
// 테넌트 B의 컨텍스트 설정
var tenantBContext = new RequestContext { UserId = "UserB", TenantId = "TenantB" };
RequestContextProvider.Set(tenantBContext);
var serviceB = new MultiTenantService();
serviceB.ProcessTenantData();
}
}
[Multi-Tenant] Processing data for Tenant: TenantA
[Multi-Tenant] Processing data for Tenant: TenantB
TenantId
를 유지하여 데이터가 섞이지 않도록 안전하게 관리할 수 있습니다.MCP는 HttpContext
를 대체하는 것뿐만 아니라, 다양한 비동기 환경에서 안정적인 컨텍스트 전파를 가능하게 합니다.
활용 사례 | MCP 장점 |
---|---|
백그라운드 작업 | 비동기 작업에서도 컨텍스트 유지 |
메시지 큐(Kafka, RabbitMQ) | 메시지 처리 시 CorrelationId 자동 유지 |
분산 트레이싱(OpenTelemetry) | CorrelationId 를 유지하여 서비스 간 요청 추적 가능 |
다중 테넌트 SaaS | TenantId 를 유지하여 다중 테넌트 환경에서 데이터 분리 가능 |
AsyncLocal
기반으로 비동기 요청에서도 컨텍스트를 유지할 수 있으며,
참고 사이트
Model Context Protocol with .NET 9: A Game Changer for Scalable Applications
.NET 9 brings several enhancements to the framework, but one of the most compelling additions for backend developers is the Model Context…
medium.com
ASP.NET Core 8 환경, NLB(네트워크 로드 밸런싱) 세션(Session) 조치 제안방법 찾기 (0) | 2025.04.02 |
---|---|
ASP.NET Core : 정적 파일 제공 시 보안적인 측면 고려 (0) | 2025.03.27 |
ASP.NET Core + SixLabors 이모티콘 생성 및 실시간 미리보기 기능 (0) | 2025.03.14 |
ASP.NET Core 8 MVC 의 Tailwind CSS 3 버전 설치 및 설정 가이드 (0) | 2025.03.13 |
.NET Development Rules (0) | 2025.03.12 |
내 블로그 - 관리자 홈 전환 |
Q
Q
|
---|---|
새 글 쓰기 |
W
W
|
글 수정 (권한 있는 경우) |
E
E
|
---|---|
댓글 영역으로 이동 |
C
C
|
이 페이지의 URL 복사 |
S
S
|
---|---|
맨 위로 이동 |
T
T
|
티스토리 홈 이동 |
H
H
|
단축키 안내 |
Shift + /
⇧ + /
|
* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.