Использовать запрос с загрузкой файла в контроллере

Я написал функцию загрузки файлов для своего приложения. В основном приложение представляет собой веб-структуру папок, в которую включены файлы.

Не знаю, но меня это не устраивает. Это слишком долго? Могу я сделать некоторые детали проще? Регистрация в порядке? Так много вопросов … FileModel наследует от ParentModel.

   public ActionResult FileUpload()
        {
            int id = Convert.ToInt32(base.Request.Form["id"]);
            bool isJson = Convert.ToBoolean(base.Request.Form["isJson"]);
            try
            {
                if (id < 1)
                {
                    id = Convert.ToInt32(base.Request.Form["folderId"]);
                }
                if (id < 1)
                {
                    Logging.LogToFile("Could not load " + id ".", 3);
                    base.Response.StatusCode = 500;
                    return Json(new
                    {
                        success = false,
                        errFileUploadMsg = string.Concat(DateTime.Now, " Folder ID ", id, " couldn't load. Please try again.")
                    }, JsonRequestBehavior.AllowGet);
                }
                ParentModel pm = new ParentModel
                {
                    Files = new Files()
                };
                
                Files fm = pm.Files;
                int lastPosition = _mainFolderRepository.GetLastNumberOfFileInFolder(id);
                int position = ((lastPosition.GetType() != typeof(DBNull)) ? (lastPosition + 1) : 0);
                
                for (int i = 0; i < base.Request.Files.Count; i++)
                {
                    HttpPostedFileBase file = base.Request.Files[i];
                    Stream str = base.Request.Files[i].InputStream;
                    BinaryReader br = new BinaryReader(str);
                    byte[] FileBytes = br.ReadBytes((int)str.Length);
                    fm.FullTextSearch = "";
                    fm.File = FileBytes;
                    fm.ContentLength = file.ContentLength;
                    fm.FileName = Path.GetFileName(file.FileName);
                    
                    if (Regex.IsMatch(fm.FileName, "\d+_\d+"))
                    {
                        string[] fileNameSections = Path.GetFileNameWithoutExtension(fm.FileName).Split(' ')[0].Split('_');
                        if (fileNameSections[0].All(char.IsDigit) && fileNameSections[1].All(char.IsDigit))
                        {
                            fm.FileName = fm.FileName.Replace("_", "/");
                        }
                    }
                    
                    if (_mainFolderRepository.IsFileNameInFolder(id, fm.FileName))
                    {
                        int fileIdForChange = _mainFolderRepository.GetFileId(id, fm.FileName);
                        _mainFolderRepository.UpdateFile(fileIdForChange, fm.File, fm.ContentLength);
                    }
                    else
                    {
                        if (!Helper.CheckIfExtensionStringAllowed(Path.GetExtension(file.FileName).ToLower()))
                        {
                            throw new FileFormatException(fm.Extension);
                        }
                        fm.Extension = Path.GetExtension(file.FileName).ToLower();

                        if ((fm.Extension == ".pdf" || fm.Extension == ".doc" || fm.Extension == ".docx") && fm.File.Length != 0)
                        {
                            fm.VolltextSuche = ConverterController.ConvertFileToText(fm.File, fm.FileName, fm.Extension);
                        }
                        _mainFolderRepository.FileUpload(fm.File, fm.ContentLength, fm.FileName, "", "", base.User.Identity.Name, DateTime.Now, isPublic: false, fm.Extension, id, fm.RessortId, position, fm.FullTextSearch, "");
                    }
                    position++;
                }
            }
            catch (FileFormatException ex)
            {
                Logging.LogToFile(ex, 3);
                if (!isJson)
                {
                    base.TempData["Error"] = string.Concat(DateTime.Now, " - Extension ", ex.Message, " not allowed.");
                    return RedirectToAction("Index", "MainFolder");
                }
                base.Response.StatusCode = 500;
                return Json(new
                {
                    success = false,
                    errFileUploadMsg = string.Concat(DateTime.Now, " - Extension ", ex.Message, " not allowed.")
                }, JsonRequestBehavior.AllowGet);
            }
            return RedirectToAction("Index", "MainFolder");
        }

