<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Program.cs Archives - 어제와 내일의 나 그 사이의 이야기</title>
	<atom:link href="https://lycos7560.com/tag/program-cs/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>생각의 흐름을 타고 다니며 만드는 블로그</description>
	<lastBuildDate>Wed, 30 Jul 2025 07:13:31 +0000</lastBuildDate>
	<language>ko-KR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>

<image>
	<url>https://lycos7560.com/wp-content/uploads/2022/11/cropped-cropped-cropped-log-1-150x150-1-80x80.png</url>
	<title>Program.cs Archives - 어제와 내일의 나 그 사이의 이야기</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>ASP.NET Core의 미들웨어(Middleware)</title>
		<link>https://lycos7560.com/c/asp-net-core%ec%9d%98-%eb%af%b8%eb%93%a4%ec%9b%a8%ec%96%b4middleware/40130/</link>
					<comments>https://lycos7560.com/c/asp-net-core%ec%9d%98-%eb%af%b8%eb%93%a4%ec%9b%a8%ec%96%b4middleware/40130/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Thu, 24 Jul 2025 23:32:09 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[action]]></category>
		<category><![CDATA[API Gateway]]></category>
		<category><![CDATA[API 게이트웨이]]></category>
		<category><![CDATA[ASP.NET Core]]></category>
		<category><![CDATA[ASP.NET Core MVC]]></category>
		<category><![CDATA[async]]></category>
		<category><![CDATA[Asynchronous]]></category>
		<category><![CDATA[Authentication]]></category>
		<category><![CDATA[Authorization]]></category>
		<category><![CDATA[Await]]></category>
		<category><![CDATA[Caching]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Compression]]></category>
		<category><![CDATA[Conditional Middleware]]></category>
		<category><![CDATA[Configuration]]></category>
		<category><![CDATA[Configure]]></category>
		<category><![CDATA[Container]]></category>
		<category><![CDATA[Controller]]></category>
		<category><![CDATA[Conventional Middleware]]></category>
		<category><![CDATA[CORS]]></category>
		<category><![CDATA[Cross-Origin Resource Sharing]]></category>
		<category><![CDATA[Custom Middleware]]></category>
		<category><![CDATA[Debugging]]></category>
		<category><![CDATA[DELETE]]></category>
		<category><![CDATA[Dependency Injection]]></category>
		<category><![CDATA[Deployment]]></category>
		<category><![CDATA[Developer]]></category>
		<category><![CDATA[Development Environment]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[DI]]></category>
		<category><![CDATA[Error Handling]]></category>
		<category><![CDATA[event]]></category>
		<category><![CDATA[Event-driven]]></category>
		<category><![CDATA[Exception Handling]]></category>
		<category><![CDATA[Extension Method]]></category>
		<category><![CDATA[Factory-based Middleware]]></category>
		<category><![CDATA[filter]]></category>
		<category><![CDATA[GET]]></category>
		<category><![CDATA[HEAD]]></category>
		<category><![CDATA[Headers]]></category>
		<category><![CDATA[HTTP Context]]></category>
		<category><![CDATA[HTTP Method]]></category>
		<category><![CDATA[HTTP Request]]></category>
		<category><![CDATA[HTTP Response]]></category>
		<category><![CDATA[HTTP 메서드]]></category>
		<category><![CDATA[HTTP 요청]]></category>
		<category><![CDATA[HTTP 응답]]></category>
		<category><![CDATA[HTTP 컨텍스트]]></category>
		<category><![CDATA[HTTP/1.1]]></category>
		<category><![CDATA[HTTP/2]]></category>
		<category><![CDATA[HttpContext]]></category>
		<category><![CDATA[HTTPS Redirection]]></category>
		<category><![CDATA[HTTPS 리디렉션]]></category>
		<category><![CDATA[IApplicationBuilder]]></category>
		<category><![CDATA[IMiddleware]]></category>
		<category><![CDATA[Integration Testing]]></category>
		<category><![CDATA[Invoke]]></category>
		<category><![CDATA[Kestrel]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[Logging]]></category>
		<category><![CDATA[Logging Provider]]></category>
		<category><![CDATA[Maintainability]]></category>
		<category><![CDATA[Microservices]]></category>
		<category><![CDATA[Middleware]]></category>
		<category><![CDATA[Middleware Chain]]></category>
		<category><![CDATA[Minimal APIs]]></category>
		<category><![CDATA[Modularization]]></category>
		<category><![CDATA[next]]></category>
		<category><![CDATA[Non-Terminal Middleware]]></category>
		<category><![CDATA[Ops]]></category>
		<category><![CDATA[options]]></category>
		<category><![CDATA[Order Critical]]></category>
		<category><![CDATA[PATCH]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[pipeline]]></category>
		<category><![CDATA[POST]]></category>
		<category><![CDATA[Production Environment]]></category>
		<category><![CDATA[Program.cs]]></category>
		<category><![CDATA[Protocol]]></category>
		<category><![CDATA[PUT]]></category>
		<category><![CDATA[Request Body]]></category>
		<category><![CDATA[Request Flow]]></category>
		<category><![CDATA[Request Pipeline]]></category>
		<category><![CDATA[RequestDelegate]]></category>
		<category><![CDATA[Response Body]]></category>
		<category><![CDATA[Response Flow]]></category>
		<category><![CDATA[Reusability]]></category>
		<category><![CDATA[Reverse Proxy]]></category>
		<category><![CDATA[Routing]]></category>
		<category><![CDATA[Run]]></category>
		<category><![CDATA[Scalability]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Separation of Concerns]]></category>
		<category><![CDATA[Service Container]]></category>
		<category><![CDATA[Short-circuit]]></category>
		<category><![CDATA[Single Responsibility Principle]]></category>
		<category><![CDATA[SoC]]></category>
		<category><![CDATA[SSL]]></category>
		<category><![CDATA[Startup]]></category>
		<category><![CDATA[Static Files]]></category>
		<category><![CDATA[Status Code]]></category>
		<category><![CDATA[study]]></category>
		<category><![CDATA[Terminal Middleware]]></category>
		<category><![CDATA[Testing]]></category>
		<category><![CDATA[TLS]]></category>
		<category><![CDATA[Unit Testing]]></category>
		<category><![CDATA[Use]]></category>
		<category><![CDATA[UseWhen]]></category>
		<category><![CDATA[Web Application]]></category>
		<category><![CDATA[Web Application Framework]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[Web Server]]></category>
		<category><![CDATA[Web Service]]></category>
		<category><![CDATA[WebApplication]]></category>
		<category><![CDATA[WebApplicationBuilder]]></category>
		<category><![CDATA[개발 환경]]></category>
		<category><![CDATA[개발자]]></category>
		<category><![CDATA[공부]]></category>
		<category><![CDATA[관심사의 분리]]></category>
		<category><![CDATA[기초]]></category>
		<category><![CDATA[단락]]></category>
		<category><![CDATA[단위 테스트]]></category>
		<category><![CDATA[단일 책임 원칙]]></category>
		<category><![CDATA[디버깅]]></category>
		<category><![CDATA[라우팅]]></category>
		<category><![CDATA[로깅]]></category>
		<category><![CDATA[로깅 프로바이더]]></category>
		<category><![CDATA[리버스 프록시]]></category>
		<category><![CDATA[마이크로서비스]]></category>
		<category><![CDATA[모듈화]]></category>
		<category><![CDATA[미들웨어]]></category>
		<category><![CDATA[미들웨어 체인]]></category>
		<category><![CDATA[배포]]></category>
		<category><![CDATA[보안]]></category>
		<category><![CDATA[비동기]]></category>
		<category><![CDATA[비종료 미들웨어]]></category>
		<category><![CDATA[상태 코드]]></category>
		<category><![CDATA[서비스 메쉬]]></category>
		<category><![CDATA[서비스 컨테이너]]></category>
		<category><![CDATA[설정]]></category>
		<category><![CDATA[성능]]></category>
		<category><![CDATA[순서 중요]]></category>
		<category><![CDATA[압축]]></category>
		<category><![CDATA[액션]]></category>
		<category><![CDATA[예외 처리]]></category>
		<category><![CDATA[오류 처리]]></category>
		<category><![CDATA[요청 본문]]></category>
		<category><![CDATA[요청 파이프라인]]></category>
		<category><![CDATA[요청 흐름]]></category>
		<category><![CDATA[웹 개발]]></category>
		<category><![CDATA[웹 서버]]></category>
		<category><![CDATA[웹 서비스]]></category>
		<category><![CDATA[웹 애플리케이션]]></category>
		<category><![CDATA[웹 애플리케이션 프레임워크]]></category>
		<category><![CDATA[유지보수성]]></category>
		<category><![CDATA[응답 본문]]></category>
		<category><![CDATA[응답 흐름]]></category>
		<category><![CDATA[의존성 주입]]></category>
		<category><![CDATA[이벤트]]></category>
		<category><![CDATA[이벤트 드리븐]]></category>
		<category><![CDATA[인가]]></category>
		<category><![CDATA[인증]]></category>
		<category><![CDATA[재사용성]]></category>
		<category><![CDATA[정적 파일]]></category>
		<category><![CDATA[조건부 미들웨어]]></category>
		<category><![CDATA[종료 미들웨어]]></category>
		<category><![CDATA[최소 API]]></category>
		<category><![CDATA[캐싱]]></category>
		<category><![CDATA[커스텀 미들웨어]]></category>
		<category><![CDATA[컨벤셔널 미들웨어]]></category>
		<category><![CDATA[컨테이너]]></category>
		<category><![CDATA[컨트롤러]]></category>
		<category><![CDATA[쿠버네티스]]></category>
		<category><![CDATA[클라우드]]></category>
		<category><![CDATA[테스트]]></category>
		<category><![CDATA[통합 테스트]]></category>
		<category><![CDATA[파이프라인]]></category>
		<category><![CDATA[팩토리 기반 미들웨어]]></category>
		<category><![CDATA[프로덕션 환경]]></category>
		<category><![CDATA[프로토콜]]></category>
		<category><![CDATA[필터]]></category>
		<category><![CDATA[헤더]]></category>
		<category><![CDATA[확장 메서드]]></category>
		<category><![CDATA[확장성]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=40130</guid>

					<description><![CDATA[<p>❓ 미들웨어(Middleware) https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-8.0 ASP.NET Core의 미들웨어는 모든 HTTP 요청과 응답 파이프라인을 형성하는 일련의 구성 요소입니다. 각 미들웨어 구성 요소는 다음을 수행할 수 있습니다: 이러한 파이프라인을 통해 애플리케이션의 로직을 모듈화하고, 인증, 로깅, 오류 처리, 라우팅 등과 같은 기능을 깔끔하고 유지 관리하기 쉬운 방식으로 추가할 수 있습니다. ⛓️ 미들웨어 체인 (요청 파이프라인) ASP.NET Core 요청 파이프라인은 차례로 [&#8230;]</p>
<p>The post <a href="https://lycos7560.com/c/asp-net-core%ec%9d%98-%eb%af%b8%eb%93%a4%ec%9b%a8%ec%96%b4middleware/40130/">ASP.NET Core의 미들웨어(Middleware)</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-db9d164c      "
					data-scroll= "1"
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							목차						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#미들웨어middleware" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2753.png" alt="❓" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 미들웨어(Middleware)</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#미들웨어-체인-요청-파이프라인" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26d3.png" alt="⛓" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 미들웨어 체인 (요청 파이프라인)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#요청-파이프라인-단락short-circuiting" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2702.png" alt="✂" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 요청 파이프라인 단락(Short-circuiting)</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#단락과-nextinvoke-이후-코드-실행" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 단락과 next.Invoke() 이후 코드 실행</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#경고-응답-전송-후-작업-주의" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 경고: 응답 전송 후 작업 주의</a></li></ul><li class="uagb-toc__list"><a href="#appuse-vs-apprun" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1fae0.png" alt="🫠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> app.Use vs. app.Run</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#aspnet-core의-커스텀-미들웨어" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2753.png" alt="❓" class="wp-smiley" style="height: 1em; max-height: 1em;" /> ASP.NET Core의 커스텀 미들웨어</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#커스텀-미들웨어-클래스의-구조" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f527.png" alt="🔧" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 커스텀 미들웨어 클래스의 구조</a></li></ul><li class="uagb-toc__list"><a href="#커스텀-컨벤셔널-미들웨어-custom-conventional-middleware" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 커스텀 컨벤셔널 미들웨어 (Custom Conventional Middleware)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#미들웨어-파이프라인의-이상적인-순서" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f500.png" alt="🔀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 미들웨어 파이프라인의 이상적인 순서</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#usewhen" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> UseWhen()</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#usewhen-작동-방식" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> UseWhen() 작동 방식</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#usewhen-사용-시점" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f98b.png" alt="🦋" class="wp-smiley" style="height: 1em; max-height: 1em;" /> UseWhen() 사용 시점</a></ul></ul></ol>					</div>
									</div>
				</div>
			


<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2753.png" alt="❓" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 미들웨어(Middleware)</h2>



<p class="wp-block-paragraph"><a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-8.0" target="_blank" rel="noreferrer noopener">https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-8.0</a></p>



<p class="wp-block-paragraph">ASP.NET Core의 <strong>미들웨어</strong>는 모든 HTTP 요청과 응답 <strong>파이프라인을 형성하는 일련의 구성 요소</strong>입니다.</p>



<p class="wp-block-paragraph">각 미들웨어 구성 요소는 다음을 수행할 수 있습니다:</p>



<ul class="wp-block-list">
<li>들어오는 <strong>요청을 검사</strong>합니다.</li>



<li>요청 또는 응답을 <strong>수정</strong>합니다 (필요한 경우).</li>



<li>파이프라인의 다음 미들웨어를 <strong>호출</strong>하거나, 프로세스를 <strong>단락(short-circuit)</strong>시키고 자체적으로 응답을 생성합니다.</li>
</ul>



<p class="wp-block-paragraph">이러한 파이프라인을 통해 <strong>애플리케이션의 로직을 모듈화하고, 인증, 로깅, 오류 처리, 라우팅 등과 </strong>같은 기능을 깔끔하고<strong> 유지 관리하기 쉬운 방식으로 추가</strong>할 수 있습니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26d3.png" alt="⛓" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 미들웨어 체인 (요청 파이프라인)</h3>



<p class="wp-block-paragraph">ASP.NET Core 요청 파이프라인은 차례로 호출되는 일련의 요청 대리자로 구성됩니다.</p>



<p class="wp-block-paragraph">요청 파이프라인을 일련의 연결된 파이프라고 상상해 보세요. </p>



<p class="wp-block-paragraph">각 미들웨어 조각은 이 파이프라인의 밸브와 같아서, <strong>정보의 흐름을 제어하고 다양한 단계에서 특정 작업을 적용</strong>할 수 있습니다. </p>



<p class="wp-block-paragraph">미들웨어를 등록하는 <strong>순서는 매우 중요</strong>하며, 등록된 순서대로 실행됩니다.</p>



<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="607" height="389" src="https://lycos7560.com/wp-content/uploads/2025/07/image-12.png" alt="" class="wp-image-40131" srcset="https://lycos7560.com/wp-content/uploads/2025/07/image-12.png 607w, https://lycos7560.com/wp-content/uploads/2025/07/image-12-300x192.png 300w" sizes="(max-width: 607px) 100vw, 607px" /><figcaption class="wp-element-caption"><a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-8.0" target="_blank" rel="noreferrer noopener">https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-8.0</a></figcaption></figure>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph">각 델리게이트는 <strong>다음 델리게이트를 호출하기 전과 후에 작업</strong>을 수행할 수 있습니다. </p>



<p class="wp-block-paragraph">예외 처리 델리게이트는 파이프라인의 후반 단계에서 발생하는 예외를 Catch할 수 있도록 파이프라인의 <strong>초기에 호출</strong>되어야 합니다.</p>



<p class="wp-block-paragraph">가장 간단한 ASP.NET Core 앱은 모든 요청을 처리하는 <strong>단일 요청 델리게이트</strong>를 설정합니다. </p>



<p class="wp-block-paragraph">이 경우에는 실제 요청 파이프라인이 포함되지 않습니다. </p>



<p class="wp-block-paragraph">대신, 모든 HTTP 요청에 대한 응답으로 단일 익명 함수가 호출됩니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello world!");
});

app.Run(); // 이 app.Run은 위의 app.Run이 파이프라인을 종료하므로 실행되지 않습니다.</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph"><strong><code>Use</code> 메서드를 사용하면 여러 요청 델리게이트를 체인으로 연결</strong>할 수 있습니다. </p>



<p class="wp-block-paragraph">이때 <code>next</code> 매개변수는 파이프라인의 다음 델리게이트를 나타냅니다.</p>



<p class="wp-block-paragraph"><code>next</code> 매개변수를 호출하지 않음으로써 <strong>파이프라인을 단락(short-circuit)</strong>시킬 수 있습니다. </p>



<p class="wp-block-paragraph">다음 예시에서 보여주듯이, 일반적으로 <code>next</code> 델리게이트를 호출하기 전과 후에 모두 작업을 수행할 수 있습니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">var builder = WebApplication.CreateBuilder(args); // 웹 애플리케이션 빌더를 생성합니다.
var app = builder.Build(); // 빌더를 사용하여 웹 애플리케이션 인스턴스를 생성합니다.

// 첫 번째 미들웨어: app.Use()를 사용하여 파이프라인에 추가합니다.
app.Use(async (context, next) =>
{
    // 응답에 쓸 수 있는 작업을 수행합니다. (예: 헤더 추가, 응답의 시작 부분 작성)
    // 이 부분의 코드는 다음 미들웨어가 실행되기 전에 실행됩니다.

    await next.Invoke(); // 다음 미들웨어(이 경우 app.Run)를 호출하여 제어를 넘깁니다.

    // 응답에 쓰지 않는 로깅 또는 다른 작업을 수행합니다.
    // 이 부분의 코드는 다음 미들웨어가 실행된 후(응답이 생성된 후) 실행됩니다.
});

// 두 번째 미들웨어: app.Run()을 사용하여 파이프라인에 추가합니다.
// app.Run()은 파이프라인을 종료하는 미들웨어입니다.
app.Run(async context =>
{
    // 이 미들웨어는 "Hello from 2nd delegate."를 응답에 작성하고 파이프라인을 종료합니다.
    await context.Response.WriteAsync("Hello from 2nd delegate.");
});

// 이 app.Run()은 위의 app.Run()이 이미 파이프라인을 종료했기 때문에 실행되지 않습니다.
app.Run();</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2702.png" alt="✂" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 요청 파이프라인 단락(Short-circuiting)</h3>



<p class="wp-block-paragraph">ASP.NET Core의 미들웨어 파이프라인에서, 특정 델리게이트(미들웨어)가 요청을 <strong>다음 델리게이트로 전달하지 않을 때</strong> 이를 <strong>요청 파이프라인을 단락(short-circuiting)시킨다</strong>고 합니다. </p>



<p class="wp-block-paragraph">파이프라인 단락은 불필요한 작업을 피할 수 있기 때문에 종종 유용합니다.</p>



<p class="wp-block-paragraph">예를 들어, <strong>정적 파일 미들웨어(Static File Middleware)</strong>는 요청된 파일이 정적 파일(이미지, CSS, JavaScript 등)일 경우 해당 요청을 처리하고</p>



<p class="wp-block-paragraph"> 파이프라인의 나머지 부분을 단락시킴으로써 <strong>종료 미들웨어(terminal middleware)</strong> 역할을 할 수 있습니다. </p>



<p class="wp-block-paragraph">이렇게 되면 정적 파일을 제공한 후에는 <strong>인증이나 라우팅과 같은 다른 미들웨어들이 실행될 필요가 없으므로 효율성이 높아집니다.</strong></p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 단락과 <code>next.Invoke()</code> 이후 코드 실행</h4>



<p class="wp-block-paragraph">파이프라인의 추가적인 처리를 종료시키는 미들웨어보다 <strong>앞서 파이프라인에 추가된 미들웨어</strong>는 여전히 <code>next.Invoke()</code> 구문 이후의 코드를 처리합니다. </p>



<p class="wp-block-paragraph">즉, 비록 파이프라인이 단락되어 최종 응답이 더 이상 아래로 전달되지 않더라도, <code>next.Invoke()</code>를 호출했던 이전 미들웨어들은 응답이 완료된 후 자신의 후처리 로직을 실행할 수 있습니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 경고: 응답 전송 후 작업 주의</h4>



<p class="wp-block-paragraph"><strong>응답이 클라이언트에게 이미 전송되었거나 전송되기 시작한 후에는 <code>next.Invoke()</code>를 호출하거나 응답에 쓰려고 시도하지 마세요.</strong> </p>



<p class="wp-block-paragraph"><code>HttpResponse</code>가 시작된 후에는 응답에 변경을 가하려고 하면 <strong>예외가 발생</strong>합니다. </p>



<p class="wp-block-paragraph">예를 들어, 응답이 시작된 후 헤더나 상태 코드를 설정하려고 하면 예외가 발생합니다.</p>



<p class="wp-block-paragraph"><code>next.Invoke()</code> 호출 후 응답 본문에 쓰는 것은 다음과 같은 문제를 야기할 수 있습니다:</p>



<ul class="wp-block-list">
<li><strong>프로토콜 위반:</strong> 명시된 <code>Content-Length</code>보다 더 많은 내용을 작성하는 것과 같은 프로토콜 위반을 초래할 수 있습니다.</li>



<li><strong>본문 형식 손상:</strong> CSS 파일에 HTML 푸터(footer)를 작성하는 것처럼 본문 형식을 손상시킬 수 있습니다.</li>
</ul>



<p class="wp-block-paragraph"><code>HasStarted</code> 속성은 헤더가 전송되었는지 또는 본문이 작성되었는지 여부를 나타내는 유용한 힌트가 될 수 있습니다.</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1fae0.png" alt="🫠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <code>app.Use</code> vs. <code>app.Run</code></h3>



<p class="wp-block-paragraph">이 두 메서드는 파이프라인에 미들웨어를 추가하는 데 기본적이지만, 핵심적인 차이점이 있습니다:</p>



<p class="wp-block-paragraph"><code><strong>app.Use(async (context, next) => { ... })</strong></code></p>



<ul class="wp-block-list">
<li><strong>요청 수정 불가:</strong> <br>마지막 단계이므로 요청을 다음으로 전달하기 전에 수정할 수 없습니다.</li>



<li><strong>비종료(Non-Terminal) 미들웨어:</strong> <br>이 유형의 미들웨어는 일반적으로 어떤 작업을 수행한 다음, <code>next</code> 델리게이트를 호출하여 파이프라인의 다음 미들웨어로 제어를 전달합니다.</li>



<li><strong>요청/응답 수정 가능:</strong> <br>요청을 다음으로 전달하기 전에 요청이나 응답을 변경할 수 있습니다.</li>



<li><strong>예시:</strong> <br>인증, 로깅, 커스텀 헤더 추가 등.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph"><code>a<strong>pp.Run(async (context) => { ... })</strong></code></p>



<ul class="wp-block-list">
<li><strong>종료(Terminal) 미들웨어:</strong> <br>이 미들웨어는 <code>next</code>를 호출하지 않습니다. <br>파이프라인을 종료하고 <strong>자체적으로 응답을 생성</strong>합니다.</li>



<li><strong>최종 응답에 주로 사용:</strong> <br>더 이상 처리가 필요 없는 요청(예: 간단한 메시지 반환)을 처리하는 데 일반적으로 사용됩니다.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// 여러 app.Run 호출의 결과

app.Run(async (HttpContext context) => {
    await context.Response.WriteAsync("Hello");
});

app.Run(async (HttpContext context) => {
    await context.Response.WriteAsync("Hello again");
});

app.Run(); // 이 app.Run은 위의 app.Run들이 이미 파이프라인을 종료했기 때문에 절대 실행되지 않습니다.</pre>



<p class="wp-block-paragraph">이 코드에서는 <strong>오직 첫 번째 <code>app.Run</code> 미들웨어만 실행됩니다.</strong> </p>



<p class="wp-block-paragraph">&#8220;Hello&#8221;를 응답에 작성하여 파이프라인을 종료하고, 그 뒤의 <code>app.Run</code> (이것은 &#8220;Hello again&#8221;을 작성할 것임)은 실행될 기회를 얻지 못합니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// app.Use와 app.Run으로 미들웨어 체인 연결하기

// 미들웨어 1
app.Use(async (context, next) => {
    await context.Response.WriteAsync("Hello "); // 1. "Hello " 작성
    await next(context); // 2. 다음 미들웨어 호출
});

// 미들웨어 2
app.Use(async (context, next) => {
    await context.Response.WriteAsync("Hello again "); // 3. "Hello again " 작성
    await next(context); // 4. 다음 미들웨어 호출 (이 경우 app.Run)
});

// 미들웨어 3 (종료 미들웨어)
app.Run(async (HttpContext context) => {
    await context.Response.WriteAsync("Hello again"); // 5. "Hello again" 작성 후 파이프라인 종료
});</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph">이 코드는 미들웨어를 올바르게 연결하는 방법을 보여줍니다.</p>



<ol start="1" class="wp-block-list">
<li>첫 번째 <code>app.Use</code>는 응답에 &#8220;Hello &#8220;를 작성하고 <code>next</code>를 호출하여 다음 미들웨어로 제어를 전달합니다.</li>



<li>두 번째 <code>app.Use</code>는 &#8220;Hello again &#8220;을 작성하고 역시 <code>next</code>를 호출합니다.</li>



<li>마지막 <code>app.Run</code> (종료 미들웨어)는 &#8220;Hello again&#8221;을 작성하고 파이프라인을 종료합니다.</li>
</ol>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2753.png" alt="❓" class="wp-smiley" style="height: 1em; max-height: 1em;" /> ASP.NET Core의 커스텀 미들웨어</h3>



<p class="wp-block-paragraph">ASP.NET Core는 다양한 내장 미들웨어 구성 요소를 제공하지만, 때로는 애플리케이션 고유의 특정 요구 사항을 해결하기 위해 자신만의 <strong>커스텀 미들웨어</strong>를 만들어야 할 수도 있습니다. </p>



<p class="wp-block-paragraph">커스텀 미들웨어를 통해 다음을 수행할 수 있습니다:</p>



<ul class="wp-block-list">
<li><strong>로직 캡슐화:</strong> <br>관련 작업(예: 로깅, 보안 검사, 사용자 정의 헤더)을 재사용 가능한 구성 요소로 묶습니다.</li>



<li><strong>동작 사용자 정의:</strong> <br>애플리케이션의 요구 사항에 정확히 맞게 요청/응답 파이프라인을 조정합니다.</li>



<li><strong>코드 구성 개선:</strong> <br>미들웨어 코드를 깔끔하고 유지 관리하기 쉽게 만듭니다.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f527.png" alt="🔧" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 커스텀 미들웨어 클래스의 구조</h4>



<p class="wp-block-paragraph"><strong><code>IMiddleware</code> 구현:</strong> 이 인터페이스는 단 하나의 메서드 <code>InvokeAsync(HttpContext context, RequestDelegate next)</code>를 요구합니다. </p>



<p class="wp-block-paragraph">이 메서드는 미들웨어 로직의 핵심입니다</p>



<p class="wp-block-paragraph"><code>InvokeAsync</code> 또는 <code>Invoke</code> 메서드</p>



<ul class="wp-block-list">
<li><strong><code>context</code>:</strong> <br><code>HttpContext</code>는 요청 및 응답 객체에 대한 접근을 제공합니다.</li>



<li><strong><code>next</code>:</strong> <br><code>RequestDelegate</code>는 파이프라인의 다음 미들웨어를 호출할 수 있도록 합니다.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// MyCustomMiddleware.cs
namespace MiddlewareExample.CustomMiddleware
{
    public class MyCustomMiddleware : IMiddleware // IMiddleware 인터페이스 구현
    {
        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            await context.Response.WriteAsync("My Custom Middleware - Starts\n"); // 1. 응답 시작 부분에 출력
            await next(context); // 2. 다음 미들웨어 호출
            await context.Response.WriteAsync("My Custom Middleware - Ends\n"); // 3. 다음 미들웨어 완료 후 응답 끝 부분에 출력
        }
    }

    // 쉽게 등록하기 위한 확장 메서드
    public static class CustomMiddlewareExtension
    {
        public static IApplicationBuilder UseMyCustomMiddleware(this IApplicationBuilder app)
        {
            return app.UseMiddleware&lt;MyCustomMiddleware>();
        }
    }
}</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// Program.cs (또는 Startup.cs)
using MiddlewareExample.CustomMiddleware;

// ... (다른 설정 코드) ...

builder.Services.AddTransient&lt;MyCustomMiddleware>(); // 트랜지언트 서비스로 등록

app.Use(async (HttpContext context, RequestDelegate next) => {
    await context.Response.WriteAsync("From Middleware 1\n"); // 첫 번째 미들웨어: 시작 부분
    await next(context);
});

app.UseMyCustomMiddleware(); // 확장 메서드를 사용하여 커스텀 미들웨어 추가

app.Run(async (HttpContext context) => {
    await context.Response.WriteAsync("From Middleware 3\n"); // 세 번째 미들웨어: 파이프라인 종료
});</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<ul class="wp-block-list">
<li><strong>등록:</strong> <br>ASP.NET Core가 필요할 때 <code>MyCustomMiddleware</code> 인스턴스를 생성할 수 있도록 이를 트랜지언트 서비스로 등록합니다.</li>



<li><strong>파이프라인 통합:</strong> <br><code>app.UseMyCustomMiddleware()</code> 확장 메서드는 커스텀 미들웨어를 파이프라인에 추가합니다.</li>



<li><strong>실행 순서:</strong> <br>미들웨어 구성 요소는 파이프라인에 추가된 순서대로 실행됩니다. 이 경우 순서는 미들웨어 1, <code>MyCustomMiddleware</code>, 그리고 미들웨어 3이 됩니다.</li>
</ul>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 커스텀 컨벤셔널 미들웨어 (Custom Conventional Middleware)</h3>



<p class="wp-block-paragraph">ASP.NET Core 미들웨어에는 두 가지 유형이 있습니다: <strong>컨벤셔널(Conventional)</strong>과 <strong>팩토리 기반(Factory-based)</strong> </p>



<p class="wp-block-paragraph">예시에서 보여진 컨벤셔널 미들웨어는 HTTP 요청 및 응답 처리를 위한 커스텀 로직을 캡슐화하는 간단하면서도 강력한 방법입니다.</p>



<p class="wp-block-paragraph">주요 특징</p>



<ul class="wp-block-list">
<li><strong>클래스 기반:</strong> <br>컨벤셔널 미들웨어는 클래스로 구현됩니다.</li>



<li><strong>생성자 주입:</strong> <br>의존성(있는 경우)을 생성자를 통해 받습니다.</li>



<li><strong><code>Invoke</code> 메서드:</strong> <br>이 메서드는 각 요청을 처리하는 로직을 포함하는 미들웨어의 핵심입니다.</li>



<li><strong><code>RequestDelegate</code>:</strong> <br><code>Invoke</code> 메서드는 <code>RequestDelegate</code> 매개변수(<code>_next</code>로 명명)를 받습니다. 이 델리게이트는 파이프라인의 다음 미들웨어를 나타냅니다.</li>



<li><strong>유연성:</strong> <br><code>Invoke</code> 메서드 내에서 요청 및 응답 객체를 완벽하게 제어할 수 있습니다.</li>
</ul>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="689" height="343" src="https://lycos7560.com/wp-content/uploads/2025/07/image-13.png" alt="" class="wp-image-40132" srcset="https://lycos7560.com/wp-content/uploads/2025/07/image-13.png 689w, https://lycos7560.com/wp-content/uploads/2025/07/image-13-300x149.png 300w" sizes="(max-width: 689px) 100vw, 689px" /></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// NameConcatenationMiddleware.cs
public class NameConcatenationMiddleware
{
    private readonly RequestDelegate _next;

    public NameConcatenationMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        if (context.Request.Query.ContainsKey("firstname") &amp;&amp;
            context.Request.Query.ContainsKey("lastname"))
        {
            string fullName = $"{context.Request.Query["firstname"]} {context.Request.Query["lastname"]}";
            await context.Response.WriteAsync(fullName);
            return; // 명시적으로 반환하여 다음 미들웨어 호출 방지
        }
        
        await _next(context);
    }
}

