自从开始使用ASP.NET Web API,各种路由的蛋疼问题一直困扰着我,相信大家也都一样。
Web API的路由配置与ASP.MVC类似,在App_Start文件夹下,有一个WebApiConfig类文件
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
以上为一个空Web API项目的路由配置。
我们新建一个Controller
public class TestRouteController : ApiController
{
public HttpResponseMessage GetUser(int id)
{
return Request.CreateResponse(HttpStatusCode.OK, new
{
status = "success",
data = new { Id = id, Name = "用户" + id }
});
}
}
按照msdn所述
To find the action, Web API looks at the HTTP method, and then looks for an action whose name begins with that HTTP method name. For example, with a GET request, Web API looks for an action that starts with "Get...", such as "GetContact" or "GetAllContacts". This convention applies only to GET, POST, PUT, and DELETE methods. You can enable other HTTP methods by using attributes on your controller. We’ll see an example of that later.
Web API 约定了,如果方法名带有Get,则为Get请求,其他请求方式同样道理
当然,我们也可以使用HttpGet、HttpPost等特性,或者AcceptVerbs("GET","POST",...)等等,来控制我们的请求方式。
根据路由配置,我们可以理解,我们的访问地址应为:
api/TestRoute/123,请求方式为GET
毫无疑问的,我们拿到了想要的结果:
{"status":"success","data":{"Id":123,"Name":"用户123"}}
按照我们之前MVC路由的理解,路由中,new { id = RouteParameter.Optional }表示id参数是可选参数,我们期望的,在没有id传入的情况下,地址可以正常访问,id为默认值0。
很遗憾,直接404了。
我们简单改动一下代码
public HttpResponseMessage GetUser(int id = 0)
{
return Request.CreateResponse(HttpStatusCode.OK, new
{
status = "success",
data = new { Id = id, Name = "用户" + id }
});
}
我们将方法参数id设定了一个默认值,居然成功了
我们再变一种访问方式,api/TestRoute/?id=123
在有参数的情况下,是可以正常访问的。
而访问api/TestRoute/?id=,则会出现 {"Message":"请求无效。","MessageDetail":"对于“WebApiTest.Controllers.TestRouteController”中方法“System.Net.Http.HttpResponseMessage GetUser(System.DateTime)”的不可以为 null 的类型“System.DateTime”的参数“time”,参数字典包含一个 null 项。可选参数必须为引用类型、可以为 null 的类型或声明为可选参数。"}的400错误。
将id参数设定为int?类型,我们访问http://localhost:62488/api/TestRoute/?id=则可正常访问,并且此时id为null。
经过以上的测试,我们是否可以得出结论:
在ASP.NET Web API中,并且我们熟知的C# int未赋值时默认0,bool未赋值时默认false等在此都是不适用的
如果请求的参数在方法上定义,则参数名必须拼接在访问地址上
我们再试一种情况,我们将需要传入的参数放到一个类中,在方法上直接传入这个参数对象
public class QueryParams
{
public int Id { get; set; }
public string Name { get; set; }
}
public HttpResponseMessage GetUser(QueryParams queryParams)
{
return Request.CreateResponse(HttpStatusCode.OK, new
{
status = "success",
data = new { Id = queryParams.Id, Name = "用户:" + queryParams.Name }
});
}
直接访问api/TestRoute/,我们会发现,不管我们是否传入参数,我们的参数对象都是null。
这时候我们需要为我们的参数对象添加一个FromUri的特性,来告诉web api,我们这个对象的中属性都是从url链接上传过来的
这时候依旧不传入任何参数,却惊奇的发现,我们的对象参数不再是null,其中属性的值也与我们料想的一致(C# int未赋值时默认0,string默认null)
经过这进一步的尝试,我们可以完善我们的结论
通过queryString方法拼接参数时
如果请求的参数为C#语法定义的类型,且在方法上定义,则参数名必须拼接在访问地址上
如果请求的参数为一个实体类,则需要为该参数添加[FromUri]的特性。