1 ответ
1

  • У метода есть несколько функций смешивания, у него должна быть одна ответственность и более четкая область действия.
  • именование переменных не соответствует соглашению об именах (например, id , fm, str) вы всегда должны выбирать более четкие имена для своих переменных.
  • при синтаксическом анализе или преобразовании типов вы всегда должны проверять их или использовать соответствующие методы преобразования, такие как int.TryParse.
  • всегда работайте с копией источника, не работайте напрямую с источником. это позволит вам избежать большого количества работы и ошибок. как id вы переназначаете это с folderId что сбивает с толку, его следует объявлять отдельно, а затем переключаться между ними.
  • Не использовал using пункт с Disposable объект.
  • ParentModel неправильно используется, вы можете объявить Files без необходимости ParentModel.
  • catch пункт, будет только ловить FileFormatException вам также следует рассмотреть возможность перехвата других исключений, поскольку они не будут перехватывать одно и игнорировать остальные.
  • при работе с Controller ответа, рекомендуется создать метод для повторяющихся действий, чтобы объединить ваши контроллеры и сохранить простоту и управляемость.
  • возврат кода состояния 500 для каждой ошибки не рекомендуется, вы должны вернуть соответствующий код состояния, например, если папка или файл не существует, вы можете вернуть 404 код состояния, если операция не разрешена, используйте 405 код состояния и используйте 500 код для всех неизвестных исключений.
  • Не использовать соответствующий built-in объекты статуса, такие как HttpNotFoundResult ..так далее.
  • Однако вспомогательные методы или расширения очень полезны. Helper.CheckIfExtensionStringAllowed не подскажет где его можно использовать? к каким действиям можно применить? Если это для глобальной области (это означает, что это расширение должно применяться ко всем файлам), то оно должно быть реализовано внутри FileUpload и не используется как Помощник. но если это для текущей области, тогда вам нужно найти более четкое имя или реализовать его в другом месте с более четким именем.

Создайте свой базовый контроллер
используя базу Controller класс в порядке, но иногда вам нужно реализовать абстрактный контроллер Controller Сама по себе эта аннотация будет содержать основные функции, которые будут применяться ко всем контроллерам, чтобы унифицировать вашу работу и сделать ваш код более управляемым.

Например. Скажи это base.Request.Form["id"] вызывается в каждом Action, а также многие действия вернутся Json(). мы можем реализовать что-то вроде:

public abstract class BaseController : Controller 
{
    protected int Id => int.TryParse(base.Request.Form["id"], out int id) && id > 0 ? id : -1;
    
    protected bool IsJson => bool.TryParse(base.Request.Form["isJson"], out bool isJson) && isJson;

    private ActionResult JsonResponse(HttpStatusCode code, int logId, string message, bool isSuccess)
    {
        Logging.LogToFile(message, logId);
        base.Response.StatusCode = (int) code;
        return Json(new
        {
            success = isSuccess,
            errFileUploadMsg = $"{DateTime.Now} {message}";
        }, JsonRequestBehavior.AllowGet);
    }
    
    protected ActionResult JsonSuccess()
    {
        return JsonResponse(HttpStatusCode.OK, logId, "success", true); 
    }
    
    protected ActionResult JsonFailed(HttpStatusCode code, int logId, string message)
    {
        return JsonResponse(code, logId, message, false); 
    }
    
    protected ActionResult JsonInternalServerError(int logId, string message)
    {
        return JsonResponse(HttpStatusCode.InternalServerError, logId, message, false); 
    }
    
    protected ActionResult JsonNotFound(int logId, string message)
    {
        return JsonFailed(HttpStatusCode.NotFound, logId, message);
    }

    protected ActionResult JsonNotAllowed(int logId, string message)
    {
        return JsonFailed(HttpStatusCode.MethodNotAllowed, logId, message);
    }   
}

теперь, если вы унаследуете этот базовый класс, вы можете сделать это:

public class FileController : BaseController
{
    protected int FolderId => int.TryParse(base.Request.Form["folderId"], out int id) && id > 0 ? id : -1;

    protected ActionResult RedirectToMainFolder()
    {
        return RedirectToAction("Index", "MainFolder");
    }
    
    private bool UploadFile(Files file, int folderId, int position)
    {
        // upload file logic
    }

