【问题标题】:Using .Net MVC, how can I list multiple html audio players that play different files?使用 .Net MVC,如何列出播放不同文件的多个 html 音频播放器?
【发布时间】:2014-04-04 08:51:25
【问题描述】:

我和我的朋友正在使用 .Net 进行一个大学项目。我们正在尝试建立一个网站,允许用户以与 Soundcloud 等网站类似的方式收听音频剪辑。 目前我们有一个基本的 MVC 站点,它允许用户将音频上传到服务器文件系统,并在数据库表中记录有关文件的各种详细信息。

所以现在我正在尝试向客户端提供可用音频文件的列表以及播放每个文件的控件。我特别想为每个文件设置一组不同的控件;在项目的后期,我们也打算为每个文件添加波形图像。

经过一些研究,我发现this stackoverflow post 帮助我从服务器提供和播放单个音频文件,但是,我无法让它与多个 mp3 一起使用。 在上面的帖子中,控制器向网页返回一个文件,然后在一个空网页中播放该文件。我在控制器中对此进行了测试,首先使用 Server.PathMap,然后将绝对路径作为 File 方法的参数返回,如下所示:

public ActionResult Index()
{
    var file = Server.MapPath("~/App_Data/Audio/09 - Supergrass - Cheapskate.mp3");
    return File(@"c:\users\paul\documents\visual studio 2013\Projects\Web Applications Project\MVCTest2\App_Data\Audio\05. Debaser.mp3", "audio/mp3");
}

两者都运行良好。然后我考虑了如何使用文件列表来做到这一点,但我还没有运气。

我的数据库表包含以下有关音频文件的信息:

  • 唯一的 id (int)
  • 文件名
  • 绝对文件路径
  • 用户 ID

在我找到的示例中调用的 File 方法将 FilePathResult 返回给客户端。我试图用 FilePathResult 替换数据库中的绝对路径列,但它不起作用。我收到一条错误消息,说 The class 'System.Web.Mvc.FilePathResult' has no parameterless constructor。我是否正确地认为这个错误意味着我需要将参数传递到 FilePathResult 中,因为我可能从数据库中调用它?

无论如何,我放弃了这种做法并寻找其他方法来获得进入元素的正确路径,但我没有取得任何成功。

我了解它在另一个示例中的工作原理,因为它只有一个音频结果要返回,因此对 Index() 的简单调用可以返回该单个结果。 这是包含播放器的样子,但它们不起作用,当我检查元素时,这是因为它指向绝对路径:

下面是标记的样子:

<tr>
    <td>
        02 - Supergrass - Richard III.mp3
    </td>
    <td>
        <article class="audio">
            <audio controls>
                <source src="/AudioClip/http%3a/localhost/50279/App_Data/Audio/02%20-%20Supergrass%20-%20Richard%20III.mp3" type="audio/mp3" />
                <p>Your browser does not support HTML 5 audio element</p>
            </audio>
        </article>
    </td>
    <td>
        http://localhost/50279/App_Data/Audio/02 - Supergrass - Richard III.mp3
    </td>
    <td>
        1
    </td>
    <td>
        0
    </td>
    <td>
        <a href="/AudioClip/Edit/20">Edit</a> |
        <a href="/AudioClip/Details/20">Details</a> |
        <a href="/AudioClip/Delete/20">Delete</a>
    </td>
</tr>

这是我的 AudioClipController 的相关部分:

namespace MVCTest2.Controllers
{
    public class AudioClipController : Controller
    {
        //
        // GET: /AudioClip/
        string audioFilePath = "~/App_Data/Audio";
        AudioDb _db = new AudioDb();

        public ActionResult Index(string searchTerm = null)
        {
            var model =
                _db.AudioClips
                .OrderBy(r => r.Title)
                .Where(r => searchTerm == null ||  r.Title.StartsWith(searchTerm))
                .Take(10)
                .Select(r => r);

            return View(model);
        }

        //
        // GET: /AudioClip/Details/5

        public ActionResult Details(int id)
        {
            return View();
        }

        //
        // GET: /AudioClip/Create

        [HttpGet]
        public ActionResult Create()
        {

            return View("Create");
        }

        //
        // POST: /AudioClip/Create

