asp.net mvc upload wielu plików

Odpowiedz Nowy wątek
2016-12-13 13:59

Rejestracja: 10 lat temu

Ostatnio: 1 rok temu

0

Witam,

Temat wydawał mi się prosty. Ale utknąłem i mimo, że przeczytałem "całe Internety" nie znalazłem rozwiązania.

W ASP.NET MVC mam formularz z jakimiś danymi, w którym ma być przesłane także klika plików. Ilość plików nie jest określona.

Poszukuję jakiegoś "ładnego" rozwiązania. Próbowałem wykorzystać jQuery File Upload https://github.com/blueimp/jQuery-File-Upload. Próbowałem plupload http://www.plupload.com/. Ale nic z tego nie wyszło. Dostaję jakieś dziwne błędy po stronie skryptów js. Także próbowałem wykorzystać PluploadMvc. Jednak przykłady są tylko dla pojedynczych plików.

Oczywiście znam <input multiple="multiple"> ale to nie rozwiązuje mojego problemu. Nie widać listy załączonych plików a drugie kliknięcie powoduje usunięcie wcześniej dodanych plików.

Wracając do tematu. Widzę dwa rozwiązania.

  1. Przesyłam pliki pojedynczo za pomocą ajax.
    Tu pojawia się problem. Jak powiązać zapisane na serwerze pliki z danymi z formularza? Bo rozumiem, że najpierw przesyłane są pliki i gdzieś tam je sobie zapisuję. Po zapisie musiałbym gdzieś zaktualizować informacje o tych plikach. Gdzie to zrobić? w TempData? W Session? A może za pomocą partial view przekazać je z powrotem do formularza? Ta opcja by się przydała aby pokazać klientowi jakie pliki zostały przesłane. Można by ją także wykorzystać do umożliwienia klientowi usunięcia pliku.
    A co w przypadku gdy klient nie zapisze formularza? Pliki pozostaną "bezpańskie" na serwerze.

  2. Szukam pluginu do przesyłania plików zbiorowo.
    Nie ukrywam, że wolałbym tą opcję aby razem z przesłanym formularzem otrzymać pliki.
    Może szanowni forumowicze mają jakieś rozwiązanie? Coś w stylu plupload?

1. Jak to bezpańskie, chyba ty masz kontrolę nad tym co znajduje się na serwerze i sam decydujesz czy przypinasz te pliki do użytkownika czy tylko do sesji użytkownika, jak sesja znika kasujesz także dane 2. To jest HTML, jak brakuje Ci kontrolki która działa tak jak potrzebujesz to możesz ją chyba sam zrobić bazując na standardach sieciowych. - mr-owl 2016-12-13 15:56
Jak sprawdzić, kiedy sesja znika? Możesz mi podać przykładowy kod? - TolkWimasz 2016-12-14 10:00

Pozostało 580 znaków

dotnerd
2016-12-13 16:14
dotnerd
0

Ja bym zrobił tak:

1) Podczas otwierania formularza (przed wyrenderowaniem widoku) dodajesz do bazy wpis o tym formularzu (tabela form_info) gdzie masz Id, Nazwę użytkownika i co tam jeszcze chcesz,
2) W ViewModelu zwracasz id nowo dodanego rekordu form_info,
3) Podczas przesyłania pliku AJAX'em przesyłasz również id form_info (które otrzymałeś w ViewModelu). Po zapisaniu pliku na dysku bierzesz jego nazwą i wrzucasz do tabeli file_info która jest w relacji 1-N do form_info.

Plusem tego rozwiązania jest fakt, że po wywaleniu się aplikacji, połączenia użytkownik może do niego wrócić i nie musi znowu przesyłać plików oraz masz od razu listę przesłanych i skojarzonych z użytkownikiem plików.

Pozostało 580 znaków

2016-12-14 10:51

Rejestracja: 10 lat temu

Ostatnio: 1 rok temu

1

Znalazłem w końcu rozwiązanie. Nie wiem czy poprawne. Opiszę je dla "potomności" :) i w celu weryfikacji przez szanownych forumowiczów.

1. W Gloabal.asax.cs dodaję

