<?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>ModelState Archives - 어제와 내일의 나 그 사이의 이야기</title>
	<atom:link href="https://lycos7560.com/tag/modelstate/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>생각의 흐름을 타고 다니며 만드는 블로그</description>
	<lastBuildDate>Sun, 03 Nov 2024 07:52:50 +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>ModelState Archives - 어제와 내일의 나 그 사이의 이야기</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<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 fetchpriority="high" 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>Model validation in ASP.NET Core</title>
		<link>https://lycos7560.com/c/model-validation-in-asp-net-core/38496/</link>
					<comments>https://lycos7560.com/c/model-validation-in-asp-net-core/38496/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Mon, 28 Oct 2024 22:44:14 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[ApiController]]></category>
		<category><![CDATA[App]]></category>
		<category><![CDATA[ASP.NET Core]]></category>
		<category><![CDATA[attribute]]></category>
		<category><![CDATA[Attributes]]></category>
		<category><![CDATA[binding]]></category>
		<category><![CDATA[IsValid]]></category>
		<category><![CDATA[Model]]></category>
		<category><![CDATA[model binding]]></category>
		<category><![CDATA[Model state]]></category>
		<category><![CDATA[Model validation]]></category>
		<category><![CDATA[ModelState]]></category>
		<category><![CDATA[ModelState.IsValid]]></category>
		<category><![CDATA[Razor]]></category>
		<category><![CDATA[Rerun validation]]></category>
		<category><![CDATA[State]]></category>
		<category><![CDATA[study]]></category>
		<category><![CDATA[Validation]]></category>
		<category><![CDATA[Validation attributes]]></category>
		<category><![CDATA[Web]]></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=38496</guid>

					<description><![CDATA[<p>Model Validations https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-8.0 ASP.NET Core MVC 또는 Razor Pages 앱에서 사용자 입력의 유효성을 검사하는 방법 Model state Model state represents errors that come from two subsystems: model binding and model validation.Model state는 model binding(모델 바인딩)과 model validation(모델 유효성 검사)라는 두 가지 서브 시스템에서 발생한 오류를 나타냅니다. Errors that originate from&#160;model binding&#160;are generally data conversion errors.model [&#8230;]</p>
<p>The post <a href="https://lycos7560.com/c/model-validation-in-asp-net-core/38496/">Model validation in ASP.NET Core</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Model Validations</h2>



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



<p class="wp-block-paragraph"> ASP.NET Core MVC 또는 Razor Pages 앱에서 <strong>사용자 입력의 유효성을 검사하는 방법</strong></p>


				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-460a819b      "
					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="#model-validations" class="uagb-toc-link__trigger">Model Validations</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#model-state" class="uagb-toc-link__trigger">Model state</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#rerun-validation" class="uagb-toc-link__trigger">Rerun validation</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#validation-attributes" class="uagb-toc-link__trigger">Validation attributes</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#built-in-attributes" class="uagb-toc-link__trigger">Built-in attributes</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#error-messages" class="uagb-toc-link__trigger">Error messages</a></ul></ol>					</div>
									</div>
				</div>
			


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



<h3 class="wp-block-heading" id="model-state">Model state</h3>



<p class="wp-block-paragraph">Model state represents errors that come from two subsystems: model binding and model validation.<br><strong>Model state</strong>는 <strong>model binding(모델 바인딩)</strong>과 <strong>model validation(모델 유효성 검사)</strong>라는 두 가지 서브 시스템에서 발생한 오류를 나타냅니다.</p>



<p class="wp-block-paragraph">Errors that originate from&nbsp;<a href="https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding?view=aspnetcore-8.0" target="_blank" rel="noreferrer noopener"><strong>model binding</strong></a>&nbsp;are generally data conversion errors.<br><a href="https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding?view=aspnetcore-8.0" target="_blank" rel="noreferrer noopener"><strong>model binding</strong></a>에서 발생한 오류는 일반적으로 <strong>데이터 변환 오류</strong>입니다.</p>



<p class="wp-block-paragraph">For example, an &#8220;x&#8221; is entered in an integer field.<br>예를 들어, 정수(int) 필드에 &#8216;x'(char)가 입력된 경우입니다. </p>



<p class="wp-block-paragraph"><strong>Model validation</strong> occurs after model binding and reports errors where data doesn&#8217;t conform to business rules.<br><strong>Model validation</strong>는 모델 바인딩 후에 발생하며, 데이터가 비즈니스 규칙에 부합하지 않는 경우 오류를 보고합니다.</p>



<p class="wp-block-paragraph">For example, a 0 is entered in a field that expects a rating between 1 and 5.<br>예를 들어, 1에서 5 사이의 값을 기대하는 필드에 0이 입력된 경우입니다.</p>



<p class="wp-block-paragraph">Both <strong>model binding</strong> and <strong>model validation</strong> occur before the execution of a controller action or a Razor Pages handler method.<br><strong>model binding</strong>과 <strong>model validation</strong>는 <strong>컨트롤러 액션이나 Razor Pages 핸들러 메서드가 실행되기 전</strong>에 발생합니다.</p>



<p class="wp-block-paragraph">For web apps, it&#8217;s the app&#8217;s responsibility to inspect<strong>&nbsp;<code>ModelState.IsValid</code></strong>&nbsp;and react appropriately.<br>웹 애플리케이션에서는 <code><strong>ModelState.IsValid</strong></code>를 검사하고 적절하게 반응하는 것이 <strong>애플리케이션의 책임</strong>입니다.</p>



<p class="wp-block-paragraph">Web apps typically redisplay the page with an error message, as shown in the following Razor Pages example:<br>웹 애플리케이션은 일반적으로 오류 메시지가 포함된 페이지를 다시 표시합니다. 다음은 Razor Pages의 예제입니다:</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 async Task&lt;IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }
    _context.Movies.Add(Movie);
    await _context.SaveChangesAsync();
    return RedirectToPage("./Index");
}
</pre>



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



