C# 为什么我的属性被激发到所有动作上,包括那些没有';你没有这个属性吗?
我的web api中有一个控制器。让我们称之为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); }
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自定义属性属性代码中,IGET
方法没有。我收到一个500内部服务器错误
,告诉我找到了多个与请求匹配的操作。但是,PUT
在我的情况下工作正常。我已更新了默认路由配置我已更新了路由配置中的行,并更新了PUT方法,使它们更匹配。这解决了您的问题吗?该操作现在是否在不添加RouteVersion属性的情况下解析?不,它没有。如果有,我会将其标记为已应答。此外,我已经用?id={id}调用了它,它是404,只是为了确定,您现在使用的url是什么(在操作中的id更新之后)?我认为操作不需要路由属性,因为我使用的是routeconfig以及路由属性。