        [HttpPost]
        public ActionResult Create(HttpPostedFileBase file) //FormCollection collection
        {

             // Verify that the user selected a file
        if (file != null && file.ContentLength > 0) 
        {
            // extract only the fielname
            var fileName = Path.GetFileName(file.FileName);
            // store the file inside ~/App_Data/uploads folder
            var path = Path.Combine(Server.MapPath(audioFilePath), fileName);
            file.SaveAs(path);
            AudioClip audioClip = new AudioClip(fileName, path, 1, 0);
            _db.AudioClips.Add(audioClip);
            _db.SaveChanges();
            return RedirectToAction("INDEX", new { Id = audioClip.AudioClipId });
        }
        // redirect back to the index action to show the form once again
        return RedirectToAction("Index");        
    }

我的音频剪辑模型:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;

    namespace MVCTest2.Models
    {
        public class AudioClip
        {

            [Display(Name="ID")]
            public int AudioClipId { get; set; }
            [Display(Name = "Clip Title")]        
            public string Title { get; set; }
            [Display(Name = "File Path")] 
            public string FilePath { get;set; }
            [Display(Name = "User Name")] 
            public int BloggerId { get; set; }
            [Display(Name = "Linked To")] 
            public int MasterId { get; set; }
            // the virtual keyword issues a second query to solve null
            // pointer at AudioClip.Comments. There are multiple ways to do this
            // including more efficent ones, see:
            // Loading Related Entities: http://msdn.microsoft.com/en-US/data/jj574232
            public virtual ICollection<Comment> Comments { get; set; }

            public AudioClip() { 

            }

            public AudioClip(string title, string filePath, int bloggerId, int masterId) {
                Title = title;
                FilePath = filePath;
                BloggerId = bloggerId;
                MasterId = masterId; 
            }
        }
    }

还有我的 AudioClip Index 视图:

@model IEnumerable<MVCTest2.Models.AudioClip>

@{
    ViewBag.Title = "Index";
}

<h2>Audio Clips</h2>

<form method="get">
    <input type="search" name="searchTerm" />
    <input type="submit" value="Search by Name" />
</form>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table>
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Title)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.FilePath)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.BloggerId)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.MasterId)
        </th>
        <th></th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Title)
        </td>
        <td>
            <article class="audio">
                <audio controls>
                    <source src="@Url.Action(item.FilePath)" type="audio/mp3" />
                    <p>Your browser does not support HTML 5 audio element</p>
                </audio>
            </article>
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.FilePath)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.BloggerId)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.MasterId)
        </td>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id=item.AudioClipId }) |
            @Html.ActionLink("Details", "Details", new { id=item.AudioClipId }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.AudioClipId })
        </td>
    </tr>
}

</table>

我想我必须能够将此信息添加到 AudioClip 模型和数据库中,以允许我生成多个播放不同文件的音频播放器,但现在我看不到它。你们中的任何人都可以指出我正确的方向吗?

【问题讨论】:

    标签: asp.net-mvc html asp.net-mvc-4 audio html5-audio


    【解决方案1】:

    我想到的简单逻辑解决方案是,如果使用服务器上文件的绝对路径 (C:\files\media.mp3),您应该使用文件的 URL 并将其分配给您的播放器。

    以下关于音频标签的链接解释了如何将它与音频文件 URL 一起使用。 http://www.w3schools.com/tags/tag_audio.asp

    您应该考虑只向客户端返回文件 URL 而不是 FileContentResult。

    感谢和问候, 切坦兰帕里亚

    【讨论】:

    • 嗨 Chetan,我也尝试过使用该 URL,但仍然无法正常工作。
    • 其实我想我现在有了。如果它有效,我会标记为正确的。
    • 好的,你的评论让我重新审视自己在做什么。主要问题是我的音频文件夹位于受保护的 App_Data 文件夹中。因此,当我将音频文件夹移到 App_Data 文件夹之外时,一切正常。但是现在除了通过播放器进行流式传输外,还可以右键单击源中的链接并将 mp3 保存到您的硬盘驱动器。如果可能的话,我想消除这种可能性。
    猜你喜欢
    • 1970-01-01
    • 2014-06-13
    • 1970-01-01
    • 1970-01-01
    • 2015-04-02
    • 1970-01-01
    • 1970-01-01
    • 2023-02-16
    相关资源
    最近更新 更多