// MiddlewareExtensions.cs
public static class MiddlewareExtensions
{
    public static IApplicationBuilder UseNameConcatenation(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware&lt;NameConcatenationMiddleware>();
    }
}</pre>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f500.png" alt="🔀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 미들웨어 파이프라인의 이상적인 순서</h3>



<p class="wp-block-paragraph">미들웨어의 순서는 애플리케이션의 동작과 효율성, 보안에 큰 영향을 미칩니다. </p>



<p class="wp-block-paragraph">다음은 일반적으로 권장되는 이상적인 순서입니다</p>



<figure class="wp-block-image size-full"><img decoding="async" width="858" height="485" src="https://lycos7560.com/wp-content/uploads/2025/07/image-14.png" alt="" class="wp-image-40133" srcset="https://lycos7560.com/wp-content/uploads/2025/07/image-14.png 858w, https://lycos7560.com/wp-content/uploads/2025/07/image-14-300x170.png 300w, https://lycos7560.com/wp-content/uploads/2025/07/image-14-768x434.png 768w" sizes="(max-width: 858px) 100vw, 858px" /><figcaption class="wp-element-caption"><a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-8.0" target="_blank" rel="noreferrer noopener">https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-8.0</a></figcaption></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph"><strong>예외/오류 처리(Exception/Error Handling):</strong></p>



<ul class="wp-block-list">
<li><strong>목적:</strong> 파이프라인의 어느 곳에서든 발생하는 예외를 Catch하고 처리합니다.</li>



<li><strong>예시:</strong> <code>UseExceptionHandler</code> (프로덕션용), <code>UseDeveloperExceptionPage</code> (개발 환경용).</li>



<li><strong>이유:</strong> 예외를 초기에 Catch하여 파이프라인 아래로 전파되어 더 큰 문제를 일으키는 것을 방지합니다.</li>
</ul>



<p class="wp-block-paragraph"><strong>HTTPS 리디렉션(HTTPS Redirection):</strong></p>



<ul class="wp-block-list">
<li><strong>목적:</strong> 보안을 위해 HTTP 요청을 HTTPS로 리디렉션합니다.</li>



<li><strong>예시:</strong> <code>UseHttpsRedirection</code>.</li>



<li><strong>이유:</strong> 보안을 최우선으로 하여 모든 통신이 암호화되도록 합니다.</li>
</ul>



<p class="wp-block-paragraph"><strong>정적 파일(Static Files):</strong></p>



<ul class="wp-block-list">
<li><strong>목적:</strong> 이미지, CSS, JavaScript 파일과 같은 정적 파일을 클라이언트에게 직접 제공합니다.</li>



<li><strong>예시:</strong> <code>UseStaticFiles</code>.</li>



<li><strong>이유:</strong> 정적 파일 요청은 빠르게 처리되어야 하며, 불필요하게 파이프라인의 다른 무거운 구성 요소를 거치지 않도록 일찍 처리합니다.</li>
</ul>



<p class="wp-block-paragraph"><strong>라우팅(Routing):</strong></p>



<ul class="wp-block-list">
<li><strong>목적:</strong> URL을 기반으로 들어오는 요청을 특정 엔드포인트에 매칭합니다.</li>



<li><strong>예시:</strong> <code>UseRouting</code>, <code>UseEndpoints</code>.</li>



<li><strong>이유:</strong> 라우팅은 애플리케이션의 핵심 로직이 요청을 어떻게 처리할지 결정하는 기반이 됩니다.</li>
</ul>



<p class="wp-block-paragraph"><strong>CORS (Cross-Origin Resource Sharing):</strong></p>



<ul class="wp-block-list">
<li><strong>목적:</strong> 다른 도메인으로부터의 안전한 교차 출처(cross-origin) 요청을 가능하게 합니다.</li>



<li><strong>예시:</strong> <code>UseCors</code>.</li>



<li><strong>이유:</strong> 인증/인가 전에 위치하여, 사전 요청(preflight request)이 불필요하게 인증/인가 미들웨어를 거치지 않도록 합니다.</li>
</ul>



<p class="wp-block-paragraph"><strong>인증(Authentication):</strong></p>



<ul class="wp-block-list">
<li><strong>목적:</strong> 사용자 신원을 확인하고 사용자 주체(principal)를 설정합니다.</li>



<li><strong>예시:</strong> <code>UseAuthentication</code>.</li>



<li><strong>이유:</strong> 사용자가 누구인지 확인한 후에 리소스에 대한 접근 권한을 부여할 수 있습니다.</li>
</ul>



<p class="wp-block-paragraph"><strong>인가(Authorization):</strong></p>



<ul class="wp-block-list">
<li><strong>목적:</strong> 사용자가 특정 리소스에 접근하거나 특정 작업을 수행할 수 있는지 여부를 결정합니다.</li>



<li><strong>예시:</strong> <code>UseAuthorization</code>.</li>



<li><strong>이유:</strong> 인증된 사용자에게만 권한 부여 여부를 검사합니다.</li>
</ul>



<p class="wp-block-paragraph"><strong>커스텀 미들웨어(Custom Middleware):</strong></p>



<ul class="wp-block-list">
<li><strong>목적:</strong> 로깅, 기능 플래그 등 애플리케이션별 미들웨어 구성 요소를 처리합니다.</li>



<li><strong>이유:</strong> 애플리케이션별 로직을 적절한 단계에서 파이프라인 내에 배치합니다.</li>
</ul>



<p class="wp-block-paragraph"><strong>MVC/Razor Pages/Minimal APIs:</strong></p>



<ul class="wp-block-list">
<li><strong>목적:</strong> 실제 애플리케이션의 최종 엔드포인트 처리 로직을 실행합니다.</li>



<li><strong>예시:</strong> <code>MapControllers()</code>, <code>MapRazorPages()</code>, <code>MapGet()</code> 등.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="848" height="589" src="https://lycos7560.com/wp-content/uploads/2025/07/image-15.png" alt="" class="wp-image-40134" srcset="https://lycos7560.com/wp-content/uploads/2025/07/image-15.png 848w, https://lycos7560.com/wp-content/uploads/2025/07/image-15-300x208.png 300w, https://lycos7560.com/wp-content/uploads/2025/07/image-15-768x533.png 768w" sizes="(max-width: 848px) 100vw, 848px" /><figcaption class="wp-element-caption"><a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-8.0" target="_blank" rel="noreferrer noopener">https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-8.0</a></figcaption></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph"><code>Program.cs</code> 파일에 미들웨어 구성 요소가 추가되는 순서는 요청 시 미들웨어 구성 요소가 호출되는 순서를 정의하며, 응답 시에는 역순으로 호출됩니다. </p>



<p class="wp-block-paragraph">이러한 <strong>순서는 보안, 성능 및 기능에 매우 중요합니다.</strong></p>



<p class="wp-block-paragraph"><code>Program.cs</code>의 다음 강조 표시된 코드는 보안 관련 미들웨어 구성 요소를 일반적으로 권장되는 순서로 추가하는 예시입니다:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="19-43" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using WebMiddleware.Data;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection")
    ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext&lt;ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity&lt;IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores&lt;ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
// app.UseCookiePolicy();

app.UseRouting();
// app.UseRateLimiter();
// app.UseRequestLocalization();
// app.UseCors();

app.UseAuthentication();
app.UseAuthorization();
// app.UseSession();
// app.UseResponseCompression();
// app.UseResponseCaching();

app.MapRazorPages();
app.MapDefaultControllerRoute();

app.Run();</pre>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> UseWhen()</h3>



<p class="wp-block-paragraph"><code>UseWhen()</code>은 ASP.NET Core의 <code>IApplicationBuilder</code> 인터페이스에 있는 강력한 확장 메서드입니다. </p>



<p class="wp-block-paragraph">이는 <strong>조건(predicate)에 따라 미들웨어를 요청 파이프라인에 조건부로 추가</strong>할 수 있도록 합니다. </p>



<p class="wp-block-paragraph">즉, 특정 조건이 충족될 때만 특정 미들웨어 구성 요소가 실행되는 동적인 파이프라인을 만들 수 있습니다.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">app.UseWhen(
    context => /* 여기에 조건 */, // HttpContext를 받아 true/false 반환
    app => /* 이 분기에서 실행될 미들웨어 구성 */ // 조건이 true일 때 실행될 미들웨어 파이프라인
);</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<ul class="wp-block-list">
<li><strong><code>context</code>:</strong> <br>현재 요청을 나타내는 <code>HttpContext</code> 객체입니다.</li>



<li><strong>Predicate (조건):</strong> <br><code>HttpContext</code>를 받아들이고 미들웨어 분기가 실행되어야 할 경우 <code>true</code>를, 그렇지 않을 경우 <code>false</code>를 반환하는 함수입니다.</li>



<li><strong>Middleware Configuration (미들웨어 구성):</strong> <br>조건이 <code>true</code>일 때 실행되어야 할 미들웨어 구성 요소를 구성하는 액션입니다. <br>여기서 <code>app.Use()</code>, <code>app.Run()</code>, 또는 다른 미들웨어 등록 메서드를 사용합니다.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <code>UseWhen()</code> 작동 방식</h4>



<ul class="wp-block-list">
<li><strong>조건 평가:</strong> <br>요청이 들어오면 <code>UseWhen()</code> 메서드는 먼저 <code>HttpContext</code>에 대해 조건 함수를 평가합니다.</li>



<li><strong>분기(조건이 true일 경우):</strong> <br>조건이 <code>true</code>를 반환하면, 구성 액션에 지정된 미들웨어 분기가 실행됩니다. <br>요청은 이 분기를 통해 흐르며, 수정되거나 응답을 생성할 수 있습니다.</li>



<li><strong>메인 파이프라인 재진입:</strong> <br>분기가 실행된 후(또는 조건이 <code>false</code>여서 건너뛰어진 경우), 요청 흐름은 메인 파이프라인으로 다시 진입하여 <code>UseWhen()</code> 호출 뒤에 등록된 다음 미들웨어 구성 요소로 계속 진행됩니다.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">app.UseWhen(
    context => context.Request.Query.ContainsKey("username"), // 조건: 쿼리 문자열에 "username"이 있는지 확인
    app => {
        app.Use(async (context, next) =>
        {
            await context.Response.WriteAsync("Hello from Middleware branch\n"); // 분기 미들웨어: "Hello from Middleware branch" 작성
            await next(); // 다음 미들웨어 호출
        });
    });

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from middleware at main chain"); // 메인 파이프라인 미들웨어
});</pre>



<ul class="wp-block-list">
<li><strong>조건:</strong> <br><code>context.Request.Query.ContainsKey("username")</code> 조건은 쿼리 문자열에 &#8220;username&#8221;이라는 매개변수가 포함되어 있는지 확인합니다.</li>



<li><strong>분기 미들웨어:</strong> <br>&#8220;username&#8221; 매개변수가 존재하면 분기 미들웨어가 실행됩니다. <br>이 미들웨어는 응답에 &#8220;Hello from Middleware branch&#8221;를 작성하고 <code>next</code>를 호출하여 나머지 파이프라인이 계속되도록 합니다.</li>



<li><strong>메인 파이프라인:</strong> <br>마지막 <code>app.Run</code> 미들웨어는 메인 파이프라인의 일부입니다. <br>이는 응답에 &#8220;Hello from middleware at main chain&#8221;을 작성합니다.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f98b.png" alt="🦋" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <code>UseWhen()</code> 사용 시점</h4>



<ul class="wp-block-list">
<li><strong>조건부 기능:</strong> <br>요청에 따라 특정 기능을 활성화하거나 비활성화합니다 (예: 특정 사용자에게만 로깅, 쿼리 매개변수에 따른 캐싱 규칙 적용).</li>



<li><strong>동적 파이프라인:</strong> <br>다양한 요청에 맞춰 조정되는 파이프라인을 만듭니다 (예: 특정 경로에 대해 다른 인증 미들웨어).</li>



<li><strong>A/B 테스트:</strong> <br>실험을 위해 사용자 하위 집합을 대체 미들웨어 분기를 통해 라우팅합니다.</li>



