Загрузка и просмотр файлов ASP.NET MVC 5

У меня есть этот код:

    [HttpPost]
    public ActionResult Create(Knowledgebase KB, HttpPostedFileBase file)
    {
        var KBFilePath = "";
        if (ModelState.IsValid)
        {
            if (file.ContentLength > 0)
            {
                var fileName = Path.GetFileName(KB.KnowledgebaseTitle);
                var path = Path.Combine(Server.MapPath("~/Resources/KBArticles"), fileName + ".pdf");
                KBFilePath = path;
                file.SaveAs(path);
            }
            KB.KnowledgebaseLink = KBFilePath;
            db.Knowledgebases.Add(KB);
            db.SaveChanges();
            return RedirectToAction("Index", "Home");
        }

        else
        {
            return View();
        }

Ссылка - это путь к файлу, который хранится в БД, который начинается с C:/

На другой странице я могу просмотреть содержимое записи. Когда я нажимаю ссылку, на которую она была сохранена на C:/, Chrome говорит: "Не удалось загрузить локальный ресурс". Я сохраняю в папке Ресурсы, которая является частью моего каталога приложений ASP.NET. Во всяком случае, вокруг этого?

ИЗМЕНИТЬ Страница открывается из этого представления:

public ActionResult Suggestions(String Tag)
{
      return View();
}

ИЗМЕНИТЬ 2 - Я ввел изменения в свое мнение:

@{
string tag = "<td><a href=" + "~/Content/Files/" + ">" + item.Title.Replace(" ", "") + ".pdf" + "</a>" + "</td>";
 }
 @Html.Raw(tag)

Запрошенный файл в адресной строке браузера

http://localhost:62165/Incident/~/Content/Files/

Теперь я получаю ошибку HTTP Error 404.0 Not Found

Ответ 1

Попробуйте сохранить файлы в папке "Содержимое". Вы можете создать подпапку Content/Files. Поместите туда файлы. Затем создайте ссылки как:

<a href="~/Content/Files/file1.pdf">File1</a>

или используйте атрибут загрузки, если вы хотите напрямую загрузить:

<a href="~/Content/Files/file1.pdf" download>File1</a>.

Большинство веб-серверов настроены на отклонение запросов на контент вне папки содержимого. Это можно изменить в файле конфигурации, но проще (и безопаснее), если вы используете папку содержимого. Это основано на моем опыте, если кто-то подумает, что я не прав, сообщите мне, чтобы исправить мой ответ. Я всегда рад узнать что-то новое.

РЕДАКТИРОВАТЬ 1: Как динамически построить тег a

В представлении вам понадобится строковая переменная link, которая содержит текст ссылки, которую вы хотите показать, и другую переменную path для хранения пути (возможно, оба они загружаются из db в контроллере). Затем вы можете создать тег вручную следующим образом:

@{
    string tag = "<a href=" + path + ">" + link + "</a>";
}

@Html.Raw(tag)

РЕДАКТИРОВАТЬ 2: Работа с пробелами в URL.

Вам нужно использовать Html.Content, чтобы получить правильный относительный Url.

@{
    string link = item.Title;
    string path = Url.Content("~/Content/Files/") + link.Replace(" ", "%20") + ".pdf";
    string tag = "<a href=" + path + ">" + link + "</a>";
}

@Html.Raw(tag)

Ответ 2

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

Создайте пустой MVC-проект. Я использую MVC 4, но он должен работать с MVC 5.

Контроллер:

В HomeController у нас будет одно действие Index, в котором будет отображаться список файлов, доступных для загрузки, и возможность загрузки новых файлов.

Действие Index GET:

  • Найдите путь к "Контент/Файлы/".
  • Получить список всех файлов в этой папке.
  • Используйте этот список в качестве модели представления Index.

Действие Index POST:

  • Найдите путь к "Контент/Файлы/".
  • Создайте временный массив для хранения содержимого файла.
  • Прочитайте содержимое в буфере.
  • Введите содержимое в файл в папке "Содержимое/Файлы/".

код:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var path = Server.MapPath("~/Content/Files/");

        var dir = new DirectoryInfo(path);

        var files = dir.EnumerateFiles().Select(f => f.Name);

        return View(files);
    }

    [HttpPost]
    public ActionResult Index(HttpPostedFileBase file)
    {
        var path = Path.Combine(Server.MapPath("~/Content/Files/"), file.FileName);

        var data = new byte[file.ContentLength];
        file.InputStream.Read(data, 0, file.ContentLength);

        using (var sw = new FileStream(path, FileMode.Create))
        {
            sw.Write(data, 0, data.Length);
        }

        return RedirectToAction("Index");
    }

}

