65.9K
CodeProject 正在变化。 阅读更多。
Home

在 ASP.NET MVC 中通过文件浏览、拖放和使用网络摄像头上传图片

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (68投票s)

2014年10月26日

CPOL

9分钟阅读

viewsIcon

152276

downloadIcon

4566

在本文中,我将解释三种上传图片的方法(通过浏览文件、拖放以及使用网络摄像头捕获),从 ASP.NET MVC Web 应用程序上传到服务器,并再次访问这些图片以显示在网页上。

引言

在本文中,我将解释三种将图像从 ASP.NET MVC Web 应用程序上传到服务器并将其取回以显示在网页上的方法。在创建 Web 应用程序时,经常会出现上传和显示图像的场景,例如用户个人资料图像以及与产品、文章、项目或事件等关联的图像。我希望本文能帮助快速实现这些场景。我们将使用 Visual Studio 创建一个示例演示应用程序来理解实现。本文解释了以下三种上传图像的方法:

  • 通过文件浏览上传图片
  • 通过拖放上传图片
  • 通过网络摄像头捕获上传图片

先决条件:您应该具备 C# 和 ASP.NET MVC、jQuery 和 HTML 的中级水平,才能更好地理解本文。对于初学者,请先学习上述技术的基础知识,如有任何疑问,可以在文章下方留言。我将很乐意回答您的问题。谢谢。

致谢:在撰写本文时,我参考了一些博客并使用了其他受尊敬的程序员编写的库。我已经在本文的“参考文献”部分提到了这些博客和库的链接。非常感谢这些作者和程序员。

示例演示概述

为了快速了解本文代码演示结束时我们将实现什么,下面是完成的应用程序的截图,其中包含所有三个演示的链接:

Screenshot of Demo Application