<li><strong>디버깅 및 진단:</strong> <br>개발 환경에서만 진단 미들웨어를 적용합니다.</li>
</ul>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://lycos7560.com/c/asp-net-core%ec%9d%98-%eb%af%b8%eb%93%a4%ec%9b%a8%ec%96%b4middleware/40130/">ASP.NET Core의 미들웨어(Middleware)</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/c/asp-net-core%ec%9d%98-%eb%af%b8%eb%93%a4%ec%9b%a8%ec%96%b4middleware/40130/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>ASP.NET Core &#8211; UseStaticFiles</title>
		<link>https://lycos7560.com/c/asp-net/asp-net-core-usestaticfiles/40147/</link>
					<comments>https://lycos7560.com/c/asp-net/asp-net-core-usestaticfiles/40147/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Sun, 13 Jul 2025 04:33:03 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[.NET Development]]></category>
		<category><![CDATA[.NET 개발]]></category>
		<category><![CDATA[404 Not Found]]></category>
		<category><![CDATA[app.UseStaticFiles()]]></category>
		<category><![CDATA[Application Root]]></category>
		<category><![CDATA[ASP.NET Core]]></category>
		<category><![CDATA[ASP.NET Core Fundamentals]]></category>
		<category><![CDATA[Backend]]></category>
		<category><![CDATA[Browser Cache]]></category>
		<category><![CDATA[Cache Invalidation]]></category>
		<category><![CDATA[Cache-Control]]></category>
		<category><![CDATA[Caching]]></category>
		<category><![CDATA[Caching Strategy]]></category>
		<category><![CDATA[Configure 메서드]]></category>
		<category><![CDATA[Content Delivery]]></category>
		<category><![CDATA[Content Type]]></category>
		<category><![CDATA[Content-Type]]></category>
		<category><![CDATA[ContentRootPath]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Debugging]]></category>
		<category><![CDATA[Development Environment]]></category>
		<category><![CDATA[Development Purpose]]></category>
		<category><![CDATA[Directory Browse]]></category>
		<category><![CDATA[Endpoint Routing]]></category>
		<category><![CDATA[Environment]]></category>
		<category><![CDATA[Error Handling]]></category>
		<category><![CDATA[File Access]]></category>
		<category><![CDATA[File Extension]]></category>
		<category><![CDATA[file management]]></category>
		<category><![CDATA[File Path]]></category>
		<category><![CDATA[File Serving]]></category>
		<category><![CDATA[File System]]></category>
		<category><![CDATA[FileProvider]]></category>
		<category><![CDATA[Font]]></category>
		<category><![CDATA[Frontend]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[HTTP Headers]]></category>
		<category><![CDATA[HTTP Request]]></category>
		<category><![CDATA[HTTP Response]]></category>
		<category><![CDATA[HTTP 요청]]></category>
		<category><![CDATA[HTTP 응답]]></category>
		<category><![CDATA[HTTP 헤더]]></category>
		<category><![CDATA[HttpRequest]]></category>
		<category><![CDATA[HttpResponse]]></category>
		<category><![CDATA[IIS]]></category>
		<category><![CDATA[Image]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Kestrel]]></category>
		<category><![CDATA[Middleware]]></category>
		<category><![CDATA[Middleware Order]]></category>
		<category><![CDATA[Middleware Pipeline]]></category>
		<category><![CDATA[MIME Type]]></category>
		<category><![CDATA[MIME 타입]]></category>
		<category><![CDATA[Optimization]]></category>
		<category><![CDATA[Option Configuration]]></category>
		<category><![CDATA[Path Mapping]]></category>
		<category><![CDATA[Path.Combine]]></category>
		<category><![CDATA[Performance Optimization]]></category>
		<category><![CDATA[Performance Tuning]]></category>
		<category><![CDATA[Permissions]]></category>
		<category><![CDATA[Physical File]]></category>
		<category><![CDATA[PhysicalFileProvider]]></category>
		<category><![CDATA[Production Environment]]></category>
		<category><![CDATA[Program.cs]]></category>
		<category><![CDATA[Request Processing Flow]]></category>
		<category><![CDATA[RequestPath]]></category>
		<category><![CDATA[resource management]]></category>
		<category><![CDATA[Response Headers]]></category>
		<category><![CDATA[Root Folder]]></category>
		<category><![CDATA[Routing Configuration]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Security Vulnerability]]></category>
		<category><![CDATA[Server Configuration]]></category>
		<category><![CDATA[Server Resources]]></category>
		<category><![CDATA[Startup.cs]]></category>
		<category><![CDATA[Static Content]]></category>
		<category><![CDATA[Static File]]></category>
		<category><![CDATA[Static File Hosting]]></category>
		<category><![CDATA[StaticFileOptions]]></category>
		<category><![CDATA[study]]></category>
		<category><![CDATA[URL Mapping]]></category>
		<category><![CDATA[URL Path]]></category>
		<category><![CDATA[URL Redirection]]></category>
		<category><![CDATA[URL 경로]]></category>
		<category><![CDATA[URL 리디렉션]]></category>
		<category><![CDATA[URL 매핑]]></category>
		<category><![CDATA[UseDirectoryBrowser]]></category>
		<category><![CDATA[UseRouting]]></category>
		<category><![CDATA[UseStaticFiles]]></category>
		<category><![CDATA[Virtual Path]]></category>
		<category><![CDATA[Web Application]]></category>
		<category><![CDATA[Web Application Development]]></category>
		<category><![CDATA[Web Cache]]></category>
		<category><![CDATA[Web Content]]></category>
		<category><![CDATA[Web Deployment]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[Web Page]]></category>
		<category><![CDATA[Web Project]]></category>
		<category><![CDATA[Web Publishing]]></category>
		<category><![CDATA[Web Resource]]></category>
		<category><![CDATA[Web Root]]></category>
		<category><![CDATA[Web Security]]></category>
		<category><![CDATA[Web Server]]></category>
		<category><![CDATA[Web Server Configuration]]></category>
		<category><![CDATA[Web Service]]></category>
		<category><![CDATA[Web Standards]]></category>
		<category><![CDATA[WebApplication]]></category>
		<category><![CDATA[WebApplicationBuilder]]></category>
		<category><![CDATA[wwwroot]]></category>
		<category><![CDATA[가상 경로]]></category>
		<category><![CDATA[개발 목적]]></category>
		<category><![CDATA[개발 환경]]></category>
		<category><![CDATA[경로 매핑]]></category>
		<category><![CDATA[공부]]></category>
		<category><![CDATA[권한]]></category>
		<category><![CDATA[기초]]></category>
		<category><![CDATA[디렉터리 브라우징]]></category>
		<category><![CDATA[디버깅]]></category>
		<category><![CDATA[라우팅 구성]]></category>
		<category><![CDATA[루트 폴더]]></category>
		<category><![CDATA[물리적 파일]]></category>
		<category><![CDATA[미들웨어]]></category>
		<category><![CDATA[미들웨어 순서]]></category>
		<category><![CDATA[미들웨어 파이프라인]]></category>
		<category><![CDATA[백엔드]]></category>
		<category><![CDATA[보안]]></category>
		<category><![CDATA[보안 취약점]]></category>
		<category><![CDATA[브라우저 캐시]]></category>
		<category><![CDATA[서버 리소스]]></category>
		<category><![CDATA[서버 설정]]></category>
		<category><![CDATA[성능 최적화]]></category>
		<category><![CDATA[성능 튜닝]]></category>
		<category><![CDATA[애플리케이션 루트]]></category>
		<category><![CDATA[엔드포인트 라우팅]]></category>
		<category><![CDATA[오류 처리]]></category>
		<category><![CDATA[옵션 설정]]></category>
		<category><![CDATA[요청 처리 흐름]]></category>
		<category><![CDATA[운영 환경]]></category>
		<category><![CDATA[웹 개발]]></category>
		<category><![CDATA[웹 루트]]></category>
		<category><![CDATA[웹 리소스]]></category>
		<category><![CDATA[웹 배포]]></category>
		<category><![CDATA[웹 보안]]></category>
		<category><![CDATA[웹 서버]]></category>
		<category><![CDATA[웹 서버 구성]]></category>
		<category><![CDATA[웹 서비스]]></category>
		<category><![CDATA[웹 애플리케이션]]></category>
		<category><![CDATA[웹 애플리케이션 개발]]></category>
		<category><![CDATA[웹 캐시]]></category>
		<category><![CDATA[웹 콘텐츠]]></category>
		<category><![CDATA[웹 퍼블리싱]]></category>
		<category><![CDATA[웹 페이지]]></category>
		<category><![CDATA[웹 표준]]></category>
		<category><![CDATA[웹 프로젝트]]></category>
		<category><![CDATA[응답 헤더]]></category>
		<category><![CDATA[이미지]]></category>
		<category><![CDATA[자원 관리]]></category>
		<category><![CDATA[정적 콘텐츠]]></category>
		<category><![CDATA[정적 파일]]></category>
		<category><![CDATA[정적 파일 호스팅]]></category>
		<category><![CDATA[최적화]]></category>
		<category><![CDATA[캐시 무효화]]></category>
		<category><![CDATA[캐싱]]></category>
		<category><![CDATA[캐싱 전략]]></category>
		<category><![CDATA[콘텐츠 전달]]></category>
		<category><![CDATA[콘텐츠 타입]]></category>
		<category><![CDATA[파일 경로]]></category>
		<category><![CDATA[파일 관리]]></category>
		<category><![CDATA[파일 서빙]]></category>
		<category><![CDATA[파일 시스템]]></category>
		<category><![CDATA[파일 접근]]></category>
		<category><![CDATA[파일 확장자]]></category>
		<category><![CDATA[폰트]]></category>
		<category><![CDATA[프론트엔드]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=40147</guid>

					<description><![CDATA[<p>🔥 UseStaticFiles https://learn.microsoft.com/ko-kr/aspnet/core/fundamentals/static-files?view=aspnetcore-8.0 UseStaticFiles는 ASP.NET Core 애플리케이션에서 정적 파일(Static Files)을 제공하기 위해 사용되는 미들웨어입니다. 정적 파일이란 웹 서버가 클라이언트에 그대로 전달하는 파일들로, 웹 페이지를 구성하는 데 필요한 이미지, CSS 파일, JavaScript 파일, 폰트 등을 의미합니다. 1️⃣ UseStaticFiles 미들웨어의 개념 ASP.NET Core는 기본적으로 보안을 위해 웹 루트(wwwroot 폴더) 외부의 파일에 대한 직접적인 웹 접근을 허용하지 않습니다. [&#8230;]</p>
<p>The post <a href="https://lycos7560.com/c/asp-net/asp-net-core-usestaticfiles/40147/">ASP.NET Core &#8211; UseStaticFiles</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-39abf3bb      "
					data-scroll= "1"
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							목차						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#usestaticfiles" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> UseStaticFiles</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-usestaticfiles-미들웨어의-개념" class="uagb-toc-link__trigger">1&#x20e3; UseStaticFiles 미들웨어의 개념</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#2-usestaticfiles의-주요-역할" class="uagb-toc-link__trigger">2&#x20e3; UseStaticFiles의 주요 역할</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#3-usestaticfiles-사용-방법" class="uagb-toc-link__trigger">3&#x20e3; UseStaticFiles 사용 방법</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#기본-사용법-wwwroot-폴더" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 기본 사용법 (wwwroot 폴더)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#다른-폴더의-정적-파일-제공" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 다른 폴더의 정적 파일 제공</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#디렉터리-브라우징-활성화-권장하지-않음" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 디렉터리 브라우징 활성화 (권장하지 않음)</a></li></ul><li class="uagb-toc__list"><a href="#4-usestaticfiles-미들웨어의-위치" class="uagb-toc-link__trigger">4&#x20e3; UseStaticFiles 미들웨어의 위치</a></ul></ol>					</div>
									</div>
				</div>
			


<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> UseStaticFiles</h2>



<p class="wp-block-paragraph"><a href="https://learn.microsoft.com/ko-kr/aspnet/core/fundamentals/static-files?view=aspnetcore-8.0" target="_blank" rel="noreferrer noopener">https://learn.microsoft.com/ko-kr/aspnet/core/fundamentals/static-files?view=aspnetcore-8.0</a></p>



<p class="wp-block-paragraph"><code>UseStaticFiles</code>는 ASP.NET Core 애플리케이션에서 <strong>정적 파일(Static Files)을 제공하기 위해 사용되는 미들웨어</strong>입니다. </p>



<p class="wp-block-paragraph">정적 파일이란 웹 서버가 클라이언트에 그대로 전달하는 파일들로, 웹 페이지를 구성하는 데 필요한 이미지, CSS 파일, JavaScript 파일, 폰트 등을 의미합니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">1&#x20e3; UseStaticFiles 미들웨어의 개념</h3>



<p class="wp-block-paragraph">ASP.NET Core는 기본적으로 보안을 위해 웹 루트(<code>wwwroot</code> 폴더) 외부의 파일에 대한 직접적인 웹 접근을 허용하지 않습니다. </p>



<p class="wp-block-paragraph"><code>UseStaticFiles</code> 미들웨어는 이러한 제한을 해제하고, 웹 서버가 특정 디렉토리(기본값은 <code>wwwroot</code>)에 있는 정적 파일 요청을 처리할 수 있도록 파이프라인에 기능을 추가합니다.</p>



<p class="wp-block-paragraph">이 미들웨어가 없으면, 브라우저가 <code>/css/site.css</code>나 <code>/images/logo.png</code> 같은 경로로 정적 파일을 요청했을 때, 서버는 해당 파일을 찾지 못하고 404 Not Found 오류를 반환하게 됩니다. </p>



<p class="wp-block-paragraph"><code>UseStaticFiles</code>를 추가함으로써, ASP.NET Core 애플리케이션은 이러한 요청을 가로채어 지정된 위치에서 파일을 찾아 클라이언트에게 응답할 수 있게 됩니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">2&#x20e3; UseStaticFiles의 주요 역할</h3>



<ul class="wp-block-list">
<li><strong>정적 파일 서빙 활성화</strong>: <br>웹 루트(<code>wwwroot</code>)에 있는 HTML, CSS, JavaScript, 이미지 등 정적 파일을 웹 브라우저가 요청할 수 있도록 허용합니다.</li>



<li><strong>파일 경로 매핑</strong>: <br>들어오는 URL 요청을 서버의 실제 파일 시스템 경로에 매핑합니다.</li>



<li><strong>캐싱 헤더 추가</strong>: <br>효율적인 캐싱을 위해 <code>Cache-Control</code> 같은 HTTP 응답 헤더를 자동으로 추가하여 브라우저가 정적 파일을 효율적으로 캐싱하고, 다음 요청 시 서버에 다시 요청하는 대신 로컬 캐시를 사용하도록 돕습니다.</li>



<li><strong>MIME 타입 추론</strong>: <br>파일 확장자를 기반으로 올바른 MIME 타입(<code>Content-Type</code> 헤더)을 응답에 포함하여 브라우저가 파일을 올바르게 해석하도록 합니다.</li>



<li><strong>디렉터리 브라우징 방지</strong>: <br>기본적으로 보안을 위해 디렉터리 목록을 보여주지 않습니다. (이를 허용하려면 추가 설정 필요)</li>
</ul>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">3&#x20e3; UseStaticFiles 사용 방법</h3>



<p class="wp-block-paragraph"><code>UseStaticFiles</code> 미들웨어는 보통 <code>Program.cs</code> 파일의 <code>Configure</code> 메서드에서 다른 미들웨어들과 함께 구성됩니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 기본 사용법 (wwwroot 폴더)</h4>



<p class="wp-block-paragraph">가장 기본적인 사용법은 웹 루트(<code>wwwroot</code>) 폴더에 있는 정적 파일을 제공하는 것입니다. </p>



<p class="wp-block-paragraph">이 경우, <code>UseStaticFiles()</code> 메서드를 인자 없이 호출하면 됩니다.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages(); // 또는 AddControllersWithViews 등

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();

// UseStaticFiles 미들웨어를 추가합니다.
// 이는 wwwroot 폴더의 정적 파일을 제공합니다.
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages(); // 또는 app.MapControllerRoute 등

app.Run();</pre>



<ul class="wp-block-list">
<li>위 코드에서 <code>UseStaticFiles()</code>를 호출하면, ASP.NET Core 프로젝트 템플릿에 기본으로 생성되는 <code>wwwroot</code> 폴더의 내용이 웹에 노출됩니다.</li>



<li>예를 들어, <code>wwwroot/css/site.css</code> 파일이 있다면, 브라우저에서 <code>http://localhost:포트번호/css/site.css</code>로 접근할 수 있게 됩니다.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 다른 폴더의 정적 파일 제공</h4>



<p class="wp-block-paragraph"><code>wwwroot</code> 외의 다른 폴더에 있는 정적 파일을 제공하고 싶을 때는 <code>StaticFileOptions</code>를 구성하여 경로를 지정할 수 있습니다.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// Program.cs

var builder = WebApplication.CreateBuilder(args);

// ... 서비스 설정 ...

var app = builder.Build();

// ... 기타 미들웨어 설정 ...

// wwwroot 외의 'MyStaticFiles' 폴더에 있는 정적 파일을 제공합니다.
// URL 경로는 `/MyFiles`로 시작합니다.
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/MyFiles" // URL 프리픽스
});

// 기존 wwwroot 폴더도 계속 사용하려면 이 줄도 유지합니다.
app.UseStaticFiles();

app.UseRouting();

// ... 나머지 미들웨어 및 엔드포인트 설정 ...

app.Run();</pre>



<ul class="wp-block-list">
<li><code>FileProvider</code>: <code>PhysicalFileProvider</code>를 사용하여 서버의 실제 파일 시스템 경로를 지정합니다. <br><code>ContentRootPath</code>는 애플리케이션의 기본 디렉토리를 나타냅니다.</li>



<li><code>RequestPath</code>: 이 <code>StaticFileOptions</code> 인스턴스에 의해 제공되는 파일에 접근하기 위한 URL 프리픽스를 정의합니다. <br>위 예시에서는 <code>MyStaticFiles</code> 폴더에 있는 <code>image.png</code> 파일을 <code>http://localhost:포트번호/MyFiles/image.png</code>로 접근할 수 있습니다.</li>



<li><code>UseStaticFiles()</code>를 여러 번 호출하여 여러 정적 파일 소스를 구성할 수 있습니다.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 디렉터리 브라우징 활성화 (권장하지 않음)</h4>



<p class="wp-block-paragraph">보안상의 이유로 기본적으로 비활성화되어 있지만, 개발 목적으로 디렉터리 목록을 웹에 노출해야 하는 경우 <code>UseDirectoryBrowser</code> 미들웨어를 함께 사용할 수 있습니다.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// Program.cs

var builder = WebApplication.CreateBuilder(args);

// 서비스에 디렉터리 브라우징 추가
builder.Services.AddDirectoryBrowser();

var app = builder.Build();

// ... 기타 미들웨어 설정 ...

// 'MyDirectory' 폴더를 웹에 노출하고, 해당 폴더의 내용을 `/MyFolder` URL로 브라우징할 수 있도록 합니다.
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(app.Environment.ContentRootPath, "MyDirectory")),
    RequestPath = "/MyFolder"
});

// 'MyDirectory' 폴더의 정적 파일도 제공합니다.
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(app.Environment.ContentRootPath, "MyDirectory")),
    RequestPath = "/MyFolder"
});

// ... 나머지 미들웨어 및 엔드포인트 설정 ...

app.Run();</pre>



<ul class="wp-block-list">
<li><strong>경고</strong>: <code>UseDirectoryBrowser</code>는 <strong>보안 취약점</strong>이 될 수 있으므로, <strong>운영 환경에서는 절대 사용해서는 안 됩니다.</strong> <br>오직 개발/디버깅 목적으로만 제한적으로 사용해야 합니다.</li>
</ul>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">4&#x20e3; <code>UseStaticFiles</code> 미들웨어의 위치</h3>



<p class="wp-block-paragraph">미들웨어 파이프라인에서 <code>UseStaticFiles</code>의 위치는 중요합니다.</p>



<ul class="wp-block-list">
<li>일반적으로 <code>UseStaticFiles</code>는 <code>UseRouting</code> 미들웨어 <strong>앞</strong>에 위치하는 것이 좋습니다. <br>이렇게 하면 라우팅 시스템이 복잡한 컨트롤러/엔드포인트 매칭 로직을 시작하기 전에, 정적 파일 요청을 먼저 빠르게 처리하고 응답할 수 있어 성능에 유리합니다.</li>



<li>만약 <code>UseStaticFiles</code>가 <code>UseRouting</code> 뒤에 오면, 정적 파일 요청도 라우팅 시스템의 대상이 되어 불필요한 처리 오버헤드가 발생할 수 있습니다.</li>



<li>하지만, 특정 미들웨어(예: 인증/인가 미들웨어)를 통해 정적 파일 접근을 제어하고 싶다면, 해당 미들웨어 뒤에 <code>UseStaticFiles</code>를 배치할 수도 있습니다. <br>이 경우 정적 파일 요청도 인증/인가 절차를 거치게 됩니다.</li>
</ul>



<p class="wp-block-paragraph"><code>UseStaticFiles</code> 미들웨어는 <strong>ASP.NET Core 웹 애플리케이션에서 정적인 웹 리소스를 효율적이고 안전하게 제공하는 데 필수적인 구성 요소</strong>입니다.</p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://lycos7560.com/c/asp-net/asp-net-core-usestaticfiles/40147/">ASP.NET Core &#8211; UseStaticFiles</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/c/asp-net/asp-net-core-usestaticfiles/40147/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Swagger/OpenAPI for .NET</title>
		<link>https://lycos7560.com/c/asp-net/swagger-openapi-for-net/40167/</link>
					<comments>https://lycos7560.com/c/asp-net/swagger-openapi-for-net/40167/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Wed, 18 Jun 2025 07:06:11 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[.NET6]]></category>
		<category><![CDATA[.NET7]]></category>
		<category><![CDATA[.NET8]]></category>
		<category><![CDATA[Accept헤더]]></category>
		<category><![CDATA[API가이드라인]]></category>
		<category><![CDATA[API계약]]></category>
		<category><![CDATA[API명세]]></category>
		<category><![CDATA[API문서화]]></category>
		<category><![CDATA[API버전관리]]></category>
		<category><![CDATA[API설계]]></category>
		<category><![CDATA[API테스트]]></category>
		<category><![CDATA[Application Insights]]></category>
		<category><![CDATA[appsettings]]></category>
		<category><![CDATA[ASP.NET Core]]></category>
		<category><![CDATA[Bearer토큰]]></category>
		<category><![CDATA[CI/CD]]></category>
		<category><![CDATA[Content-Type]]></category>
		<category><![CDATA[CORS]]></category>
		<category><![CDATA[DTO패턴]]></category>
		<category><![CDATA[FluentValidation]]></category>
		<category><![CDATA[FromBody]]></category>
		<category><![CDATA[FromQuery]]></category>
		<category><![CDATA[HTTP메서드]]></category>
		<category><![CDATA[HTTP상태코드]]></category>
		<category><![CDATA[Identity]]></category>
		<category><![CDATA[IdentityServer]]></category>
		<category><![CDATA[Interactive Documentation]]></category>
		<category><![CDATA[JSON Schema]]></category>
		<category><![CDATA[JSON직렬화]]></category>
		<category><![CDATA[JWT인증]]></category>
		<category><![CDATA[NuGet패키지]]></category>
		<category><![CDATA[OAuth2]]></category>
		<category><![CDATA[OpenAPI]]></category>
		<category><![CDATA[OpenAPI Specification]]></category>
		<category><![CDATA[ProducesResponseType]]></category>
		<category><![CDATA[Program.cs]]></category>
		<category><![CDATA[REST API]]></category>
		<category><![CDATA[RESTful설계]]></category>
		<category><![CDATA[Swagger]]></category>
		<category><![CDATA[SwaggerGen]]></category>
		<category><![CDATA[SwaggerUI]]></category>
		<category><![CDATA[Swashbuckle]]></category>
		<category><![CDATA[XML주석]]></category>
		<category><![CDATA[개발도구]]></category>
		<category><![CDATA[개발생산성]]></category>
		<category><![CDATA[개발환경]]></category>
		<category><![CDATA[검색]]></category>
		<category><![CDATA[결과필터]]></category>
		<category><![CDATA[구성관리]]></category>
		<category><![CDATA[권한부여]]></category>
		<category><![CDATA[글로벌필터]]></category>
		<category><![CDATA[기초]]></category>
		<category><![CDATA[네이밍컨벤션]]></category>
		<category><![CDATA[단위테스트]]></category>
		<category><![CDATA[데이터어노테이션]]></category>
		<category><![CDATA[디버깅]]></category>
		<category><![CDATA[라우팅]]></category>
		<category><![CDATA[로깅]]></category>
		<category><![CDATA[리플렉션]]></category>
		<category><![CDATA[린팅]]></category>
		<category><![CDATA[메타데이터추출]]></category>
		<category><![CDATA[모니터링]]></category>
		<category><![CDATA[모델바인딩]]></category>
		<category><![CDATA[문서화자동화]]></category>
		<category><![CDATA[미들웨어]]></category>
		<category><![CDATA[미들웨어파이프라인]]></category>
		<category><![CDATA[백엔드개발]]></category>
		<category><![CDATA[보안설정]]></category>
		<category><![CDATA[사용량추적]]></category>
		<category><![CDATA[상태코드]]></category>
		<category><![CDATA[서비스등록]]></category>
		<category><![CDATA[성능분석]]></category>
		<category><![CDATA[성능최적화]]></category>
		<category><![CDATA[순환참조]]></category>
		<category><![CDATA[스키마생성]]></category>
		<category><![CDATA[스키마필터]]></category>
		<category><![CDATA[스테이징환경]]></category>
		<category><![CDATA[액션메서드]]></category>
		<category><![CDATA[액션필터]]></category>
		<category><![CDATA[에러핸들링]]></category>
		<category><![CDATA[역할기반접근제어]]></category>
		<category><![CDATA[예외처리]]></category>
		<category><![CDATA[오류처리]]></category>
		<category><![CDATA[요청응답]]></category>
		<category><![CDATA[웹API]]></category>
		<category><![CDATA[유효성검사]]></category>
		<category><![CDATA[응답타입]]></category>
		<category><![CDATA[의존성주입]]></category>
		<category><![CDATA[인증통합]]></category>
		<category><![CDATA[인증필터]]></category>
		<category><![CDATA[자동문서화]]></category>
		<category><![CDATA[자동화배포]]></category>
		<category><![CDATA[정렬]]></category>
		<category><![CDATA[정적분석]]></category>
		<category><![CDATA[제네릭타입]]></category>
		<category><![CDATA[지속적통합]]></category>
		<category><![CDATA[컨트롤러]]></category>
		<category><![CDATA[코드리뷰]]></category>
		<category><![CDATA[코드퍼스트]]></category>
		<category><![CDATA[코드품질]]></category>
		<category><![CDATA[클레임기반인증]]></category>
		<category><![CDATA[타입안전성]]></category>
		<category><![CDATA[텔레메트리]]></category>
		<category><![CDATA[통합테스트]]></category>
		<category><![CDATA[트러블슈팅]]></category>
		<category><![CDATA[팀협업]]></category>
		<category><![CDATA[파라미터바인딩]]></category>
		<category><![CDATA[페이징]]></category>
		<category><![CDATA[프로덕션배포]]></category>
		<category><![CDATA[프론트엔드백엔드]]></category>
		<category><![CDATA[필터링]]></category>
		<category><![CDATA[환경변수]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=40167</guid>

					<description><![CDATA[<p>📖 Swagger(스웨거)란 무엇인가? Swagger는 현재 OpenAPI Specification (OAS)라는 이름으로 표준화된 RESTful API 명세 및 문서화 도구입니다. 2015년 SmartBear Software에서 OpenAPI Initiative에 기증한 후, 현재는 Linux Foundation 산하에서 관리되고 있습니다. 핵심 개념 🎯 Swagger가 필요한 이유 1. 개발 생산성 향상 2. 팀 협업 효율성 3. 운영 및 테스트 📦 Swashbuckle.AspNetCore 아키텍처 Swashbuckle.AspNetCore는 .NET에서 Swagger/OpenAPI를 구현하는 가장 [&#8230;]</p>
<p>The post <a href="https://lycos7560.com/c/asp-net/swagger-openapi-for-net/40167/">Swagger/OpenAPI for .NET</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-aee946f9      "
					data-scroll= "1"
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							목차						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#swagger스웨거란-무엇인가" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4d6.png" alt="📖" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Swagger(스웨거)란 무엇인가?</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#핵심-개념" class="uagb-toc-link__trigger">핵심 개념</a></li></ul></li><li class="uagb-toc__list"><a href="#swagger가-필요한-이유" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f3af.png" alt="🎯" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Swagger가 필요한 이유</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-개발-생산성-향상" class="uagb-toc-link__trigger">1. 개발 생산성 향상</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#2-팀-협업-효율성" class="uagb-toc-link__trigger">2. 팀 협업 효율성</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#3-운영-및-테스트" class="uagb-toc-link__trigger">3. 운영 및 테스트</a></li></ul></li></ul></li><li class="uagb-toc__list"><a href="#swashbuckleaspnetcore-아키텍처" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4e6.png" alt="📦" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Swashbuckle.AspNetCore 아키텍처</a><li class="uagb-toc__list"><a href="#net-6-프로젝트에서-swagger-구성" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f6e0.png" alt="🛠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> .NET 6+ 프로젝트에서 Swagger 구성</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-패키지-설치" class="uagb-toc-link__trigger">1. 패키지 설치</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#2-기본-구성-programcs" class="uagb-toc-link__trigger">2. 기본 구성 (Program.cs)</a></li></ul></li></ul></li></ul></li><li class="uagb-toc__list"><a href="#swaggergen의-동작-원리" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f50d.png" alt="🔍" class="wp-smiley" style="height: 1em; max-height: 1em;" /> SwaggerGen의 동작 원리</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#생성되는-openapi-문서-예시" class="uagb-toc-link__trigger">생성되는 OpenAPI 문서 예시</a></li></ul></li></ul></li></ul></li></ul></li><li class="uagb-toc__list"><a href="#swagger-ui-고급-활용" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4c4.png" alt="📄" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Swagger UI 고급 활용</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#주요-기능" class="uagb-toc-link__trigger">주요 기능</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#커스터마이징-옵션" class="uagb-toc-link__trigger">커스터마이징 옵션</a></li></ul></li></ul></li></ul></li></ul></li></ul></li><li class="uagb-toc__list"><a href="#실무-필수-확장-기능" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9e9.png" alt="🧩" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 실무 필수 확장 기능</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-xml-주석-통합" class="uagb-toc-link__trigger">1. XML 주석 통합</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#2-jwt-bearer-인증-통합" class="uagb-toc-link__trigger">2. JWT Bearer 인증 통합</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#3-api-버전-관리" class="uagb-toc-link__trigger">3. API 버전 관리</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#4-사용자-정의-스키마-필터" class="uagb-toc-link__trigger">4. 사용자 정의 스키마 필터</a></li></ul></li></ul></li></ul></li></ul></li></ul></li></ul></li><li class="uagb-toc__list"><a href="#성능-최적화-및-모범-사례" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4ca.png" alt="📊" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 성능 최적화 및 모범 사례</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-프로덕션-환경-고려사항" class="uagb-toc-link__trigger">1. 프로덕션 환경 고려사항</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#2-대용량-api-문서-최적화" class="uagb-toc-link__trigger">2. 대용량 API 문서 최적화</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#3-보안-강화" class="uagb-toc-link__trigger">3. 보안 강화</a></li></ul></li></ul></li></ul></li></ul></li></ul></li></ul></li></ul></li><li class="uagb-toc__list"><a href="#트러블슈팅-가이드" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f527.png" alt="🔧" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 트러블슈팅 가이드</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#일반적인-문제와-해결책" class="uagb-toc-link__trigger">일반적인 문제와 해결책</a></li></ul></li></ul></li></ul></li></ul></li></ul></li></ul></li></ul></li></ul></li><li class="uagb-toc__list"><a href="#모니터링-및-분석" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4c8.png" alt="📈" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 모니터링 및 분석</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#application-insights-통합" class="uagb-toc-link__trigger">Application Insights 통합</a></li></ul></li></ul></li></ul></li></ul></li></ul></li></ul></li></ul></li></ul></li></ul></li><li class="uagb-toc__list"><a href="#요약-및-베스트-프랙티스" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4cc.png" alt="📌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 요약 및 베스트 프랙티스</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#핵심-도구-정리" class="uagb-toc-link__trigger">핵심 도구 정리</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#개발팀을-위한-권장사항" class="uagb-toc-link__trigger">개발팀을 위한 권장사항</a></ul></ul></ul></ul></ul></ul></ul></ul></ul></ul></ol>					</div>
									</div>
				</div>
			


<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4d6.png" alt="📖" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Swagger(스웨거)란 무엇인가?</h2>



<p class="wp-block-paragraph"><strong>Swagger</strong>는 현재 OpenAPI Specification (OAS)라는 이름으로 표준화된 <strong>RESTful API 명세 및 문서화 도구</strong>입니다. </p>



<p class="wp-block-paragraph">2015년 SmartBear Software에서 OpenAPI Initiative에 기증한 후, 현재는 Linux Foundation 산하에서 관리되고 있습니다.</p>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">핵심 개념</h3>



<ul class="wp-block-list">
<li><strong>API 명세의 표준화</strong>: REST API의 엔드포인트, 파라미터, 응답 구조를 JSON/YAML 형식으로 정의</li>



<li><strong>Code-First 접근</strong>: 소스코드로부터 API 문서를 자동 생성하여 문서와 구현 간 불일치 방지</li>



<li><strong>Interactive Documentation</strong>: 브라우저에서 직접 API를 테스트할 수 있는 UI 제공</li>
</ul>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f3af.png" alt="🎯" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Swagger가 필요한 이유</h2>



<h3 class="wp-block-heading">1. 개발 생산성 향상</h3>



<ul class="wp-block-list">
<li><strong>자동 문서화</strong>: 수동으로 API 문서를 작성하고 유지보수하는 비용 절약</li>



<li><strong>실시간 동기화</strong>: 코드 변경 시 문서가 자동으로 업데이트</li>



<li><strong>타입 안전성</strong>: .NET의 강타입 시스템을 활용한 정확한 스키마 생성</li>
</ul>



<h3 class="wp-block-heading">2. 팀 협업 효율성</h3>



<ul class="wp-block-list">
<li><strong>프론트엔드-백엔드 협업</strong>: 명확한 API 계약 정의를 통한 병렬 개발 지원</li>



<li><strong>API 계약 테스트</strong>: 구현 전 API 설계 검증 가능</li>



<li><strong>버전 관리</strong>: API 변경사항 추적 및 하위 호환성 관리</li>
</ul>



<h3 class="wp-block-heading">3. 운영 및 테스트</h3>



<ul class="wp-block-list">
<li><strong>통합 테스트</strong>: CI/CD 파이프라인에서 자동화된 API 테스트</li>



<li><strong>모니터링</strong>: API 사용 패턴 분석 및 성능 모니터링 기반 제공</li>
</ul>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4e6.png" alt="📦" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Swashbuckle.AspNetCore 아키텍처</h2>



<p class="wp-block-paragraph">Swashbuckle.AspNetCore는 .NET에서 Swagger/OpenAPI를 구현하는 가장 널리 사용되는 라이브러리입니다.</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>패키지</th><th>역할</th><th>주요 기능</th></tr></thead><tbody><tr><td><code>Swashbuckle.AspNetCore.Swagger</code></td><td>OpenAPI 문서 생성 엔진</td><td>JSON/YAML 형식의 OpenAPI 명세 생성</td></tr><tr><td><code>Swashbuckle.AspNetCore.SwaggerGen</code></td><td>코드 분석 및 메타데이터 추출</td><td>리플렉션을 통한 컨트롤러/액션 분석</td></tr><tr><td><code>Swashbuckle.AspNetCore.SwaggerUI</code></td><td>웹 UI 렌더링</td><td>인터랙티브한 API 문서 및 테스트 인터페이스</td></tr></tbody></table></figure>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f6e0.png" alt="🛠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> .NET 6+ 프로젝트에서 Swagger 구성</h2>



<h3 class="wp-block-heading">1. 패키지 설치</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Package Manager Console
Install-Package Swashbuckle.AspNetCore

# .NET CLI
dotnet add package Swashbuckle.AspNetCore
</pre>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">2. 기본 구성 (Program.cs)</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">var builder = WebApplication.CreateBuilder(args);

// 컨트롤러 서비스 등록
builder.Services.AddControllers();

// Swagger 서비스 등록
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =>
{
    options.SwaggerDoc("v1", new OpenApiInfo
    {
        Version = "v1",
        Title = "My API",
        Description = "ASP.NET Core Web API for demonstration",
        Contact = new OpenApiContact
        {
            Name = "Developer Name",
            Email = "developer@example.com"
        }
    });
});

var app = builder.Build();

// 개발 환경에서만 Swagger 활성화
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI(options =>
    {
        options.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
        options.RoutePrefix = string.Empty; // 루트 경로에서 Swagger UI 제공
    });
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

app.Run();
</pre>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f50d.png" alt="🔍" class="wp-smiley" style="height: 1em; max-height: 1em;" /> SwaggerGen의 동작 원리</h2>



<p class="wp-block-paragraph">SwaggerGen은 다음과 같은 과정을 통해 OpenAPI 문서를 생성합니다:</p>



<ol class="wp-block-list">
<li><strong>어셈블리 스캔</strong>: 등록된 컨트롤러와 액션 메서드 탐색</li>



<li><strong>메타데이터 추출</strong>: 라우트, HTTP 메서드, 파라미터, 반환 타입 분석</li>



<li><strong>스키마 생성</strong>: .NET 타입을 JSON Schema로 변환</li>



<li><strong>문서 조합</strong>: OpenAPI 3.0 사양에 맞는 JSON 문서 생성</li>
</ol>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">생성되는 OpenAPI 문서 예시</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{
  "openapi": "3.0.1",
  "info": {
    "title": "My API",
    "version": "v1"
  },
  "paths": {
    "/api/products": {
      "get": {
        "tags": ["Products"],
        "summary": "제품 목록 조회",
        "responses": {
          "200": {
            "description": "성공",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Product"
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Product": {
        "type": "object",
        "properties": {
          "id": { "type": "integer", "format": "int32" },
          "name": { "type": "string", "nullable": true }
        }
      }
    }
  }
}
</pre>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="1378" height="1299" src="https://lycos7560.com/wp-content/uploads/2025/07/image-19.png" alt="" class="wp-image-40168" srcset="https://lycos7560.com/wp-content/uploads/2025/07/image-19.png 1378w, https://lycos7560.com/wp-content/uploads/2025/07/image-19-300x283.png 300w, https://lycos7560.com/wp-content/uploads/2025/07/image-19-768x724.png 768w" sizes="(max-width: 1378px) 100vw, 1378px" /></figure>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4c4.png" alt="📄" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Swagger UI 고급 활용</h2>



<p class="wp-block-paragraph">Swagger UI는 생성된 OpenAPI 문서를 기반으로 다음 기능을 제공합니다:</p>



<h3 class="wp-block-heading">주요 기능</h3>



<ul class="wp-block-list">
<li><strong>HTTP 메서드별 분류</strong>: GET, POST, PUT, DELETE 등 시각적 구분</li>



<li><strong>스키마 검증</strong>: 요청/응답 데이터 구조 실시간 검증</li>



<li><strong>Try it Out</strong>: 브라우저에서 직접 API 호출 및 결과 확인</li>



<li><strong>모델 정의</strong>: 복잡한 객체 구조의 시각적 표현</li>



<li><strong>인증 통합</strong>: 다양한 인증 방식 지원 (Bearer, API Key 등)</li>
</ul>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">커스터마이징 옵션</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">app.UseSwaggerUI(options =>
{
    options.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
    options.DocumentTitle = "My API Documentation";
    options.DefaultModelsExpandDepth(2);
    options.DefaultModelRendering(ModelRendering.Model);
    options.DisplayRequestDuration();
    options.EnableDeepLinking();
    options.EnableFilter();
    options.ShowExtensions();
});
</pre>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9e9.png" alt="🧩" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 실무 필수 확장 기능</h2>



<h3 class="wp-block-heading">1. XML 주석 통합</h3>



<p class="wp-block-paragraph">프로젝트 파일 설정:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;PropertyGroup>
  &lt;GenerateDocumentationFile>true&lt;/GenerateDocumentationFile>
  &lt;NoWarn>$(NoWarn);1591&lt;/NoWarn>
&lt;/PropertyGroup>
</pre>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph">Program.cs 구성:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">builder.Services.AddSwaggerGen(options =>
{
    var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
    options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
    
    // 상속된 XML 주석 포함
    options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "MyModels.xml"));
});
</pre>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph">컨트롤러 예시:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">/// &lt;summary>
/// 제품 관리 API
/// &lt;/summary>
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    /// &lt;summary>
    /// 제품 목록을 조회합니다.
    /// &lt;/summary>
    /// &lt;param name="pageSize">페이지당 항목 수 (기본값: 10)&lt;/param>
    /// &lt;returns>제품 목록&lt;/returns>
    /// &lt;response code="200">성공적으로 조회됨&lt;/response>
    /// &lt;response code="400">잘못된 요청 파라미터&lt;/response>
    [HttpGet]
    [ProducesResponseType(typeof(IEnumerable&lt;Product>), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task&lt;ActionResult&lt;IEnumerable&lt;Product>>> GetProducts(
        [FromQuery] int pageSize = 10)
    {
        // 구현 로직
    }
}
</pre>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">2. JWT Bearer 인증 통합</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">builder.Services.AddSwaggerGen(options =>
{
    options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
    {
        Name = "Authorization",
        Type = SecuritySchemeType.Http,
        Scheme = "Bearer",
        BearerFormat = "JWT",
        In = ParameterLocation.Header,
        Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\""
    });

    options.AddSecurityRequirement(new OpenApiSecurityRequirement
    {
        {
            new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference
                {
                    Type = ReferenceType.SecurityScheme,
                    Id = "Bearer"
                }
            },
            Array.Empty&lt;string>()
        }
    });
});
</pre>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">3. API 버전 관리</h3>



<p class="wp-block-paragraph">패키지 설치:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">dotnet add package Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer
</pre>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph">구성:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">builder.Services.AddApiVersioning(options =>
{
    options.DefaultApiVersion = new ApiVersion(1, 0);
    options.AssumeDefaultVersionWhenUnspecified = true;
    options.ApiVersionReader = ApiVersionReader.Combine(
        new UrlSegmentApiVersionReader(),
        new HeaderApiVersionReader("X-Version"),
        new MediaTypeApiVersionReader("ver"));
});

builder.Services.AddVersionedApiExplorer(setup =>
{
    setup.GroupNameFormat = "'v'VVV";
    setup.SubstituteApiVersionInUrl = true;
});

builder.Services.AddSwaggerGen();
builder.Services.ConfigureOptions&lt;ConfigureSwaggerOptions>();
</pre>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">4. 사용자 정의 스키마 필터</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">public class EnumSchemaFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        if (context.Type.IsEnum)
        {
            schema.Enum.Clear();
            Enum.GetNames(context.Type)
                .ToList()
                .ForEach(name => schema.Enum.Add(new OpenApiString(name)));
        }
    }
}