Вид:

В представлении нам нужно сгенерировать список со ссылками на файлы. Здесь нам нужно позаботиться о именах файлов, содержащих пробелы, и заменить их на "%20".

Форма для загрузки файла проста. Просто введите тег, чтобы получить файл и одну кнопку, чтобы отправить форму.

@model IEnumerable<string>

@{
    ViewBag.Title = "Index";
}

<h2>Files</h2>

<ul>
    @foreach (var fName in Model)
    {
        var name = fName;
        var link = @Url.Content("~/Content/Files/") + name.Replace(" ", "%20");

        <li>
            <a href="@link">@name</a>
        </li>
    }
</ul>

<div>
    @using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
    {
        <input type="File" name="file" id="file" value="Choose File"/>
        <button type="submit">Upload</button>
    }
</div>

Результат должен быть:

Index view

Ответ 3

Сначала создайте представление <

<div class="form-group"> @Html.LabelFor(model => model.ImageData, new { @class = "control-label col-md-2" }) 
  <div class="col-md-10"> <input name="Image" type="file" /> 
    @Html.ValidationMessageFor(model => model.ImageData) 
  </div> 
</div>

Затем контроллер Create Action

public ActionResult Create(ArtWork artwork, HttpPostedFileBase image) { 
  if (ModelState.IsValid) { 
    if (image != null) { //attach the uploaded image to the object before saving to Database 
      artwork.ImageMimeType = image.ContentLength; 
      artwork.ImageData = new byte[image.ContentLength]; 
      image.InputStream.Read(artwork.ImageData, 0, image.ContentLength); //Save image to file 
      var filename = image.FileName; 
      var filePathOriginal = Server.MapPath("/Content/Uploads/Originals"); 
      var filePathThumbnail = Server.MapPath("/Content/Uploads/Thumbnails"); 
      string savedFileName = Path.Combine(filePathOriginal, filename); 
      image.SaveAs(savedFileName); //Read image back from file and create thumbnail from it 
      var imageFile = Path.Combine(Server.MapPath("~/Content/Uploads/Originals"), filename); 

      using (var srcImage = Image.FromFile(imageFile)) 
      using (var newImage = new Bitmap(100, 100)) 
      using (var graphics = Graphics.FromImage(newImage)) 
      using (var stream = new MemoryStream()) { 
        graphics.SmoothingMode = SmoothingMode.AntiAlias; 
        graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; 
        graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; 
        graphics.DrawImage(srcImage, new Rectangle(0, 0, 100, 100)); 
        newImage.Save(stream, ImageFormat.Png); 
        var thumbNew = File(stream.ToArray(), "image/png"); 
        artwork.ArtworkThumbnail = thumbNew.FileContents; 
      } 
    } 

    //Save model object to database 
    db.ArtWorks.Add(artwork); 
    db.SaveChanges(); 
    return RedirectToAction("Index"); 
  } 
  return View(artwork); 
}

Затем метод get Image или GetThumbnail

public FileContentResult GetThumbnailImage(int artworkId) { 
  ArtWork art = db.ArtWorks.FirstOrDefault(p => p.ArtWorkId == artworkId); 
  if (art != null) { 
    return File(art.ArtworkThumbnail, art.ImageMimeType.ToString()); 
  } else { 
    return null; 
  } 
}

И вот для отображения в представлении

<td> <img src="@Url.Action("GetThumbnailImage", "Artwork", new { Model.ArtWorkId })" alt="Artwork Image" /> </td>