성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] 그냥 RSS Reader 기능과 약간의 UI 편의성 때문에 사용...
[이종효] 오래된 소프트웨어는 보안 위협이 되기도 합니다. 혹시 어떤 기능...
[정성태] @Keystroke IEEE의 문서를 소개해 주시다니... +_...
[손민수 (Keystroke)] 괜히 듀얼채널 구성할 때 한번에 같은 제품 사라고 하는 것이 아...
[정성태] 전각(Full-width)/반각(Half-width) 기능을 토...
[정성태] Vector에 대한 내용은 없습니다. Vector가 닷넷 BCL...
[orion] 글 읽고 찾아보니 디자인 타임에는 InitializeCompon...
[orion] 연휴 전에 재현 프로젝트 올리자 생각해 놓고 여의치 않아서 못 ...
[정성태] 아래의 글에 정리했으니 참고하세요. C# - Typed D...
[정성태] 간단한 재현 프로젝트라도 있을까요? 저런 식으로 설명만 해...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>.NET Core Kestrel 호스팅 - Web API 추가</h1> <p> 지금까지 콘솔 프로젝트로 시작해 Kestrel을 이용한 웹 애플리케이션 코드를 하나씩 추가해 봤는데요,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > .NET Core 콘솔 프로젝트에서 Kestrel 호스팅 방법 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/12496'>https://www.sysnet.pe.kr/2/0/12496</a> .NET Core Kestrel 호스팅 - 포트 변경, non-localhost 접속 지원 및 https 등의 설정 변경 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/12499'>https://www.sysnet.pe.kr/2/0/12499</a> ASP.NET Core(Kestrel)의 HTTP/2 지원 여부 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/12500'>https://www.sysnet.pe.kr/2/0/12500</a> </pre> <br /> 이번에는 OWIN에서도 구현했던,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C# - OWIN Web API 예제 프로젝트 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/12497'>https://www.sysnet.pe.kr/2/0/12497</a> </pre> <br /> Web API도 추가해 보겠습니다. (참고로, 기반 프로젝트는 <a target='tab' href='https://www.sysnet.pe.kr/2/0/12500'>ASP.NET Core(Kestrel)의 HTTP/2 지원 여부</a>에 첨부한 예제 코드로 시작합니다.)<br /> <br /> <hr style='width: 50%' /><br /> <a name='webapi_sample'></a> <br /> 당연히 Web API 역할을 할 클래스를 추가해야 하고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // 비주얼 스튜디오에서는 "API Controller - Empty" 항목을 추가해도 됩니다. using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace ConsoleApp1 { <span style='color: blue; font-weight: bold'>[Route("api/[controller]")] [ApiController]</span> public class ValuesController : <span style='color: blue; font-weight: bold'>ControllerBase</span> { public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } } } </pre> <br /> 이렇게 추가한 Controller를 서비스하도록 AddControllers 메서드와, 이에 대한 호출 경로를 자동으로 잡아주는 MapControllers를 추가하면 끝입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // Program.cs public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddControllers(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseRouting(); app.UseEndpoints(endpoints => { <span style='color: blue; font-weight: bold'>endpoints.MapControllers();</span> endpoints.MapGet("/", async context => { await context.Response.WriteAsync("Hello World!"); }); }); } } </pre> <br /> 이후 빌드/실행하면 (이 글의 예제 프로젝트에서는) 이제 다음과 같은 경로로 Web API를 호출할 수 있습니다.<br /> <br /> <ul> <li>http://localhost:16000/api/values</li> <li>https://localhost:16002/api/values</li> </ul> <br /> <hr style='width: 50%' /><br /> <br /> 부가적으로, 개발의 편의성을 위한 작업을 하나 더 추가해보겠습니다. 일반적으로, 개발 환경에서는 자세한 오류 메시지를 보여주는 것이 디버깅을 위해서도 좋기 때문에 다음과 같은 코드를 추가할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { <span style='color: blue; font-weight: bold'>if (env.IsDevelopment()) { Console.WriteLine("IsDevelopment"); app.UseDeveloperExceptionPage(); }</span> app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } </pre> <br /> 이후 비주얼 스튜디오에서 실행하면 화면에 "IsDevelopment" 출력을 확인할 수 있습니다. 반면, 빌드 디렉터리로 이동 후 ConsoleApp1.exe를 직접 실행하면 저 문자열이 안 보입니다.<br /> <a name='launchSettings'></a> <br /> 왜냐하면, 비주얼 스튜디오의 경우 실행 시 "Properties" / "launchSettings.json" 파일을 참조해 미리 환경 구성을 하기 때문입니다. 실제로 launchSettings.json 파일을 보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > { "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:15000/", "sslPort": 44338 } }, "profiles": { "<span style='color: blue; font-weight: bold'>IIS Express</span>": { "commandName": "IISExpress", "launchBrowser": true, "environmentVariables": { <span style='color: blue; font-weight: bold'>"ASPNETCORE_ENVIRONMENT": "Development"</span> } }, "<span style='color: blue; font-weight: bold'>ConsoleApp1</span>": { "commandName": "Project", "launchBrowser": true, "environmentVariables": { <span style='color: blue; font-weight: bold'>"ASPNETCORE_ENVIRONMENT": "Development"</span> }, "applicationUrl": "https://localhost:5001;http://localhost:5000" } } } </pre> <br /> 환경 설정 값이 나오는데요, 따라서 ConsoleApp1.exe를 직접 실행하는 경우에도 저 동작을 흉내 내려면 이런 식으로 구동할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp> <span style='color: blue; font-weight: bold'>SET ASPNETCORE_ENVIRONMENT=Development</span> C:\temp> <span style='color: blue; font-weight: bold'>ConsoleApp1.exe</span> <span style='color: blue; font-weight: bold'>IsDevelopment</span> info: Microsoft.Hosting.Lifetime[0] Now listening on: http://[::]:16000 info: Microsoft.Hosting.Lifetime[0] Now listening on: http://[::]:16001 info: Microsoft.Hosting.Lifetime[0] Now listening on: https://[::]:16002 info: Microsoft.Hosting.Lifetime[0] ...[생략]... </pre> <br /> 그리고 이쯤 되면 눈치채셨겠지만, launchSettings.json 파일은 비주얼 스튜디오의 프로파일 설정과 직접적으로 연관됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > .NET Core Kestrel 호스팅 - 비주얼 스튜디오의 Kestrel/IIS Express 프로파일 설정 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/12498'>https://www.sysnet.pe.kr/2/0/12498</a> </pre> <br /> (<a target='tab' href='https://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1720&boardid=331301885'>첨부 파일은 이 글의 예제 코드를 포함</a>합니다.)<br /> <br /> <hr style='width: 50%' /><br /> <br /> 참고로, services.AddControllers(); 코드 없이 endpoints.MapControllers();만 호출하면 다음과 같은 식의 에러를 볼 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > System.InvalidOperationException HResult=0x80131509 Message=Unable to find the required services. Please add all the required services by calling 'IServiceCollection.AddControllers' inside the call to 'ConfigureServices(...)' in the application startup code. Source=Microsoft.AspNetCore.Mvc.Core StackTrace: at Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.EnsureControllerServices(IEndpointRouteBuilder endpoints) in /_/src/Mvc/Mvc.Core/src/Builder/ControllerEndpointRouteBuilderExtensions.cs:line 581 at Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapControllers(IEndpointRouteBuilder endpoints) in /_/src/Mvc/Mvc.Core/src/Builder/ControllerEndpointRouteBuilderExtensions.cs:line 33 at WebApplication3.Startup.<>c.<Configure>b__1_0(IEndpointRouteBuilder endpoints) in C:\temp\ConsoleApp1\Startup.cs:line 34 at Microsoft.AspNetCore.Builder.EndpointRoutingApplicationBuilderExtensions.UseEndpoints(IApplicationBuilder builder, Action`1 configure) in /_/src/Http/Routing/src/Builder/EndpointRoutingApplicationBuilderExtensions.cs:line 99 at WebApplication3.Startup.Configure(IApplicationBuilder app, IWebHostEnvironment env) in C:\temp\ConsoleApp1\Startup.cs:line 32 at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) in /_/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.cs:line 399 at Microsoft.AspNetCore.Hosting.ConfigureBuilder.Invoke(Object instance, IApplicationBuilder builder) in /_/src/Hosting/Hosting/src/Internal/ConfigureBuilder.cs:line 31 at Microsoft.AspNetCore.Hosting.ConfigureBuilder.<>c__DisplayClass4_0.<Build>b__0(IApplicationBuilder builder) in /_/src/Hosting/Hosting/src/Internal/ConfigureBuilder.cs:line 20 ...[생략]... at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host) in /_/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/HostingAbstractionsHostExtensions.cs:line 51 at WebApplication3.Program.Main(String[] args) in C:\temp\ConsoleApp1\Program.cs:line 16 This exception was originally thrown at this call stack: Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.EnsureControllerServices(Microsoft.AspNetCore.Routing.IEndpointRouteBuilder) in ControllerEndpointRouteBuilderExtensions.cs Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapControllers(Microsoft.AspNetCore.Routing.IEndpointRouteBuilder) in ControllerEndpointRouteBuilderExtensions.cs WebApplication3.Startup.Configure.AnonymousMethod__1_0(Microsoft.AspNetCore.Routing.IEndpointRouteBuilder) in Startup.cs Microsoft.AspNetCore.Builder.EndpointRoutingApplicationBuilderExtensions.UseEndpoints(Microsoft.AspNetCore.Builder.IApplicationBuilder, System.Action<Microsoft.AspNetCore.Routing.IEndpointRouteBuilder>) in EndpointRoutingApplicationBuilderExtensions.cs WebApplication3.Startup.Configure(Microsoft.AspNetCore.Builder.IApplicationBuilder, Microsoft.AspNetCore.Hosting.IWebHostEnvironment) in Startup.cs Microsoft.AspNetCore.Hosting.ConfigureBuilder.Invoke(object, Microsoft.AspNetCore.Builder.IApplicationBuilder) in ConfigureBuilder.cs Microsoft.AspNetCore.Hosting.ConfigureBuilder.Build.AnonymousMethod__0(Microsoft.AspNetCore.Builder.IApplicationBuilder) in ConfigureBuilder.cs Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.UseStartup.AnonymousMethod__1(Microsoft.AspNetCore.Builder.IApplicationBuilder) in GenericWebHostBuilder.cs Microsoft.AspNetCore.HostFilteringStartupFilter.Configure.AnonymousMethod__0(Microsoft.AspNetCore.Builder.IApplicationBuilder) in HostFilteringStartupFilter.cs Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(System.Threading.CancellationToken) in GenericWebHostedService.cs ... [Call Stack Truncated] </pre> <br /> <hr style='width: 50%' /><br /> <br /> 그나저나, 황조롱이(Kestrel)가 엄청 귀여운 새군요. ^^<br /> <br /> <blockquote class="twitter-tweet"><p lang="en" dir="ltr">Head stabilisation of the American Kestrel <br><br>📹 Talons and Teeth<br> <a href="https://t.co/Crd28jvA29">pic.twitter.com/Crd28jvA29</a></p>— Science girl (@gunsnrosesgirl3) <a href="https://twitter.com/gunsnrosesgirl3/status/1676958144327712768?ref_src=twsrc%5Etfw">July 6, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1492
(왼쪽의 숫자를 입력해야 합니다.)