// 등록
builder.Services.AddSwaggerGen(options =>
{
    options.SchemaFilter&lt;EnumSchemaFilter>();
});
</pre>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4ca.png" alt="📊" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 성능 최적화 및 모범 사례</h2>



<h3 class="wp-block-heading">1. 프로덕션 환경 고려사항</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// 조건부 Swagger 활성화
if (app.Environment.IsDevelopment() || app.Environment.IsStaging())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

// 또는 구성 기반 활성화
if (builder.Configuration.GetValue&lt;bool>("EnableSwagger"))
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
</pre>



<h3 class="wp-block-heading">2. 대용량 API 문서 최적화</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">builder.Services.AddSwaggerGen(options =>
{
    // 불필요한 스키마 제외
    options.SchemaFilter&lt;ExcludeInternalTypesFilter>();
    
    // 문서 압축
    options.EnableAnnotations();
    
    // 메모리 사용량 최적화
    options.UseAllOfToExtendReferenceSchemas();
    options.UseOneOfForPolymorphism();
});
</pre>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">3. 보안 강화</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">app.UseSwagger(options =>
{
    // JSON 문서 접근 제한
    options.PreSerializeFilters.Add((swagger, httpReq) =>
    {
        if (!httpReq.Headers.ContainsKey("X-API-Key"))
        {
            throw new UnauthorizedAccessException();
        }
    });
});
</pre>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f527.png" alt="🔧" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 트러블슈팅 가이드</h2>



<h3 class="wp-block-heading">일반적인 문제와 해결책</h3>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>문제</th><th>원인</th><th>해결방법</th></tr></thead><tbody><tr><td>XML 주석이 표시되지 않음</td><td>XML 파일 경로 오류</td><td>빌드 출력 디렉토리 확인 및 경로 수정</td></tr><tr><td>복잡한 제네릭 타입 오류</td><td>스키마 생성 실패</td><td>사용자 정의 SchemaFilter 구현</td></tr><tr><td>순환 참조 오류</td><td>모델 간 순환 의존성</td><td>JsonIgnore 또는 DTO 패턴 적용</td></tr><tr><td>인증 테스트 실패</td><td>CORS 또는 인증 설정 문제</td><td>CORS 정책 및 인증 미들웨어 순서 확인</td></tr></tbody></table></figure>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4c8.png" alt="📈" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 모니터링 및 분석</h2>



<h3 class="wp-block-heading">Application Insights 통합</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">builder.Services.AddApplicationInsightsTelemetry();

// Swagger 사용량 추적
app.UseSwagger(options =>
{
    options.PreSerializeFilters.Add((swagger, httpReq) =>
    {
        var telemetryClient = httpReq.HttpContext.RequestServices
            .GetRequiredService&lt;TelemetryClient>();
        telemetryClient.TrackEvent("SwaggerAccessed");
    });
});
</pre>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4cc.png" alt="📌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 요약 및 베스트 프랙티스</h2>



<h3 class="wp-block-heading">핵심 도구 정리</h3>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>도구/개념</th><th>설명</th><th>권장 사용 시나리오</th></tr></thead><tbody><tr><td><strong>OpenAPI/Swagger</strong></td><td>REST API 명세 표준</td><td>모든 REST API 프로젝트</td></tr><tr><td><strong>Swashbuckle.AspNetCore</strong></td><td>.NET용 Swagger 구현체</td><td>ASP.NET Core 웹 API</td></tr><tr><td><strong>Swagger UI</strong></td><td>인터랙티브 API 문서</td><td>개발 및 테스트 환경</td></tr><tr><td><strong>SwaggerGen</strong></td><td>코드 기반 문서 생성기</td><td>자동화된 문서 관리</td></tr></tbody></table></figure>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">개발팀을 위한 권장사항</h3>



<ol class="wp-block-list">
<li><strong>개발 초기</strong>부터 Swagger 도입하여 API 설계 단계에서 문서화</li>



<li><strong>XML 주석</strong>을 활용한 상세한 API 설명 작성</li>



<li><strong>DTO 패턴</strong> 적용으로 명확한 API 계약 정의</li>



<li><strong>버전 관리</strong> 전략 수립으로 하위 호환성 보장</li>



<li><strong>보안 설정</strong> 통합으로 실제 운영 환경과 일치하는 테스트 환경 구축</li>



<li><strong>CI/CD 파이프라인</strong>에 OpenAPI 스펙 검증 단계 포함</li>
</ol>



