轶哥博客

妄图改变世界的全栈程序员。

ASP.NET 5 MVC 6 Web API 上传图片

  使用ASP.NET 5 MVC 6 编写 Web API的代码和老版本的有很大区别。特别在连接数据库、图片上传下载等问题上非常难处理。主要原因是新版本中很多类的用法产生变更。

  ASP.NET 5 及 EF7(Entity Framework 7)可以跨平台的新特性使得Linux服务器更能大展身手。但随之而来的便是运维难度的加大和编程人员的“再学习”成本。

  对于使用MAC的程序员来说,这是一个福音。因为现在可以使用Visual Studio Code作为替代 Visual Studio的编辑器并且使用C#进行开发。然而Visual Studio Code并非IDE,只是一个编辑器,需要配合ASP.NET 5 DNX才能正常运行.net程序。通常轶哥在macbook中采用PD虚拟机运行win10融合模式编写调试C#代码,不过VS太消耗系统资源,有条件用台式机还是用台式机吧。

关于 ASP.NET 5 MVC 6 Web API 的一些你需要知道的东西

Web API运行模式

  Web API的编程方式是实现微应用的方式之一,通过 ASP.NET 编写 Web API 进行数据交互是一种非常理想的实现前端数据渲染、“动静分离”的方式。ASP.NET WebAPI是一套RESTful API开发框架。会自动序列化返回的对象成XML或JSON,其序列化后的格式取决于Request的header中的Accept。常见的有:

  • application/json
  • application/xml
  • text/json
  • text/xml(最后这两种已经被废弃了)

  如果不指定的话默认返回的Content-Type是:“application/json; charset=utf-8”。

  一般来讲,我们希望API的范围格式规范化,这回加速团队开发的效率。

错误返回格式
{
"status": "Error",
"error_code": "404",//出错代码
"error_detail_code":"40401",//具体代码
"error_message": "40401: File or folder not found at the specified path"//详细的出错信息
}
成功返回格式
{
    "status": "OK",
    "result": "相应的结果"
}

  这是微软官方ASP.NET 5 MVC 6 Web API入门指引

  这是一些ASP.NET5的新特性/闪光点:

Having two distinct hosting models for ASP.NET 5 introduced a number of complexities and inconsistencies that were difficult or impossible to resolve.

Simplifying the model with a single host option (but the same scenarios still supported) means less things for developers to code for and test. And it's easier for us to build!

Some added benefits of this approach:

The IIS AppPool doesn't need to run any managed code (you can literally configure it to not load the CLR at all) The existing ASP.NET Windows component does not need to be installed to run on Windows Servers Existing ASP.NET 4.x modules can run in IIS alongside the HttpPlatformHandler since the ASP.NET 5 process is separate You can set environment variables per process since HttpPlatformHandler supports it. It will make setting things like the ASP.NET 5 "environment" configuration possible on local IIS servers. Unified error handling for startup errors across all servers Code and behavior unification Support for app.config when running on .NET Framework (full CLR) whether self-hosted or in IIS (no more web.config even for .NET Framework compatibility) Unified servicing story Unified boot-up story (no odd AspNetLoader.dll in the bin folder)

大概意思:

新的宿主模型带来的好处包括:

  • IIS应用程序池不需要运行托管代码,类似于在IIS上运行PHP那样,根本不会在IIS上加载CLR。
  • 不再需要安装Windows的asp.net组件。
  • IIS上可以同时运行ASP.NET 4.x模块和HttpPlatformHandler。
  • HttpPlatformHandler支持给每个进程设置环境变量。
关于 ASP.NET 5 MVC 6 Web API 如何在Linux和Win服务器部署,我将另行撰文。

  更多关于Web API的信息, 请看: http://go.microsoft.com/fwlink/?LinkID=397860

ASP.NET 5 MVC 6 Web API 图片上传代码

API控制器类:

using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Http;
using Upload;
using Microsoft.AspNet.Hosting;

namespace znggj.Controllers
{
    [Route("api/[controller]")]
    public class imgurlController : Controller
    {
        private IHostingEnvironment _environment;

        public imgurlController(IHostingEnvironment environment)
        {
            _environment = environment;
        }
        [HttpPost]
        public string POST(string Movies)
        {
            //get posted file from web form
            IFormFile Moviesfile = Request.Form.Files.GetFile("Imgurl");
            FormUpload upload = new FormUpload();
            string Moviesfile_sting = upload.SaveFile(Moviesfile, _environment.WebRootPath);
            return Moviesfile_sting;
        }
    }
}

图片上传处理类

using System;
using System.Linq;
using System.IO;
using Microsoft.AspNet.Http;
using Microsoft.Net.Http.Headers;