<p class="wp-block-paragraph">ASP.NET Core MVC 컨트롤러와 뷰를 사용하는 경우, 다음 예제는 컨트롤러 액션 내부에서 <code>ModelState.IsValid</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="">public async Task&lt;IActionResult> Create(Movie movie)
{
    if (!ModelState.IsValid)
    {
        return View(movie);
    }
    _context.Movies.Add(movie);
    await _context.SaveChangesAsync();
    return RedirectToAction(nameof(Index));
}
</pre>



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



<p class="wp-block-paragraph">Web API 컨트롤러는 <code>[ApiController]</code> 특성을 가진 경우 <code>ModelState.IsValid</code>를 확인할 필요가 없습니다. </p>



<p class="wp-block-paragraph">이 경우, 모델 상태가 유효하지 않으면 오류 세부 정보가 포함된 자동 HTTP 400 응답이 반환됩니다. </p>



<p class="wp-block-paragraph">자세한 내용은 <a href="https://aka.ms/aspnetcore-docs-mvc-model-validation?form=MG0AV3" target="_blank" rel="noreferrer noopener">Automatic HTTP 400 responses</a>에서 확인할 수 있습니다.</p>



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



<h3 class="wp-block-heading" id="rerun-validation">Rerun validation</h3>



<p class="wp-block-paragraph">Validation is automatic, but you might want to repeat it manually.<br>유효성 검사 다시 실행 유효성 검사는 자동으로 이루어지지만, <strong>수동으로 다시 실행</strong>하고 싶을 때가 있습니다.</p>



<p class="wp-block-paragraph">For example, you might compute a value for a property and want to rerun validation after setting the property to the computed value.<br>예를 들어, 속성의 값을 계산한 후 해당 <strong>속성에 계산된 값을 설정한 후에 유효성 검사를 다시 실행</strong>하고 싶을 수 있습니다.</p>



<p class="wp-block-paragraph">To rerun validation, call&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.modelbinding.modelstatedictionary.clearvalidationstate">ModelStateDictionary.ClearValidationState</a>&nbsp;to clear validation specific to the model being validated followed by&nbsp;<code>TryValidateModel</code>:<br>유효성 검사를 다시 실행하려면, <a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.modelbinding.modelstatedictionary.clearvalidationstate"><strong>ModelStateDictionary.ClearValidationState</strong></a>를 호출하여 검사를 수행할 모델의 유효성 검사를 지우고, <strong><code>TryValidateModel</code>을 호출</strong>합니다:</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="">public async Task&lt;IActionResult> OnPostTryValidateAsync()
{
    var modifiedReleaseDate = DateTime.Now.Date;
    Movie.ReleaseDate = modifiedReleaseDate;
    ModelState.ClearValidationState(nameof(Movie));
    if (!TryValidateModel(Movie, nameof(Movie)))
    {
        return Page();
    }
    _context.Movies.Add(Movie);
    await _context.SaveChangesAsync();
    return RedirectToPage("./Index");
}
</pre>



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



<h3 class="wp-block-heading" id="validation-attributes">Validation attributes </h3>



<p class="wp-block-paragraph">Validation attributes let you specify validation rules for model properties.<br>V<strong>alidation attributes(유효성 검사 속성)</strong>을 사용하면 모델 속성에 대한 <strong>유효성 검사 규칙을 지정</strong>할 수 있습니다</p>



<p class="wp-block-paragraph">The following example from the&nbsp;<a href="https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/mvc/models/validation/samples" target="_blank" rel="noreferrer noopener">sample app</a>&nbsp;shows a model class that is annotated with validation attributes.<br>다음 예제는 <a href="https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/mvc/models/validation/samples" target="_blank" rel="noreferrer noopener">sample app</a>에서 Validation attributes으로 주석이 달린 모델 클래스를 보여줍니다.</p>



