Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (seongtaejeong at gmail.com)
홈페이지
첨부 파일
 

C# - Blazor의 razor 페이지에서 code-behind 파일로 코드를 분리 및 DI 사용법

Blazor 프로젝트를 생성하면 기본적으로 Counter 페이지 예제가 제공되는데요,

@page "/counter"
@rendermode InteractiveServer

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

혹시 저기서 @code 블록을 별도의 C# 코드 파일로 분리할 수 있지 않을까요? 검색해 보니 바로 방법이 나옵니다. ^^;

How to split Blazor WASM components code of C# and HTML in different files? [duplicate]
; https://stackoverflow.com/questions/59934099/how-to-split-blazor-wasm-components-code-of-c-sharp-and-html-in-different-files

정리하면, 2가지 방법으로 나뉘는데요, 첫 번째 방법은 상속을 이용해 분리하는 것입니다. 예를 들면, 코드 파일을 하나 추가해 ComponentBase를 상속받는 클래스를 만들어 그 안에 C# 코드를 분리하는데,

using Microsoft.AspNetCore.Components;

namespace BlazorWebAppServerPerPage8.Components.Pages;

public class HomeComponent : ComponentBase
{
    protected int currentCount = 0;

    protected void IncrementCount()
    {
        currentCount++;
    }
}

이때 razor 페이지에서 사용할 멤버에 대해서는 "protected"로 선언해야 합니다. 왜냐하면, razor 페이지에서는 아래와 같이 "@inherits"를 사용해 상속으로 처리하기 때문입니다.

@page "/counter"
@inherits MyComponent
@rendermode InteractiveServer

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

두 번째 방법은 partial 클래스를 이용하는 것인데요, 역시 마찬가지로 C# 코드 파일을 추가한 다음 이번에는 단순히 Razor 페이지 파일명과 동일하게 partial class를 하나 만들어 분리하면 됩니다.

namespace BlazorApp1.Components.Pages;

public partial class Counter
{
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

대신 이번에는 partial class의 특성 덕분에 굳이 protected 접근자로 변경해야 할 필요가 없습니다.




그나저나, 굳이 코드 파일을 분리할 필요가 있을까요? 물론, 코드가 길어지면 가독성을 높이기 위해 분리하는 것이 좋겠습니다. 그 외에도 Visual Studio로 다른 PC에서 디버깅하기 위해 attach to process로 연결할 때 코드 파일이 분리돼 있어야 BP(Breakpoint)가 제대로 동작하는 경우도 있으니 참고하시기 바랍니다. ^^

마지막으로, razor 페이지와 code-behind 파일을 분리했으면 그룹핑시켜 두는 것도 관리 측면에서 도움이 될 것입니다. ^^

Visual Studio - Code-behind처럼 cs 파일을 그룹핑하는 방법
; https://www.sysnet.pe.kr/2/0/13886




razor 구문의 경우 "@inject"를 이용하면 쉽게 Dependency Injection가 가능합니다.

@page "/counter"
@inject IConfiguration Configuration
@rendermode InteractiveServer

<PageTitle>Counter</PageTitle>

<p>Configuration value: @Configuration.GetConnectionString("db")</p>

그렇다면 코드 파일로 분리한 경우에는 어떻게 해야 할까요? 이에 대해서는 아래의 문서에서 자세히 설명하고 있는데요,

ASP.NET Core Blazor dependency injection
; https://learn.microsoft.com/en-us/aspnet/core/blazor/fundamentals/dependency-injection

간단하게는 InjectAttribute를 통해 가능한데, 아래는 partial class에서의 사용법을 보여줍니다.

public partial class Counter
{
    protected int currentCount = 0;

    [Inject]
    private IConfiguration _configuration { get; set; } = default!;

    public Counter()
    {
        // 생성자 단계에서는 Injection이 되지 않아 사용할 수 없지만,
        System.Diagnostics.Trace.WriteLine($"IConfiguration _configuration == {(_configuration == null ? "(null)" : $"{_configuration}")}");
    }

    protected async Task IncrementCount()
    {
        // 개체 생성 후의 단계에서는 Injection이 되어 사용할 수 있습니다.
        System.Diagnostics.Trace.WriteLine($"IConfiguration _configuration == {(_configuration == null ? "(null)" : $"{_configuration}")}");

        currentCount++;
    }
}

또는, (partial class로 정의했기 때문에) razor에서 "@inject IConfiguration Configuration"를 추가하고,

@page "/counter"
@inject IConfiguration Configuration
@rendermode InteractiveServer

...[생략]...

이것을 그냥 바로 가져다 사용하는 것도 가능합니다.

public partial class Counter
{
    protected int currentCount = 0;

    protected async Task IncrementCount()
    {
        string cs = this.Configuration.GetConnectionString("testdb");
        currentCount++;
    }
}

(물론, partial class가 아닌 상속으로 처리한 코드 파일이라면 razor에서 정의한 DI 인스턴스를 코드에서 쓸 수는 없습니다.)

그런데, 문서상으로 좀 이상한 것이 있는데요, 아래의 링크를 보면,

Constructor injection
; https://learn.microsoft.com/en-us/aspnet/core/blazor/fundamentals/dependency-injection

Primary Constructor 구문을 이용한 Constructor injection 예제를 소개하고 있습니다.

@page "/constructor-injection"

<button @onclick="HandleClick">
    Take me to the Counter component
</button>

using Microsoft.AspNetCore.Components;

public partial class ConstructorInjection(IConfiguration configuration)
{
    protected int currentCount = 0;