namespace Upload
{
    public class FormUpload
    {
        private static string UploadDestination { get; set; }
        private static string[] AllowedExtensions { get; set; }

        public FormUpload()
        {
            //upload config
            FormUpload.AllowedExtensions = new string[] { ".jpg", ".png", ".gif" };
            FormUpload.UploadDestination = "\\upload\\";
        }

        private bool VerifyFileExtension(string path)
        {
            return FormUpload.AllowedExtensions.Contains(Path.GetExtension(path));
        }

        private bool VerifyFileSize(IFormFile file)
        {
            Double fileSize = 0;
            using (var reader = file.OpenReadStream())
            {
                //get filesize in kb
                fileSize = (reader.Length / 1024);
            }

            //filesize less than 1000MB => true, else => false
            return (fileSize < 1024000) ? true : false;
        }


        public string SaveFile(IFormFile file,string UploadURL)
        {

            string Filename = "";
            string newfilename = string.Empty;

            if (file.ContentDisposition != null)
            {
                //parse uploaded file
                var parsedContentDisposition = ContentDispositionHeaderValue.Parse(file.ContentDisposition);
                Filename = parsedContentDisposition.FileName.Trim('"');
                DateTime currentTime = new DateTime();
                currentTime = DateTime.Now;//取当前年月日时分秒
                string FileExtension = Path.GetExtension(Filename);
                newfilename = currentTime.ToFileTime().ToString() + FileExtension;
                string uploadPath = UploadURL + FormUpload.UploadDestination + newfilename;

                //check extension
                bool extension = this.VerifyFileExtension(uploadPath);
                if (extension == false)
                {
                    return "";
                }

                //check file size
                bool filesize = this.VerifyFileSize(file);
                if (filesize == false)
                {
                    return "";
                }

                //save the file to upload destination
                file.SaveAs(uploadPath);
            }

            return newfilename;
        }



    }
}

  以上代码中,为了避免文件名带来一些特殊字符导致安全问题,已将文件的文件名转换为时间数字后存储。这个API可以直接用Ajax进行上传或直接使用From(表单)上传。

附:前端实现代码

  前端大家可以尝试普通上传方式,不过为了优化上传体验,也可以选择基于jQuery和Bootstrap的Ajax无刷新上传插件“Bootstrap File Input”。

  使用方法非常简单,引入必须的CSS和JS文件:

//在</head>之前插入以下代码
<link href="css/bootstrap.min.css" rel="stylesheet" />
<link href="css/bootstrap-theme.min.css" rel="stylesheet" />
<link href="css/fileinput.min.css" media="all" rel="stylesheet" type="text/css" />
//在</body>之前插入以下代码
<script src="js/jquery-2.2.0.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/fileinput.min.js"></script>
<script src="js/fileinput_locale_zh.js"></script>

  其中fileinput_locale_zh.js是本土化语言文件,让上传插件的语言支持中文。不要忘记js代码设置里面要添加:“language: 'zh'”。

  在需要上传的地方插入HTML代码:

<div class="form-group">
<label for="inputImageTitle" class="col-sm-2 control-label">图片上传</label>
<div class="col-sm-10">
<input id="input-id" type="file" name="Imgurl" multiple class="file" data-overwrite-initial="false" data-min-file-count="1" data-max-file-count="1">
</div>

在对应页面的js文件中插入:

//加载上传插件
$("#input-id").fileinput({
    language: 'zh',
    uploadUrl: api_url + '/images', // you must set a valid URL here else you will get an error,填写对应/api/imgurl路径即可
    allowedFileExtensions: ['jpg', 'png', 'gif'],
    overwriteInitial: false,
    maxFileSize: 1024000,
    maxFilesNum: 1,
    //allowedFileTypes: ['image', 'video', 'flash'],
    slugCallback: function (filename) {
        return filename.replace('(', '_').replace(']', '_');
    }
});

  这样一来,就可以成功上传文件了。如果需要在前端获取上传了的文件的文件名,可以使用以下代码:

$("#input-id").on("fileuploaded", function (event, data, previewId, index) {
     filename_save = data.response.result;
     console.log(filename_save);
 });

  如果你原样照搬我的代码,运行肯定会报错的,因为还没有对Web API返回的数据做序化json数据处理,因此插件认为没有返回正确的上传结果。如何使用 ASP.NET 5 MVC 6 Web API 处理返回数据为JavaScript支持的标准json格式呢?期待我的下一篇文章吧。请访问:《ASP.NET 5 MVC 6 Web API JSON序化》。

  上一篇 (ASP.NET 5 MVC 6 Web API JSON序化)
下一篇 (平板电脑安装Ubuntu教程-以V975w为例,Z3735系列CPU通用)