Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/29.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么我的属性被激发到所有动作上,包括那些没有';你没有这个属性吗?_C#_Asp.net_Asp.net Mvc_Custom Attributes - Fatal编程技术网

C# 为什么我的属性被激发到所有动作上,包括那些没有';你没有这个属性吗?

C# 为什么我的属性被激发到所有动作上,包括那些没有';你没有这个属性吗?,c#,asp.net,asp.net-mvc,custom-attributes,C#,Asp.net,Asp.net Mvc,Custom Attributes,我的web api中有一个控制器。让我们称之为TimeController 我有一个GET动作和一个PUT动作。它们看起来像这样: public class TimeController : ApiController { [HttpGet] public HttpResponseMessage Get() { return Request.CreateResponse(HttpStatusCode.OK, DateTime.UtcNow); }

我的web api中有一个控制器。让我们称之为
TimeController

我有一个
GET
动作和一个
PUT
动作。它们看起来像这样:

public class TimeController : ApiController
{
    [HttpGet]
    public HttpResponseMessage Get()
    {
        return Request.CreateResponse(HttpStatusCode.OK, DateTime.UtcNow);
    }

    [HttpPut]
    public HttpResponseMessage Put(int id)
    {
        _service.Update(id);
        return Request.CreateResponse(HttpStatusCode.OK);
    }
}
public class TimeController : ApiController
{
    private IService _service;

    public TimeController(IService service)
    {
        _service = service;
    }

    [HttpGet, RouteVersion("Time", 1)]
    public HttpResponseMessage Get()
    {
        return Request.CreateResponse(HttpStatusCode.Ok, DateTime.UtcNow);
    }

    [HttpGet, RouteVersion("Time", 2)]
    public HttpResponseMessage GetV2()
    {
        return Request.CreateResponse(HttpStatusCode.Ok, DateTime.UtcNow.AddDays(1));
    }

    [HttpPut]
    public HttpResponseMessage Put(int id)
    {
        _service.Update(id);
        return Request.CreateResponse(HttpStatusCode.OK);
    }
}
我还有一个路由配置,如下所示:

routes.MapHttpRoute(“DefaultApi”、“{controller}/{id}”、新的{id=RouteParameter.Optional})

所以我可以以一种安静的方式访问它

现在,我还想使用自定义路由属性对
GET
操作进行版本设置。我使用的代码与Richard Tasker在本文中所说的非常相似

(不同之处在于,我使用正则表达式从accept头获取版本。其他所有内容基本相同)

我的控制器现在看起来像这样:

public class TimeController : ApiController
{
    [HttpGet]
    public HttpResponseMessage Get()
    {
        return Request.CreateResponse(HttpStatusCode.OK, DateTime.UtcNow);
    }

    [HttpPut]
    public HttpResponseMessage Put(int id)
    {
        _service.Update(id);
        return Request.CreateResponse(HttpStatusCode.OK);
    }
}
public class TimeController : ApiController
{
    private IService _service;

    public TimeController(IService service)
    {
        _service = service;
    }

    [HttpGet, RouteVersion("Time", 1)]
    public HttpResponseMessage Get()
    {
        return Request.CreateResponse(HttpStatusCode.Ok, DateTime.UtcNow);
    }

    [HttpGet, RouteVersion("Time", 2)]
    public HttpResponseMessage GetV2()
    {
        return Request.CreateResponse(HttpStatusCode.Ok, DateTime.UtcNow.AddDays(1));
    }

    [HttpPut]
    public HttpResponseMessage Put(int id)
    {
        _service.Update(id);
        return Request.CreateResponse(HttpStatusCode.OK);
    }
}
然而,现在当我尝试访问PUT端点时,我从服务器得到了404响应。如果我在调试模式下单步执行代码,我可以看到
RouteVersion
属性正在被激发,即使我没有用它修饰操作

如果我将属性添加到版本为1的PUT操作中,或者像这样添加内置路由属性:
Route(“Time”)
,那么它就可以工作了

所以我的问题是:为什么即使我没有用属性装饰动作,属性也会被激活

编辑:以下是属性的代码:

public class RouteVersion : RouteFactoryAttribute
{
    private readonly int _allowedVersion;

    public RouteVersion(string template, int allowedVersion) : base(template)
    {
        _allowedVersion = allowedVersion;
    }

    public override IDictionary<string, object> Constraints
    {
        get
        {
            return new HttpRouteValueDictionary
            { 
                {"version", new VersionConstraint(_allowedVersion)}
            };
        }
    }
}

public class VersionConstraint : IHttpRouteConstraint
{
    private const int DefaultVersion = 1;
    private readonly int _allowedVersion;
    public VersionConstraint(int allowedVersion)
    {
        _allowedVersion = allowedVersion;
    }