    public ActionResult UploadFiles()
    {
        if(!int.TryParse(base.Request.Form["id"], out int folderId) || folderId < 1)    
        {
            return JsonNotFound(3, $"Could not load Folder ID {folderId}, Please try again.");
        }
        //...
        try
        {
            //... uploading file logic
        
        }
        catch (FileFormatException ex)
        {
            Logging.LogToFile(ex, 3);
            
            var message = $"Extension {ex.Message} not allowed.";
            
            if (!IsJson)
            {
                base.TempData["Error"] = message;
                
                return RedirectToMainFolder();
            }
            
            return JsonNotAllowed(3, message);
        }
        catch(Exception ex)
        {           
            return JsonInternalServerError(3, ex.Message);  
        }
        
        return RedirectToMainFolder();
}

В контроллере MVC уже существует множество методов, которые уже определены для каждого HttpStatusCode, такой как NotFound(), Forbidden ..etc., который вы должны использовать, однако я просто хочу показать вам, как вы можете получить свои собственные результаты, которые помогут вам лучше управлять своими контроллерами.

Для нынешнего UploadFiles Action, вам нужно будет выделить обработку файла в отдельный метод, а затем вызвать его изнутри действия. Что-то вроде этого :

private bool UploadFile(Files file, int folderId, int position)
{
    if(folderId < 1)
    {
        throw new InvalidOperationException("Folder ID {folderId} couldn't load. Please try again.");
    }
    
    if(file.File?.Length == 0)
    {
        throw new ArgumentNullException(nameof(file));
    }
    
    if(!Regex.IsMatch(file.FileName, "\d+_\d+"))
    {
        return false;
    }
    
    string[] fileNameSections = Path.GetFileNameWithoutExtension(file.FileName).Split(' '); 
        
    if(fileNameSections?.Length == 0)
    {
        throw new Exception("File name couldn't be read.");
    }

    var sectionParts = fileNameSections[0].Split('_');
    
    if(sectionParts?.Length >= 2 && sectionParts[0].All(char.IsDigit) && sectionParts[1].All(char.IsDigit))
    {
        file.FileName = file.FileName.Replace("_", "/");
    }
    
    if (_mainFolderRepository.IsFileNameInFolder(folderId, file.FileName))
    {
        int fileIdForChange = _mainFolderRepository.GetFileId(folderId, file.FileName);

        _mainFolderRepository.UpdateFile(fileIdForChange, file.File, file.ContentLength);
    }
    else
    {
        if (!Helper.CheckIfExtensionStringAllowed(Path.GetExtension(file.FileName).ToLower()))
        {
            throw new FileFormatException(file.Extension);
        }
        
        fm.Extension = Path.GetExtension(file.FileName).ToLower();

        if ((file.Extension == ".pdf" || file.Extension == ".doc" || file.Extension == ".docx") && file.File.Length != 0)
        {
            file.VolltextSuche = ConverterController.ConvertFileToText(file.File, file.FileName, file.Extension);
        }
        
        _mainFolderRepository.FileUpload(file.File, file.ContentLength, file.FileName, "", "", base.User.Identity.Name, DateTime.Now, isPublic: false, file.Extension, id, file.RessortId, position, file.FullTextSearch, "");
    }           
    
    return true;
}

public ActionResult UploadFiles()
{
    if(FolderId < 1)    
    {
        return JsonNotFound(3, $"Could not load Folder ID {FolderId}, Please try again.");
    }
    
    try
    {
        Files fileModel = new Files();

        int lastPosition = _mainFolderRepository.GetLastNumberOfFileInFolder(id);
        
        int position = ((lastPosition.GetType() != typeof(DBNull)) ? (lastPosition + 1) : 0);
        
        for (int i = 0; i < base.Request.Files.Count; i++)
        {
            HttpPostedFileBase file = base.Request.Files[i];
            
            int fileLength = file.InputStream.Length;
            
            byte[] fileBytes = new byte[fileLength];
            
            using(var stream = new Stream(file.InputStream))            
            {
                stream.Seek(0 , SeekOrigin.Begin);
                stream.Read(fileBytes , 0 , (int) stream.Length);
            }

            fileModel.FullTextSearch = "";
            fileModel.File = fileBytes;
            fileModel.ContentLength = file.ContentLength;
            fileModel.FileName = Path.GetFileName(file.FileName);
            
            var isSuccess = UploadFile(fileModel, FolderId, position++);
            
            if(!isSuccess)
            {
                // do something 
            }
        }
    }
    catch (FileFormatException ex)
    {
        Logging.LogToFile(ex, 3);
        
        var message = $"Extension {ex.Message} not allowed.";
        
        if (!IsJson)
        {
            base.TempData["Error"] = message;
            
            return RedirectToMainFolder();
        }
        
        return JsonNotAllowed(3, message);
    }
    catch(Exception ex)
    {           
        return JsonInternalServerError(3, ex.Message);  
    }
    
    return RedirectToMainFolder();
}

Это просто демонстрация вышеперечисленных пунктов, вам следует сосредоточиться на очистке кода, разделении его на фрагменты в зависимости от роли и ответственности, использовать другие принципы OPP, такие как наследование, для лучшего восприятия кода. Кроме того, используйте уже существующие функции, которые поставлялись с .NET.

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *