使用.Net MVC,如何列出播放不同文件的多个html音频播放器?

时间:2014-04-04 08:51:26

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

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

Database view without audio player

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

经过一些研究后,我发现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替换数据库中的绝对路径列,但它不起作用。我收到错误的说法'System.Web.Mvc.FilePathResult' has no parameterless constructor。我是否正确认为这个错误意味着我需要将参数传递给FilePathResult,因为我可能从数据库中调用它?

无论如何,我放弃了这一行动方式,并寻找其他方法来获得正确的路径,但我没有取得任何成功。

我理解它在其他示例中是如何工作的,因为它只返回一个音频结果,因此对Index()的简单调用可以返回该单个结果。 这是包含在内的玩家的样子,但它们不起作用,当我检查这些元素时,它是因为它指向绝对路径:

Database with audio players

这是标记的样子:

<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");        
    }

我的AudioClip模型:

    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索引视图:

@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模型和数据库中,以便允许我生成多个播放不同文件的音频播放器,但现在我无法看到它。你们有人能指出我正确的方向吗?

1 个答案:

答案 0 :(得分:1)

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

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

您应该考虑仅将文件URL返回给客户端而不是FileContentResult。

谢谢和问候, Chetan Ranpariya