在示例演示中,我们有三种上传图像的方式,但图像的访问方式对于所有三种方式都是相同的。因此,附加的代码解决方案包含一个主视图 (Index.cshtml),它将使用三个部分视图 (GetPVDragDrop.cshtml、GetPVforFileBrowsing.cshtml 和 GetPVUsingWebCam.cshtml) 进行不同的演示。另一个部分视图 (ViewSavedImage.cshtml) 用于访问和显示已上传的图像。(要了解有关部分视图的更多信息,请参阅此链接。

所有三个不同的部分视图都将具有相似的 HTML 结构以获得相同的布局,但将图像文件发送到控制器操作方法的方式在所有这些情况下将有所不同。为了保持简单易懂,对应每个部分视图,添加了三个 JavaScript 文件(file-browsing.js、drag-and-dropping.js 和 web-cam.js)。(因此您可能会发现这在某种程度上违反了DRY 原则,因为存在一些代码重复,但我们在此处将优先选择简单性而不是 DRY 原则)。

注意:我们假设您已经下载了包含运行项目的附加示例代码。如果没有,请务必下载,因为我们在此处不提供所有代码的详细信息或屏幕截图。

YouTube 视频: 非常感谢 sashkhdr 分享了基于本文的 YouTube 视频。该视频包含实时演示,描述了我们将在本文中创建的应用程序的功能。谢谢。

让我们开始创建一个演示应用程序。

创建 ASP.NET MVC 4 应用程序

在开始之前,请注意在遵循创建演示应用程序的步骤时以下几点:

  • 我们使用 Visual Studio 2012 和 ASP.NET MVC 4 开发演示,因此附加代码在相同设置下无需任何更改即可完美运行。
  • 我们已在 Internet Explorer 10 和 Chrome 38 上测试了运行中的应用程序。本文附带的屏幕截图是在 Chrome 浏览器中运行应用程序时拍摄的。
  • 您也可以使用已安装 ASP.NET MVC 4 或 5 的 Visual Studio 2013。
  • 如果您使用的是旧版本的 Visual Studio/ASP.NET MVC,则需要创建类似的解决方案,并注意由于版本不同而导致的细微更改。
  • ASP.NET MVC 和 jQuery 的基本知识是先决条件。
  • 为了方便起见,我们将图像保存在应用程序中的一个文件夹中。您可以根据需要使用任何数据库/机制,并对代码进行必要的更改。

现在让我们启动 Visual Studio 并开始构建演示

  1. 让我们通过选择 ASP.NET MVC4 Web 应用程序模板来创建一个示例应用程序,并将其项目名称命名为 ImageUploadDemo,然后单击“确定”。

    Screenshot of Project Tempalate
     
  2. 选择 Internet 应用程序模板,然后单击“确定”。Visual Studio 将为您创建一个 ImageUploadDemo 项目解决方案。

    Screenshot of Intranet Application Tempalate
     
  3. 转到解决方案资源管理器并展开“内容”和“脚本”文件夹。您将获得 Visual Studio 为所选项目模板添加的“脚本”文件夹中所有必需的 jQuery、jQueryUI 库,以及“内容”文件夹中的 CSS 文件。

    作为一个好习惯,我们应该删除应用程序中未使用的文件。因此,让我们从应用程序中删除不必要的文件,正如您在下载的演示中看到的那样,我删除了很多。您可以与下载的代码进行比较并进行必要的处理。这不是一个必要的步骤,您也可以稍后进行。

    现在添加一些 JavaScript、CSS 文件和一个 ImagesUploaded 文件夹,我们稍后会用到它们,这些文件和文件夹的名称如下。

    JavaScript 文件
    1. drag-and-dropping.js
    2. file-browsing.js
    3. web-cam.js
    所需插件
    1. jquery.webcam.js
    2. jscam.swf
    CSS 文件
    1. appcss.css
    文件夹
    1. ImagesUploaded
  4. 在 Shared 文件夹中,我们将修改 _Layout.cshtml 文件中的现有代码。首先在 head 标签中写入以下代码:
    <head>
        <meta charset="utf-8" />
        <title>@ViewBag.Title - My ASP.NET MVC Application</title>
        <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
        <meta name="viewport" content="width=device-width" />
        <script src="~/Scripts/jquery-1.8.2.min.js"></script>
        @*Referenced appcss file having custom CSS*@
        <link href="~/Content/custom/appcss.css" rel="stylesheet" />
    </head>
    
  5. 在 body 标签中写入以下代码以创建左侧导航链接:
    <body>
    <div class="navigationPanel">
        <div style="margin: 40px 25px 2px 25px;">
            <span style="color:green;font-weight:bolder; font-size:large">Links to Demostrations</span> 
            <br />
            <br />               
            <span style="color: #CC3300; font-weight: bold; font-style: italic">Uploading Image by</span>
            <br />
            <br />                 
            <a href="~/Home/GetPVforFileBrowsing">Browsing  File</a>
            <br />
            <br />
            <a href="~/Home/GetPVDragDropUsingjQuery">Dragging and Dropping</a>
            <br />
            <br />
            <a href="~/Home/GetPVUsingWebCam">Capturing using Webcam</a>
            <br />
            <br />             
        </div>
        </div>
        <div style="float: left; margin: 25px 2px 2px 80px;">
        @RenderBody()
    </div>
    </body>
            
  6. 从 index.cshtml 页面中删除所有内容。因为我们已经将演示链接放在布局页面中,并且此 index 页面将在单击链接时显示相关的局部视图。
     
  7. 添加一个名为 ImageModel 的模型,它将具有两个属性。我们将使用此模型在控制器中保存最新的图像详细信息,并在“ViewSavedImage”部分视图中作为其模型显示图像名称和上次请求中上传的图像。
    public class ImageModel
    {
        public string ImageName { get; set; }
        public string ImagePath { get; set; }
    }
            

到目前为止,我们已经创建了基本内容并编写了将在所有三个演示中使用的通用代码。接下来,我们将逐一为每个场景编写代码。

通过文件浏览上传图片

  1. 在 Home 控制器中添加一个名为 GetPVforFileBrowsing 的 Action 方法,并编写以下代码:
    public ActionResult GetPVforFileBrowsing()
    {
      return View();
    }
            
  2. 现在右键单击上面的方法添加一个局部视图,并在 GetPVforFileBrowsing.cshtml 文件中写入以下 html 代码以创建布局并提供 file-upload.js 文件的引用。目前 file-upload.js 是一个空文件,我们稍后将在其中编写代码。
    <h3>Uploading Image by Browsing File:</h3>
    <table>
        <tr>
            <td>
                <span>Image Name</span>
            </td>
            <td>
                <input type="text" id="txtImageName" />           
            </td>
            <td>
                <div id="validateImageInput" class="warrningMessage">Please enter image name</div>
            </td>
        </tr>
        <tr>
            <td>
                <br />
                <span>Upload Image</span>
            </td>
            <td>
                <br />
                <input type="file" id="selectedImage" name="image" />
            </td>
            <td>
                <br />
                <div id="validateSelectedImage" class="warrningMessage">Please browse image file</div>
            </td>
        </tr>
        <tr>
            <td>
                <br />
                <input type="button" id="btnBrowsedSave" value="Save Borwsed Image" />
            </td>
            <td>
                <br />
                <input type="button" id="btnViewImage" value="View Saved Image" />
            </td>
        </tr>
    </table>
    <br />
    <br />
    @*Container of  ViewSavedImage partial view*@
    <div id="pvContainerDiv">
    </div>
    <script src="~/Scripts/Js/file-browsing.js"></script>
            
  3. 在 file-browsing.js 文件中写入以下代码。
    $(document).ready(function (){
        $("#btnViewImage").hide();
        $("#validateImageInput ").hide();
        $("#validateSelectedImage").hide();
    });
    $("#txtImageName").keydown(function () {
        $("#validateImageInput").hide();
    });
    $("#selectedImage").click(function () {
        $("#validateSelectedImage").hide();
    });
    $("#btnBrowsedSave").click(function () {
        var imageName = $("#txtImageName").val();
        var formData = new FormData();
        var totalFiles = document.getElementById("selectedImage").files.length;
        var browsedFile = document.getElementById("selectedImage").files[0];
        if (imageName == "")
            $("#validateImageInput").show();
        if (totalFiles == 0)
            $("#validateSelectedImage").show()
        if ((imageName != "") && (totalFiles != 0)) {
            if (browsedFile.type.match('image.*')) {
                formData.append("FileUpload", browsedFile);
                formData.append("ImageName", imageName);
                $.ajax({
                    type: "POST",
                    url: '/Home/UploadImage',
                    data: formData,
                    dataType: "html",
                    contentType: false,
                    processData: false,
                    success: function (result) {
                        $("#btnViewImage").show();
                    }
                });
            }
            else {
                alert("Please browse image file only.");
            }
        }
    });
            
    在上面的代码中,我们首先隐藏了“查看已保存图像”按钮(当用户单击“保存捕获的图像”按钮时,该按钮将可见以查看刚刚上传的图像)以及两个包含用于验证目的的文本的 div。我们使用 Ajax 请求将上传的图像发送到控制器中的 UploadImage 操作方法。
     
  4. 添加一个 Action 方法,该方法将通过 Http 请求接受图像文件并将其保存在 ImagesUploaded 文件夹中。
    [HttpPost]
    public void UploadImage()
    {
        foreach (string upload in Request.Files)
        {
            string path = AppDomain.CurrentDomain.BaseDirectory + "ImagesUploaded/";
            string filename = Path.GetFileName(Request.Files[upload].FileName);
            Request.Files[upload].SaveAs(Path.Combine(path, filename));
            imageModel.ImagePath = filename;
            imageModel.ImageName = Request.Form["ImageName"];
        }
    }
            
  5. 现在我们将访问此保存的图像。为此,在 Shared 文件夹中添加一个名为 ViewSavedImage 的局部视图,因为此局部视图将用于所有三种情况,因此我们将其添加到 Shared 文件夹中。它将接受一个 ImageModel。在此局部视图中写入以下代码:
    @model ImageUploadDemo.Models.ImageModel
    <div id="viewSavedContentAreaDiv">
        <h4>This is your recently uploaded image details:</h4>
        <table>
            <tr>
                <td class="pvTdFirst">
                    <span>Image Name</span>
                </td>
                <td class="pvTdSecond">
                    <span>@Model.ImageName</span>
                </td>
            </tr>
            <tr>
                <td class="pvTdFirst"><br />
                    <span>Uploaded Image</span>
                </td>
                <td class="pvTdSecond"><br />
                    <div >
                        <img class="viewSavedImage" src="@Url.Content(String.Format("~/ImagesUploaded/{0}", Model.ImagePath))">
                    </div>
                </td>
            </tr>
        </table>
    </div>
            
  6. 添加一个名为“ViewSavedImage”的动作方法,它将返回这个局部视图。
    [OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
    public ActionResult ViewSavedImage()
    {
        return PartialView("ViewSavedImage", imageModel);
    }
            
    这里我们使用了 OutputCache 属性并设置了一些属性:NoStore = true(不维护缓存);Duration = 0(缓存持续时间为零)和 VaryByParam = "*"(可以根据任何参数变化)。我们不希望此动作方法的输出被缓存,因为它应该始终返回最新上传的图像。

  7. 在 file-browsing.js 文件中添加以下代码,它将向 ViewSavedImage action 方法发起 ajax 调用,该方法将返回 ViewSavedImage.cshtm partial view,成功后该 partial view 将插入到 id 为 pvContainerDiv 的 div 标签中。
    $("#btnViewImage").click(function () {
    $.ajax({
        type: "Get",
        url: '/Home/ViewSavedImage',
        dataType: "html",
        contentType: false,
        processData: false,
        success: function (result)
        {
            $("#pvContainerDiv").empty().append(result);
        }
    });
    });
              
  8. 运行应用程序,浏览任意图像文件,提供适当的图像名称,然后单击“保存浏览的图像”按钮。您的图像将以给定名称保存在 ImagesUpload 文件夹中。单击“查看已保存图像”按钮。保存的图像将显示在同一页面下方,如下图所示。

    Screenshot of File Browsing
     

通过拖放上传图片

  1. 在 Home 控制器中添加一个名为 GetPVDragDropand 的 Action 方法,并编写以下代码:
    public ActionResult GetPVDragDrop()
    {
       return View();
    }
                
  2. 现在,右键单击上述方法并添加一个局部视图,在 GetPVDragDrop.cshtml 文件中编写以下 HTML 代码。大部分代码与 GetPVforFileBrowsing.cshtml 相同,但 HTML 控件的一些 id 已更改,以便在当前上下文中给出适当的名称。请根据下载的代码更改这些名称。在 GetPVDragDrop.cshtml 中引用 drag-drop.js 文件。现在我们将在 drag-drop.js 中编写代码,这将使某些区域可拖放并在页面上显示拖放的图像。
                        
    $(document).ready(function () {
        $("#btnViewImage").hide();
        $("#validateImageInput ").hide();
        $("#validateDroppedImage").hide();
    });
    var dropArea = $("#dropAreaDiv");
    var newFile;
    // Providing handlers three events to the drop area
    dropArea.on({
        "drop": makeDrop,
        "dragenter": ignoreDrag,
        "dragover": ignoreDrag
    });
    //Stop default behavior 
    function ignoreDrag(e) {
        e.stopPropagation();
        e.preventDefault();
    }
    //Handling drop event
    function makeDrop(e) {
        var fileList = e.originalEvent.dataTransfer.files, fileReader;
        e.stopPropagation();
        e.preventDefault();
        if (fileList.length > 0) {
            newFile = fileList[0];
            if (newFile.type.match('image.*')) {
                $("#validateDroppedImage").hide();
                fileReader = new FileReader();
                fileReader.onloadend = handleReaderOnLoadEnd($("<img />"));
                fileReader.readAsDataURL(fileList[0]);
            }
            else {
                alert("Please select an image file only.");
            }
        }
    }
    //Setting the image source
    function handleReaderOnLoadEnd($image) {
        return function (event) {
            $image.attr("src", this.result)
                .addClass("small")
                .appendTo("#dropAreaDiv");
        };
    }
    $("#txtImageName").keydown(function () {
        $("#validateImageInput").hide();
    });
    $("#btnDroppedSave").click(function () {
        var imageName = $("#txtImageName").val();
        if (imageName == "")
            $("#validateImageInput").show();
        var imgSource = $("#dropAreaDiv").find("img").attr("src");
        if (imgSource == undefined)
            $("#validateDroppedImage").show();
        if ((imageName != "") && (imgSource != undefined)) {
            var formData = new FormData();
            var totalFiles = 1;
            var dropedFile = newFile;
            formData.append("FileUpload", dropedFile);
            formData.append("ImageName", imageName);
            $.ajax({
                type: "POST",
                url: '/Home/UploadImage',
                data: formData,
                dataType: "html",
                contentType: false,
                processData: false,
                success: function (result) {
                    $("#btnViewImage").show();
                }
            });
        }
    });
    $("#btnViewImage").click(function () {
        $.ajax({
            type: "Get",
            url: '/Home/ViewSavedImage',
            dataType: "html",
            contentType: false,
            processData: false,
            success: function (result) {
                $("#pvContainerDiv").empty().append(result);
            }
        });
    });
            
    在上述 ajax 调用中,我们目标是 UploadImage action 方法,这与我们上面演示中用于通过浏览图像文件保存图像的方法相同。
     
  3. 运行应用程序,在文本框中输入图像名称,并将任意图像文件拖放到虚线可拖放区域内,然后单击“保存已放置图像”按钮。已放置的图像将以您在文本框中给出的名称保存。单击“查看已保存图像”按钮,希望您能看到刚刚放置和保存的图像,如下图所示在“示例演示概述”标题下。

通过网络摄像头捕获上传图片

在这种情况下,我们将从系统的网络摄像头捕获图像,因此您的系统必须有网络摄像头才能运行和测试应用程序。我使用了由 jQuery 编写的插件和由 Adobe Flash ActionScript 编写的 swf 文件。这个插件是由 Robert Eisele 编写的,请在本文的参考部分找到他博客的链接。我已将这两个文件保存在应用程序的 ExternalJs 文件夹中。
 

  1. 在 Home Controller 中添加一个名为 GetPVUsingWebCam 的 Action 方法,并添加一个同名的 Partial View。Action 方法的代码如下所示:
    public ActionResult GetPVUsingWebCam ()
    {
        return View();
    }
            
  2. GetPVUsingWebCam.cshtml 文件中的 HTML 代码将与 GetPVforFileBrowsing.cshtml 相同,但 HTML 控件的一些 id 已更改,请根据下载的代码进行更改。在 GetPVUsingWebCam.cshtml 中引用 web-cam.js 文件。现在我们将在 web-cam.js 中编写以下代码:
    $(document).ready(function () {
        $("#btnViewImage").hide();
        $("#validateImageInput").hide();
        $("#validateCameraInput").hide();
        // assigning properties and adding callback fuctions
        $("#cameraArea").webcam({        
            width: 250,
            height: 160,
            mode: "save",
            swffile: "/Scripts/ExternalJs/jscam.swf",
            onTick: function () { },
            onSave: function () {
            },
            onCapture: function ()
            {
                var imageName = $("#txtImageName").val();
                var url = getContextPath() + "CameraCapture/" + imageName;          
                webcam.save(url);
                $("#btnViewImage").show();
            },
            debug: function (type, message)
            {
                if (message === "Camera started") { window.webcam.started = true; }            
            },
            onLoad: function () { }
        });
        // Validating and calling capture method of webcam
        $("#btnCaptureSave").click(function () {      
            var imageName = $("#txtImageName").val();
            if (imageName === "")
            {
                $("#validateImageInput").show();
            }
            else
            {
                $("#validateImageInput").hide();
                if (!webcam.started) {            
                    $("#validateCameraInput").show();
                }
                else
                {
                    $("#validateCameraInput").hide();
                    $("#btnViewImage").hide();
                    webcam.capture();
                }
            }
        });
        
        function getContextPath()
        {
            var ctx = window.location.pathname,
                path = '/' !== ctx ? ctx.substring(0, ctx.indexOf('/', 1) + 1) : ctx;
            return path + (/\/$/.test(path) ? '' : '/');
        }
        
        $("#txtImageName").keydown(function () {
            $("#validateImageInput").hide();
        });
        $("#btnViewImage").click(function () {
            $.ajax({
                type: "Get",
                url: '/Home/ViewSavedImage',
                dataType: "html",
                contentType: false,
                processData: false,
                success: function (result)
                {
                    $("#pvContainerDiv").empty().append(result);
                }
            });
        });
    });
            
    在上述 ajax 调用中,我们目标是 CameraCapture action 方法以保存图像。
     
  3. 运行应用程序,然后单击左侧菜单中的“使用网络摄像头捕获”链接,您应该会看到网络摄像头演示的初始屏幕,如下图所示,要求您允许访问网络摄像头:

    Screenshot Webcam Start
     
  4. 现在点击“允许”按钮启动网络摄像头,在文本框中输入图像名称,捕捉快照,然后点击“保存捕捉图像”按钮保存图像。捕捉到的图像将以您在文本框中给出的名称保存。点击“查看保存的图像”按钮,查看最近保存的捕捉到的图像,如下图所示:

    Image Capture by Webcam
     

结论

在本文中,我们学习了在 ASP.NET MVC 应用程序中保存图像的三种方法:通过浏览文件、拖放和使用网络摄像头拍摄快照。我尽量使代码尽可能简单,以便易于理解和重用。欢迎您提出意见和建议,并提供详细信息以改进本文。感谢您的阅读。

参考文献

  1. Gunnar Peipman 的 ASP.NET 博客
  2. Robert Eisele 的 jQuery 网络摄像头插件
  3. Elijah Manor 在 Stackoverflow 上的回答
© . All rights reserved.