    protected void IncrementCount()
    {
        currentCount++;
        string text = configuration.GetConnectionString("BloggingDatabase") ?? "(null)";
        System.Diagnostics.Trace.WriteLine(text);
    }
}

그런데, 실제로 저 코드를 실행해 보면 이런 예외가 발생합니다.

MissingMethodException: Cannot dynamically create an instance of type 'BlazorWebAppServerTest.Components.Pages.Counter'. Reason: No parameterless constructor defined.

혹시 제가 뭔가 놓친 것이 있나요? 아시는 분은 덧글 부탁드립니다. ^^




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 3/27/2025]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




1  2  3  [4]  5  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13878정성태2/3/20255237오류 유형: 945. Windows - 최대 절전 모드 시 DRIVER_POWER_STATE_FAILURE 발생 (pacer.sys)
13877정성태1/25/20254473닷넷: 2315. C# - PCI 장치 열거 (레지스트리, SetupAPI)파일 다운로드1
13876정성태1/25/20255520닷넷: 2314. C# - ProcessStartInfo 타입의 Arguments와 ArgumentList파일 다운로드1
13875정성태1/24/20254079스크립트: 69. 파이썬 - multiprocessing 패키지의 spawn 모드로 동작하는 uvicorn의 workers
13874정성태1/24/20255302스크립트: 68. 파이썬 - multiprocessing Pool의 기본 프로세스 시작 모드(spawn, fork)
13873정성태1/23/20253929디버깅 기술: 217. WinDbg - PCI 장치 열거파일 다운로드1
13872정성태1/23/20253538오류 유형: 944. WinDbg - 원격 커널 디버깅이 연결은 되지만 Break (Ctrl + Break) 키를 눌러도 멈추지 않는 현상
13871정성태1/22/20254044Windows: 278. Windows - 윈도우를 다른 모니터 화면으로 이동시키는 단축키 (Window + Shift + 화살표)
13870정성태1/18/20254923개발 환경 구성: 741. WinDbg - 네트워크 커널 디버깅이 가능한 NIC 카드 지원 확대
13869정성태1/18/20254246개발 환경 구성: 740. WinDbg - _NT_SYMBOL_PATH 환경 변수에 설정한 경로로 심벌 파일을 다운로드하지 않는 경우
13868정성태1/17/20253882Windows: 277. Hyper-V - Windows 11 VM의 Enhanced Session 모드로 로그인을 할 수 없는 문제
13867정성태1/17/20255373오류 유형: 943. Hyper-V에 Windows 11 설치 시 "This PC doesn't currently meet Windows 11 system requirements" 오류
13866정성태1/16/20255601개발 환경 구성: 739. Windows 10부터 바뀐 device driver 서명 방법
13865정성태1/15/20255145오류 유형: 942. C# - .NET Framework 4.5.2 이하의 버전에서 HttpWebRequest로 https 호출 시 "System.Net.WebException" 예외 발생
13864정성태1/15/20255150Linux: 114. eBPF를 위해 필요한 SELinux 보안 정책
13863정성태1/14/20254063Linux: 113. Linux - 프로세스를 위한 전용 SELinux 보안 문맥 지정
13862정성태1/13/20254564Linux: 112. Linux - 데몬을 위한 SELinux 보안 정책 설정
13861정성태1/11/20254678Windows: 276. 명령행에서 원격 서비스를 동기/비동기로 시작/중지
13860정성태1/10/20254334디버깅 기술: 216. WinDbg - 2가지 유형의 식 평가 방법(MASM, C++)
13859정성태1/9/20255074디버깅 기술: 215. Windbg - syscall 이후 실행되는 KiSystemCall64 함수 및 SSDT 디버깅
13858정성태1/8/20255112개발 환경 구성: 738. PowerShell - 원격 호출 시 "powershell.exe"가 아닌 "pwsh.exe" 환경으로 명령어를 실행하는 방법
13857정성태1/7/20255377C/C++: 187. Golang - 콘솔 응용 프로그램을 Linux 데몬 서비스를 지원하도록 변경파일 다운로드1
13856정성태1/6/20254309디버깅 기술: 214. Windbg - syscall 단계까지의 Win32 API 호출 (예: Sleep)
13855정성태12/28/20245938오류 유형: 941. Golang - os.StartProcess() 사용 시 오류 정리
13854정성태12/27/20245827C/C++: 186. Golang - 콘솔 응용 프로그램을 NT 서비스를 지원하도록 변경파일 다운로드1
13853정성태12/26/20244765디버깅 기술: 213. Windbg - swapgs 명령어와 (Ring 0 커널 모드의) FS, GS Segment 레지스터
1  2  3  [4]  5  6  7  8  9  10  11  12  13  14  15  ...