使用WebImage Class在asp.net webapi中上传图像

时间:2015-12-04 06:53:13

标签: asp.net asp.net-mvc asp.net-mvc-4 asp.net-web-api asp.net-web-api2

我想为我的webapi项目上传一个Image,我在 Asp.net MVC 4 中使用WebImage类来保存,裁剪,使用此类旋转图像。

我在ApiController中包含WebHelper,其功能与mvc project相同 我的问题是在webapi项目中,当我在Webapi控制器上传图像时,我收到错误:

    {
Message: "An error has occurred."
ExceptionMessage: "No MediaTypeFormatter is available to read an object of type 'WebImage' from content with media type 'multipart/form-data'."
ExceptionType: "System.InvalidOperationException"
StackTrace: " at System.Net.Http.HttpContentExtensions.ReadAsAsync[T](HttpContent content, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger) at System.Net.Http.HttpContentExtensions.ReadAsAsync(HttpContent content, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger) at System.Web.Http.ModelBinding.FormatterParameterBinding.ReadContentAsync(HttpRequestMessage request, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger) at System.Web.Http.ModelBinding.FormatterParameterBinding.ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken) at System.Web.Http.Controllers.HttpActionBinding.<>c__DisplayClass1.<ExecuteBindingAsync>b__0(HttpParameterBinding parameterBinder) at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext() at System.Threading.Tasks.TaskHelpers.IterateImpl(IEnumerator`1 enumerator, CancellationToken cancellationToken)"
}

和我的上传方法示例:

 [HttpPost]
   public HttpResponseMessage filer(WebImage data)
    {
        HttpResponseMessage response = null;
        if (data == null)
        {
            response = new HttpResponseMessage()
            {
                Content = new StringContent("Not a image file"),
                StatusCode = HttpStatusCode.BadRequest
            };
        }
        else {
            response = new HttpResponseMessage()
            {
                Content = new StringContent(data.FileName.ToString()),
                StatusCode = HttpStatusCode.OK
            };
        }


        return response;
    }

请解释我如何添加 MediaTypeFormatter 以支持WebImage类。

1 个答案:

答案 0 :(得分:1)

有两种方法涉及不使用MediaFormatter,这些方法包括创建自定义ModelBinder或实现接受base64编码字符串或字节数组以接受数据的模型类,然后将数据从该模型类转换为一个WebImage。但是要回答这个问题,这个过程非常简单。这是一个实现。

 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Net.Http.Formatting;
 using System.Web;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Web.Helpers;
 using System.Net.Http.Headers;
 using System.IO;
 using System.Net.Http;
 using Newtonsoft.Json;
 using Newtonsoft.Json.Linq;
 using System.Text;
 using System.Diagnostics;
 namespace StackOverFlowWI.Infrastructure
 {
     public class WebImageMediaFormatter : MediaTypeFormatter
     {
         public WebImageMediaFormatter()
         {
             SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
         }
         public override bool CanReadType(Type type)
         {
             return type == typeof(WebImage);
         }
         public override bool CanWriteType(Type type)
         {
             return false;
         }
         public async override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger, CancellationToken cancellationToken)
         {
             byte[] buffer = new byte[content.Headers.ContentLength.Value];
             while (await readStream.ReadAsync(buffer, (int)readStream.Position, buffer.Length - (int) readStream.Position) > 0)  {    }
             string stringData = Encoding.Default.GetString(buffer);
             JObject myJson = JObject.Parse(stringData);
             JToken myJToken = myJson.GetValue("imageBytes");
             byte[] myBytes = myJToken.Values().Select(x => (byte)x).ToArray();
             return new WebImage(myBytes);
         }
     }
 }

您必须在IIS托管应用程序中的HttpConfiguration对象格式化程序集合的实例中注册mediaformatter,这将在WebApiConfig.Register方法中。

        config.Formatters.Insert(0, new WebImageMediaFormatter());

我认为这是一个有趣的问题所以经历了一个实现,并为了完整性而包含一些javascript代码:

var ajaxCall = function (data) {

    dataString = data.toString();
    dataString = "[" + dataString + "]";
    dataString = JSON.parse(dataString);
    console.log(dataString.length);
    //console.log(dataString);
    var imageData = {};
    imageData.imageBytes = dataString;
    console.log(imageData);
    //console.log(imageData);
    var ajaxOptions = {};
    ajaxOptions.url = "/api/image/PostWebImage";
    ajaxOptions.type = "Post";
    ajaxOptions.contentType = "application/json";
    ajaxOptions.data = JSON.stringify(imageData);
    ajaxOptions.success = function () {
        console.log('no error detected');
    };
    ajaxOptions.error = function (jqXHR) {
        console.log(jqXHR);
    };
    $.ajax(ajaxOptions);

};
    var postImage = function () {
        var file = $('input[type=file]')[0].files[0];
        var myfilereader = new FileReader();
        myfilereader.onloadend = function () {

            var uInt8Array = new Uint8Array(myfilereader.result);
            ajaxCall(uInt8Array);
        }
        if (file) {
            myfilereader.readAsArrayBuffer(file);

        } else {
            console.log("failed to read file");
        }
    };

另请注意,除非您修改web.config文件以修改httpRuntime环境以接受大量请求,否则Web api中的硬编码限制将接受有限数量的数据。 (这假设您没有将上传缓冲到块中,这是一种更好的方法)。

<httpRuntime targetFramework="4.5" maxRequestLength="1024000" />

最后,如上所述,不需要mediaformatter的替代解决方案是创建一个带有公共属性的模型类,该属性在发送时接受数据。

namespace StackOverFlowWI.Models
{
     public class myModel
    {
        public byte [] imageBytes { get; set; }
     }
}

然后,您可以在操作方法中创建对象。

    public IHttpActionResult Post( myModel imageData )
    {
        WebImage myWI = new WebImage(imageData.imageBytes);
        string path = System.Web.Hosting.HostingEnvironment.MapPath("~/Images/somefile.png");
        myWI.Save(path);
        return Ok();
    }

为了将来参考,请记住,web api中的默认模型绑定器实现不接受任何类作为没有无参数构造函数的操作方法中的参数。此规则的唯一例外是使用依赖注入依赖注入添加ins(例如ninject或unity)时。