1

我有一个MediaTypeFormatter将图像的内部代表转换为 png/jpeg/等。如果有人要求。但是,WriteToStreamAsync除非我添加 image/png 或类似于接受标头,否则我永远不会被调用。

首先,这是我的 webapi 方法,为简洁起见,删除了一些关键位:

public ImageFormatter.BinaryImage GetImage(int cId, int iId)
{
    ....

    using (var input = iFIO.OpenRead())
    {
        input.Read(b.data, 0, (int)iFIO.Length);
    }

    // With this next line my mediatypeformatter is correctly called.
    Request.Headers.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("image/png"));

    return b;
}

这是我的写部分MediaTypeFormatter(还有一个读部分,实际上效果很好)。

namespace PivotWebsite.MediaFormatters
{
    public class ImageFormatter : MediaTypeFormatter
    {
        public class BinaryImage
        { 
            public byte[] data;
            public string metaData;
        }

        public ImageFormatter()
        {
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("image/jpg"));
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("image/jpeg"));
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("image/png"));
        }

        public override bool CanWriteType(Type type)
        {
            return true;
        }

        public override async Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
        {
            var b = value as BinaryImage;
            if (b == null)
                throw new InvalidOperationException("Can only work with BinaryImage types!");

            await writeStream.WriteAsync(b.data, 0, b.data.Length);
        }
    }
}

我希望能够做的是,在WriteToStreamAsync中更改传出标题以将 Content-Type 包含为“image/png”(或其他任何内容,具体取决于数据类型)。

但是,当我从带有“ http://my.testdomain.net:57441/api/Images?cID=1&iID=1”之类的 URL 的 Web 浏览器调用它时,WriteToStreamAsync永远不会调用它(接受的标头列为 {text/html, application/xhtml+xml, */*})。如果我在上面添加添加正确图像类型的行,那么一切都会按我的预期调用。

我在这里想念什么?接受的“*/*”标头应该触发了我的媒体格式化程序,对吧?或者...我是否缺少有关 Web API 管道的基本知识。

4

2 回答 2

2

如果 Accept 标头是“ / ” ,您是否希望始终使用图像格式化程序?如果是这种情况,那么您应该首先在 Formatters 集合中插入您的格式化程序,如下所示:

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

当没有像您的情况那样的完全 Accept 标头匹配时会发生什么情况是,第一个可以写入类型的格式化程序被选中以序列化对象。因此,如果您先注册格式化程序,它将被使用。

这可能会产生意想不到的副作用,因为它会影响您的所有控制器。我建议将 CanWriteType 实现更改为仅在为 BinaryImage 时才返回 true。那应该使格式化程序仅在您的返回类型时才被使用。

您可以做的另一件事是通过返回 HttpResponseMessage 直接在您的操作中选择格式化程序:

return Request.CreateResponse(HttpStatusCode.OK, image, new ImageFormatter());

这基本上是说“此操作应始终使用图像格式化程序,无论内容类型如何,接受标题等”。如果您总是只返回图像并且您需要使用格式化程序对其进行序列化,那么这在您的情况下可能是合理的。

于 2013-03-24T15:45:37.977 回答
0

我正在编写一个 CsvFormatter,我希望能够从浏览器调用 API 来触发文件下载。由于我无法控制 Accept 标头,因此我想使用扩展来触发我的 CSV 格式化程序,但 XML 格式化程序不断收到请求。我发现通过添加“text/html”媒体类型,我可以处理 CSV 扩展。希望这不会导致其他问题:)。

public CsvFormatter()
{
    var header = new MediaTypeHeaderValue("text/csv");
    SupportedMediaTypes.Add(header);
    MediaTypeMappings.Add(new UriPathExtensionMapping("csv", header));

    // From Chrome: Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    // Allow the formatter to run from a standard browser request.
    header = new MediaTypeHeaderValue("text/html");
    SupportedMediaTypes.Add(header);
    MediaTypeMappings.Add(new UriPathExtensionMapping("csv", header));
}
于 2014-03-12T03:13:29.407 回答