是否可以根据 Accept 标头的媒体类型在 .NET MVC 中选择带有 AttributeRouting 的操作? [英] Is it possible to select an Action with AttributeRouting in .NET MVC based on the Media Type of the Accept header?

查看:14
本文介绍了是否可以根据 Accept 标头的媒体类型在 .NET MVC 中选择带有 AttributeRouting 的操作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想根据 Accept 标头中请求的媒体类型选择我的控制器的操作.

I want to select an Action of my Controller based on the Media Type requested in the Accept header.

例如,我有一个名为主题的资源.其分配的路线是:

For example, I have a resource called a subject. Its assigned route is:

GET/subjects/{subjectId:int}

GET /subjects/{subjectId:int}

通常,浏览器请求的是 text/html,这很好.默认的 Media Formatter 处理得很好.

Normally, the browser is requesting text/html, which is fine. The default Media Formatter handles this great.

现在,当使用指定 application/pdf 作为接受的媒体类型的接受标头访问同一路由时,我想要执行自定义逻辑.

Now, I have custom logic I want to perform when this same route is accessed with an accept header specifying application/pdf as the accepted Media Type.

我可以创建一个自定义的媒体格式化程序,但是,据我所知,这意味着在接受标头设置为 application/pdf 的情况下请求的任何路由也将通过这个媒体格式化程序运行.这是不可接受的.

I could create a custom Media Formatter, but, to my understanding, this would mean that any route that is requested with the Accept header set to application/pdf would also run through this Media Formatter. This is unacceptable.

在Java中,有一个注释叫做@Produces:

In Java, there is an annotation called @Produces:

@Produces 注释用于指定 MIME 媒体类型或资源可以产生并发送回客户端的表示.如果@Produces 应用于类级别,资源中的所有方法默认情况下可以生成指定的 MIME 类型.如果在申请方法级别,注释覆盖任何@Produces 注释应用于班级.

The @Produces annotation is used to specify the MIME media types or representations a resource can produce and send back to the client. If @Produces is applied at the class level, all the methods in a resource can produce the specified MIME types by default. If applied at the method level, the annotation overrides any @Produces annotations applied at the class level.

这将允许我执行以下操作:

This would allow me to do the following:

namespace MyNamespace
{
    [RoutePrefix("subjects")]
    public class SubjectsController : Controller
    {
        [Route("{subjectId:int}")]
        [HttpGet]
        public ActionResult GetSubject(int subjectId)
        {
        }

        [Route("{subjectId:int}")]
        [HttpGet]
        [Produces("application/pdf")]
        public ActionResult GetSubjectAsPdf(int subjectId)
        {
            //Run my custom logic here to generate a PDF.
        }
    }
}

当然,.NET 中没有我可以找到的 Produces 属性,所以这不起作用.我也找不到类似的属性.

There is no Produces Attribute in .NET that I can find, of course, so this doesn't work. I haven't been able to find a similar attribute, either.

我当然可以手动检查动作正文中的标题,并将其重定向到另一个动作,但这充其量看起来很黑.

I could of course manually check the header within the body of the action, and redirect it to another action, but that seems hackish at best.

.NET 4.5 中是否有一种机制可以用来解决我忽略或遗漏的问题?

(我正在使用 NuGet 存储库中的 MVC 5.2.2)

(I'm using MVC 5.2.2 from NuGet repository)

推荐答案

在 Internet 上搜索了一段时间后,我想到最好通过创建 ActionMethodSelectorAttribute 来实现这一点.

After searching around the Internet for awhile, I came up with the idea that this would be best accomplished by creating an ActionMethodSelectorAttribute.

以下是我编写的 ProducesAttribute 的一个非常幼稚的第一遍实现,其最终目的是模仿 Java 的 Produces 注释:

The following is a very naive, first-pass implementation of a ProducesAttribute that I wrote with the eventual intent of mimicking Java's Produces annotation:

namespace YourNamespace
{
    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Net.Mime;
    using System.Web.Mvc;

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public sealed class ProducesAttribute : ActionMethodSelectorAttribute
    {
        private readonly ISet<ContentType> acceptableMimeTypes;

        public ProducesAttribute(params string[] acceptableMimeTypes)
        {
            this.acceptableMimeTypes = new HashSet<ContentType>();

            foreach (string acceptableMimeType in acceptableMimeTypes)
                this.acceptableMimeTypes.Add(new ContentType(acceptableMimeType));
        }

        public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
        {
            string acceptHeader = controllerContext.RequestContext.HttpContext.Request.Headers[HttpRequestHeader.Accept.ToString()];
            string[] headerMimeTypes = acceptHeader.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries);

            foreach (var headerMimeType in headerMimeTypes)
            {
                if (this.acceptableMimeTypes.Contains(new ContentType(headerMimeType)))
                    return true;
            }

            return false;
        }
    }
}

它旨在与属性路由一起使用,可以按如下方式应用:

It is meant to be used with Attribute Routing, and can be applied as follows:

public sealed class MyController : Controller
{
    [Route("subjects/{subjectId:int}")] //My route
    [Produces("application/pdf")]
    public ActionResult GetSubjectAsPdf(int subjectId)
    {
        //Here you would return the PDF representation.
    }

    [Route("subjects/{subjectId:int}")]
    public ActionResult GetSubject(int subjectId)
    {
        //Would handle all other routes.
    }
}

这篇关于是否可以根据 Accept 标头的媒体类型在 .NET MVC 中选择带有 AttributeRouting 的操作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