前面一系列我们纯粹是讲AngularJS,在讲一门知识时我们应该结合之前所学综合起来来做一个小的例子,前面我们讲了在MVC中上传文件的例子,在本节我们讲讲如何利用AngularJS在WebAPi中如何上传,来巩固下WebAPi并结合AngularJS中对应的一些组件学习下。
(一)在WebAPi中我们如何获得上传本地文件的物理路径呢?需要实现此类: MultipartFormDataStreamProvider ,从该类中获取上传文件的物理路径并返回。如下:
- public class UploadMultipartFormProvider : MultipartFormDataStreamProvider
- {
- public UploadMultipartFormProvider(string rootPath) : base(rootPath) { }
- public override string GetLocalFileName(HttpContentHeaders headers)
- {
- if (headers != null &&
- headers.ContentDisposition != null)
- {
- return headers
- .ContentDisposition
- .FileName.TrimEnd('"').TrimStart('"');
- }
- return base.GetLocalFileName(headers);
- }
- }
(二)为避免有些浏览器不支持多个文件上传我们通过实现 ActionFilterAttribute 特性来加以判断,如下:
- public class MimeMultipart : ActionFilterAttribute
- {
- public override void OnActionExecuting(HttpActionContext actionContext)
- {
- if (!actionContext.Request.Content.IsMimeMultipartContent())
- {
- throw new HttpResponseException(
- new HttpResponseMessage(
- HttpStatusCode.UnsupportedMediaType)
- );
- }
- }
- public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
- {
- }
- }
以上两个类为我们在WebAPi中上传提供一个保障。接下来我们需要的是如何利用AngularJS来上传。
在AngularJS中上传需要用到 ng-file-upload 组件,而非 angularFileUpload 组件,在此之前一直是利用angularFileUpload组件,但是后来逐步迁移并且命名为ng-file-upload组件。同时为了一些加载效果如在github中顶部有加载线的过程,决定也在这里实现一下看看【说明:上传过程用到angular-loading-bar(加载)和ng-file-upload(上传)组件】。
(1)为了重用,我们将加载组件进行封装。
- //common.load.js
(function () {- 'use strict';
- angular
- .module('common.load', [
- 'angular-loading-bar',
- 'ngAnimate'
- ]);
- })();
(2)启动加载线。
- //loadBarCtrl.js
(function (app) {- "use strict";
- app.controller("loadCtrl", loadCtrl);
- function loadCtrl(cfpLoadingBar) {
- cfpLoadingBar.start();
- }
- })(angular.module("common.load"));
(3)上传文件代码
- //fileUploadCtrl.js
(function (app) {- 'use strict';
- app.controller('fileUploadCtrl', fileUploadCtrl);
- fileUploadCtrl.$inject = ['$scope', '$http', '$timeout', 'Upload'];
- function fileUploadCtrl($scope, $http, $timeout, Upload, cfpLoadingBar) {
- $scope.upload = [];
- $scope.UploadedFiles = [];
- $scope.startUploading = function ($files) {
- for (var i = 0; i < $files.length; i++) {
- var $file = $files[i];
- (function (index) {
- $scope.upload[index] = Upload.upload({
- url: "/api/upload",
- method: "POST",
- file: $file,
- withCredentials: false
- }).progress(function (evt) {
- }).success(function (data, status, headers, config) {
- $scope.UploadedFiles.push({ FileName: data.FileName, FilePath: data.LocalFilePath, FileLength: data.FileLength });
- cfpLoadingBar.complete();
- }).error(function (data, status, headers, config) {
- });
- })(i);
- }
- }
- }
- })(angular.module("common.load"));
(4)加载主模块以及依赖模块。
- //app.js
(function () {- 'use strict';
- angular
- .module('angularUploadApp', [
- 'ngRoute',
- 'ngFileUpload',
- 'common.load'
- ])
- .config(config)
- config.$inject = ['$routeProvider'];
- function config($routeProvider) {
- $routeProvider
- .when('/', {
- templateUrl: '../../app/templates/fileUpload.html',
- controller: 'fileUploadCtrl'
- })
- .otherwise({
- redirectTo: '/'
- });
- }
- })();
- @{
- Layout = null;
- }
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8" />
- <title></title>
- <link href="~/Content/bootstrap.min.css" rel="stylesheet" />
- <link href="~/Content/loading-bar.min.css" rel="stylesheet" media="all" />
- </head>
- <body ng-app="angularUploadApp" ng-controller="loadCtrl">
- <nav class="navbar navbar-default" role="navigation">
- <div class="navbar-header">
- <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
- <span class="sr-only">Toggle navigation</span>
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- </button>
- <a class="navbar-brand" href="http://www.cnblogs.com/createmyself">Angular File WebAPi Upload by <i style="color:#2da12d;font-weight:bolder;">xpy0928</i></a>
- </div>
- <div id="navbar" class="navbar-collapse collapse">
- </div>
- </nav>
- <div class="container">
- <div ng-include src="'../../app/templates/fileUpload.html'"></div>
- </div>
- <script src="../../Scripts/jquery-1.10.2.min.js"></script>
- <script src="../../Scripts/angular.min.js"></script>
- <script src="../../Scripts/angular-animate.min.js"></script>
- <script src="../../Scripts/angular-route.js"></script>
- <script src="../../app/plugins/loading-bar.min.js"></script>
- <script src="../../app/modules/common.load.js"></script>
- <script src="../../Scripts/ng-file-upload.min.js"></script>
- <script src="../../app/app.js"></script>
- <script src="../../app/controllers/loadBarCtrl.js"></script>
- <script src="../../app/controllers/fileUploadCtrl.js"></script>
- </body>
- </html>
模板页:
- <div class="row" ng-controller="fileUploadCtrl">
- <div class="col-xs-3">
- <div>
- <input type="file" accept="images/*" ngf-pattern="'.png,.jpg,.gif'" ngf-select="startUploading($files)" multiple>
- </div>
- </div>
- <div class="col-xs-9">
- <div class="panel-body">
- <div class="panel panel-default" ng-repeat="uploadedFile in UploadedFiles track by $index">
- <div class="panel-heading">
- <strong>{{uploadedFile.FileName}}</strong>
- </div>
- <div class="panel-body">
- <div class=" media">
- <a class="pull-left" href="#">
- <img class="media-object" width="100" ng-src="../uploadimages/{{uploadedFile.FileName}}" />
- </a>
- <div class="media-body">
- <div class="lead" style="font-size:14px;color: crimson;width:500px;word-wrap:break-word">{{uploadedFile.FilePath}}</div>
- </div>
- </div>
- </div>
- <div class="panel-footer">
- 图片总字节: <span style="color:black">{{uploadedFile.FileLength}}</span>
- </div>
- </div>
- </div>
- </div>
- </div>
后台api服务:
- [RoutePrefix("api/upload")]
- public class FileUploadController : ApiController
- {
- [Route("")]
- [MimeMultipart]
- public async Task<FileUploadResult> Post()
- {
- var uploadPath = HttpRuntime.AppDomainAppPath + "UploadImages";
- if (!Directory.Exists(uploadPath))
- Directory.CreateDirectory(uploadPath);
- var multipartFormDataStreamProvider = new UploadMultipartFormProvider(uploadPath);
- await Request.Content.ReadAsMultipartAsync(multipartFormDataStreamProvider);
- string _localFileName = multipartFormDataStreamProvider
- .FileData.Select(multiPartData => multiPartData.LocalFileName).FirstOrDefault();
- return new FileUploadResult
- {
- LocalFilePath = _localFileName,
- FileName = Path.GetFileName(_localFileName),
- FileLength = new FileInfo(_localFileName).Length
- };
- }
- }
首先我们来看看例子搭建的结构:
生成界面效果:
下面我们来演示下最终效果:
(1)在WebAPi中用到路由特性时,若在控制器中如 [RoutePrefix("api/upload")] 此时在方法中若未有 [Route("")] 此时在上传的url必须显示添加Post如: url: "/api/upload/post" 若添加则不用显示添加方法名。
(2)在angular中加载模板为
- <div ng-include src="''"></div> 【注】:src中要加单引号,否则出错
- 或者
- <div ng-include></div>
(3)对于在WebAPi中上传可以参看此链接,更加详细。
WebAPi:https://github.com/stewartm83/angular-fileupload-sample
对于AngularJS组件中的加载和上传还有更多用法,可以参看如下链接:
ng-file-upload:https://github.com/danialfarid/ng-file-upload
angular-loading-bar:https://github.com/chieffancypants/angular-loading-bar