Razor pages - file dialog się nie pokazuje

0

Witam,

przed chwilą przypadkowo usunąłem ten temat, więc zakładam drugi raz.
Mam taki problem, mianowicie w mojej apce mam 2 typy plików dla użytkownika - pdf i doc, które są trzymane na dysku sieciowym.
Do pdf'a używam prostego hrefa, natomiast chciałbym aby użytkownik miał możliwość ściągnięcia plików .doc.
Tak więc lokalnie wyciągnąłem sobie ścieżkę do pulpitu i działa, natomiast problem mam po opublikowaniu na serwerze - wtedy wyciąganie SpecialFolderu nie za bardzo śmiga i nie mam jak zapisać u kogoś na kompie pliku, dlatego myślałem o file dialogu.
Na necie wyczytałem, że trzeba dodać header do responsa (content-disposition i ustawić attachment), ale niestety nie działa - w sensie nie ma żadnych błędów, ale file dialog też się nie pokazuje.
Kod:

HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync(path);
response.Content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse(MimeMapping.KnownMimeTypes.Docx);
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment") { FileName = filename };
response.EnsureSuccessStatusCode();

using (FileStream fileStream = new FileStream(localFilename, FileMode.Create))
{
    await response.Content.CopyToAsync(fileStream);
}

Generalnie mój dialog się nie pokazuje, bo nawet nie potrafię go stworzyć. Do tej pory korzystałem z <input type="file" />, ale korzystałem z tego do uploadowania plików, ale nie wiem jak mam korzystać z tego przy próbie wyciągnięcia od usera folderu, do którego plik ma się zapisać?

0

Co tu się w ogóle dzieje w kodzie? Tworzysz klienta HTTP po czym zachowujesz się jak serwer i do odpowiedzi z serwera dodajesz własną treść i nagłówki? Coś tu jest strasznie pomieszane. To serwer ma odpowiedzieć tym nagłówkiem do przeglądarki.

0

W najprostszym sposobie w akcji pagea robisz:

public ActionResult OnPostDownloadFile()
{
    return File("/DownloadableFiles/TestFile34.csv", "application/octet-stream", "NewName34.csv");
}

oraz

<button type="submit" asp-page-handler="DownloadFile" style="width:75px" class="cancel"> Download </button>

src: https://stackoverflow.com/questions/48952832/download-file-to-browser-using-net-core-razor-pages

W sensowniejszym podejściu byś sobie wydelegował jakiś serwis, który wykona różne dodatkowe bajery typu sprawdzenie uprawnień itd. i zwróci byte[] i wykorzysta inny overload File()

Zerknij na: Security considerations

0

ja się dopiero uczę, ale po sesji googlowania zrobiłem w swoim kodzie coś takiego:
Views:

<div class="form-group">
                    <label><strong>Ścieżka do avatara:</strong></label>
                    <div class="custom-file">
                        <input asp-for="@Model.Avatar" class="custom-file-input" id="customFile">
                        <label class="custom-file-label" for="customFile">Wybierz plik .png</label>
                    </div>
                    <span asp-validation-for="@Model.Avatar" class="text-danger"></span>
                </div>

JS in View

<script type="text/javascript">
        // Add the following code if you want the name of the file appear on select
        $(".custom-file-input").on("change", function () {
            var fileName = $(this).val().split("\\").pop();
            $(this).siblings(".custom-file-label").addClass("selected").html(fileName);
        });
    </script>   

DisplayRoomsModel:

...
[Required(ErrorMessage = "Wybierz ścieżkę do obrazu")]
public IFormFile Avatar { get; set; }
...

Service:

public string UploadRoomImage(DisplayRooms Model, Guid guid)
        {
            string uniqueFileName = string.Empty;

            if (Model.Avatar != null)
            {
                string uploadsFolder = Path.Combine(_webHostEnvironment.WebRootPath, "Rooms/Images");
                uniqueFileName = guid.ToString() + "_" + Model.Avatar.FileName;
                string filePath = Path.Combine(uploadsFolder, uniqueFileName);
                using (var fileStream = new FileStream(filePath, FileMode.Create))
                {
                    Model.Avatar.CopyTo(fileStream);
                }
            }
            return uniqueFileName;
        }

In Controller:

string FileName = _roomService.UploadRoomImage(Model, room.ID);
                    if (string.IsNullOrEmpty(FileName))
                    {
                        ModelState.AddModelError("Avatar", "Nie udało się wysłać zdjęcia");
                        return View("DisplayRooms", Model);
                    }
                    room.Avatar = FileName;
                    await _roomService.Create(room);

Jeżeli to działa ale nie jest zrobione jak trzeba proszę mnie poprawić :) działa dla każdego plik z dowolnej lokalizacji

0

@gswidwa1:

a po co Ci to?

+ "_" + Model.Avatar.FileName;

0

@gswidwa1:

var guid = Guid.NewGuid().ToString();
Console.WriteLine(Path.Combine(guid, @"\..\..\..\secret_folder\passwords.txt"));

wynik

\..\..\..\secret_folder\passwords.txt

Generalnie w nazwy plików / ścieżki nie wrzuca się NIC od usera. Takie rzeczy zapisuje się np. w bazie :P

1

@gswidwa1:

Security considerations

Use a safe file name determined by the app. Don't use a file name provided by the user or the untrusted file name of the uploaded file. HTML encode the untrusted file name when displaying it. For example, logging the file name or displaying in UI (Razor automatically HTML encodes output).

1 użytkowników online, w tym zalogowanych: 0, gości: 1