【问题标题】:Web Api 2 or Generic Handler to serve images?提供图像的 Web Api 2 或通用处理程序?
【发布时间】:2015-06-17 13:50:08
【问题描述】:

我想创建一个图像处理程序,但我在使用Web API 2 或只是普通的Generic Handler (ashx) 之间纠结

我过去都实现过,但哪一个是最正确的。 我找到了一个旧的 SO 帖子 LINK,但它仍然真的相关吗?

【问题讨论】:

    标签: c# asp.net asp.net-web-api


    【解决方案1】:

    WebApi 功能齐全,我更喜欢它。另一个答案是正确的,JSON 和 XML 是默认的,但是您可以添加自己的 MediaFormatter 并为任何模型提供任何内容类型。这允许您执行内容协商并根据 Accept 标头或文件扩展名提供不同的内容。让我们假设我们的模型是“用户”。想象一下以 json、xml、jpg、pdf 格式请求“用户”。使用 WebApi,我们可以使用文件扩展名或 Accept 标头并要求 /Users/1 或 Users/1.json 用于 JSON,Users/1.jpg 用于 jpg,Users/1.xml 用于 xml,/Users/1.pdf对于 pdf 等。所有这些也可能只是 /Users/1 具有不同的 Accept 标头和质量,因此您的客户可以要求带有 Accept 标头的 Users/1 首先要求 jpg,但回退到 png。

    这是一个如何为 .jpg 创建格式化程序的示例。

    public class JpegFormatter : MediaTypeFormatter
    {
        public JpegFormatter()
        {
            //this allows a route with extensions like /Users/1.jpg
            this.AddUriPathExtensionMapping(".jpg", "image/jpeg");
    
            //this allows a normal route like /Users/1 and an Accept header of image/jpeg
            this.SupportedMediaTypes.Add(new MediaTypeHeaderValue("image/jpeg"));
        }
    
        public override bool CanReadType(Type type)
        {
            //Can this formatter read binary jpg data?
            //answer true or false here
            return false;
        }
    
        public override bool CanWriteType(Type type)
        {
            //Can this formatter write jpg binary if for the given type?
            //Check the type and answer. You could use the same formatter for many different types.
            return type == typeof(User);
        }
    
        public override async Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content,
            TransportContext transportContext)
        {
            //value will be whatever model was returned from your controller
            //you may need to check data here to know what jpg to get
    
            var user = value as User;
            if (null == user)
            {
                throw new NotFoundException();
            }
    
            var stream = SomeMethodToGetYourStream(user);
    
            await stream.CopyToAsync(writeStream);
        }
    }
    

    现在我们需要注册我们的格式化程序(通常是 App_Start/WebApiConfig.cs)

    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            ...
    
            //typical route configs to allow file extensions
            config.Routes.MapHttpRoute("ext", "{controller}/{id}.{ext}");
            config.Routes.MapHttpRoute("default", "{controller}/{id}", new { id = RouteParameter.Optional });
    
            //remove any default formatters such as xml
            config.Formatters.Clear();
    
            //order of formatters matter!
            //let's put JSON in as the default first
            config.Formatters.Add(new JsonMediaTypeFormatter());
    
            //now we add our custom formatter
            config.Formatters.Add(new JpegFormatter());
        }
    }
    

    最后,我们的控制器

    public class UsersController : ApiController
    {
        public IHttpActionResult Get(int id)
        {
            var user = SomeMethodToGetUsersById(id);
    
            return this.Ok(user);
        }
    }
    

    当您添加不同的格式化程序时,您的控制器不必更改。它只是返回您的模型,然后格式化程序稍后在管道中启动。我喜欢格式化程序,因为它提供了如此丰富的 api。您可以在WebApi website 上阅读有关格式化程序的更多信息。

    【讨论】:

    • 当您的默认格式化程序是 JSON 时,请告诉我<img src='/api/image/getImg' /> 的输出是什么?我认为根据您上面的示例的答案是它不起作用
    • 我在您的回答中回答了同样的问题,但也在这里回答:默认格式化程序将在此处运行并且是 json。这是一个 HTML 问题,无法在图像标记中表达 Accept 标头。因此,您需要添加文件扩展名src='/api/image/getImg.jpg'。然后这将路由到 JpegFormatter。任何能够设置标头的客户端都可以简单地将 Accept 标头放入 image/jpeg 并运行格式化程序。
    • @ManOVision,感谢您的回复,这正是我过去的做法。而且我认为在我想使用它的情况下,您的解决方案可能是最好的。
    【解决方案2】:

    正确的是ashx,原因是内容类型。如果您使用 Web Api,则响应的内容类型(即媒体格式化程序(格式))是为所有服务定义的类型,即 JSON、XML 或 oData。

    //Global Asax, Web Api register methods is used to defined WebApi formatters
    

    config.Formatters.Insert(0, new System.Net.Http.Formatting.JsonMediaTypeFormatter());

    但是图像是二进制文件,因此您需要以原始格式发送图像,而不是 JSON 或 XML

    response.AddHeader("content-type", "image/png");

     response.BinaryWrite(imageContent);
     response.Flush();
    

    这就是为什么 ashx 是适合这项工作的工具。

    另一个优点是您可以更好地控制您的输出,而无需为您想要返回的每种图像类型编写一个新的“格式化程序”(使用 WebApi 来解决此问题的方法),方法如下: Ashx 文件:

    var png = Image.FromFile("some.png");
    png.Save("a.gif", var png = Image.FromFile("some.png");
    png.Save("a.gif", ImageFormat.Gif); //Note you can save the new image into a MemoryStream to return it later in the same method.
    

    而且你有各种各样的类型可以玩:

    https://msdn.microsoft.com/en-us/library/system.drawing.imaging.imageformat(v=vs.110).aspx

    重要提示:我们都清楚WebApiAshx 都可以返回图像。我并不是说 WebApi 无法实现这一点,我只是说为什么我相信 Ashx 是正确的选择。

    【讨论】:

    • WebAPI 处理二进制格式没有任何问题,您只需要创建一个格式化程序。
    • 然而,您将影响该格式化程序下的所有路由,而不是一个返回图像的单一方法。我不是说你不能,只是工具不对
    • 如果你想发送二进制格式,你想影响所有返回它的路由。我不明白你的意思。
    • 检查我的答案,如果每个格式化程序可以响应给定的类型,它必须返回。它仅适用于您明确表示可以格式化的那些类型。
    • 但是您正在更改和定义来自客户端的图像的内容类型,它可能是 png 或我的 POV 中的 bmp 之类的东西,您不应该让客户端从动态中决定您的图像内容类型生成器
    【解决方案3】:

    我非常喜欢灵活性和定制化。我个人会选择httpHandler。所以要回答你的问题,这真的取决于你的要求。

    首先,WebAPI 是从 http (GET/POST) 调用到 Web 服务的演变的结果,并且需要能够以比 Web 服务更低的成本传输数据。 HttpHandlers 早在 web apis 之前就使用了相同的概念。基本上,web api 只不过是一个没有用户界面的 http 页面(如果你愿意的话)。

    在选择 HttpHandler 或 Web Api 之前需要了解的几件事

    1. 开发时间 - 您是否都非常了解以及哪些内容将花费更少的时间来实施
    2. 正如 ManOVision 在他的回答中提到的,路由 user/1 您仍然可以使用简单的代码和 httphandler 来实现,因此您实际上并不需要 Web API。只有您可能需要手动修改代码,这会增加一些开发时间
    3. 灵活性,我个人喜欢这部分,因为我可以根据用户提供的数据来控制我想要的响应内容类型。我不需要执行会话检查并重定向到任何页面。我仍然可以将这种行为控制为我想要的任何东西。您也可以使用 Web API,但大多数事情是在运行时自行处理到我们在开发时进行的配置。
    4. 两者的渲染网页是相同的。虽然 httphandler 很简单,为什么要使用 Web API?

    可能会有更多比较(作为一名经理,我认为也是从管理方面而不是完全技术角度),因此您可能需要权衡您的选择并决定要做什么。由于处理程序文件无论如何都是 Web API 的基础,我会说它为开发人员提供了比 Web API 更多的功能。就像 http 套接字比 httphandler 做的更多。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-11
      • 1970-01-01
      • 2017-02-01
      • 1970-01-01
      • 2012-07-28
      • 1970-01-01
      • 2014-03-30
      相关资源
      最近更新 更多