Blazor wasm 를 테스트 해보고 있습니다. 파일 업로드를 위해 InputFile과 OnChange 이벤트를 이용해서 서버로 파일 업로드를 아래와 같이 구현 했습니다.
<InputFile OnChange="@OnChooseFile"/>
...중략...
private async void OnChooseFile(InputFileChangeEventArgs e)
{
Console.WriteLine($"file info : {e.File.Name} , {e.File.Size}");
using (var filestream = e.File.OpenReadStream(1024 * 300 * 1000))
{
var url = GetApiUrl("/upload/bigfiletest");
var httpclient = new HttpClient();
httpclient.DefaultRequestHeaders.Add("filename" , e.File.Name);
var r = await httpclient.PostAsync(url, new StreamContent(filestream));
if (r.IsSuccessStatusCode == false)
{
var raw = await r.Content.ReadAsStringAsync();
}
else
{
var raw = await r.Content.ReadAsStringAsync();
}
}
}
결과적으로는 잘 업로드 되나, 한가지 개운하지 못한 점은 큰 파일을 업로드 하게 되면 문제를 확인 할 수 있는데, e.File.OpenStream 에서 파일 전체 bytes를 다 읽고 나서 Post 하는것 처럼 보입니다.
이렇게 생각하는 이유는 Postman, Javascript 의 fetch, 별도의 Console 프로젝트 위에 HttpClient 를 이용해서 동일한 파일을 업로드 하게 되면 Post 하자마자 거의 시간차 없이 서버가 반응 하는것을 확인 했습니다만 위의 코드 처럼 e.File.OpenStream 을 이용하면 프로시져가 시작된 한~참 뒤에 서버가 반응 하는것을 확인 했습니다.
질문
혹시 Blazor 의 InputFile 의 내부적인 동작을 설명 해주실 분이 있으실지요 ?
혹은 문제 상황 처럼 메모리에 모두 적제 한뒤 서버로 Post 하지 않고, 서버로 업로드 할 방법이 있을까요?
(사실 불필요 하게 메모리에 적재 하지 않기 위해 OpenStream 을 이용한건데, 뜻대로 동작하지 않네요)
(Javascript 에 익숙치 못해 군데 군데 console log 가 있네요 )
주요 아이디어는 input 컨트롤을 만들고, 이것의 모양이 지금 적용하고 있는 스타일 (Fluent) 와 어울리지 않기에, 숨김 처리 (display:none) 하고, 별도의 버튼을 클릭 하면 숨겼던 input을 강제로 클릭 (fileinput.click()) 시켜 파일 브라우져를 엽니다.
이후 change 이벤트에서 일상(?) 적으로 fetch를 수행 하여 파일을 업로드 합니다.
이러한 방법은 c# 을 이용하여 스트림을 얻어 대용량 파일도 클라이언트 메모리 적제 없이 첫번째 패킷부터 서버에 곧바로 업로드 됩니다 (아시는것 처럼 )
일전에 razor 를 사용할때 항상 js 파일을 별도로 만들어 그것을 JSRuntime 으로 로드 하여 사용 하였는데, 이렇게 간편하게 razor 안에서도 를 사용 할 수 있는지는 이번에 알게 되었네요. 간단한 코드는 이 방법이 한결 더 간편 한것 같습니다.
출처
InputFile 이 어떻게 동작하는지에 대한 한가지 단서로 위의 문구를 MSDN에서 발견 하였습니다.
어줍잖은 지식으로 뇌피셜 해보면 c# 레벨에서 브라우져를 통해 획득한 데이터 활용을 위해, 스트림을 호출 하면 모든 byte를 base64로 바꾼 후 다시 이것을 활용 하는것이 아닐까 하는 생각 입니다. 때문에 어디 서버로 다시 POST 하려면 또 한번 더 시간이 걸리는 것 아닐까 하는 아이디어 입니다.