【问题标题】:Upload Image in asp.net webapi using WebImage Class使用 Web Image Class 在 asp.net web api 中上传图像
【发布时间】:2016-03-09 01:02:42
【问题描述】:

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

我在 ApiController 中包含 WebHelper,其功能与 mvc 项目相同 我的问题是在 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 类。

【问题讨论】:

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


【解决方案1】:

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

 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 api 中的硬编码限制接受有限数量的数据,除非您修改 web.config 文件以修改 httpRuntime 环境以接受大型请求。 (这是假设您不将上传缓冲成块,这将是一种更好的方法)。

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

最后,一个不需要上述媒体格式化程序的替代解决方案是创建一个模型类,该模型类具有一个在发送数据时接受数据的公共属性。

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 中的默认模型绑定器实现不接受任何类作为没有无参数构造函数的操作方法中的参数。此规则的唯一例外是使用依赖注入插件(如 ninject 或 unity)的依赖注入。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-16
    • 1970-01-01
    • 1970-01-01
    • 2015-11-24
    • 1970-01-01
    • 1970-01-01
    • 2019-01-06
    • 1970-01-01
    相关资源
    最近更新 更多