<p class="wp-block-paragraph">이러한 접근을 통해 Swagger/OpenAPI는 단순한 문서화 도구를 넘어서 API 개발 생명주기 전반을 지원하는 핵심 인프라가 될 수 있습니다.</p>
<p>The post <a href="https://lycos7560.com/c/asp-net/swagger-openapi-for-net/40167/">Swagger/OpenAPI for .NET</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/c/asp-net/swagger-openapi-for-net/40167/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Dependency Inversion Principle(DIP, 의존성 역전 원리)</title>
		<link>https://lycos7560.com/c/dependency-inversion-principledip-%ec%9d%98%ec%a1%b4%ec%84%b1-%ec%97%ad%ec%a0%84-%ec%9b%90%eb%a6%ac/38731/</link>
					<comments>https://lycos7560.com/c/dependency-inversion-principledip-%ec%9d%98%ec%a1%b4%ec%84%b1-%ec%97%ad%ec%a0%84-%ec%9b%90%eb%a6%ac/38731/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Sun, 03 Nov 2024 07:48:04 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Blazor]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[.Net Core]]></category>
		<category><![CDATA[AddModelError]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[ASP.NET Core]]></category>
		<category><![CDATA[Azure]]></category>
		<category><![CDATA[Consuming]]></category>
		<category><![CDATA[Controller]]></category>
		<category><![CDATA[Create]]></category>
		<category><![CDATA[Data]]></category>
		<category><![CDATA[Data access logic]]></category>
		<category><![CDATA[DataBase]]></category>
		<category><![CDATA[DbContext]]></category>
		<category><![CDATA[DbSet]]></category>
		<category><![CDATA[DELETE]]></category>
		<category><![CDATA[Dependency]]></category>
		<category><![CDATA[Dependency Inversion]]></category>
		<category><![CDATA[Deploying]]></category>
		<category><![CDATA[DI]]></category>
		<category><![CDATA[DIP]]></category>
		<category><![CDATA[Domain]]></category>
		<category><![CDATA[Domain Model]]></category>
		<category><![CDATA[File]]></category>
		<category><![CDATA[FileDescription]]></category>
		<category><![CDATA[Filestream]]></category>
		<category><![CDATA[GET]]></category>
		<category><![CDATA[IFormFile]]></category>
		<category><![CDATA[Image]]></category>
		<category><![CDATA[Image Controller]]></category>
		<category><![CDATA[IsValid]]></category>
		<category><![CDATA[Migration]]></category>
		<category><![CDATA[Model]]></category>
		<category><![CDATA[ModelState]]></category>
		<category><![CDATA[pepe]]></category>
		<category><![CDATA[POST]]></category>
		<category><![CDATA[program]]></category>
		<category><![CDATA[Program.cs]]></category>
		<category><![CDATA[PUT]]></category>
		<category><![CDATA[Repository]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[REST Web API]]></category>
		<category><![CDATA[study]]></category>
		<category><![CDATA[Upload]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[web API]]></category>
		<category><![CDATA[wpf]]></category>
		<category><![CDATA[기초]]></category>
		<category><![CDATA[배포]]></category>
		<category><![CDATA[의존성]]></category>
		<category><![CDATA[의존성 역전]]></category>
		<category><![CDATA[의존성 역전 원리]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=38731</guid>

					<description><![CDATA[<p>Dependency Inversion Principle(DIP, 의존성 역전 원리) https://learn.microsoft.com/en-us/dotnet/architecture/modern-web-apps-azure/architectural-principles#dependency-inversion The direction of dependency within the application should be in the direction of abstraction, not implementation details.애플리케이션 내의 종속성 방향은 구현 세부 사항이 아닌 추상화 방향이어야 합니다. Most applications are written such that compile-time dependency flows in the direction of runtime execution, producing a direct dependency graph.대부분의 애플리케이션은 [&#8230;]</p>
<p>The post <a href="https://lycos7560.com/c/dependency-inversion-principledip-%ec%9d%98%ec%a1%b4%ec%84%b1-%ec%97%ad%ec%a0%84-%ec%9b%90%eb%a6%ac/38731/">Dependency Inversion Principle(DIP, 의존성 역전 원리)</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" id="dependency-inversion">Dependency Inversion Principle(DIP, 의존성 역전 원리)</h2>



<p class="wp-block-paragraph"><a href="https://learn.microsoft.com/en-us/dotnet/architecture/modern-web-apps-azure/architectural-principles#dependency-inversion" target="_blank" rel="noreferrer noopener">https://learn.microsoft.com/en-us/dotnet/architecture/modern-web-apps-azure/architectural-principles#dependency-inversion</a></p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph">The direction of dependency within the application should be in the direction of abstraction, not implementation details.<br>애플리케이션 내의 종속성 방향은 구현 세부 사항이 아닌 추상화 방향이어야 합니다. <br>Most applications are written such that compile-time dependency flows in the direction of runtime execution, producing a direct dependency graph.<br>대부분의 애플리케이션은 컴파일 타임 종속성이 런타임 실행 방향으로 흐르도록 작성되어 직접적인 종속성 그래프를 생성합니다.</p>



<p class="wp-block-paragraph">That is, if class A calls a method of class B and class B calls a method of class C, then at compile time class A will depend on class B, and class B will depend on class C.<br>즉, class A가 class B의 메서드를 호출하고 class B가 class C의 메서드를 호출하는 경우 컴파일 타임에 class A는 class B에 종속되고 class B는 class C에 종속됩니다.</p>



<p class="wp-block-paragraph">코드 구조에서 세부 구현 내용에 의존하지 말고, 더 추상적이고 일반적인 개념에 의존해야 한다는 뜻<br>이렇게 하면 코드가 더 유연해지고, 변경하기 쉽고, 재사용하기도 쉬워진다.<br>예를 들어, 어떤 기능을 <strong>직접 호출하는 것보다 그 기능을 일반적으로 설명하는 인터페이스를 사용하는 것이 더 좋다는 의미</strong>)</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="669" height="556" src="https://lycos7560.com/wp-content/uploads/2024/11/image-73.png" alt="" class="wp-image-38735" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-73.png 669w, https://lycos7560.com/wp-content/uploads/2024/11/image-73-300x249.png 300w" sizes="(max-width: 669px) 100vw, 669px" /><figcaption class="wp-element-caption">Direct dependency graph.</figcaption></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph">Applying the dependency inversion principle allows A to call methods on an abstraction that B implements, making it possible for A to call B at run time, but for B to depend on an interface controlled by A at compile time (thus,&nbsp;<em>inverting</em>&nbsp;the typical compile-time dependency).<br>종속성 반전 원칙을 적용하면 A가 B가 구현하는 추상화에 대한 메서드를 호출할 수 있으므로 A가 런타임에 B를 호출할 수 있지만 B는 컴파일 타임에 A에 의해 제어되는 인터페이스에 의존할 수 있습니다<br>(따라서 일반적인 컴파일 타임 종속성을&nbsp;<em>반전시킵니다</em>).&nbsp;</p>



<p class="wp-block-paragraph">At run time, the flow of program execution remains unchanged, but the introduction of interfaces means that different implementations of these interfaces can easily be plugged in.<br>런타임에 프로그램 실행의 흐름은 변경되지 않지만 인터페이스의 도입은 이러한 인터페이스의 다른 구현을 쉽게 연결할 수 있음을 의미합니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="838" height="455" src="https://lycos7560.com/wp-content/uploads/2024/11/image-74.png" alt="" class="wp-image-38736" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-74.png 838w, https://lycos7560.com/wp-content/uploads/2024/11/image-74-300x163.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-74-768x417.png 768w" sizes="(max-width: 838px) 100vw, 838px" /><figcaption class="wp-element-caption">Inverted dependency graph.</figcaption></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph"><strong>Dependency inversion</strong>&nbsp;is a key part of building loosely coupled applications, since implementation details can be written to depend on and implement higher-level abstractions, rather than the other way around.<br><strong>종속성 반전</strong>은 느슨하게 결합된 애플리케이션을 구축하는 데 있어 중요한 부분인데, 그 이유는 구현 세부 정보를 작성하여 더 높은 수준의 추상화에 의존하고 구현하도록 할 수 있기 때문입니다.</p>



<p class="wp-block-paragraph">The resulting applications are more testable, modular, and maintainable as a result.<br>그 결과 응용 프로그램은 더 쉽게 테스트할 수 있고, 모듈화되며, 유지 관리가 더 용이합니다.&nbsp;</p>



<p class="wp-block-paragraph">The practice of&nbsp;<em>dependency injection</em>&nbsp;is made possible by following the dependency inversion principle.<br><em>종속성 주입</em>의 연습은 종속성 반전 원칙을 따름으로써 가능합니다.</p>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20)"/>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph">애플리케이션의 의존성을 구체적인 구현이 아니라 추상화된 개념에 맞추는 것</p>



<p class="wp-block-paragraph">대부분의 애플리케이션은 A 클래스가 B 클래스를, B 클래스가 C 클래스를 호출하는 형태로 작성됩니다. </p>



<p class="wp-block-paragraph">이는 A가 B에, B가 C에 의존하게 만든다는 뜻입니다. 종속성 반전 원칙을 적용하면 A는 B의 구체적인 구현이 아니라 B가 구현하는 추상 개념에 의존하게 됩니다. </p>



<p class="wp-block-paragraph">이렇게 하면 코드를 더 쉽게 테스트할 수 있고, 변경 및 유지보수가 용이해집니다. </p>



<p class="wp-block-paragraph">간단히 말해, 코드를 유연하고 재사용 가능하게 만들어줍니다.</p>



<div style="height:102px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph"><strong>종속성 반전 적용 전</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// 엔진 클래스
public class Engine
{
    public void Start()
    {
        Console.WriteLine("Engine starts.");
    }
}

// 자동차 클래스
public class Car
{
    private Engine _engine = new Engine();

    public void Start()
    {
        _engine.Start();
        Console.WriteLine("Car starts.");
    }
}

// 메인 프로그램
public class Program
{
    public static void Main(string[] args)
    {
        Car car = new Car();
        car.Start();
    }
}
</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph"><strong>종속성 반전 적용 후</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// 인터페이스 정의
public interface IEngine
{
    void Start();
}

// 엔진 클래스
public class Engine : IEngine
{
    public void Start()
    {
        Console.WriteLine("Engine starts.");
    }
}

// 전기 엔진 클래스
public class ElectricEngine : IEngine
{
    public void Start()
    {
        Console.WriteLine("Electric engine starts.");
    }
}

// 자동차 클래스
public class Car
{
    private IEngine _engine;

    public Car(IEngine engine)
    {
        _engine = engine;
    }

    public void Start()
    {
        _engine.Start();
        Console.WriteLine("Car starts.");
    }
}

// 메인 프로그램
public class Program
{
    public static void Main(string[] args)
    {
        IEngine engine = new Engine();
        Car car = new Car(engine);
        car.Start();
        
        IEngine electricEngine = new ElectricEngine();
        Car electricCar = new Car(electricEngine);
        electricCar.Start();
    }
}
</pre>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://lycos7560.com/c/dependency-inversion-principledip-%ec%9d%98%ec%a1%b4%ec%84%b1-%ec%97%ad%ec%a0%84-%ec%9b%90%eb%a6%ac/38731/">Dependency Inversion Principle(DIP, 의존성 역전 원리)</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/c/dependency-inversion-principledip-%ec%9d%98%ec%a1%b4%ec%84%b1-%ec%97%ad%ec%a0%84-%ec%9b%90%eb%a6%ac/38731/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Deploying ASP.NET Web API To Azure</title>
		<link>https://lycos7560.com/c/deploying-asp-net-web-api-to-azure/38646/</link>
					<comments>https://lycos7560.com/c/deploying-asp-net-web-api-to-azure/38646/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Fri, 01 Nov 2024 08:08:45 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[.Net Core]]></category>
		<category><![CDATA[AddModelError]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[ASP.NET Core]]></category>
		<category><![CDATA[Azure]]></category>
		<category><![CDATA[Consuming]]></category>
		<category><![CDATA[Controller]]></category>
		<category><![CDATA[Create]]></category>
		<category><![CDATA[Data]]></category>
		<category><![CDATA[Data access logic]]></category>
		<category><![CDATA[DataBase]]></category>
		<category><![CDATA[DbContext]]></category>
		<category><![CDATA[DbSet]]></category>
		<category><![CDATA[DELETE]]></category>
		<category><![CDATA[Deploying]]></category>
		<category><![CDATA[Domain]]></category>
		<category><![CDATA[Domain Model]]></category>
		<category><![CDATA[File]]></category>
		<category><![CDATA[FileDescription]]></category>
		<category><![CDATA[Filestream]]></category>
		<category><![CDATA[GET]]></category>
		<category><![CDATA[IFormFile]]></category>
		<category><![CDATA[Image]]></category>
		<category><![CDATA[Image Controller]]></category>
		<category><![CDATA[IsValid]]></category>
		<category><![CDATA[Migration]]></category>
		<category><![CDATA[Model]]></category>
		<category><![CDATA[ModelState]]></category>
		<category><![CDATA[pepe]]></category>
		<category><![CDATA[POST]]></category>
		<category><![CDATA[program]]></category>
		<category><![CDATA[Program.cs]]></category>
		<category><![CDATA[PUT]]></category>
		<category><![CDATA[Repository]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[REST Web API]]></category>
		<category><![CDATA[study]]></category>
		<category><![CDATA[Upload]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[web API]]></category>
		<category><![CDATA[wpf]]></category>
		<category><![CDATA[기초]]></category>
		<category><![CDATA[배포]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=38646</guid>

					<description><![CDATA[<p>Deploying ASP.NET Web API To Azure https://azure.microsoft.com/ko-kr</p>
<p>The post <a href="https://lycos7560.com/c/deploying-asp-net-web-api-to-azure/38646/">Deploying ASP.NET Web API To Azure</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Deploying ASP.NET Web API To Azure</h2>



<p class="wp-block-paragraph"><a href="https://azure.microsoft.com/ko-kr" target="_blank" rel="noreferrer noopener">https://azure.microsoft.com/ko-kr</a></p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1462" height="565" src="https://lycos7560.com/wp-content/uploads/2024/11/image.png" alt="" class="wp-image-38647" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image.png 1462w, https://lycos7560.com/wp-content/uploads/2024/11/image-300x116.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-768x297.png 768w" sizes="(max-width: 1462px) 100vw, 1462px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1242" height="801" src="https://lycos7560.com/wp-content/uploads/2024/11/image-1.png" alt="" class="wp-image-38650" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-1.png 1242w, https://lycos7560.com/wp-content/uploads/2024/11/image-1-300x193.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-1-768x495.png 768w" sizes="(max-width: 1242px) 100vw, 1242px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1019" height="525" src="https://lycos7560.com/wp-content/uploads/2024/11/image-2.png" alt="" class="wp-image-38651" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-2.png 1019w, https://lycos7560.com/wp-content/uploads/2024/11/image-2-300x155.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-2-768x396.png 768w" sizes="(max-width: 1019px) 100vw, 1019px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="745" height="541" src="https://lycos7560.com/wp-content/uploads/2024/11/image-3.png" alt="" class="wp-image-38652" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-3.png 745w, https://lycos7560.com/wp-content/uploads/2024/11/image-3-300x218.png 300w" sizes="(max-width: 745px) 100vw, 745px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1242" height="801" src="https://lycos7560.com/wp-content/uploads/2024/11/image-4.png" alt="" class="wp-image-38653" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-4.png 1242w, https://lycos7560.com/wp-content/uploads/2024/11/image-4-300x193.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-4-768x495.png 768w" sizes="(max-width: 1242px) 100vw, 1242px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1242" height="801" src="https://lycos7560.com/wp-content/uploads/2024/11/image-10.png" alt="" class="wp-image-38659" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-10.png 1242w, https://lycos7560.com/wp-content/uploads/2024/11/image-10-300x193.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-10-768x495.png 768w" sizes="(max-width: 1242px) 100vw, 1242px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1456" height="399" src="https://lycos7560.com/wp-content/uploads/2024/11/image-11.png" alt="" class="wp-image-38661" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-11.png 1456w, https://lycos7560.com/wp-content/uploads/2024/11/image-11-300x82.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-11-768x210.png 768w" sizes="(max-width: 1456px) 100vw, 1456px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="936" height="769" src="https://lycos7560.com/wp-content/uploads/2024/11/image-12.png" alt="" class="wp-image-38662" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-12.png 936w, https://lycos7560.com/wp-content/uploads/2024/11/image-12-300x246.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-12-768x631.png 768w" sizes="(max-width: 936px) 100vw, 936px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1176" height="457" src="https://lycos7560.com/wp-content/uploads/2024/11/image-13.png" alt="" class="wp-image-38663" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-13.png 1176w, https://lycos7560.com/wp-content/uploads/2024/11/image-13-300x117.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-13-768x298.png 768w" sizes="(max-width: 1176px) 100vw, 1176px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1510" height="801" src="https://lycos7560.com/wp-content/uploads/2024/11/image-14.png" alt="" class="wp-image-38664" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-14.png 1510w, https://lycos7560.com/wp-content/uploads/2024/11/image-14-300x159.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-14-768x407.png 768w" sizes="(max-width: 1510px) 100vw, 1510px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image"><img decoding="async" width="1146" height="521" src="https://lycos7560.com/wp-content/uploads/2024/11/image-15.png" alt="" class="wp-image-38665" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-15.png 1146w, https://lycos7560.com/wp-content/uploads/2024/11/image-15-300x136.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-15-768x349.png 768w" sizes="(max-width: 1146px) 100vw, 1146px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="845" height="518" src="https://lycos7560.com/wp-content/uploads/2024/11/image-16.png" alt="" class="wp-image-38666" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-16.png 845w, https://lycos7560.com/wp-content/uploads/2024/11/image-16-300x184.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-16-768x471.png 768w" sizes="(max-width: 845px) 100vw, 845px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="662" height="978" src="https://lycos7560.com/wp-content/uploads/2024/11/image-17.png" alt="" class="wp-image-38668" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-17.png 662w, https://lycos7560.com/wp-content/uploads/2024/11/image-17-203x300.png 203w" sizes="(max-width: 662px) 100vw, 662px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="661" height="820" src="https://lycos7560.com/wp-content/uploads/2024/11/image-18.png" alt="" class="wp-image-38670" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-18.png 661w, https://lycos7560.com/wp-content/uploads/2024/11/image-18-242x300.png 242w" sizes="(max-width: 661px) 100vw, 661px" /></figure>
</div>
</div>



<figure class="wp-block-image size-full"><img decoding="async" width="1726" height="984" src="https://lycos7560.com/wp-content/uploads/2024/11/image-20.png" alt="" class="wp-image-38672" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-20.png 1726w, https://lycos7560.com/wp-content/uploads/2024/11/image-20-300x171.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-20-768x438.png 768w, https://lycos7560.com/wp-content/uploads/2024/11/image-20-1536x876.png 1536w" sizes="(max-width: 1726px) 100vw, 1726px" /></figure>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="895" height="295" src="https://lycos7560.com/wp-content/uploads/2024/11/image-21.png" alt="" class="wp-image-38673" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-21.png 895w, https://lycos7560.com/wp-content/uploads/2024/11/image-21-300x99.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-21-768x253.png 768w" sizes="(max-width: 895px) 100vw, 895px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="688" height="328" src="https://lycos7560.com/wp-content/uploads/2024/11/image-25.png" alt="" class="wp-image-38677" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-25.png 688w, https://lycos7560.com/wp-content/uploads/2024/11/image-25-300x143.png 300w" sizes="(max-width: 688px) 100vw, 688px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="645" height="987" src="https://lycos7560.com/wp-content/uploads/2024/11/image-27.png" alt="" class="wp-image-38679" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-27.png 645w, https://lycos7560.com/wp-content/uploads/2024/11/image-27-196x300.png 196w" sizes="(max-width: 645px) 100vw, 645px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="696" height="1020" src="https://lycos7560.com/wp-content/uploads/2024/11/image-26.png" alt="" class="wp-image-38678" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-26.png 696w, https://lycos7560.com/wp-content/uploads/2024/11/image-26-205x300.png 205w" sizes="(max-width: 696px) 100vw, 696px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="824" height="415" src="https://lycos7560.com/wp-content/uploads/2024/11/image-28.png" alt="" class="wp-image-38680" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-28.png 824w, https://lycos7560.com/wp-content/uploads/2024/11/image-28-300x151.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-28-768x387.png 768w" sizes="(max-width: 824px) 100vw, 824px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="826" height="330" src="https://lycos7560.com/wp-content/uploads/2024/11/image-29.png" alt="" class="wp-image-38681" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-29.png 826w, https://lycos7560.com/wp-content/uploads/2024/11/image-29-300x120.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-29-768x307.png 768w" sizes="(max-width: 826px) 100vw, 826px" /></figure>
</div>
</div>



<figure class="wp-block-image size-full"><img decoding="async" width="1404" height="1005" src="https://lycos7560.com/wp-content/uploads/2024/11/image-30.png" alt="" class="wp-image-38682" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-30.png 1404w, https://lycos7560.com/wp-content/uploads/2024/11/image-30-300x215.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-30-768x550.png 768w" sizes="(max-width: 1404px) 100vw, 1404px" /></figure>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.34%">
<figure class="wp-block-image size-full"><img decoding="async" width="714" height="604" src="https://lycos7560.com/wp-content/uploads/2024/11/image-31.png" alt="" class="wp-image-38683" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-31.png 714w, https://lycos7560.com/wp-content/uploads/2024/11/image-31-300x254.png 300w" sizes="(max-width: 714px) 100vw, 714px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.34%">
<figure class="wp-block-image size-full"><img decoding="async" width="618" height="372" src="https://lycos7560.com/wp-content/uploads/2024/11/image-32.png" alt="" class="wp-image-38684" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-32.png 618w, https://lycos7560.com/wp-content/uploads/2024/11/image-32-300x181.png 300w" sizes="(max-width: 618px) 100vw, 618px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.33%">
<figure class="wp-block-image size-full"><img decoding="async" width="473" height="496" src="https://lycos7560.com/wp-content/uploads/2024/11/image-33.png" alt="" class="wp-image-38685" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-33.png 473w, https://lycos7560.com/wp-content/uploads/2024/11/image-33-286x300.png 286w" sizes="(max-width: 473px) 100vw, 473px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.34%">
<figure class="wp-block-image size-full"><img decoding="async" width="762" height="475" src="https://lycos7560.com/wp-content/uploads/2024/11/image-34.png" alt="" class="wp-image-38686" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-34.png 762w, https://lycos7560.com/wp-content/uploads/2024/11/image-34-300x187.png 300w" sizes="(max-width: 762px) 100vw, 762px" /><figcaption class="wp-element-caption">Azure 계정확인</figcaption></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.34%">
<figure class="wp-block-image size-full"><img decoding="async" width="596" height="362" src="https://lycos7560.com/wp-content/uploads/2024/11/image-35.png" alt="" class="wp-image-38687" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-35.png 596w, https://lycos7560.com/wp-content/uploads/2024/11/image-35-300x182.png 300w" sizes="(max-width: 596px) 100vw, 596px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.33%">
<figure class="wp-block-image size-full"><img decoding="async" width="781" height="549" src="https://lycos7560.com/wp-content/uploads/2024/11/image-36.png" alt="" class="wp-image-38688" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-36.png 781w, https://lycos7560.com/wp-content/uploads/2024/11/image-36-300x211.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-36-768x540.png 768w" sizes="(max-width: 781px) 100vw, 781px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.34%">
<figure class="wp-block-image size-full"><img decoding="async" width="787" height="541" src="https://lycos7560.com/wp-content/uploads/2024/11/image-38.png" alt="" class="wp-image-38690" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-38.png 787w, https://lycos7560.com/wp-content/uploads/2024/11/image-38-300x206.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-38-768x528.png 768w" sizes="(max-width: 787px) 100vw, 787px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.34%">
<figure class="wp-block-image size-full"><img decoding="async" width="779" height="545" src="https://lycos7560.com/wp-content/uploads/2024/11/image-39.png" alt="" class="wp-image-38691" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-39.png 779w, https://lycos7560.com/wp-content/uploads/2024/11/image-39-300x210.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-39-768x537.png 768w" sizes="(max-width: 779px) 100vw, 779px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.33%">
<figure class="wp-block-image size-full"><img decoding="async" width="764" height="523" src="https://lycos7560.com/wp-content/uploads/2024/11/image-40.png" alt="" class="wp-image-38692" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-40.png 764w, https://lycos7560.com/wp-content/uploads/2024/11/image-40-300x205.png 300w" sizes="(max-width: 764px) 100vw, 764px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50.01%">
<figure class="wp-block-image size-full"><img decoding="async" width="785" height="547" src="https://lycos7560.com/wp-content/uploads/2024/11/image-41.png" alt="" class="wp-image-38693" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-41.png 785w, https://lycos7560.com/wp-content/uploads/2024/11/image-41-300x209.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-41-768x535.png 768w" sizes="(max-width: 785px) 100vw, 785px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:49.99%">
<figure class="wp-block-image size-full"><img decoding="async" width="1133" height="772" src="https://lycos7560.com/wp-content/uploads/2024/11/image-42.png" alt="" class="wp-image-38694" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-42.png 1133w, https://lycos7560.com/wp-content/uploads/2024/11/image-42-300x204.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-42-768x523.png 768w" sizes="(max-width: 1133px) 100vw, 1133px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1074" height="288" src="https://lycos7560.com/wp-content/uploads/2024/11/image-43.png" alt="" class="wp-image-38695" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-43.png 1074w, https://lycos7560.com/wp-content/uploads/2024/11/image-43-300x80.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-43-768x206.png 768w" sizes="(max-width: 1074px) 100vw, 1074px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="786" height="549" src="https://lycos7560.com/wp-content/uploads/2024/11/image-44.png" alt="" class="wp-image-38697" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-44.png 786w, https://lycos7560.com/wp-content/uploads/2024/11/image-44-300x210.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-44-768x536.png 768w" sizes="(max-width: 786px) 100vw, 786px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="777" height="540" src="https://lycos7560.com/wp-content/uploads/2024/11/image-45.png" alt="" class="wp-image-38698" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-45.png 777w, https://lycos7560.com/wp-content/uploads/2024/11/image-45-300x208.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-45-768x534.png 768w" sizes="(max-width: 777px) 100vw, 777px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="775" height="543" src="https://lycos7560.com/wp-content/uploads/2024/11/image-46.png" alt="" class="wp-image-38699" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-46.png 775w, https://lycos7560.com/wp-content/uploads/2024/11/image-46-300x210.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-46-768x538.png 768w" sizes="(max-width: 775px) 100vw, 775px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="788" height="564" src="https://lycos7560.com/wp-content/uploads/2024/11/image-47.png" alt="" class="wp-image-38700" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-47.png 788w, https://lycos7560.com/wp-content/uploads/2024/11/image-47-300x215.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-47-768x550.png 768w" sizes="(max-width: 788px) 100vw, 788px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1059" height="338" src="https://lycos7560.com/wp-content/uploads/2024/11/image-48.png" alt="" class="wp-image-38701" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-48.png 1059w, https://lycos7560.com/wp-content/uploads/2024/11/image-48-300x96.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-48-768x245.png 768w" sizes="(max-width: 1059px) 100vw, 1059px" /><figcaption class="wp-element-caption">위와 같은 작업 반복</figcaption></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="858" height="260" src="https://lycos7560.com/wp-content/uploads/2024/11/image-49.png" alt="" class="wp-image-38702" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-49.png 858w, https://lycos7560.com/wp-content/uploads/2024/11/image-49-300x91.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-49-768x233.png 768w" sizes="(max-width: 858px) 100vw, 858px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1117" height="772" src="https://lycos7560.com/wp-content/uploads/2024/11/image-54.png" alt="" class="wp-image-38708" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-54.png 1117w, https://lycos7560.com/wp-content/uploads/2024/11/image-54-300x207.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-54-768x531.png 768w" sizes="(max-width: 1117px) 100vw, 1117px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1151" height="377" src="https://lycos7560.com/wp-content/uploads/2024/11/image-53.png" alt="" class="wp-image-38711" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-53.png 1151w, https://lycos7560.com/wp-content/uploads/2024/11/image-53-300x98.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-53-768x252.png 768w" sizes="(max-width: 1151px) 100vw, 1151px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="686" height="544" src="https://lycos7560.com/wp-content/uploads/2024/11/image-55.png" alt="" class="wp-image-38712" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-55.png 686w, https://lycos7560.com/wp-content/uploads/2024/11/image-55-300x238.png 300w" sizes="(max-width: 686px) 100vw, 686px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1170" height="123" src="https://lycos7560.com/wp-content/uploads/2024/11/image-50.png" alt="" class="wp-image-38703" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-50.png 1170w, https://lycos7560.com/wp-content/uploads/2024/11/image-50-300x32.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-50-768x81.png 768w" sizes="(max-width: 1170px) 100vw, 1170px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1046" height="319" src="https://lycos7560.com/wp-content/uploads/2024/11/image-56.png" alt="" class="wp-image-38713" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-56.png 1046w, https://lycos7560.com/wp-content/uploads/2024/11/image-56-300x91.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-56-768x234.png 768w" sizes="(max-width: 1046px) 100vw, 1046px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.34%">
<figure class="wp-block-image size-full"><img decoding="async" width="687" height="537" src="https://lycos7560.com/wp-content/uploads/2024/11/image-57.png" alt="" class="wp-image-38714" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-57.png 687w, https://lycos7560.com/wp-content/uploads/2024/11/image-57-300x234.png 300w" sizes="(max-width: 687px) 100vw, 687px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.33%">
<figure class="wp-block-image size-full"><img decoding="async" width="319" height="342" src="https://lycos7560.com/wp-content/uploads/2024/11/image-65.png" alt="" class="wp-image-38722" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-65.png 319w, https://lycos7560.com/wp-content/uploads/2024/11/image-65-280x300.png 280w" sizes="(max-width: 319px) 100vw, 319px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.34%">
<figure class="wp-block-image size-full"><img decoding="async" width="1091" height="731" src="https://lycos7560.com/wp-content/uploads/2024/11/image-58.png" alt="" class="wp-image-38715" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-58.png 1091w, https://lycos7560.com/wp-content/uploads/2024/11/image-58-300x201.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-58-768x515.png 768w" sizes="(max-width: 1091px) 100vw, 1091px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="672" height="599" src="https://lycos7560.com/wp-content/uploads/2024/11/image-59.png" alt="" class="wp-image-38716" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-59.png 672w, https://lycos7560.com/wp-content/uploads/2024/11/image-59-300x267.png 300w" sizes="(max-width: 672px) 100vw, 672px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1066" height="750" src="https://lycos7560.com/wp-content/uploads/2024/11/image-60.png" alt="" class="wp-image-38717" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-60.png 1066w, https://lycos7560.com/wp-content/uploads/2024/11/image-60-300x211.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-60-768x540.png 768w" sizes="(max-width: 1066px) 100vw, 1066px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="304" height="432" src="https://lycos7560.com/wp-content/uploads/2024/11/image-61.png" alt="" class="wp-image-38718" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-61.png 304w, https://lycos7560.com/wp-content/uploads/2024/11/image-61-211x300.png 211w" sizes="(max-width: 304px) 100vw, 304px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="528" height="628" src="https://lycos7560.com/wp-content/uploads/2024/11/image-62.png" alt="" class="wp-image-38719" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-62.png 528w, https://lycos7560.com/wp-content/uploads/2024/11/image-62-252x300.png 252w" sizes="(max-width: 528px) 100vw, 528px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1034" height="568" src="https://lycos7560.com/wp-content/uploads/2024/11/image-63.png" alt="" class="wp-image-38720" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-63.png 1034w, https://lycos7560.com/wp-content/uploads/2024/11/image-63-300x165.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-63-768x422.png 768w" sizes="(max-width: 1034px) 100vw, 1034px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1005" height="434" src="https://lycos7560.com/wp-content/uploads/2024/11/image-64.png" alt="" class="wp-image-38721" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-64.png 1005w, https://lycos7560.com/wp-content/uploads/2024/11/image-64-300x130.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-64-768x332.png 768w" sizes="(max-width: 1005px) 100vw, 1005px" /></figure>
</div>
</div>



<figure class="wp-block-image size-full"><img decoding="async" width="1593" height="225" src="https://lycos7560.com/wp-content/uploads/2024/11/image-66.png" alt="" class="wp-image-38723" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-66.png 1593w, https://lycos7560.com/wp-content/uploads/2024/11/image-66-300x42.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-66-768x108.png 768w, https://lycos7560.com/wp-content/uploads/2024/11/image-66-1536x217.png 1536w" sizes="(max-width: 1593px) 100vw, 1593px" /></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1359" height="598" src="https://lycos7560.com/wp-content/uploads/2024/11/image-67.png" alt="" class="wp-image-38724" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-67.png 1359w, https://lycos7560.com/wp-content/uploads/2024/11/image-67-300x132.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-67-768x338.png 768w" sizes="(max-width: 1359px) 100vw, 1359px" /></figure>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="940" height="534" src="https://lycos7560.com/wp-content/uploads/2024/11/image-68.png" alt="" class="wp-image-38725" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-68.png 940w, https://lycos7560.com/wp-content/uploads/2024/11/image-68-300x170.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-68-768x436.png 768w" sizes="(max-width: 940px) 100vw, 940px" /><figcaption class="wp-element-caption">계정 생성</figcaption></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1435" height="379" src="https://lycos7560.com/wp-content/uploads/2024/11/image-69.png" alt="" class="wp-image-38726" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-69.png 1435w, https://lycos7560.com/wp-content/uploads/2024/11/image-69-300x79.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-69-768x203.png 768w" sizes="(max-width: 1435px) 100vw, 1435px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-full"><img decoding="async" width="927" height="637" data-id="38727" src="https://lycos7560.com/wp-content/uploads/2024/11/image-70.png" alt="" class="wp-image-38727" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-70.png 927w, https://lycos7560.com/wp-content/uploads/2024/11/image-70-300x206.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-70-768x528.png 768w" sizes="(max-width: 927px) 100vw, 927px" /></figure>
</figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="939" height="447" src="https://lycos7560.com/wp-content/uploads/2024/11/image-71.png" alt="" class="wp-image-38728" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-71.png 939w, https://lycos7560.com/wp-content/uploads/2024/11/image-71-300x143.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-71-768x366.png 768w" sizes="(max-width: 939px) 100vw, 939px" /></figure>
</div>
</div>



<figure class="wp-block-image size-full"><img decoding="async" width="942" height="762" src="https://lycos7560.com/wp-content/uploads/2024/11/image-72.png" alt="" class="wp-image-38729" srcset="https://lycos7560.com/wp-content/uploads/2024/11/image-72.png 942w, https://lycos7560.com/wp-content/uploads/2024/11/image-72-300x243.png 300w, https://lycos7560.com/wp-content/uploads/2024/11/image-72-768x621.png 768w" sizes="(max-width: 942px) 100vw, 942px" /></figure>
<p>The post <a href="https://lycos7560.com/c/deploying-asp-net-web-api-to-azure/38646/">Deploying ASP.NET Web API To Azure</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/c/deploying-asp-net-web-api-to-azure/38646/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Consuming REST Web APIs</title>
		<link>https://lycos7560.com/c/consuming-rest-web-apis/38585/</link>
					<comments>https://lycos7560.com/c/consuming-rest-web-apis/38585/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Thu, 31 Oct 2024 09:56:32 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[.Net Core]]></category>
		<category><![CDATA[AddModelError]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[ASP.NET Core]]></category>
		<category><![CDATA[Consuming]]></category>
		<category><![CDATA[Controller]]></category>
		<category><![CDATA[Create]]></category>
		<category><![CDATA[Data]]></category>
		<category><![CDATA[Data access logic]]></category>
		<category><![CDATA[DataBase]]></category>
		<category><![CDATA[DbContext]]></category>
		<category><![CDATA[DbSet]]></category>
		<category><![CDATA[DELETE]]></category>
		<category><![CDATA[Domain]]></category>
		<category><![CDATA[Domain Model]]></category>
		<category><![CDATA[File]]></category>
		<category><![CDATA[FileDescription]]></category>
		<category><![CDATA[Filestream]]></category>
		<category><![CDATA[GET]]></category>
		<category><![CDATA[IFormFile]]></category>
		<category><![CDATA[Image]]></category>
		<category><![CDATA[Image Controller]]></category>
		<category><![CDATA[IsValid]]></category>
		<category><![CDATA[Migration]]></category>
		<category><![CDATA[Model]]></category>
		<category><![CDATA[ModelState]]></category>
		<category><![CDATA[pepe]]></category>
		<category><![CDATA[POST]]></category>
		<category><![CDATA[program]]></category>
		<category><![CDATA[Program.cs]]></category>
		<category><![CDATA[PUT]]></category>
		<category><![CDATA[Repository]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[REST Web API]]></category>
		<category><![CDATA[study]]></category>
		<category><![CDATA[Upload]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[web API]]></category>
		<category><![CDATA[wpf]]></category>
		<category><![CDATA[기초]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=38585</guid>

					<description><![CDATA[<p>Consuming REST Web APIs 1. 프로젝트 생성(MVC UI) ASP.Net Core Web App (MVC) 2. GET Controller 생성 HttpClient 적용 .Net에서 제공하는 HttpClient Class https://learn.microsoft.com/ko-kr/dotnet/api/system.net.http.httpclient?view=net-8.0 HTTP 요청을 보내고 URI로 식별된 리소스에서 HTTP 응답을 수신하기 위한 클래스를 제공합니다. 사용 예제 HttpClient를 사용하려면, Program.cs 파일에 HttpClient Factory를 설정 이를 통해 효율적으로 HttpClient 인스턴스를 관리하고, 특히 성능 문제를 해결할 [&#8230;]</p>
<p>The post <a href="https://lycos7560.com/c/consuming-rest-web-apis/38585/">Consuming REST Web APIs</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">Consuming REST Web APIs</h2>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>


				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-b7f87031      "
					data-scroll= "1"
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							목차						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#consuming-rest-web-apis" class="uagb-toc-link__trigger">Consuming REST Web APIs</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-프로젝트-생성mvc-ui" class="uagb-toc-link__trigger">1. 프로젝트 생성(MVC UI)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#2-get-controller-생성" class="uagb-toc-link__trigger">2. GET Controller 생성</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#httpclient-적용" class="uagb-toc-link__trigger">HttpClient 적용</a></li></ul><li class="uagb-toc__list"><a href="#3-indexcshtml-layoutcshtml-생성-및-수정" class="uagb-toc-link__trigger">3. Index.cshtml , _Layout.cshtml 생성 및 수정</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#4-regiondtocs-생성-및-indexcshtml-적용" class="uagb-toc-link__trigger">4. RegionDto.cs 생성 및 Index.cshtml 적용</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#5-post-method-생성" class="uagb-toc-link__trigger">5. POST Method 생성</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#6-단일-편집-기능" class="uagb-toc-link__trigger">6. 단일 편집 기능</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#7-삭제-기능" class="uagb-toc-link__trigger">7. 삭제 기능</a></ul></ol>					</div>
									</div>
				</div>
			


<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">1. 프로젝트 생성(MVC UI)</h3>



<p class="wp-block-paragraph">ASP.Net Core Web App (MVC)</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="807" height="611" src="https://lycos7560.com/wp-content/uploads/2024/10/image-154.png" alt="" class="wp-image-38586" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-154.png 807w, https://lycos7560.com/wp-content/uploads/2024/10/image-154-300x227.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-154-768x581.png 768w" sizes="(max-width: 807px) 100vw, 807px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1005" height="626" src="https://lycos7560.com/wp-content/uploads/2024/10/image-155.png" alt="" class="wp-image-38587" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-155.png 1005w, https://lycos7560.com/wp-content/uploads/2024/10/image-155-300x187.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-155-768x478.png 768w" sizes="(max-width: 1005px) 100vw, 1005px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1207" height="800" src="https://lycos7560.com/wp-content/uploads/2024/10/image-156.png" alt="" class="wp-image-38588" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-156.png 1207w, https://lycos7560.com/wp-content/uploads/2024/10/image-156-300x199.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-156-768x509.png 768w" sizes="(max-width: 1207px) 100vw, 1207px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="957" height="805" src="https://lycos7560.com/wp-content/uploads/2024/10/image-157.png" alt="" class="wp-image-38589" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-157.png 957w, https://lycos7560.com/wp-content/uploads/2024/10/image-157-300x252.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-157-768x646.png 768w" sizes="(max-width: 957px) 100vw, 957px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="787" height="539" src="https://lycos7560.com/wp-content/uploads/2024/10/image-158.png" alt="" class="wp-image-38590" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-158.png 787w, https://lycos7560.com/wp-content/uploads/2024/10/image-158-300x205.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-158-768x526.png 768w" sizes="(max-width: 787px) 100vw, 787px" /><figcaption class="wp-element-caption">여러 개의 시작 프로젝트로 변경</figcaption></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1905" height="1023" src="https://lycos7560.com/wp-content/uploads/2024/10/image-159.png" alt="" class="wp-image-38591" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-159.png 1905w, https://lycos7560.com/wp-content/uploads/2024/10/image-159-300x161.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-159-768x412.png 768w, https://lycos7560.com/wp-content/uploads/2024/10/image-159-1536x825.png 1536w" sizes="(max-width: 1905px) 100vw, 1905px" /><figcaption class="wp-element-caption">MVC UI와 API(Swagger)</figcaption></figure>
</div>
</div>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">2. GET Controller 생성</h3>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1286" height="394" src="https://lycos7560.com/wp-content/uploads/2024/10/image-160.png" alt="" class="wp-image-38592" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-160.png 1286w, https://lycos7560.com/wp-content/uploads/2024/10/image-160-300x92.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-160-768x235.png 768w" sizes="(max-width: 1286px) 100vw, 1286px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="935" height="406" src="https://lycos7560.com/wp-content/uploads/2024/10/image-161.png" alt="" class="wp-image-38593" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-161.png 935w, https://lycos7560.com/wp-content/uploads/2024/10/image-161-300x130.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-161-768x333.png 768w" sizes="(max-width: 935px) 100vw, 935px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="992" height="431" src="https://lycos7560.com/wp-content/uploads/2024/10/image-162.png" alt="" class="wp-image-38594" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-162.png 992w, https://lycos7560.com/wp-content/uploads/2024/10/image-162-300x130.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-162-768x334.png 768w" sizes="(max-width: 992px) 100vw, 992px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1251" height="440" src="https://lycos7560.com/wp-content/uploads/2024/10/image-171.png" alt="" class="wp-image-38603" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-171.png 1251w, https://lycos7560.com/wp-content/uploads/2024/10/image-171-300x106.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-171-768x270.png 768w" sizes="(max-width: 1251px) 100vw, 1251px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="737" height="619" src="https://lycos7560.com/wp-content/uploads/2024/10/image-172.png" alt="" class="wp-image-38604" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-172.png 737w, https://lycos7560.com/wp-content/uploads/2024/10/image-172-300x252.png 300w" sizes="(max-width: 737px) 100vw, 737px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1032" height="440" src="https://lycos7560.com/wp-content/uploads/2024/10/image-177.png" alt="" class="wp-image-38609" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-177.png 1032w, https://lycos7560.com/wp-content/uploads/2024/10/image-177-300x128.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-177-768x327.png 768w" sizes="(max-width: 1032px) 100vw, 1032px" /></figure>
</div>
</div>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading">HttpClient 적용</h4>



<p class="wp-block-paragraph">.Net에서 제공하는 <strong>HttpClient Class</strong></p>



<p class="wp-block-paragraph"><a href="https://learn.microsoft.com/ko-kr/dotnet/api/system.net.http.httpclient?view=net-8.0" target="_blank" rel="noreferrer noopener">https://learn.microsoft.com/ko-kr/dotnet/api/system.net.http.httpclient?view=net-8.0</a></p>



<p class="wp-block-paragraph">HTTP 요청을 보내고 URI로 식별된 리소스에서 HTTP 응답을 수신하기 위한 클래스를 제공합니다.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">public class HttpClient : System.Net.Http.HttpMessageInvoker</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph"><strong>사용 예제</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// HttpClient는 매번 사용될 때마다 인스턴스화되지 않고, 애플리케이션 전체에서 한 번만 인스턴스화되어야 합니다. 참고 사항을 참조하세요.
static readonly HttpClient client = new HttpClient();

static async Task Main()
{
    // 비동기 네트워크 메서드를 try/catch 블록 내에서 호출하여 예외를 처리합니다.
    try
    {
        // 비동기적으로 GET 요청을 보냅니다.
        using HttpResponseMessage response = await client.GetAsync("http://www.contoso.com/");
        
        // 요청이 성공적으로 완료되었는지 확인합니다.
        response.EnsureSuccessStatusCode();
        
        // 응답 본문을 문자열로 읽어옵니다.
        string responseBody = await response.Content.ReadAsStringAsync();
        
        // 위의 세 줄은 아래 새로운 헬퍼 메서드로 대체할 수 있습니다.
        // string responseBody = await client.GetStringAsync(uri);
        
        // 응답 본문을 콘솔에 출력합니다.
        Console.WriteLine(responseBody);
    }
    catch (HttpRequestException e)
    {
        // 예외가 발생했을 때 예외 메시지를 콘솔에 출력합니다.
        Console.WriteLine("\nException Caught!");
        Console.WriteLine("Message :{0} ", e.Message);
    }
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph"><a href="https://learn.microsoft.com/ko-kr/dotnet/api/system.net.http.httpclient?view=net-8.0#remarks"></a></p>



<p class="wp-block-paragraph">HttpClient를 사용하려면, Program.cs 파일에 HttpClient Factory를 설정</p>



<p class="wp-block-paragraph">이를 통해 효율적으로 <strong>HttpClient 인스턴스를 관리하고, 특히 성능 문제를 해결</strong>할 수 있음</p>



<p class="wp-block-paragraph">Program.cs</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();

// HttpClient 삽입
builder.Services.AddHttpClient();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="920" height="469" src="https://lycos7560.com/wp-content/uploads/2024/10/image-178.png" alt="" class="wp-image-38610" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-178.png 920w, https://lycos7560.com/wp-content/uploads/2024/10/image-178-300x153.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-178-768x392.png 768w" sizes="(max-width: 920px) 100vw, 920px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1077" height="459" src="https://lycos7560.com/wp-content/uploads/2024/10/image-179.png" alt="" class="wp-image-38611" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-179.png 1077w, https://lycos7560.com/wp-content/uploads/2024/10/image-179-300x128.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-179-768x327.png 768w" sizes="(max-width: 1077px) 100vw, 1077px" /><figcaption class="wp-element-caption">NZWalks.API의 launchSettings.json</figcaption></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1306" height="778" src="https://lycos7560.com/wp-content/uploads/2024/10/image-180.png" alt="" class="wp-image-38612" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-180.png 1306w, https://lycos7560.com/wp-content/uploads/2024/10/image-180-300x179.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-180-768x458.png 768w" sizes="(max-width: 1306px) 100vw, 1306px" /><figcaption class="wp-element-caption">RegionsController의 GetAll Api를 사용</figcaption></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="907" height="668" src="https://lycos7560.com/wp-content/uploads/2024/10/image-181.png" alt="" class="wp-image-38613" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-181.png 907w, https://lycos7560.com/wp-content/uploads/2024/10/image-181-300x221.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-181-768x566.png 768w" sizes="(max-width: 907px) 100vw, 907px" /><figcaption class="wp-element-caption">테스트를 위해서 인증 주석</figcaption></figure>
</div>
</div>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph"><strong>RegionsController.cs 수정</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using Microsoft.AspNetCore.Mvc;

namespace NZWalksUI.Controllers
{
    public class RegionsController : Controller
    {
        private readonly IHttpClientFactory httpClientFactory;

        // Http 클라이언트 팩토리를 삽입하기 위한 생성자를 생성
        public RegionsController(IHttpClientFactory httpClientFactory)
        {
            this.httpClientFactory = httpClientFactory;
        }

        // Index 액션 메서드
        public async Task&lt;IActionResult> Index()
        {
            try
            {
                // Get All Regions From Web API
                // 새로운 Http 클라이언트가 생성
                var client = httpClientFactory.CreateClient();
                
                // Web API로 GET 요청을 보냄
                var httpResponseMessage = await client.GetAsync("https://localhost:7256/api/regions");
                
                // 요청이 성공적으로 완료되었는지 확인
                httpResponseMessage.EnsureSuccessStatusCode();
                
                // 응답 본문을 문자열로 읽어옴
                var stringResponse = await httpResponseMessage.Content.ReadAsStringAsync();
                
                // 응답 내용을 ViewBag에 저장
                ViewBag.Response = stringResponse;
                
                // 응답 메시지를 반환
                return Ok(httpResponseMessage);
            }
            catch (Exception ex)
            {
                // 예외를 로깅 (로그 기록)
            }
            
            // View를 반환
            return View();
        }
    }
}
</pre>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">3. Index.cshtml , <strong>_Layout.cshtml </strong>생성 및 수정 </h3>



<p class="wp-block-paragraph"><strong>Index.cshtml</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="html" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@*
    For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
*@
@{
}

&lt;h1 class="mt-3">Regions&lt;/h1>

@if (ViewBag.Respose is not null)
{
    &lt;p>ViewBag.Respose&lt;/p>
}</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph"><strong>_Layout.cshtml</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="html" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;!DOCTYPE html>
&lt;html lang="en">
&lt;head>
    &lt;meta charset="utf-8" />
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" />
    &lt;title>@ViewData["Title"] - NZWalksUI&lt;/title>
    &lt;link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    &lt;link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
    &lt;link rel="stylesheet" href="~/NZWalksUI.styles.css" asp-append-version="true" />
&lt;/head>
&lt;body>
    &lt;header>
        &lt;nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            &lt;div class="container-fluid">
                &lt;a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">NZWalksUI&lt;/a>
                &lt;button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    &lt;span class="navbar-toggler-icon">&lt;/span>
                &lt;/button>
                &lt;div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                    &lt;ul class="navbar-nav flex-grow-1">
                        &lt;li class="nav-item">
                            &lt;a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home&lt;/a>
                        &lt;/li>
                        &lt;li class="nav-item">
                            &lt;a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy&lt;/a>
                        &lt;/li>
                        &lt;li class="nav-item">
                            &lt;a class="nav-link text-dark" asp-area="" asp-controller="Regions" asp-action="Index">Regions&lt;/a>
                        &lt;/li>
                    &lt;/ul>
                &lt;/div>
            &lt;/div>
        &lt;/nav>
    &lt;/header>
    &lt;div class="container">
        &lt;main role="main" class="pb-3">
            @RenderBody()
        &lt;/main>
    &lt;/div>

    &lt;footer class="border-top footer text-muted">
        &lt;div class="container">
            &amp;copy; 2024 - NZWalksUI - &lt;a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy&lt;/a>
        &lt;/div>
    &lt;/footer>
    &lt;script src="~/lib/jquery/dist/jquery.min.js">&lt;/script>
    &lt;script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js">&lt;/script>
    &lt;script src="~/js/site.js" asp-append-version="true">&lt;/script>
    @await RenderSectionAsync("Scripts", required: false)
&lt;/body>
&lt;/html>
</pre>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1261" height="380" src="https://lycos7560.com/wp-content/uploads/2024/10/image-184.png" alt="" class="wp-image-38616" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-184.png 1261w, https://lycos7560.com/wp-content/uploads/2024/10/image-184-300x90.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-184-768x231.png 768w" sizes="(max-width: 1261px) 100vw, 1261px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1553" height="518" src="https://lycos7560.com/wp-content/uploads/2024/10/image-182.png" alt="" class="wp-image-38617" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-182.png 1553w, https://lycos7560.com/wp-content/uploads/2024/10/image-182-300x100.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-182-768x256.png 768w, https://lycos7560.com/wp-content/uploads/2024/10/image-182-1536x512.png 1536w" sizes="(max-width: 1553px) 100vw, 1553px" /><figcaption class="wp-element-caption">폴더 이름 수정</figcaption></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1308" height="556" src="https://lycos7560.com/wp-content/uploads/2024/10/image-183.png" alt="" class="wp-image-38618" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-183.png 1308w, https://lycos7560.com/wp-content/uploads/2024/10/image-183-300x128.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-183-768x326.png 768w" sizes="(max-width: 1308px) 100vw, 1308px" /><figcaption class="wp-element-caption">break point</figcaption></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1381" height="600" src="https://lycos7560.com/wp-content/uploads/2024/10/image-186.png" alt="" class="wp-image-38620" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-186.png 1381w, https://lycos7560.com/wp-content/uploads/2024/10/image-186-300x130.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-186-768x334.png 768w" sizes="(max-width: 1381px) 100vw, 1381px" /><figcaption class="wp-element-caption">API 적용 확인</figcaption></figure>
</div>
</div>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">4. RegionDto.cs 생성 및 Index.cshtml 적용</h3>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph"><strong>RegionDto.cs</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">namespace NZWalksUI.Models.DTO
{
    public class RegionDto
    {
        public Guid Id { get; set; }
        public string Code { get; set; }
        public string Name { get; set; }
        public string? RegionImageUrl { get; set; } // Nullable
    }
}</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph"><strong>Index.cshtml </strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="html" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@model IEnumerable&lt;NZWalksUI.Models.DTO.RegionDto> &lt;!-- 뷰 모델을 IEnumerable&lt;RegionDto>로 설정 -->

@* MVC를 빈 프로젝트에 대해 활성화하는 방법에 대한 추가 정보는 https://go.microsoft.com/fwlink/?LinkID=397860를 참조 *@

@{} &lt;!-- 블록 코드, 현재 비어 있음 -->

&lt;h1 class="mt-3">Regions&lt;/h1> &lt;!-- 페이지 제목 -->

&lt;table>
    &lt;thead>
        &lt;tr>
            &lt;th>Id&lt;/th> &lt;!-- Id 열 -->
            &lt;th>Code&lt;/th> &lt;!-- Code 열 -->
            &lt;th>Name&lt;/th> &lt;!-- Name 열 -->
        &lt;/tr>
    &lt;/thead>
    &lt;tbody>
        @foreach (var walk in Model) &lt;!-- Model을 반복하여 각 walk에 대해 테이블 행 생성 -->
        {
            &lt;tr>
                &lt;th>@walk.Id&lt;/th> &lt;!-- 현재 walk의 Id 표시 -->
                &lt;th>@walk.Code&lt;/th> &lt;!-- 현재 walk의 Code 표시 -->
                &lt;th>@walk.Name&lt;/th> &lt;!-- 현재 walk의 Name 표시 -->
            &lt;/tr>
        }
    &lt;/tbody>
&lt;/table>
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1188" height="696" src="https://lycos7560.com/wp-content/uploads/2024/10/image-187.png" alt="" class="wp-image-38621" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-187.png 1188w, https://lycos7560.com/wp-content/uploads/2024/10/image-187-300x176.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-187-768x450.png 768w" sizes="(max-width: 1188px) 100vw, 1188px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1360" height="575" src="https://lycos7560.com/wp-content/uploads/2024/10/image-188.png" alt="" class="wp-image-38622" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-188.png 1360w, https://lycos7560.com/wp-content/uploads/2024/10/image-188-300x127.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-188-768x325.png 768w" sizes="(max-width: 1360px) 100vw, 1360px" /></figure>
</div>
</div>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">5. POST Method 생성 </h3>



<p class="wp-block-paragraph"><strong>Index.cshtml 수정</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="html" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@model IEnumerable&lt;NZWalksUI.Models.DTO.RegionDto>
@*
    For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
*@
@{
}

&lt;h1 class="mt-3">Regions&lt;/h1>

&lt;div class="d-flex justify-content-end">
    &lt;a class="btn btn-secondary" asp-controller="Regions" asp-action="Add">Add Region&lt;/a>
&lt;/div>


&lt;table class="table-bordered">
    &lt;thead>
        &lt;tr>
            &lt;th>Id&lt;/th>
            &lt;th>Code&lt;/th>
            &lt;th>Name&lt;/th>
        &lt;/tr>
    &lt;/thead>
    &lt;tbody>
        @foreach (var walk in Model)
        {
            &lt;tr>
                &lt;td>@walk.Id&lt;/td>
                &lt;td>@walk.Code&lt;/td>
                &lt;td>@walk.Name&lt;/td>
            &lt;/tr>
        }
    &lt;/tbody>
&lt;/table></pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph"><strong>AddRegionViewModel.cs 생성</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">namespace NZWalksUI.Models
{
    public class AddRegionViewModel
    {
        public string Code { get; set; }
        public string Name { get; set; }
        public string RegionImageUrl { get; set; }
    }
}
</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph"><strong>RegionsController.cs 수정</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using Microsoft.AspNetCore.Mvc;
using NZWalksUI.Models;
using NZWalksUI.Models.DTO;
using System.Net.Http;
using System.Text;
using System.Text.Json;

namespace NZWalksUI.Controllers
{
    public class RegionsController : Controller
    {
        private readonly IHttpClientFactory httpClientFactory;

        // Http 클라이언트 팩토리를 삽입하기 위한 생성자를 생성
        public RegionsController(IHttpClientFactory httpClientFactory)
        {
            this.httpClientFactory = httpClientFactory;
        }

        [HttpGet]
        // Index 액션 메서드
        public async Task&lt;IActionResult> Index()
        {
            List&lt;RegionDto> response = new List&lt;RegionDto>();
            try
            {
                // Get All Regions From Web API
                // 새로운 Http 클라이언트가 생성
                var client = httpClientFactory.CreateClient();

                // Web API로 GET 요청을 보냄
                var httpResponseMessage = await client.GetAsync("https://localhost:7256/api/regions");

                // 요청이 성공적으로 완료되었는지 확인
                httpResponseMessage.EnsureSuccessStatusCode();

                // 응답 본문을 JSON으로 읽어와 리스트에 추가
                response.AddRange(await httpResponseMessage.Content.ReadFromJsonAsync&lt;IEnumerable&lt;RegionDto>>());
            }
            catch (HttpRequestException e)
            {
                // 예외 발생 시 예외 메시지를 로그로 기록
                Console.WriteLine($"Request error: {e.Message}");
            }
            catch (Exception ex)
            {
                // 기타 예외 발생 시 예외 메시지를 로그로 기록
                Console.WriteLine($"An error occurred: {ex.Message}");
            }

            // View를 반환
            return View(response);
        }

        [HttpGet]
        public IActionResult Add()
        {
            return View(); // Add View 반환
        }

        [HttpPost]
        public async Task&lt;IActionResult> Add(AddRegionViewModel model)
        {
            var client = httpClientFactory.CreateClient();

            var httpRequestMessage = new HttpRequestMessage()
            {
                Method = HttpMethod.Post,
                RequestUri = new Uri("https://localhost:7256/api/regions"),
                Content = new StringContent(JsonSerializer.Serialize(model), Encoding.UTF8, "application/json") // JSON 요청 본문 설정
            };

            var httpResponseMessage = await client.SendAsync(httpRequestMessage);
            httpResponseMessage.EnsureSuccessStatusCode(); // 요청이 성공적으로 완료되었는지 확인

            var response = await httpResponseMessage.Content.ReadFromJsonAsync&lt;RegionDto>();

            if (response is not null)
            {
                return RedirectToAction("Index", "Regions"); // Index 액션으로 리디렉션
            }

            return View(); // View 반환
        }
    }
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="553" height="334" src="https://lycos7560.com/wp-content/uploads/2024/10/image-193.png" alt="" class="wp-image-38627" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-193.png 553w, https://lycos7560.com/wp-content/uploads/2024/10/image-193-300x181.png 300w" sizes="(max-width: 553px) 100vw, 553px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<p class="wp-block-paragraph"><strong>Add.cshtml</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="css" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@model NZWalksUI.Models.AddRegionViewModel;

@*
*@

@{
}

&lt;h1 class="mt-3">Add Region&lt;/h1>

&lt;form method="post">

    &lt;div class="mt-3">
        &lt;label class="form-label">Code&lt;/label>
        &lt;input type="text" class="form-control" asp-for="Code" />
    &lt;/div>

    &lt;div class="mt-3">
        &lt;label class="form-label">Name&lt;/label>
        &lt;input type="text" class="form-control" asp-for="Name" />
    &lt;/div>

    &lt;div class="mt-3">
        &lt;label class="form-label">Image URL&lt;/label>
        &lt;input type="text" class="form-control" asp-for="RegionImageUrl" />
    &lt;/div>

    &lt;div class="mt-3">
        &lt;button type="submit" class="btn btn-primary">Save&lt;/button>
    &lt;/div>

&lt;/form></pre>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="831" height="346" src="https://lycos7560.com/wp-content/uploads/2024/10/image-194.png" alt="" class="wp-image-38628" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-194.png 831w, https://lycos7560.com/wp-content/uploads/2024/10/image-194-300x125.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-194-768x320.png 768w" sizes="(max-width: 831px) 100vw, 831px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1175" height="462" src="https://lycos7560.com/wp-content/uploads/2024/10/image-195.png" alt="" class="wp-image-38630" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-195.png 1175w, https://lycos7560.com/wp-content/uploads/2024/10/image-195-300x118.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-195-768x302.png 768w" sizes="(max-width: 1175px) 100vw, 1175px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1013" height="436" src="https://lycos7560.com/wp-content/uploads/2024/10/image-196.png" alt="" class="wp-image-38631" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-196.png 1013w, https://lycos7560.com/wp-content/uploads/2024/10/image-196-300x129.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-196-768x331.png 768w" sizes="(max-width: 1013px) 100vw, 1013px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="903" height="407" src="https://lycos7560.com/wp-content/uploads/2024/10/image-197.png" alt="" class="wp-image-38632" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-197.png 903w, https://lycos7560.com/wp-content/uploads/2024/10/image-197-300x135.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-197-768x346.png 768w" sizes="(max-width: 903px) 100vw, 903px" /></figure>
</div>
</div>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">6. 단일 편집 기능</h3>



<p class="wp-block-paragraph"><strong>RegionsController.cs 수정</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using Microsoft.AspNetCore.Mvc;
using NZWalksUI.Models;
using NZWalksUI.Models.DTO;
using System.Net.Http;
using System.Text;
using System.Text.Json;

namespace NZWalksUI.Controllers
{
    public class RegionsController : Controller
    {
        private readonly IHttpClientFactory httpClientFactory;

        // Http 클라이언트 팩토리를 삽입하기 위한 생성자를 생성
        public RegionsController(IHttpClientFactory httpClientFactory)
        {
            this.httpClientFactory = httpClientFactory;
        }

        [HttpGet]
        // Index 액션 메서드
        public async Task&lt;IActionResult> Index()
        {
            List&lt;RegionDto> response = new List&lt;RegionDto>();


            try
            {
                // Get All Regions From Web API
                // 새로운 Http 클라이언트가 생성
                var client = httpClientFactory.CreateClient();

                // Web API로 GET 요청을 보냄
                var httpResponseMessage = await client.GetAsync("https://localhost:7256/api/regions");
               

                // 요청이 성공적으로 완료되었는지 확인
                httpResponseMessage.EnsureSuccessStatusCode();

                // // 응답 본문을 문자열로 읽어옴
                // var stringResponse = await httpResponseMessage.Content.ReadAsStringAsync();


                response.AddRange(await httpResponseMessage.Content.ReadFromJsonAsync&lt;IEnumerable&lt;RegionDto>>());

            }
            catch (HttpRequestException e)
            {
                // 예외 발생 시 예외 메시지를 로그로 기록
                Console.WriteLine($"Request error: {e.Message}");
            }
            catch (Exception ex)
            {
                // 기타 예외 발생 시 예외 메시지를 로그로 기록
                Console.WriteLine($"An error occurred: {ex.Message}");
            }

            // View를 반환
            return View(response);
        }

        [HttpGet]
        public IActionResult Add()
        { 
            return View();
        }

        [HttpPost]
        public async Task&lt;IActionResult> Add(AddRegionViewModel model)
        {
            var client = httpClientFactory.CreateClient();

            var httpRequestMessage = new HttpRequestMessage()
            {
                Method = HttpMethod.Post,
                RequestUri = new Uri("https://localhost:7256/api/regions"),
                Content = new StringContent(JsonSerializer.Serialize(model), Encoding.UTF8, "application/json")
            };

            var httpResponseMessage = await client.SendAsync(httpRequestMessage);
            httpResponseMessage.EnsureSuccessStatusCode();

            var respose = await httpResponseMessage.Content.ReadFromJsonAsync&lt;RegionDto>();

            if (respose is not null)
            {
                return RedirectToAction("Index", "Regions");
            }

            return View();
        }

        [HttpGet]
        public async Task&lt;IActionResult> Edit(Guid id)
        {
            ViewBag.Id = id;
            return View();
        
        }
    }
}
</pre>



<figure class="wp-block-image size-full"><img decoding="async" width="502" height="194" src="https://lycos7560.com/wp-content/uploads/2024/10/image-198.png" alt="" class="wp-image-38633" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-198.png 502w, https://lycos7560.com/wp-content/uploads/2024/10/image-198-300x116.png 300w" sizes="(max-width: 502px) 100vw, 502px" /></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph">Edite View 생성</p>



<p class="wp-block-paragraph"><strong>Edit.cshtml</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="html" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@*
    For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
*@
@{
}

&lt;h1 class="mt-3">Edit Region&lt;/h1>

&lt;p>
    @ViewBag.Id
&lt;/p>
</pre>



<div style="height:41px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph"><strong>Index.cshtml 수정</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="html" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@model IEnumerable&lt;NZWalksUI.Models.DTO.RegionDto>
@*
    For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
*@
@{
}

&lt;h1 class="mt-3">Regions&lt;/h1>

&lt;div class="d-flex justify-content-end">
    &lt;a class="btn btn-secondary" asp-controller="Regions" asp-action="Add">Add Region&lt;/a>
&lt;/div>


&lt;table class="table-bordered">
    &lt;thead>
        &lt;tr>
            &lt;th>Id&lt;/th>
            &lt;th>Code&lt;/th>
            &lt;th>Name&lt;/th>
            &lt;th> &lt;/th>
        &lt;/tr>
    &lt;/thead>
    &lt;tbody>
        @foreach (var walk in Model)
        {
            &lt;tr>
                &lt;td>@walk.Id&lt;/td>
                &lt;td>@walk.Code&lt;/td>
                &lt;td>@walk.Name&lt;/td>
                &lt;td>
                    &lt;a asp-controller="Regions" asp-action="Edit" asp-route-id="@walk.Id" 
                    class="btn btn-light">Eidt&lt;/a>
                &lt;/td>
            &lt;/tr>
        }
    &lt;/tbody>
&lt;/table></pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="824" height="472" src="https://lycos7560.com/wp-content/uploads/2024/10/image-199.png" alt="" class="wp-image-38634" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-199.png 824w, https://lycos7560.com/wp-content/uploads/2024/10/image-199-300x172.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-199-768x440.png 768w" sizes="(max-width: 824px) 100vw, 824px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="776" height="369" src="https://lycos7560.com/wp-content/uploads/2024/10/image-201.png" alt="" class="wp-image-38636" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-201.png 776w, https://lycos7560.com/wp-content/uploads/2024/10/image-201-300x143.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-201-768x365.png 768w" sizes="(max-width: 776px) 100vw, 776px" /></figure>
</div>
</div>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide"/>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph"><strong>Error.cshtml 수정</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="html" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@model NZWalksUI.Models.DTO.RegionDto

@{
}

&lt;h1 class="mt-3">Edit Region&lt;/h1>

@if (Model is not null)
{
    &lt;form method="post">
        &lt;div class="mt-3">
            &lt;label class="form-label">Id&lt;/label>
            &lt;input type="text" class="form-control" asp-for="Id"  readonly/>
        &lt;/div>
        &lt;div class="mt-3">
            &lt;label class="form-label">Code&lt;/label>
            &lt;input type="text" class="form-control" asp-for="Code" />
        &lt;/div>

        &lt;div class="mt-3">
            &lt;label class="form-label">Name&lt;/label>
            &lt;input type="text" class="form-control" asp-for="Name" />
        &lt;/div>

        &lt;div class="mt-3">
            &lt;label class="form-label">Image URL&lt;/label>
            &lt;input type="text" class="form-control" asp-for="RegionImageUrl" />
        &lt;/div>

        &lt;div class="mt-3">
            &lt;button type="submit" class="btn btn-primary">Save&lt;/button>
        &lt;/div>

    &lt;/form>
}
</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph"><strong>RegionsController.cs 수정</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using Microsoft.AspNetCore.Mvc;
using NZWalksUI.Models;
using NZWalksUI.Models.DTO;
using System.Net.Http;
using System.Reflection;
using System.Text;
using System.Text.Json;
using static System.Net.WebRequestMethods;

namespace NZWalksUI.Controllers
{
    public class RegionsController : Controller
    {
        private readonly IHttpClientFactory httpClientFactory;

        // Http 클라이언트 팩토리를 삽입하기 위한 생성자를 생성
        public RegionsController(IHttpClientFactory httpClientFactory)
        {
            this.httpClientFactory = httpClientFactory;
        }

        [HttpGet]
        // Index 액션 메서드
        public async Task&lt;IActionResult> Index()
        {
            List&lt;RegionDto> response = new List&lt;RegionDto>();


            try
            {
                // Get All Regions From Web API
                // 새로운 Http 클라이언트가 생성
                var client = httpClientFactory.CreateClient();

                // Web API로 GET 요청을 보냄
                var httpResponseMessage = await client.GetAsync("https://localhost:7256/api/regions");
               

                // 요청이 성공적으로 완료되었는지 확인
                httpResponseMessage.EnsureSuccessStatusCode();

                // // 응답 본문을 문자열로 읽어옴
                // var stringResponse = await httpResponseMessage.Content.ReadAsStringAsync();


                response.AddRange(await httpResponseMessage.Content.ReadFromJsonAsync&lt;IEnumerable&lt;RegionDto>>());

            }
            catch (HttpRequestException e)
            {
                // 예외 발생 시 예외 메시지를 로그로 기록
                Console.WriteLine($"Request error: {e.Message}");
            }
            catch (Exception ex)
            {
                // 기타 예외 발생 시 예외 메시지를 로그로 기록
                Console.WriteLine($"An error occurred: {ex.Message}");
            }

            // View를 반환
            return View(response);
        }

        [HttpGet]
        public IActionResult Add()
        { 
            return View();
        }

        [HttpPost]
        public async Task&lt;IActionResult> Add(AddRegionViewModel model)
        {
            var client = httpClientFactory.CreateClient();

            var httpRequestMessage = new HttpRequestMessage()
            {
                Method = HttpMethod.Post,
                RequestUri = new Uri("https://localhost:7256/api/regions"),
                Content = new StringContent(JsonSerializer.Serialize(model), Encoding.UTF8, "application/json")
            };

            var httpResponseMessage = await client.SendAsync(httpRequestMessage);
            httpResponseMessage.EnsureSuccessStatusCode();

            var respose = await httpResponseMessage.Content.ReadFromJsonAsync&lt;RegionDto>();

            if (respose is not null)
            {
                return RedirectToAction("Index", "Regions");
            }

            return View();
        }

        [HttpGet]
        public async Task&lt;IActionResult> Edit(Guid id)
        {
            var client = httpClientFactory.CreateClient();

            var response = await client.GetFromJsonAsync&lt;RegionDto>($"https://localhost:7256/api/regions/{id.ToString()}");

            if (response is not null) 
            { 
                return View(response);
            }

            return View(null);
        
        }

        [HttpPost]
        public async Task&lt;IActionResult> Edit(RegionDto request) 
        {
            var client = httpClientFactory.CreateClient();

            var httpRequestMessage = new HttpRequestMessage()
            {
                Method = HttpMethod.Put,
                RequestUri = new Uri($"https://localhost:7256/api/regions/{request.Id}"),
                Content = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json")
            };

            var httpResponseMessage = await client.SendAsync(httpRequestMessage);
            httpResponseMessage.EnsureSuccessStatusCode();

            var respose = await httpResponseMessage.Content.ReadFromJsonAsync&lt;RegionDto>();

            if (respose is not null)
            {
                return RedirectToAction("Edit", "Regions");
            }

            return View();
        }

    }
}
</pre>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="895" height="503" src="https://lycos7560.com/wp-content/uploads/2024/10/image-202.png" alt="" class="wp-image-38637" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-202.png 895w, https://lycos7560.com/wp-content/uploads/2024/10/image-202-300x169.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-202-768x432.png 768w" sizes="(max-width: 895px) 100vw, 895px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="884" height="478" src="https://lycos7560.com/wp-content/uploads/2024/10/image-204.png" alt="" class="wp-image-38639" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-204.png 884w, https://lycos7560.com/wp-content/uploads/2024/10/image-204-300x162.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-204-768x415.png 768w" sizes="(max-width: 884px) 100vw, 884px" /></figure>
</div>
</div>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">7. 삭제 기능</h3>



<p class="wp-block-paragraph"><strong>Edit.cshtml 수정</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="html" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@model NZWalksUI.Models.DTO.RegionDto

@{
}

&lt;h1 class="mt-3">Edit Region&lt;/h1>

@if (Model is not null)
{
    &lt;form method="post">
        &lt;div class="mt-3">
            &lt;label class="form-label">Id&lt;/label>
            &lt;input type="text" class="form-control" asp-for="Id"  readonly/>
        &lt;/div>
        &lt;div class="mt-3">
            &lt;label class="form-label">Code&lt;/label>
            &lt;input type="text" class="form-control" asp-for="Code" />
        &lt;/div>

        &lt;div class="mt-3">
            &lt;label class="form-label">Name&lt;/label>
            &lt;input type="text" class="form-control" asp-for="Name" />
        &lt;/div>

        &lt;div class="mt-3">
            &lt;label class="form-label">Image URL&lt;/label>
            &lt;input type="text" class="form-control" asp-for="RegionImageUrl" />
        &lt;/div>

        &lt;div class="mt-3 d-flex justify-content-between">
            &lt;button type="submit" class="btn btn-primary">Save&lt;/button>
            &lt;button type="submit" asp-controller="Regions" asp-action="Delete" class="btn btn-danger">Delete&lt;/button>
        &lt;/div>

    &lt;/form>
}
</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph">RegionsController.cs 수정</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using Microsoft.AspNetCore.Mvc;
using NZWalksUI.Models;
using NZWalksUI.Models.DTO;
using System.Text;
using System.Text.Json;

namespace NZWalksUI.Controllers
{
    public class RegionsController : Controller
    {
        private readonly IHttpClientFactory httpClientFactory;

        // Http 클라이언트 팩토리를 삽입하기 위한 생성자를 생성
        public RegionsController(IHttpClientFactory httpClientFactory)
        {
            this.httpClientFactory = httpClientFactory;
        }

        [HttpGet]
        // Index 액션 메서드
        public async Task&lt;IActionResult> Index()
        {
            List&lt;RegionDto> response = new List&lt;RegionDto>();


            try
            {
                // Get All Regions From Web API
                // 새로운 Http 클라이언트가 생성
                var client = httpClientFactory.CreateClient();

                // Web API로 GET 요청을 보냄
                var httpResponseMessage = await client.GetAsync("https://localhost:7256/api/regions");
               

                // 요청이 성공적으로 완료되었는지 확인
                httpResponseMessage.EnsureSuccessStatusCode();

                // // 응답 본문을 문자열로 읽어옴
                // var stringResponse = await httpResponseMessage.Content.ReadAsStringAsync();


                response.AddRange(await httpResponseMessage.Content.ReadFromJsonAsync&lt;IEnumerable&lt;RegionDto>>());

            }
            catch (HttpRequestException e)
            {
                // 예외 발생 시 예외 메시지를 로그로 기록
                Console.WriteLine($"Request error: {e.Message}");
            }
            catch (Exception ex)
            {
                // 기타 예외 발생 시 예외 메시지를 로그로 기록
                Console.WriteLine($"An error occurred: {ex.Message}");
            }

            // View를 반환
            return View(response);
        }

        [HttpGet]
        public IActionResult Add()
        { 
            return View();
        }

        [HttpPost]
        public async Task&lt;IActionResult> Add(AddRegionViewModel model)
        {
            var client = httpClientFactory.CreateClient();

            var httpRequestMessage = new HttpRequestMessage()
            {
                Method = HttpMethod.Post,
                RequestUri = new Uri("https://localhost:7256/api/regions"),
                Content = new StringContent(JsonSerializer.Serialize(model), Encoding.UTF8, "application/json")
            };

            var httpResponseMessage = await client.SendAsync(httpRequestMessage);
            httpResponseMessage.EnsureSuccessStatusCode();

            var respose = await httpResponseMessage.Content.ReadFromJsonAsync&lt;RegionDto>();

            if (respose is not null)
            {
                return RedirectToAction("Index", "Regions");
            }

            return View();
        }

        [HttpGet]
        public async Task&lt;IActionResult> Edit(Guid id)
        {
            var client = httpClientFactory.CreateClient();

            var response = await client.GetFromJsonAsync&lt;RegionDto>($"https://localhost:7256/api/regions/{id.ToString()}");

            if (response is not null) 
            { 
                return View(response);
            }

            return View(null);
        
        }

        [HttpPost]
        public async Task&lt;IActionResult> Edit(RegionDto request) 
        {
            var client = httpClientFactory.CreateClient();

            var httpRequestMessage = new HttpRequestMessage()
            {
                Method = HttpMethod.Put,
                RequestUri = new Uri($"https://localhost:7256/api/regions/{request.Id}"),
                Content = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json")
            };

            var httpResponseMessage = await client.SendAsync(httpRequestMessage);
            httpResponseMessage.EnsureSuccessStatusCode();

            var respose = await httpResponseMessage.Content.ReadFromJsonAsync&lt;RegionDto>();

            if (respose is not null)
            {
                return RedirectToAction("Edit", "Regions");
            }

            return View();
        }

        [HttpPost]
        public async Task&lt;IActionResult> Delete(RegionDto request)
        {
            try 
            {
                var client = httpClientFactory.CreateClient();

                var httpResponseMessage = await client.DeleteAsync($"https://localhost:7256/api/regions/{request.Id}");
                httpResponseMessage.EnsureSuccessStatusCode();

                return RedirectToAction("Index", "Regions");

            }
            catch (Exception ex) 
            { 
            
            }

            return View("Edit");
        }

    }
}
</pre>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1214" height="479" src="https://lycos7560.com/wp-content/uploads/2024/10/image-205.png" alt="" class="wp-image-38640" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-205.png 1214w, https://lycos7560.com/wp-content/uploads/2024/10/image-205-300x118.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-205-768x303.png 768w" sizes="(max-width: 1214px) 100vw, 1214px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="557" height="315" src="https://lycos7560.com/wp-content/uploads/2024/10/image-206.png" alt="" class="wp-image-38641" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-206.png 557w, https://lycos7560.com/wp-content/uploads/2024/10/image-206-300x170.png 300w" sizes="(max-width: 557px) 100vw, 557px" /></figure>
</div>
</div>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://lycos7560.com/c/consuming-rest-web-apis/38585/">Consuming REST Web APIs</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/c/consuming-rest-web-apis/38585/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Image Upload In ASP.NET Core Web API</title>
		<link>https://lycos7560.com/c/image-upload-in-asp-net-core-web-api/38567/</link>
					<comments>https://lycos7560.com/c/image-upload-in-asp-net-core-web-api/38567/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Wed, 30 Oct 2024 08:41:06 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[.Net Core]]></category>
		<category><![CDATA[AddModelError]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[ASP.NET Core]]></category>
		<category><![CDATA[Controller]]></category>
		<category><![CDATA[Create]]></category>
		<category><![CDATA[Data]]></category>
		<category><![CDATA[Data access logic]]></category>
		<category><![CDATA[DataBase]]></category>
		<category><![CDATA[DbContext]]></category>
		<category><![CDATA[DbSet]]></category>
		<category><![CDATA[Domain]]></category>
		<category><![CDATA[Domain Model]]></category>
		<category><![CDATA[File]]></category>
		<category><![CDATA[FileDescription]]></category>
		<category><![CDATA[Filestream]]></category>
		<category><![CDATA[IFormFile]]></category>
		<category><![CDATA[Image]]></category>
		<category><![CDATA[Image Controller]]></category>
		<category><![CDATA[IsValid]]></category>
		<category><![CDATA[Migration]]></category>
		<category><![CDATA[Model]]></category>
		<category><![CDATA[ModelState]]></category>
		<category><![CDATA[pepe]]></category>
		<category><![CDATA[program]]></category>
		<category><![CDATA[Program.cs]]></category>
		<category><![CDATA[Repository]]></category>
		<category><![CDATA[study]]></category>
		<category><![CDATA[Upload]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[web API]]></category>
		<category><![CDATA[wpf]]></category>
		<category><![CDATA[기초]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=38567</guid>

					<description><![CDATA[<p>1. Domain Model 생성 Image.cs 2. DBContext 생성 3. Image Controller 및 Method 생성 ImageController.cs ImageUploadRequestDto.cs IImageRepository.cs LocalImageRepository.cs Program.cs 변경</p>
<p>The post <a href="https://lycos7560.com/c/image-upload-in-asp-net-core-web-api/38567/">Image Upload In ASP.NET Core Web API</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-0f1b551f      "
					data-scroll= "1"
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							목차						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-domain-model-생성" class="uagb-toc-link__trigger">1. Domain Model 생성</a><li class="uagb-toc__list"><a href="#2-dbcontext-생성" class="uagb-toc-link__trigger">2. DBContext 생성</a><li class="uagb-toc__list"><a href="#3-image-controller-및-method-생성" class="uagb-toc-link__trigger">3. Image Controller 및 Method 생성</a></ol>					</div>
									</div>
				</div>
			


<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">1. Domain Model 생성</h3>



<p class="wp-block-paragraph"><strong>Image.cs</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using System.ComponentModel.DataAnnotations.Schema;

namespace NZWalks.API.Models.Domain
{
    public class Image
    {
        public Guid Id { get; set; } // 이미지의 고유 식별자

        [NotMapped] // Entity Framework가 해당 속성을 데이터베이스 테이블에 매핑하지 않도록 지정
        public IFormFile File { get; set; } // File Data 객체를 나타내는 IFormFile 객체

        public string Filename { get; set; } // 파일 이름
        public string? FileDescription { get; set; } // 파일 설명 (nullable)
        public string FileExtension { get; set; } // 파일 확장자 (예: .jpg, .png)
        public long FileSizeInBytes { get; set; } // 파일 크기 (바이트 단위)
        public string FilePath { get; set; } // 파일 저장 경로
    }
}
</pre>



<figure class="wp-block-image size-full"><img decoding="async" width="1288" height="614" src="https://lycos7560.com/wp-content/uploads/2024/10/image-142.png" alt="" class="wp-image-38568" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-142.png 1288w, https://lycos7560.com/wp-content/uploads/2024/10/image-142-300x143.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-142-768x366.png 768w" sizes="(max-width: 1288px) 100vw, 1288px" /></figure>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">2. DBContext 생성</h3>



<figure class="wp-block-image size-full"><img decoding="async" width="1431" height="611" src="https://lycos7560.com/wp-content/uploads/2024/10/image-143.png" alt="" class="wp-image-38569" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-143.png 1431w, https://lycos7560.com/wp-content/uploads/2024/10/image-143-300x128.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-143-768x328.png 768w" sizes="(max-width: 1431px) 100vw, 1431px" /><figcaption class="wp-element-caption">Image DbSet 추가</figcaption></figure>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="powershell" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// Package Manager Console 

Add-Migration "Adding Images Table" -Context "NZWalksDbcontext"
Update-Database -Context "NZWalksDbcontext"
</pre>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="936" height="285" src="https://lycos7560.com/wp-content/uploads/2024/10/image-144.png" alt="" class="wp-image-38570" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-144.png 936w, https://lycos7560.com/wp-content/uploads/2024/10/image-144-300x91.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-144-768x234.png 768w" sizes="(max-width: 936px) 100vw, 936px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1267" height="449" src="https://lycos7560.com/wp-content/uploads/2024/10/image-145.png" alt="" class="wp-image-38571" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-145.png 1267w, https://lycos7560.com/wp-content/uploads/2024/10/image-145-300x106.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-145-768x272.png 768w" sizes="(max-width: 1267px) 100vw, 1267px" /></figure>
</div>
</div>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">3. Image Controller 및 Method 생성</h3>



<p class="wp-block-paragraph"><strong>ImageController.cs</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using Microsoft.AspNetCore.Mvc;
using NZWalks.API.Models.Domain;
using NZWalks.API.Models.DTO;
using NZWalks.API.Repositories;

namespace NZWalks.API.Controllers
{
    [Route("api/[controller]")] // 컨트롤러의 기본 경로를 설정. [controller]는 컨트롤러 이름으로 대체됨.
    [ApiController] // API 컨트롤러 특성 적용
    public class ImageController : ControllerBase
    {
        private readonly IImageRepository imageRepository;

        // IImageRepository를 주입받아 초기화
        public ImageController(IImageRepository imageRepository)
        {
            this.imageRepository = imageRepository;
        }

        // POST: /api/Images/Upload
        [HttpPost]
        [Route("Upload")]
        public async Task&lt;IActionResult> Upload([FromForm] ImageUploadRequestDto request)
        {
            // 파일 업로드 유효성 검사
            ValidateFileUpload(request);

            if (ModelState.IsValid)
            {
                // DTO를 도메인 모델로 변환
                var imageDomainModel = new Image
                {
                    File = request.File,
                    FileExtension = Path.GetExtension(request.File.FileName),
                    FileSizeInBytes = request.File.Length,
                    Filename = request.File.FileName,
                    FileDescription = request.FileDescription
                };

                // 이미지 업로드를 위해 리포지토리 사용
                await imageRepository.Uploade(imageDomainModel);

                return Ok(imageDomainModel); // 업로드된 이미지 정보 반환
            }

            return BadRequest(ModelState); // 유효성 검사 실패 시 오류 반환
        }

        // 파일 업로드 유효성 검사 메서드
        private void ValidateFileUpload(ImageUploadRequestDto request)
        {
            var allowedExtensions = new string[] { ".jpg", ".jpeg", ".Png" }; // 허용되는 확장자 목록

            // 파일 확장자 검사
            if (!allowedExtensions.Contains(Path.GetExtension(request.File.FileName)))
            {
                ModelState.AddModelError("file", "Unsupported file extension"); // 지원되지 않는 파일 확장자 오류 추가
            }

            // 파일 크기 검사 (10MB 초과 여부)
            if (request.File.Length > 10485760) // 10MB
            {
                ModelState.AddModelError("file", "File Size more than 10MB, Please upload a smaller size file"); // 파일 크기 초과 오류 추가
            }
        }
    }
}
</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph"><strong>ImageUploadRequestDto.cs</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using System.ComponentModel.DataAnnotations;

namespace NZWalks.API.Models.DTO
{
    public class ImageUploadRequestDto
    {
        [Required]
        public IFormFile File { get; set; }
        
        [Required]
        public string Filename { get; set; }

        public string? FileDescription { get; set; }

    }
}
</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph"><strong>IImageRepository.cs</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using NZWalks.API.Models.Domain;

namespace NZWalks.API.Repositories
{
    public interface IImageRepository
    {
        Task&lt;Image> Uploade(Image image);
    }
}
</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph"><strong>LocalImageRepository.cs</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using NZWalks.API.Data; // 데이터 컨텍스트를 사용하기 위한 네임스페이스
using NZWalks.API.Models.Domain; // 도메인 모델을 사용하기 위한 네임스페이스

namespace NZWalks.API.Repositories
{
    public class LocalImageRepository : IImageRepository
    {
        private readonly IWebHostEnvironment webHostEnvironment;
        private readonly IHttpContextAccessor httpContextAccessor;
        private readonly NZWalksDbcontext dbcontext;

        // LocalImageRepository 생성자
        // 필요한 종속성들(IWebHostEnvironment, IHttpContextAccessor, NZWalksDbcontext)을 주입받아 초기화
        public LocalImageRepository(IWebHostEnvironment webHostEnvironment, IHttpContextAccessor httpContextAccessor, NZWalksDbcontext dbcontext)
        {
            this.webHostEnvironment = webHostEnvironment;
            this.httpContextAccessor = httpContextAccessor;
            this.dbcontext = dbcontext;
        }

        // 이미지 업로드 메서드
        public async Task&lt;Image> Uploade(Image image)
        {
            // 로컬 파일 경로 생성
            var localFilePath = Path.Combine(webHostEnvironment.ContentRootPath, "Images", $"{Path.GetFileNameWithoutExtension(image.Filename)}{image.FileExtension}");

            // 로컬 경로에 이미지 업로드
            using var stream = new FileStream(localFilePath, FileMode.Create);
            await image.File.CopyToAsync(stream);

            // URL 경로 생성
            var urlFilePath = $"{httpContextAccessor.HttpContext.Request.Scheme}://{httpContextAccessor.HttpContext.Request.Host}{httpContextAccessor.HttpContext.Request.PathBase}/Images/{Path.GetFileNameWithoutExtension(image.Filename)}{image.FileExtension}";
            image.FilePath = urlFilePath;

            // 이미지 정보를 Images 테이블에 추가
            await dbcontext.Images.AddAsync(image);
            await dbcontext.SaveChangesAsync();

            return image; // 업로드된 이미지 반환
        }
    }
}
</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph"><strong>Program.cs 변경</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore; // Entity Framework Core 기능을 사용하기 위한 네임스페이스
using Microsoft.Extensions.FileProviders;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using NZWalks.API.Data;
using NZWalks.API.Mappings;
using NZWalks.API.Models.Domain;
using NZWalks.API.Repositories;
using System.Text; // 데이터 컨텍스트를 사용하기 위한 네임스페이스

var builder = WebApplication.CreateBuilder(args); // 웹 애플리케이션 빌더 객체 생성

// Add services to the container.
builder.Services.AddControllers(); // 컨트롤러 서비스를 추가하여 MVC 패턴을 지원

builder.Services.AddHttpContextAccessor(); // HttpContextAccessor를 서비스 컨테이너에 추가

// Swagger/OpenAPI 설정에 대한 더 많은 정보를 얻으려면 https://aka.ms/aspnetcore/swashbuckle 참고
builder.Services.AddEndpointsApiExplorer(); // API 탐색기를 추가하여 API 문서를 자동 생성

// Swagger 생성을 위한 서비스 추가
builder.Services.AddSwaggerGen(options => {    
    // 제목과 버전을 정의하여 Swagger 문서 설정
    options.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo    {        
        Title = "NZ Walks API",        
        Version = "v1"    
    });    
    // JWT Bearer 보안 정의 추가
    options.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme,        
        new Microsoft.OpenApi.Models.OpenApiSecurityScheme()        
        {            
            Name = "Authorization",  // 인증 헤더 이름                    
            In = ParameterLocation.Header,  // 인증 정보의 위치 (헤더)                    
            Type = SecuritySchemeType.ApiKey,  // 인증 유형 (API 키)                    
            Scheme = JwtBearerDefaults.AuthenticationScheme  // 스키마 설정        
        }    
    );    
    // 정의된 보안 스키마를 사용한 보안 요구 사항 추가
    options.AddSecurityRequirement(new OpenApiSecurityRequirement {        
        {            
            new OpenApiSecurityScheme {                
                Reference = new OpenApiReference {                    
                    Type = ReferenceType.SecurityScheme,  // 참조 유형 설정                    
                    Id = JwtBearerDefaults.AuthenticationScheme  // 참조 ID 설정                
                },                
                Scheme = "Oauth2",  // 스키마 설정                
                Name = JwtBearerDefaults.AuthenticationScheme,  // 스키마 이름                
                In = ParameterLocation.Header  // 위치 설정            
            },            
            new List&lt;string>()        
        }    
    });
});

// DbContext 서비스를 추가하여 SQL Server를 사용하도록 설정
builder.Services.AddDbContext&lt;NZWalksDbcontext>(options =>    
    options.UseSqlServer(builder.Configuration.GetConnectionString("NZWalksConnectionString"))
);

// DbContext 서비스를 추가하여 SQL Server를 사용하도록 설정
builder.Services.AddDbContext&lt;NZWalksAuthDbcontext>(options =>    
    options.UseSqlServer(builder.Configuration.GetConnectionString("NZWalksAuthConnectionString"))
);

builder.Services.AddScoped&lt;IRegionRepository, SQLRegionRepository>(); // Main DB Region
builder.Services.AddScoped&lt;IWalkRepository, SQLWalkRepository>(); // Main DB Walk
builder.Services.AddScoped&lt;ITokenRepository, TokenRepository>(); // Token - Controller에서 사용 가능
builder.Services.AddScoped&lt;IImageRepository, LocalImageRepository>(); // Image DB
// builder.Services.AddScoped&lt;IRegionRepository, InMemoryRegionRepository>(); // Test DB (In Memory)

builder.Services.AddAutoMapper(typeof(AutoMapperProfiles)); // AutoMapper 프로필 추가

// Identity Core 서비스를 추가하여 IdentityUser를 사용하도록 설정
builder.Services.AddIdentityCore&lt;IdentityUser>()    
    // IdentityRole을 추가하여 역할 관리를 지원
    .AddRoles&lt;IdentityRole>()    
    // 데이터 보호 토큰 제공자를 추가하여 "NZWalks"라는 이름의 토큰 제공자 설정
    .AddTokenProvider&lt;DataProtectorTokenProvider&lt;IdentityUser>>("NZWalks")    
    // Entity Framework 스토어를 사용하여 NZWalksAuthDbcontext를 통한 저장소 관리
    .AddEntityFrameworkStores&lt;NZWalksAuthDbcontext>()    
    // 기본 토큰 제공자 추가
    .AddDefaultTokenProviders();

// Identity 옵션을 구성하여 비밀번호 정책 설정
builder.Services.Configure&lt;IdentityOptions>(options =>{    
    options.Password.RequireDigit = false; // 비밀번호에 숫자 필요 없음    
    options.Password.RequireLowercase = false; // 비밀번호에 소문자 필요 없음    
    options.Password.RequireNonAlphanumeric = false; // 비밀번호에 알파벳 이외의 문자 필요 없음    
    options.Password.RequireUppercase = false; // 비밀번호에 대문자 필요 없음    
    options.Password.RequiredLength = 6; // 비밀번호 최소 길이 6자    
    options.Password.RequiredUniqueChars = 1; // 비밀번호에 최소 1개의 고유 문자 필요
});

// JWT 인증 설정 추가
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) // JWT Bearer 인증 스키마 사용    
    .AddJwtBearer(options => // JWT Bearer 인증 설정    
    options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters    
    {        
        ValidateIssuer = true, // 발행자(issuer) 유효성 검사 활성화        
        ValidateAudience = true, // 수신자(audience) 유효성 검사 활성화        
        ValidateLifetime = true, // 토큰의 유효 기간 검사 활성화        
        ValidateIssuerSigningKey = true, // 서명 키 유효성 검사 활성화        
        ValidIssuer = builder.Configuration["Jwt:Issuer"], // 유효한 발행자 설정        
        ValidAudience = builder.Configuration["Jwt:Audience"], // 유효한 수신자 설정        
        IssuerSigningKey = new SymmetricSecurityKey(            
            Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])) // 서명 키 설정    
    });

var app = builder.Build(); // 애플리케이션 빌드

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()){    
    // 개발 환경에서만 Swagger를 사용하도록 설정    
    app.UseSwagger();    
    app.UseSwaggerUI();
}

app.UseHttpsRedirection(); // HTTP 요청을 HTTPS로 리디렉션

app.UseAuthentication(); // JWT 인증 미들웨어 추가
// 이 코드는 JWT 인증을 처리하여 사용자 요청을 검증함

// 정적 파일 제공을 위한 미들웨어 설정
app.UseStaticFiles(new StaticFileOptions {     
    FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "Images")),
    RequestPath = "/Images"
});

app.UseAuthorization(); // 권한 부여 미들웨어 사용
// 인증된 사용자의 권한을 검증함

app.MapControllers(); // 컨트롤러에 대한 요청을 매핑

app.Run(); // 애플리케이션 실행
</pre>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="982" height="145" src="https://lycos7560.com/wp-content/uploads/2024/10/image-146.png" alt="" class="wp-image-38572" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-146.png 982w, https://lycos7560.com/wp-content/uploads/2024/10/image-146-300x44.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-146-768x113.png 768w" sizes="(max-width: 982px) 100vw, 982px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1027" height="213" src="https://lycos7560.com/wp-content/uploads/2024/10/image-147.png" alt="" class="wp-image-38573" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-147.png 1027w, https://lycos7560.com/wp-content/uploads/2024/10/image-147-300x62.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-147-768x159.png 768w" sizes="(max-width: 1027px) 100vw, 1027px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1307" height="1008" src="https://lycos7560.com/wp-content/uploads/2024/10/image-148.png" alt="" class="wp-image-38574" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-148.png 1307w, https://lycos7560.com/wp-content/uploads/2024/10/image-148-300x231.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-148-768x592.png 768w" sizes="(max-width: 1307px) 100vw, 1307px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1267" height="1002" src="https://lycos7560.com/wp-content/uploads/2024/10/image-149.png" alt="" class="wp-image-38575" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-149.png 1267w, https://lycos7560.com/wp-content/uploads/2024/10/image-149-300x237.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-149-768x607.png 768w" sizes="(max-width: 1267px) 100vw, 1267px" /></figure>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.34%">
<figure class="wp-block-image size-full"><img decoding="async" width="1520" height="404" src="https://lycos7560.com/wp-content/uploads/2024/10/image-150.png" alt="" class="wp-image-38576" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-150.png 1520w, https://lycos7560.com/wp-content/uploads/2024/10/image-150-300x80.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-150-768x204.png 768w" sizes="(max-width: 1520px) 100vw, 1520px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.34%">
<figure class="wp-block-image size-full"><img decoding="async" width="450" height="303" src="https://lycos7560.com/wp-content/uploads/2024/10/image-152.png" alt="" class="wp-image-38580" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-152.png 450w, https://lycos7560.com/wp-content/uploads/2024/10/image-152-300x202.png 300w" sizes="(max-width: 450px) 100vw, 450px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.33%">
<figure class="wp-block-image size-full"><img decoding="async" width="409" height="432" src="https://lycos7560.com/wp-content/uploads/2024/10/image-153.png" alt="" class="wp-image-38581" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-153.png 409w, https://lycos7560.com/wp-content/uploads/2024/10/image-153-284x300.png 284w" sizes="(max-width: 409px) 100vw, 409px" /><figcaption class="wp-element-caption">정적 파일</figcaption></figure>
</div>
</div>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://lycos7560.com/c/image-upload-in-asp-net-core-web-api/38567/">Image Upload In ASP.NET Core Web API</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/c/image-upload-in-asp-net-core-web-api/38567/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Visual studio WPF Basic Folder Structure</title>
		<link>https://lycos7560.com/c/visual-studio-wpf-basic-folder-structure/38413/</link>
					<comments>https://lycos7560.com/c/visual-studio-wpf-basic-folder-structure/38413/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Sat, 26 Oct 2024 18:54:16 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[WPF]]></category>
		<category><![CDATA[appsettings.json]]></category>
		<category><![CDATA[Controllers]]></category>
		<category><![CDATA[launchSettings.json]]></category>
		<category><![CDATA[MVVM]]></category>
		<category><![CDATA[Program.cs]]></category>
		<category><![CDATA[Visual studio]]></category>
		<category><![CDATA[wpf]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=38413</guid>

					<description><![CDATA[<p>Understand Files &#38; Folder Structure Visual studio의 Solution Visual Studio에서 솔루션(Solution)은 프로젝트들을 관리하고 구성하는 상위 개념이자 아키텍처(architecture) Visual studio의 Porject File launchSettings.json launchSettings.json 파일은 .NET 프로젝트에서 디버깅 설정을 관리하는 데 사용 이 파일은 프로젝트의 Properties 폴더 안에 위치해 있으며, 애플리케이션이 디버깅 모드로 실행될 때의 설정을 정의합니다. 주요 섹션 아래와 같이 값을 수정하여 디버깅 프로필에 적용할 수 있으며 웹브라우저 변경도 가능 (설치된 브라우저) Controllers Folder Controllers Folder는 ASP.NET Core MVC (모델-뷰-컨트롤러) 애플리케이션에서 매우 중요한 역할을 합니다.  이 폴더에는 주로 컨트롤러 클래스들이 위치합니다. 컨트롤러는 사용자의 요청을 처리하고, 필요한 데이터를 모델에서 가져와 뷰에 전달하는 역할을 합니다. appsettings.json appsettings.json 파일은 .NET Core 및 ASP.NET Core 애플리케이션에서 설정(configuration) 정보를 저장하는 데 사용되는 파일 이 파일은 JSON 형식으로 작성되며, 애플리케이션이 실행될 때 필요한 각종 설정 값을 포함 주요 역할 Program.cs Program.cs 파일은 .NET Core 및 ASP.NET Core 애플리케이션에서 진입점을 정의 이 파일은 애플리케이션이 시작될 때 처음 실행되는 코드를 포함하고 있으며, 주로 애플리케이션의 설정과 기본적인 실행을 담당합니다. 주요 역할</p>
<p>The post <a href="https://lycos7560.com/c/visual-studio-wpf-basic-folder-structure/38413/">Visual studio WPF Basic Folder Structure</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Understand Files &amp; Folder Structure</p>


				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-9f504600      "
					data-scroll= "1"
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							목차 테이블						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#visual-studio의-solution" class="uagb-toc-link__trigger">Visual studio의 Solution</a><li class="uagb-toc__list"><a href="#visual-studio의-porject-file" class="uagb-toc-link__trigger">Visual studio의 Porject File</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#launchsettingsjson" class="uagb-toc-link__trigger">launchSettings.json</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#controllers-folder" class="uagb-toc-link__trigger">Controllers Folder</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#appsettingsjson" class="uagb-toc-link__trigger">appsettings.json</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#programcs" class="uagb-toc-link__trigger">Program.cs</a></ul></ol>					</div>
									</div>
				</div>
			


<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">Visual studio의 Solution</h2>



<p class="wp-block-paragraph">Visual Studio에서 솔루션(Solution)은 <strong>프로젝트들을 관리하고 구성</strong>하는 상위 개념이자 아키텍처(architecture)</p>



<ul class="wp-block-list">
<li>파일 확장자:<strong> <code>.sln</code></strong> 확장자</li>



<li>구성 요소: <strong>하나 이상의 프로젝트를 포함</strong>할 수 있으며, 각 프로젝트는 고유의 설정, 파일 및 리소스를 가짐</li>



<li>역할: <strong>프로젝트 간의 종속성을 관리</strong>하고, <strong>빌드 및 디버깅 과정을 통합</strong>하며, <strong>여러 프로젝트를 단일 단위로 관리</strong></li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="438" height="268" src="https://lycos7560.com/wp-content/uploads/2024/10/image-26.png" alt="" class="wp-image-38414" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-26.png 438w, https://lycos7560.com/wp-content/uploads/2024/10/image-26-300x184.png 300w" sizes="(max-width: 438px) 100vw, 438px" /></figure>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">Visual studio의 <strong>Porject File</strong></h2>



<ul class="wp-block-list">
<li>파일 확장자: 주로<strong> <code>.csproj</code> </strong>(C# 프로젝트) 또는<strong> <code>.vcxproj</code> </strong>(C++ 프로젝트) 확장자를 가짐.</li>



<li>구성 요소: 소스 코드 파일, 리소스 파일, 참조, 빌드 설정 등을 포함.</li>



<li>역할: 각 <strong>프로젝트의 파일과 설정을 관리</strong>하고, 빌드 및 디버깅을 위한 정보를 제공함.</li>
</ul>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="974" height="166" src="https://lycos7560.com/wp-content/uploads/2024/10/image-31.png" alt="" class="wp-image-38419" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-31.png 974w, https://lycos7560.com/wp-content/uploads/2024/10/image-31-300x51.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-31-768x131.png 768w" sizes="(max-width: 974px) 100vw, 974px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1305" height="404" src="https://lycos7560.com/wp-content/uploads/2024/10/image-27.png" alt="" class="wp-image-38415" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-27.png 1305w, https://lycos7560.com/wp-content/uploads/2024/10/image-27-300x93.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-27-768x238.png 768w" sizes="(max-width: 1305px) 100vw, 1305px" /></figure>
</div>
</div>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;Project Sdk="Microsoft.NET.Sdk.Web"> 
  &lt;!-- 프로젝트 파일의 최상위 요소로, Microsoft.NET.Sdk.Web SDK를 사용하여 웹 애플리케이션 프로젝트를 생성 -->
  &lt;PropertyGroup>
    &lt;TargetFramework>net8.0&lt;/TargetFramework> 
    &lt;!-- 해당 프로젝트의 타겟 .NET 프레임워크 버전을 지정 -->
    &lt;Nullable>enable&lt;/Nullable> 
    &lt;!-- Nullable 참조 유형을 사용하도록 설정 -->
    &lt;ImplicitUsings>enable&lt;/ImplicitUsings>
    &lt;!-- 암시적 using 지시문을 활성화하여, 흔히 사용되는 네임스페이스를 자동으로 포함 -->
  &lt;/PropertyGroup>
  &lt;ItemGroup>
    &lt;PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" /> 
    &lt;!-- Swashbuckle.AspNetCore 패키지를 참조하여 OpenAPI(Swagger) 지원 추가 -->
	&lt;!-- Swashbuckle.AspNetCore 패키지는 ASP.NET Core 애플리케이션에 Swagger/OpenAPI 문서 생성을 위한 기능을 제공합니다. -->
	&lt;!-- Swagger는 RESTful API를 위한 인터페이스 명세서이며, 이를 통해 API를 시각화하고 테스트할 수 있는 웹 UI를 제공할 수 있습니다.-->
  &lt;/ItemGroup>
&lt;/Project>
</pre>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">launchSettings.json</h3>



<p class="wp-block-paragraph"><code>launchSettings.json</code> 파일은 <strong>.NET 프로젝트에서 디버깅 설정을 관리</strong>하는 데 사용</p>



<p class="wp-block-paragraph">이 파일은 프로젝트의 <strong><code>Properties</code> 폴더 안에 위치</strong>해 있으며, 애플리케이션이 디버깅 모드로 실행될 때의 설정을 정의합니다.</p>



<p class="wp-block-paragraph"><strong>주요 섹션</strong></p>



<ul start="1" class="wp-block-list">
<li><strong>profiles</strong>: <br>각기 다른 디버깅 프로파일을 정의<br>예를 들어, <code>IIS Express</code>와 같은 웹 서버나, 프로젝트 자체의 실행 구성을 정의할 수 있습니다.</li>



<li><strong>environmentVariables</strong>: <br>환경 변수를 설정합니다. <br>애플리케이션이 실행될 때 사용할 특정 환경 변수 값을 정의할 수 있습니다.</li>



<li><strong>commandName</strong>: <br>애플리케이션이 실행될 때 사용할 명령을 지정합니다. <br>예를 들어, <code>Project</code>는 기본 프로젝트 실행을 의미하고, <code>IISExpress</code>는 IIS Express에서 실행을 의미합니다.</li>



<li><strong>applicationUrl</strong>: <br>애플리케이션이 실행될 때 사용할 URL을 지정합니다.</li>
</ul>



<p class="wp-block-paragraph">아래와 같이 값을 수정하여 디버깅 프로필에 적용할 수 있으며 웹브라우저 변경도 가능 (설치된 브라우저)</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7387b849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="1319" height="744" src="https://lycos7560.com/wp-content/uploads/2024/10/image-29.png" alt="" class="wp-image-38417" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-29.png 1319w, https://lycos7560.com/wp-content/uploads/2024/10/image-29-300x169.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-29-768x433.png 768w" sizes="(max-width: 1319px) 100vw, 1319px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><img decoding="async" width="941" height="409" src="https://lycos7560.com/wp-content/uploads/2024/10/image-30.png" alt="" class="wp-image-38418" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-30.png 941w, https://lycos7560.com/wp-content/uploads/2024/10/image-30-300x130.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-30-768x334.png 768w" sizes="(max-width: 941px) 100vw, 941px" /></figure>
</div>
</div>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:8465",
      "sslPort": 44390
    }
  },
  "profiles": {
    "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "launchUrl": "swagger",
      "applicationUrl": "http://localhost:5118",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "https": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "launchUrl": "swagger",
      "applicationUrl": "https://localhost:7256;http://localhost:5118",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "launchSettings_Test": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "launchUrl": "swagger",
      "applicationUrl": "https://localhost:7256;http://localhost:5118",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}
</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">Controllers Folder</h3>



<p class="wp-block-paragraph">Controllers Folder는 ASP.NET Core <strong>MVC (모델-뷰-컨트롤러) 애플리케이션에서 매우 중요한 역할</strong>을 합니다. </p>



<p class="wp-block-paragraph">이 폴더에는 주로 컨트롤러 클래스들이 위치합니다. 컨트롤러는 <strong>사용자의 요청을 처리하고, 필요한 데이터를 모델에서 가져와 뷰에 전달하는 역할</strong>을 합니다.</p>



<figure class="wp-block-image size-full"><img decoding="async" width="1481" height="768" src="https://lycos7560.com/wp-content/uploads/2024/10/image-33.png" alt="" class="wp-image-38421" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-33.png 1481w, https://lycos7560.com/wp-content/uploads/2024/10/image-33-300x156.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-33-768x398.png 768w" sizes="(max-width: 1481px) 100vw, 1481px" /></figure>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">appsettings.json</h3>



<p class="wp-block-paragraph">appsettings.json 파일은 .NET Core 및 ASP.NET Core 애플리케이션에서 <strong>설정(configuration) 정보를 저장하는 데 사용</strong>되는 파일</p>



<p class="wp-block-paragraph">이 파일은 JSON 형식으로 작성되며, 애플리케이션이 <strong>실행될 때 필요한 각종 설정 값을 포함</strong></p>



<p class="wp-block-paragraph"><strong>주요 역할</strong></p>



<ul class="wp-block-list">
<li><strong>구성 설정</strong>: 데이터베이스 연결 문자열, API 키, 애플리케이션 설정 등을 포함한 각종 설정 정보 등&#8230; 을 저장</li>



<li><strong>환경별 설정</strong>: <code>appsettings.Development.json</code>, <code>appsettings.Production.json</code> 등과 같은 환경별 설정 파일을 통해 개발, 테스트, 프로덕션 등 각 환경에 맞는 설정 값을 관리</li>



<li><strong>구성 공급자(Configuration Provider)</strong>: <code>appsettings.json</code> 파일을 통해 설정 값을 로드하고, 필요에 따라 다른 구성 공급자와 결합하여 사용</li>
</ul>



<figure class="wp-block-image size-full"><img decoding="async" width="992" height="372" src="https://lycos7560.com/wp-content/uploads/2024/10/image-34.png" alt="" class="wp-image-38422" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-34.png 992w, https://lycos7560.com/wp-content/uploads/2024/10/image-34-300x113.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-34-768x288.png 768w" sizes="(max-width: 992px) 100vw, 992px" /></figure>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">Program.cs</h3>



<p class="wp-block-paragraph"><code>Program.cs</code> 파일은 .NET Core 및 ASP.NET Core 애플리케이션에서 진입점을 정의</p>



<p class="wp-block-paragraph">이 파일은 애플리케이션이 시작될 때 처음 실행되는 코드를 포함하고 있으며, <strong>주로 애플리케이션의 설정과 기본적인 실행을 담당</strong>합니다.</p>



<p class="wp-block-paragraph"><strong>주요 역할</strong></p>



<ul class="wp-block-list">
<li><strong>메인 진입점</strong>: <br>애플리케이션 실행의 시작점을 정의합니다.</li>



<li><strong>호스트 빌드</strong>: <br>웹 애플리케이션의 웹 호스트를 구성하고 빌드합니다.</li>



<li><strong>서비스 구성</strong>: <br>종속성 주입(DI), 미들웨어, 설정 등을 포함하여 애플리케이션의 기본 설정을 구성합니다.</li>
</ul>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// 웹 애플리케이션을 생성하기 위한 빌더 객체를 생성
var builder = WebApplication.CreateBuilder(args);

// 서비스 컨테이너에 서비스 추가
// 컨트롤러 서비스를 추가하여 MVC 패턴을 지원
builder.Services.AddControllers();

// Swagger/OpenAPI 설정을 위한 서비스 추가
builder.Services.AddEndpointsApiExplorer(); // API 엔드포인트 탐색기 추가
builder.Services.AddSwaggerGen(); // Swagger 생성을 위한 서비스 추가

// 애플리케이션 빌드
var app = builder.Build();

// HTTP 요청 파이프라인 구성
if (app.Environment.IsDevelopment())
{
    // 개발 환경에서만 Swagger를 사용하도록 설정
    app.UseSwagger();
    app.UseSwaggerUI();
}

// HTTP 요청을 HTTPS로 리디렉션
app.UseHttpsRedirection();

// 권한 부여 미들웨어 사용
app.UseAuthorization();

// 컨트롤러에 대한 요청을 매핑
app.MapControllers();

// 애플리케이션 실행
app.Run();
</pre>



<figure class="wp-block-image size-full"><img decoding="async" width="1484" height="771" src="https://lycos7560.com/wp-content/uploads/2024/10/image-35.png" alt="" class="wp-image-38423" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-35.png 1484w, https://lycos7560.com/wp-content/uploads/2024/10/image-35-300x156.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-35-768x399.png 768w" sizes="(max-width: 1484px) 100vw, 1484px" /></figure>
<p>The post <a href="https://lycos7560.com/c/visual-studio-wpf-basic-folder-structure/38413/">Visual studio WPF Basic Folder Structure</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/c/visual-studio-wpf-basic-folder-structure/38413/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