protected void Session_Start(Object sender, EventArgs e)
        {
            Session["init"] = 0;
        }

Umożliwia mi to pobranie dla każdej sesji unikatowego ID: Session.SessionID

2. Wykorzystałem plugin plupload. Ale nie pobrałem go z oryginalnej strony tylko z https://github.com/RickStrahl/Westwind.plUploadHandler
Potrzebne są następujące plik Java Script:

  • plupload.full.js
  • plupload.full.mini.js
  • jquery.plupload.quote.js
  • jquery.plupload.quote.mini.js

Oraz plik css:

  • jquery.plupload.quote.css

3. Do formularza dodaję

        <div id="uploader">
            <p>Your browser doesn't have Flash, Silverlight or HTML5 support.</p>
        </div>

4. Do mojego pliku java script dodaję funkcję obsługującą plugin plupload:

$("#uploader").pluploadQueue({
        runtimes: 'html5,silverlight,flash,html4',
        url: 'home/upload',
        max_file_size: '10mb',
        chunk_size: '1mb',
        unique_names: false,
        filters: [
            { title: "Images", extensions: "jpg,jpeg,bmp,gif,png" },
            { title: "Archives", extensions: "zip,rar,7z,tar,tg" },           
        ],
        rename: true,
        flash_swf_url: '/js/plupload.flash.swf',
        silverlight_xap_url: '/js/plupload.silverlight.xap',
        preinit: {
            Init: function() {
                $('#uploader_container').removeAttr("title");
            }
        }
    });

5. oraz funkcję wysyłającą pliki przed przesłaniem formularza (Nie jestem pewny tej funkcji, ale działa):

$("#form-complaint").submit(function(event)
    {
        var uploader = $('#uploader').pluploadQueue();
        if (uploader.files.length > 0) {            
            uploader.bind('StateChanged', function() {
                if (uploader.files.length === (uploader.total.uploaded + uploader.total.failed)) {
                    $(this).submit();
                }
            });
            uploader.start();
            return true;
        }
        else {
           // $(this).submit();
            return true;
        }    
        return false;
    });

6. No i pozostaje utworzenie metody w kontrolerze do pobierania plików. Metoda ta zostaje wywołana oddzielnie dla każdego przesłanego pliku. Kod javascript prześle najpierw pliki a później dane z formularza.

 [HttpPost]
        public ActionResult Upload(int? chunk, string name)
        {
            var session = Session.SessionID;
            var fileUpload = Request.Files[0];            
            var uploadPath = Server.MapPath("~/App_Data/"+session);
            if (!Directory.Exists(uploadPath))
                Directory.CreateDirectory(uploadPath);
            chunk = chunk ?? 0;

            string uploadedFilePath = Path.Combine(uploadPath, name);
            using (var fs = new FileStream(uploadedFilePath, chunk == 0 ? FileMode.Create : FileMode.Append))
            {
                var buffer = new byte[fileUpload.InputStream.Length];
                fileUpload.InputStream.Read(buffer, 0, buffer.Length);
                fs.Write(buffer, 0, buffer.Length);
            }

            return Content("Success", "text/plain");
        }

7. W metodzie odbioru danych z formularza wykorzystuję Session.SessionID. Jest ono takie samo jak poprzednie z metody Upload.
Wydaje mi się, że to rozwiązanie działa. Zastanawiam się tylko czy jest prawidłowe. Czy jednak nie powinienem dla każdej sesji wstawiać np. do Session["MojUnikatowyId"] = coś_unikatowego i z tego korzystać w metodzie Upload oraz metodzie odbioru danych z formularza.

8. Warto także dodać do pliku css ukrycie przycisku Send files z pluginu plupload:

.plupload_button.plupload_start {
    display: none!important;
}

Oczywiście jeszcze pozostaje kwestia powiązania danych z formularza z plikami. Ale one są już w folderze o unikatowej (mam nadzieję) nazwie, którą mogę przekazać do procedury zapisującej dane z formularza.

Proszę szanownych forumowiczów o komentarze czy to rozwiązanie jest prawidłowe.

Pozostało 580 znaków

Odpowiedz

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