<p class="wp-block-paragraph">The&nbsp;<code><strong>[ClassicMovie]</strong></code>&nbsp;attribute is a custom validation attribute and the others are built in.<br><code><strong>[ClassicMovie]</strong></code> 속성은 <strong>custom validation attribute(사용자 정의 속성)</strong>이고, 나머지는 내장된 속성입니다.</p>



<p class="wp-block-paragraph">Not shown is&nbsp;<code><strong>[ClassicMovieWithClientValidator]</strong></code>, which shows an alternative way to implement a custom attribute.<br><code><strong>[ClassicMovieWithClientValidator]</strong></code>는 사용자 정의 속성을 구현하는 또 다른 방법을 보여줍니다.</p>



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



<p class="wp-block-paragraph"><strong>ClassicMovieAttribute.cs</strong> (<a href="https://github.com/dotnet/AspNetCore.Docs/blob/main/aspnetcore/mvc/models/validation/samples/6.x/ValidationSample/Validation/ClassicMovieAttribute.cs" target="_blank" rel="noreferrer noopener">https://github.com/dotnet/AspNetCore.Docs/blob/main/aspnetcore/mvc/models/validation/samples/6.x/ValidationSample/Validation/ClassicMovieAttribute.cs</a>)</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;
using ValidationSample.Models;

namespace ValidationSample.Validation;

// &lt;snippet_Class>
public class ClassicMovieAttribute : ValidationAttribute
{
    public ClassicMovieAttribute(int year)
        => Year = year;

    public int Year { get; }

    public string GetErrorMessage() =>
        $"Classic movies must have a release year no later than {Year}.";

    protected override ValidationResult? IsValid(
        object? value, ValidationContext validationContext)
    {
        var movie = (Movie)validationContext.ObjectInstance;
        var releaseYear = ((DateTime)value!).Year;

        if (movie.Genre == Genre.Classic &amp;&amp; releaseYear > Year)
        {
            return new ValidationResult(GetErrorMessage());
        }

        return ValidationResult.Success;
    }
}
// &lt;/snippet_Class></pre>



<div style="height:40px" 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="">public class Movie
{
    public int Id { get; set; } // 영화의 고유 식별자

    [Required] // 이 속성은 필수 입력 값임을 나타냄
    [StringLength(100)] // 문자열 최대 길이를 100자로 제한
    public string Title { get; set; } = null!; // 영화 제목

    [ClassicMovie(1960)] // 사용자 정의 유효성 검사 속성, 1960년 이전의 클래식 영화일 경우 특정 조건을 검증
    [DataType(DataType.Date)] // 날짜 형식을 지정
    [Display(Name = "Release Date")] // 표시 이름을 "Release Date"로 지정
    public DateTime ReleaseDate { get; set; } // 영화 개봉일

    [Required] // 이 속성은 필수 입력 값임을 나타냄
    [StringLength(1000)] // 문자열 최대 길이를 1000자로 제한
    public string Description { get; set; } = null!; // 영화 설명

    [Range(0, 999.99)] // 값의 범위를 0에서 999.99로 제한
    public decimal Price { get; set; } // 영화 가격

    public Genre Genre { get; set; } // 영화 장르, Genre 클래스와 연관

    public bool Preorder { get; set; } // 영화 사전 예약 가능 여부
}
</pre>



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



<h3 class="wp-block-heading" id="built-in-attributes">Built-in attributes</h3>



<p class="wp-block-paragraph">Here are some of the built-in validation attributes:<br>다음은 일부 built-in(내장된) validation attributes입니다:</p>



<ul class="wp-block-list">
<li><a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.modelbinding.validation.validateneverattribute" target="_blank" rel="noreferrer noopener">[ValidateNever]</a>: <br>Indicates that a property or parameter should be excluded from validation.<br>속성 또는 매개 변수를 유효성 검사에서 제외합니다.</li>



<li><a href="https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.creditcardattribute" target="_blank" rel="noreferrer noopener">[CreditCard]</a>: <br>Validates that the property has a credit card format. Requires&nbsp;<a href="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/additional-methods.js" target="_blank" rel="noreferrer noopener">jQuery Validation Additional Methods</a>.<br>속성이 신용카드 형식인지 유효성 검사합니다. <a href="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/additional-methods.js" target="_blank" rel="noreferrer noopener">jQuery Validation Additional Methods</a>가 필요합니다.</li>



<li><a href="https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.compareattribute" target="_blank" rel="noreferrer noopener">[Compare]</a>: <br>Validates that two properties in a model match.<br>모델의 두 속성이 일치하는지 유효성 검사합니다.</li>



<li><a href="https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.emailaddressattribute" target="_blank" rel="noreferrer noopener">[EmailAddress]</a>: <br>Validates that the property has an email format.<br>속성이 이메일 형식인지 유효성 검사합니다.</li>



<li><a href="https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.phoneattribute" target="_blank" rel="noreferrer noopener">[Phone]</a>: <br>Validates that the property has a telephone number format.<br>속성이 전화번호 형식인지 유효성 검사합니다.</li>



<li><a href="https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.rangeattribute" target="_blank" rel="noreferrer noopener">[Range]</a>: <br>Validates that the property value falls within a specified range.<br>속성 값이 지정된 범위 내에 있는지 유효성 검사합니다.</li>



<li><a href="https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.regularexpressionattribute" target="_blank" rel="noreferrer noopener">[RegularExpression]</a>: <br>Validates that the property value matches a specified regular expression.<br>속성 값이 지정된 정규 표현식과 일치하는지 유효성 검사합니다.</li>



<li><a href="https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.requiredattribute" target="_blank" rel="noreferrer noopener">[Required]</a>: <br>Validates that the field isn&#8217;t null. See&nbsp;<a href="https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-8.0#non-nullable-reference-types-and-required-attribute"><code>[Required]</code>&nbsp;attribute</a>&nbsp;for details about this attribute&#8217;s behavior.<br>필드가 null이 아닌지 유효성 검사합니다. 이 속성의 동작에 대한 자세한 내용은 [Required] 속성을 참조하세요.</li>



<li><a href="https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.stringlengthattribute">[StringLength]</a>: <br>Validates that a string property value doesn&#8217;t exceed a specified length limit.<br>문자열 속성 값이 지정된 길이 제한을 초과하지 않는지 유효성 검사합니다.</li>



<li><a href="https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.urlattribute" target="_blank" rel="noreferrer noopener">[Url]</a>: <br>Validates that the property has a URL format.<br>속성이 URL 형식인지 유효성 검사합니다.</li>



<li><a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.remoteattribute" target="_blank" rel="noreferrer noopener">[Remote]</a>: <br>Validates input on the client by calling an action method on the server.<br>서버의 액션 메서드를 호출하여 클라이언트에서 입력을 유효성 검사합니다.<br>See&nbsp;<a href="https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-8.0#remote-attribute" target="_blank" rel="noreferrer noopener"><code>[Remote]</code>&nbsp;attribute</a>&nbsp;for details about this attribute&#8217;s behavior.<br>이 속성의 동작에 대한 자세한 내용은 <a href="https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-8.0#remote-attribute" target="_blank" rel="noreferrer noopener"><code>[Remote]</code>&nbsp;attribute</a>을 참조하세요.</li>
</ul>



<p class="wp-block-paragraph">A complete list of validation attributes can be found in the&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations" target="_blank" rel="noreferrer noopener">System.ComponentModel.DataAnnotations</a>&nbsp;namespace.<br>유효성 검사 속성의 전체 목록은 <code>System.ComponentModel.DataAnnotations</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="">using System;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc;

public class ExampleModel
{
    public int Id { get; set; } // 고유 식별자

    [Required] // 필수 입력 값
    [StringLength(100)] // 문자열 최대 길이 100자
    public string Title { get; set; } = null!; // 제목

    [CreditCard] // 신용카드 형식인지 유효성 검사
    public string CreditCardNumber { get; set; } = null!; // 신용카드 번호

    [Compare("Password", ErrorMessage = "Passwords do not match.")] // 두 속성이 일치하는지 유효성 검사
    public string ConfirmPassword { get; set; } = null!; // 비밀번호 확인

    [EmailAddress] // 이메일 형식인지 유효성 검사
    public string Email { get; set; } = null!; // 이메일 주소

    [Phone] // 전화번호 형식인지 유효성 검사
    public string PhoneNumber { get; set; } = null!; // 전화번호

    [Range(1, 100)] // 값의 범위를 1에서 100으로 제한
    public int Quantity { get; set; } // 수량

    [RegularExpression(@"^[a-zA-Z0-9]*$", ErrorMessage = "Only alphanumeric characters are allowed.")] // 알파벳과 숫자만 허용
    public string Username { get; set; } = null!; // 사용자 이름

    [Url] // URL 형식인지 유효성 검사
    public string Homepage { get; set; } = null!; // 홈페이지 URL

    [Remote(action: "VerifyUsername", controller: "Users")] // 서버의 액션 메서드를 호출하여 유효성 검사
    public string UsernameRemote { get; set; } = null!; // 원격 유효성 검사용 사용자 이름

    [ValidateNever] // 유효성 검사에서 제외
    public string InternalCode { get; set; } = null!; // 내부 코드, 유효성 검사 제외

    [ClassicMovie(1960)] // 사용자 정의 유효성 검사 속성
    [DataType(DataType.Date)] // 날짜 형식을 지정
    [Display(Name = "Release Date")] // 표시 이름을 "Release Date"로 지정
    public DateTime ReleaseDate { get; set; } // 영화 개봉일
}

</pre>



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



<h3 class="wp-block-heading" id="error-messages">Error messages</h3>



<p class="wp-block-paragraph">Validation attributes let you specify the error message to be displayed for invalid input. For example:<br>Validation attributes을 사용하면 <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="">[StringLength(8, ErrorMessage = "Name length can't be more than 8.")]
</pre>



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



<p class="wp-block-paragraph">Internally, the attributes call&nbsp;<a href="https://learn.microsoft.com/en-us/dotnet/api/system.string.format">String.Format</a>&nbsp;with a placeholder for the field name and sometimes additional placeholders. For example:<br>내부적으로, 속성은 필드 이름과 때때로 추가 자리 표시자를 위한 String.Format을 호출합니다. 예를 들어:</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="">[StringLength(8, ErrorMessage = "{0} length must be between {2} and {1}.", MinimumLength = 6)]
</pre>



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



<p class="wp-block-paragraph">When applied to a&nbsp;<code>Name</code>&nbsp;property, the error message created by the preceding code would be &#8220;Name length must be between 6 and 8.&#8221;.<br>이 코드가 Name 속성에 적용되면, 생성된 오류 메시지는 &#8220;Name length must be between 6 and 8.&#8221;가 됩니다.</p>



<p class="wp-block-paragraph">To find out which parameters are passed to&nbsp;<code>String.Format</code>&nbsp;for a particular attribute&#8217;s error message, see the&nbsp;<a href="https://github.com/dotnet/runtime/tree/main/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations" target="_blank" rel="noreferrer noopener">DataAnnotations source code</a>.<br>특정 속성의 오류 메시지에 대해 String.Format에 전달되는 매개변수를 알아보려면&nbsp;<a href="https://github.com/dotnet/runtime/tree/main/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations" target="_blank" rel="noreferrer noopener">DataAnnotations source code</a> 를 참조하세요.</p>



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



<p class="wp-block-paragraph">추가 내용<br><a href="https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-8.0#required-validation-on-the-server" target="_blank" rel="noreferrer noopener"><strong>https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-8.0#required-validation-on-the-server</strong></a></p>



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



<div style="height:50px" 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="">using System.ComponentModel.DataAnnotations;

namespace NZWalks.API.Models.DTO
{
    public class AddRegionRequestDto
    {
        [Required]
        [MinLength(3, ErrorMessage = "Code has to be a minimum of 3 characters")]
        [MaxLength(3, ErrorMessage = "Code has to be a maximum of 3 characters")]
        public string Code { get; set; }

        [Required]
        [MaxLength(100, ErrorMessage = "Code has to be a maximum of 100 characters")]
        public string Name { get; set; }
        public string? RegionImageUrl { get; set; } // Nullable

    }

}
</pre>



<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.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using NZWalks.API.Data;
using NZWalks.API.Models.Domain;
using NZWalks.API.Models.DTO;
using static System.Net.WebRequestMethods;
using System;
using Microsoft.EntityFrameworkCore;
using AutoMapper;
using System.Collections.Generic;
using NZWalks.API.CustomActionFilter;

namespace NZWalks.API.Controllers
{

    [Route("api/[controller]")] // 컨트롤러의 기본 Route를 설정. [controller]는 컨트롤러 이름으로 대체됨.
    [ApiController] // API 컨트롤러 특성 적용
    public class RegionsController : ControllerBase
    {

        private readonly NZWalksDbcontext dbcontext;
        private readonly IRegionRepository regionRepository;
        private readonly IMapper mapper;

        public RegionsController(NZWalksDbcontext dbContext, IRegionRepository regionRepository, IMapper mapper)
        {
            this.dbcontext = dbContext;
            this.regionRepository = regionRepository;
            this.mapper = mapper;
        }

        // GET ALL REGIONS
        // GET: https://localhost:1234/api/regions
        [HttpGet]
        public async Task&lt;IActionResult> GetAll()
        {
            // Get Data From Database - Domain models
            // var regionDomain = await dbcontext.Regions.ToListAsync(); // Change Async
            var regionDomain = await regionRepository.GetAllAsync();

            // Map Domain Models to DTOs
            // var regionDto = new List&lt;RegionDto>();
            // foreach (var region in regionDomain) 
            // {
            //     regionDto.Add(new RegionDto() 
            //     {
            //         Id = region.Id,
            //         Code = region.Code,
            //         Name = region.Name,
            //         RegionImageUrl = region.RegionImageUrl
            //     });
            // }

            // Map Domain Models to DTOs
            var regionDto = mapper.Map&lt;List&lt;RegionDto>>(regionDomain);

            return Ok(regionDto);
        }

        // GET SINGLE REGION (Get Region By ID)
        // GET: https://localhost:1234/api/regions/{id}
        [HttpGet]
        [Route("{id:guid}")]
        public async Task&lt;IActionResult> GetById([FromRoute]Guid id) 
        {
            // Get Data From Database - Domain models
            // var region = dbcontext.Regions.Find(id);
            // var regionDomain = await dbcontext.Regions.FirstOrDefaultAsync(x => x.Id == id);
            var regionDomain = await regionRepository.GetByIdAsync(id);
            if (regionDomain == null)
            {
                return NotFound();
            }

            // Map Domain Models to DTOs
            // var regionDto = new RegionDto() 
            // {
            //     Id = regionDomain.Id,
            //     Code = regionDomain.Code,
            //     Name = regionDomain.Name,
            //     RegionImageUrl = regionDomain.RegionImageUrl
            // };

            var regionDto = mapper.Map&lt;RegionDto>(regionDomain);

            return Ok(regionDto);

        }

        // POST To Create New Region
        // POST : https://localhost:1234/api/regions
        [HttpPost]
        [ValidateModel]
        public async Task&lt;IActionResult> Create([FromBody] AddRegionRequestDto addRegionRequestDto)
        {
            /* [ValidateModel] 적용전
                        if (ModelState.IsValid) // [ValidateModel] 
            {
                // [Require]
                // string Code, Name
                // string? RegionImageUrl

                // Map or Convert DTO to Domain Model
                //var regionDomainModel = new Region
                //{
                //    Code = addRegionRequestDto.Code,
                //    Name = addRegionRequestDto.Name,
                //    RegionImageUrl = addRegionRequestDto.RegionImageUrl
                //};

                // Map or Convert DTO to Domain Model
                var regionDomainModel = mapper.Map&lt;Region>(addRegionRequestDto);

                // Use Domain Model to create Region
                // await dbcontext.Regions.AddAsync(regionDomainModel);
                // await dbcontext.SaveChangesAsync();

                await regionRepository.CreateAsync(regionDomainModel);


                // Map Domain model back to DTO
                //var regionDto = new RegionDto 
                //{ 
                //    Id = regionDomainModel.Id,
                //    Code = addRegionRequestDto.Code,
                //    Name = regionDomainModel.Name, 
                //    RegionImageUrl = regionDomainModel.RegionImageUrl

                //};

                var regionDto = mapper.Map&lt;RegionDto>(regionDomainModel);

                // 201 Created 응답으로 생성된 DTO 반환
                return CreatedAtAction(nameof(GetById), new { id = regionDto.Id }, regionDto);
                // CreatedAtAction은 ASP.NET Core에서 HTTP POST 요청 후 201 Created 상태 코드를 반환할 때 사용되는 메서드
                // 새로운 리소스를 생성한 후, 해당 리소스에 접근할 수 있는 URI를 함께 제공하여 클라이언트가 리소스를 쉽게 찾을 수 있음
            }
            else
            {
                return BadRequest(ModelState);
            }
             
            */

            // [Require]
            // string Code, Name
            // string? RegionImageUrl

            // Map or Convert DTO to Domain Model
            //var regionDomainModel = new Region
            //{
            //    Code = addRegionRequestDto.Code,
            //    Name = addRegionRequestDto.Name,
            //    RegionImageUrl = addRegionRequestDto.RegionImageUrl
            //};

            // Map or Convert DTO to Domain Model
            var regionDomainModel = mapper.Map&lt;Region>(addRegionRequestDto);

            // Use Domain Model to create Region
            // await dbcontext.Regions.AddAsync(regionDomainModel);
            // await dbcontext.SaveChangesAsync();

            await regionRepository.CreateAsync(regionDomainModel);


            // Map Domain model back to DTO
            //var regionDto = new RegionDto 
            //{ 
            //    Id = regionDomainModel.Id,
            //    Code = addRegionRequestDto.Code,
            //    Name = regionDomainModel.Name, 
            //    RegionImageUrl = regionDomainModel.RegionImageUrl

            //};

            var regionDto = mapper.Map&lt;RegionDto>(regionDomainModel);

            // 201 Created 응답으로 생성된 DTO 반환
            return CreatedAtAction(nameof(GetById), new { id = regionDto.Id }, regionDto);
            // CreatedAtAction은 ASP.NET Core에서 HTTP POST 요청 후 201 Created 상태 코드를 반환할 때 사용되는 메서드
            // 새로운 리소스를 생성한 후, 해당 리소스에 접근할 수 있는 URI를 함께 제공하여 클라이언트가 리소스를 쉽게 찾을 수 있음
        }



        // Update Region
        // PUT: https://localhost:1234/api/regions/{id}
        [HttpPut]
        [Route("{id:guid}")]
        [ValidateModel]
        public async Task&lt;IActionResult> Update([FromRoute] Guid id, [FromBody] UpdateRegionRequestDto updateRegionRequestDto)
        {
            /* [ValidateModel] 적용 전
            if (ModelState.IsValid)
            {
                // Map 
                //var regionDomainModel = new Region
                //{
                //    Code = updateRegionRequestDto.Code,
                //    Name = updateRegionRequestDto.Name,
                //    RegionImageUrl = updateRegionRequestDto.RegionImageUrl

                //};

                var regionDomainModel = mapper.Map&lt;Region>(updateRegionRequestDto);

                // Check if region exists
                // var regionDomainModel = await dbcontext.Regions.FirstOrDefaultAsync(x => x.Id == id);
                regionDomainModel = await regionRepository.UpdateAsync(id, regionDomainModel);

                if (regionDomainModel == null)
                {
                    return NotFound();
                }

                //// Map DTO to Domain model
                //regionDomainModel.Code = updateRegionRequestDto.Code;
                //regionDomainModel.Name = updateRegionRequestDto.Name;
                //regionDomainModel.RegionImageUrl = updateRegionRequestDto.RegionImageUrl;

                //await dbcontext.SaveChangesAsync();

                // Convert Domain Model to DTO
                //var regionDto = new RegionDto
                //{
                //    Id = regionDomainModel.Id,
                //    Code = regionDomainModel.Code,
                //    Name = regionDomainModel.Name,
                //    RegionImageUrl = regionDomainModel.RegionImageUrl
                //};

                var regionDto = mapper.Map&lt;RegionDto>(regionDomainModel);

                return Ok(regionDto);

            }
            else 
            { 
                return BadRequest(ModelState);
            }
            */
            // Map 
            //var regionDomainModel = new Region
            //{
            //    Code = updateRegionRequestDto.Code,
            //    Name = updateRegionRequestDto.Name,
            //    RegionImageUrl = updateRegionRequestDto.RegionImageUrl

            //};

            var regionDomainModel = mapper.Map&lt;Region>(updateRegionRequestDto);

            // Check if region exists
            // var regionDomainModel = await dbcontext.Regions.FirstOrDefaultAsync(x => x.Id == id);
            regionDomainModel = await regionRepository.UpdateAsync(id, regionDomainModel);

            if (regionDomainModel == null)
            {
                return NotFound();
            }

            //// Map DTO to Domain model
            //regionDomainModel.Code = updateRegionRequestDto.Code;
            //regionDomainModel.Name = updateRegionRequestDto.Name;
            //regionDomainModel.RegionImageUrl = updateRegionRequestDto.RegionImageUrl;

            //await dbcontext.SaveChangesAsync();

            // Convert Domain Model to DTO
            //var regionDto = new RegionDto
            //{
            //    Id = regionDomainModel.Id,
            //    Code = regionDomainModel.Code,
            //    Name = regionDomainModel.Name,
            //    RegionImageUrl = regionDomainModel.RegionImageUrl
            //};

            var regionDto = mapper.Map&lt;RegionDto>(regionDomainModel);

            return Ok(regionDto);
        }


        // Delete Region
        // Delete https://localhost:1234/api/regions/{id}
        [HttpDelete]
        [Route("{id:guid}")]
        public async Task&lt;IActionResult> Update([FromRoute] Guid id)
        {
            //var regionDomainModel = await dbcontext.Regions.FirstOrDefaultAsync(x => x.Id == id);

            var regionDomainModel = await regionRepository.DeleteAsync(id);


            if (regionDomainModel == null)
            {
                return NotFound();
            }

            // dbcontext.Regions.Remove(regionDomainModel);
            // await dbcontext.SaveChangesAsync();

            // return deleted Region back
            // Convert Domain Model to DTO
            //var regionDto = new RegionDto
            //{
            //    Id = regionDomainModel.Id,
            //    Code = regionDomainModel.Code,
            //    Name = regionDomainModel.Name,
            //    RegionImageUrl = regionDomainModel.RegionImageUrl
            //};

            var regionDto = mapper.Map&lt;Region>(regionDomainModel);

            return Ok(regionDto);
        }
    }
}
</pre>



<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 AutoMapper;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using NZWalks.API.CustomActionFilter;
using NZWalks.API.Models.Domain;
using NZWalks.API.Models.DTO;
using NZWalks.API.Repositories;

namespace NZWalks.API.Controllers
{
    // /api/walks
    [Route("api/[controller]")]
    [ApiController]
    public class WalksController : ControllerBase
    {
        private readonly IMapper mapper;
        private readonly IWalkRepository walkRepository;

        public WalksController(IMapper mapper, IWalkRepository walkRepository)
        {
            this.mapper = mapper;
            this.walkRepository = walkRepository;
        }


        // CREATE walk
        // POST: /api/walks 
        [HttpPost]
        [ValidateModel]
        public async Task&lt;IActionResult> Create([FromBody] AddWalkRequestDto addWalkRequestDto)
        {
            /* [ValidateModel] 적용전
            if (ModelState.IsValid)
            {
                // Map DTO to Domain Model
                var walkDomaiModel = mapper.Map&lt;Walk>(addWalkRequestDto);

                await walkRepository.CreateAsync(walkDomaiModel);

                // Map Domain model to DTO
                var walkDto = mapper.Map&lt;WalkDto>(walkDomaiModel);

                return Ok(walkDto);
            }
            else 
            {
                return BadRequest(ModelState);
            }


            */

            // Map DTO to Domain Model
            var walkDomaiModel = mapper.Map&lt;Walk>(addWalkRequestDto);

            await walkRepository.CreateAsync(walkDomaiModel);

            // Map Domain model to DTO
            var walkDto = mapper.Map&lt;WalkDto>(walkDomaiModel);

            return Ok(walkDto);
        }

        // GET Walks
        // Get: /api/walks
        [HttpGet]
        public async Task&lt;IActionResult> GetAllAsync()
        {
            var walksDomain = await walkRepository.GetAllAsync();

            // Map Domain Model to DTO
            var walksDto = mapper.Map&lt;List&lt;WalkDto>>(walksDomain);

            return Ok(walksDto);
        }


        // Get Walk By Id
        // GET: /api/Walks/{id}
        [HttpGet]
        [Route("{id:Guid}")]
        public async Task&lt;IActionResult> GetByIdAsync([FromRoute] Guid id)
        {
            var walksDomain = await walkRepository.GetByIdAsync(id);

            if (walksDomain == null)
            {
                return NotFound();
            }

            var WalkDto = mapper.Map&lt;WalkDto>(walksDomain);
            
            return Ok(WalkDto);
        }

        // Update Walk By Id
        // Put: / api/Walks/{id}
        [HttpPut]
        [Route("{id:Guid}")]
        [ValidateModel]
        public async Task&lt;IActionResult> Update([FromRoute] Guid id, UpdateWalkRequestDto updateWalkRequestDto)
        {
            /*  [ValidateModel] 적용전
            if (ModelState.IsValid)
            {
                // Map DTO to Domain Model
                var walksDomain = mapper.Map&lt;Walk>(updateWalkRequestDto);

                walksDomain = await walkRepository.UpdateAsync(id, walksDomain);

                if (walksDomain == null)
                {
                    return NotFound();
                }

                var walksDto = mapper.Map&lt;Walk>(walksDomain);

                // Map Domain Model to DTO
                return Ok(walksDto);
            }
            else
            {
                return BadRequest(ModelState);
            }

            */

            // Map DTO to Domain Model
            var walksDomain = mapper.Map&lt;Walk>(updateWalkRequestDto);

            walksDomain = await walkRepository.UpdateAsync(id, walksDomain);

            if (walksDomain == null)
            {
                return NotFound();
            }

            var walksDto = mapper.Map&lt;Walk>(walksDomain);

            // Map Domain Model to DTO
            return Ok(walksDto);
        }

        // Delete a Walk By Id
        // DELETE: /api/Walks/{id}
        [HttpDelete]
        [Route("{id:Guid}")]
        public async Task&lt;IActionResult> Delete([FromRoute] Guid id)
        { 
            var deleteWalkDomainModel = await walkRepository.DeleteAsync(id);

            if (deleteWalkDomainModel == null)
            {
                return NotFound();
            }

            // Map Domain Model to DTO
            var deleteWalkDto = mapper.Map&lt;WalkDto>(deleteWalkDomainModel);

            return Ok(deleteWalkDto);
        }
    }
}
</pre>



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



<figure class="wp-block-image size-full"><img decoding="async" width="1289" height="1014" src="https://lycos7560.com/wp-content/uploads/2024/10/image-82.png" alt="" class="wp-image-38497" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-82.png 1289w, https://lycos7560.com/wp-content/uploads/2024/10/image-82-300x236.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-82-768x604.png 768w" sizes="(max-width: 1289px) 100vw, 1289px" /></figure>



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



<figure class="wp-block-image size-full"><img decoding="async" width="1264" height="721" src="https://lycos7560.com/wp-content/uploads/2024/10/image-85.png" alt="" class="wp-image-38501" srcset="https://lycos7560.com/wp-content/uploads/2024/10/image-85.png 1264w, https://lycos7560.com/wp-content/uploads/2024/10/image-85-300x171.png 300w, https://lycos7560.com/wp-content/uploads/2024/10/image-85-768x438.png 768w" sizes="(max-width: 1264px) 100vw, 1264px" /></figure>



<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.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace NZWalks.API.CustomActionFilter
{
    public class ValidateModelAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            if (context.ModelState.IsValid == false)
            { 
                context.Result = new BadRequestResult();
            }
        }
    }
}
</pre>



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



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://lycos7560.com/c/model-validation-in-asp-net-core/38496/">Model validation in ASP.NET Core</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/c/model-validation-in-asp-net-core/38496/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