    public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary<string, object> values, HttpRouteDirection routeDirection)
    {
        if (routeDirection != HttpRouteDirection.UriResolution)
        {
            return true;
        }
        int version = GetVersionFromHeader(request) ?? DefaultVersion;
        return (version == _allowedVersion);
    }

    private int? GetVersionFromHeader(HttpRequestMessage request)
    {
        System.Net.Http.Headers.HttpHeaderValueCollection<System.Net.Http.Headers.MediaTypeWithQualityHeaderValue> acceptHeader = request.Headers.Accept;
        var regularExpression = new Regex(@"application\/vnd\.\.v([0-9]+)",
            RegexOptions.IgnoreCase);

        foreach (var mime in acceptHeader)
        {
            Match match = regularExpression.Match(mime.MediaType);
            if (match.Success)
            {
                return Convert.ToInt32(match.Groups[1].Value);
            }
        }
        return null; 
    }
}
公共类RouteVersion:RouteFactoryAttribute
{
私有只读int_允许的版本;
公共路由转换(字符串模板,int-allowedVersion):基本(模板)
{
_allowedVersion=allowedVersion;
}
公共重写索引约束
{
得到
{
返回新的HttpRouteValueDictionary
{ 
{“版本”,新版本约束(_allowedVersion)}
};
}
}
}
公共类版本约束:IHttpRouteConstraint
{
private const int DefaultVersion=1;
私有只读int_允许的版本;
公共版本约束(int-allowedVersion)
{
_allowedVersion=allowedVersion;
}
公共布尔匹配(HttpRequestMessage请求、IHttpRoute路由、字符串参数名称、IDictionary值、HttpRouteDirection路由方向)
{
if(routeDirection!=HttpRouteDirection.UriResolution)
{
返回true;
}
int version=GetVersionFromHeader(请求)??默认版本;
返回(版本==\u允许的版本);
}
private int?GetVersionFromHeader(HttpRequestMessage请求)
{
System.Net.Http.Headers.HttpHeaderValueCollection acceptHeader=request.Headers.Accept;
var regular expression=new Regex(@“application\/vnd\.\.v([0-9]+)”,
RegexOptions.IgnoreCase);
foreach(acceptHeader中的变量mime)
{
Match=regularpression.Match(mime.MediaType);
如果(匹配成功)
{
返回Convert.ToInt32(match.Groups[1].Value);
}
}
返回null;
}
}

Edit2:我觉得有点混乱,所以我更新了Put操作以匹配路由配置

我认为这是因为您的操作签名与默认路由相结合

在默认路由中,您将Id属性指定为可选属性,但是在操作中使用参数days,在这种情况下框架无法解析它。您可以将其添加为查询字符串参数,例如:

?days={days}
或者更改签名以接受id作为输入

由于它无法在url中解析包含天的操作,因此将返回404

就我个人而言,我不使用默认路由,总是使用属性路由来防止这种行为

所以我的问题是:为什么即使我没有用属性装饰动作,属性也会被激活

任何没有路由属性的控制器方法都使用基于约定的路由。这样,您可以在同一项目中组合这两种类型的布线

请参阅此链接:

另外,由于方法没有使用route属性修饰,所以当webapi框架接收到HTTP请求时,它会尝试将URI与路由表中的一个路由模板匹配。如果没有匹配的路由,客户端将收到404错误。这就是你得到404的原因

请看这张:

所以我的问题是:为什么即使我没有用属性装饰动作,属性也会被激活? 从“当我尝试访问PUT端点时”问题的措辞和它与GET操作匹配(然后运行其约束)的事实可以清楚地看出,您没有向服务器发出PUT请求。大多数浏览器都不能发出PUT请求,您需要一段代码或脚本来完成这项工作

例子
参考资料:

所以我知道我可以添加
RouteVersion
属性或
Route
属性,它会工作的,我只想知道为什么没有这两个属性就不能工作。我猜问题可能出在我尝试代码时添加的RouteVersion自定义属性属性代码中,I
GET
方法没有。我收到一个
500内部服务器错误
,告诉我找到了多个与请求匹配的操作。但是,
PUT
在我的情况下工作正常。我已更新了默认路由配置我已更新了路由配置中的行,并更新了PUT方法,使它们更匹配。这解决了您的问题吗?该操作现在是否在不添加RouteVersion属性的情况下解析?不,它没有。如果有,我会将其标记为已应答。此外,我已经用?id={id}调用了它,它是404,只是为了确定,您现在使用的url是什么(在操作中的id更新之后)?我认为操作不需要路由属性,因为我使用的是routeconfig以及路由属性。