向 Restful API 添加多个自定义 "get" 调用
Adding multiple custom "get" calls to Restful API
我只使用过几个 Restful API,并且一直需要创建一个。最终我需要一个 API 并希望 Restful 方面,但那部分不是最终的焦点。
我创建了一个原型并让基本的 html 调用工作正常。然后我想转到其他类型的电话。我看过很多文章和片段,但其中 none 似乎真的能回答我的问题。我正在使用 Postman 进行测试。现在我有两个基本调用 "Get" 调用,它们都带有三个字符串参数,意识到它们具有相同的签名但名称不同。我收到与歧义相关的错误。任何帮助表示赞赏
以下是我的设置:
public class Startup
{
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "ApiByName",
routeTemplate: "api/{controller}/{name}",
defaults: null,
constraints: new { name = @"^[a-z]+$" }
);
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
config.Formatters.JsonFormatter.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
app.UseWebApi(config);
}
}
下面是我的两个方法调用
[Route("{UserId}/{Key}/{Source}", Name = "GetToken")]
[HttpGet]
public HttpResponseMessage GetToken(string UserId, string Key)
{
}
[Route("{Token}/{AcctNo}/{YearMonth}", Name = "GetInvoices")]
[HttpGet]
public HttpResponseMessage GetInvoices(string Token, string AcctNo, string YearMonth)
{
}
如果我注释掉其中一个,另一个将被调用,但我似乎无法让它工作。
------------Update------------...修改了代码如下。
"ApiByName" 已从配置启动中删除。以下是方法。我包含了一个我以前没有展示过的通用 get。
public IEnumerable<CustomListItem> Get()
{
// return new string[] { "value1", "value2" };
return _listItems;
}
[Route("GetToken/{UserId}/{Key}/{Source}")]
[HttpGet]
public HttpResponseMessage GetToken(string UserId, string Key, string Source)
{
...
}
[Route("GetInvoices/{Token}/{AcctNo}/{YearMonth}")]
[HttpGet]
public HttpResponseMessage GetInvoices(string Token, string AcctNo, string YearMonth)
{
...
}
即使进行了上述更改,调用始终转到通用 Get(显示的第一种方法)以下是来自邮递员的调用示例(以及直接粘贴在浏览器中)??
http://localhost:37788/api/listitems/GetToken?UserId=Dshadle&Key=ABC&Source=Postman
http://localhost:37788/api/listitems/GetInvoices?Token=abc&AcctNo=123&YearMonth=2019/12
如果您多次遇到此问题,那是因为您将太多操作放入单个端点。请记住将每个实体(或聚合)的操作分离到它自己的控制器中。
如果您不是这种情况,那么最简单的解决方案是使用查询参数
将所有 6 个参数放入模型中,将其作为 Get 方法的参数传递,并用 [FromQuery] 注释。
像这样:
[HttpGet]
public async Task<IActionResult> Get([FromQuery] GetRequestParameters parameters)
{
...
}
这样你就可以这样称呼它:
获取https://your_url/api/your_controller?userId=123&key=secret&source=somesource
或者
获取https://your_url/api/your_controller?token=abcd&accountNumber=secret&yearMonth=202001
请注意,您可能会同时收到无意义的参数,例如 token、key 和 userId,这些参数不符合您的要求,因此您应该验证输入
您似乎想将 api/ListItems/GetToken
映射到 GetToken()
端点,对于 GetInvoices
也是如此。根据您共享的 URL,我假设您的控制器名为 ListItems
。
实际上有两种方法可以做到这一点。无论您选择使用哪种方法,您都不需要将参数添加到您显示的 URL 的路由中。
1。 Attribute Routing
从配置中删除 ApiByName
路由。然后,您可以用完整路径(例如 [Route("api/ListItems/GetToken")]
)、 或 装饰每个动作,用 [RoutePrefix("api/ListItems")]
装饰控制器,并用 [= 装饰动作21=]。下面的示例在控制器上使用 RoutePrefix
。
[RoutePrefix("api/ListItems")]
public class ListItemsController : ApiController
{
[Route("GetToken")]
[HttpGet]
public HttpResponseMessage GetToken(string UserId, string Key, string source)
[Route("GetInvoices", Name = "GetInvoices")]
[HttpGet]
public HttpResponseMessage GetInvoices(string Token, string AcctNo, string YearMonth)
如果您想要一个看起来像 ListItems/GetToken/123/ABC/Postman
的 URL,那么只需将参数添加回路由 [Route("GetToken/{UserId}/{Key}/{Source}")]
,但是,您发布的 URL 不会匹配该格式。
Route
属性的 Name
属性 可能无法像您预期的那样工作。它实际上用于定义 API 内部的端点,而不是外部的。例如,RedirectToRoute("GetInvoices")
将 return 重定向到 GetInvoices
端点。是否需要包含它取决于您。
2。 Conventional Routing
根本不要使用 [Route]
属性。
相反,将以下路由添加到 API 路由配置(感谢 Darin Dimitrov 的 answer):
config.Routes.MapHttpRoute(
name: "ApiById",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new { id = @"^[0-9]+$" }
);
config.Routes.MapHttpRoute(
name: "ApiByAction",
routeTemplate: "api/{controller}/{action}",
defaults: new { action = "Get" }
);
然后在控制器中使用ActionName("MyAction")
属性:
[HttpGet]
[ActionName("GetToken")]
public HttpResponseMessage GetToken(string UserId, string Key, string source)
[HttpGet]
[ActionName("GetInvoices")]
public HttpResponseMessage GetInvoices(string Token, string AcctNo, string YearMonth)
我已经使用以下 URL 测试了这两种方法:
// get list of items
http://localhost:28092/api/ListItems
// get single item
http://localhost:28092/api/ListItems/1
// GetToken
http://localhost:28092/api/ListItems/GetToken?userid=123&key=ABC&source=Postman
// GetInvoices
http://localhost:28092/api/ListItems/GetInvoices?token=ABC&acctno=1234&yearmonth=2019-12
注意 1:我建议 不要 使用 /
作为URL 中的日期分隔符,因为它可能会干扰路由,请改用 -
或其他分隔符。
注2:参数必须有值,否则框架将无法找到正确的动作。如果(某些)参数应该是可选的,则在方法签名中指定默认值,例如 GetToken(string UserId, string Key, string source = "")
(source
在这里是可选的)。
但是,如果您想遵循 RESTful 模式,那么您应该真正构建端点以匹配它们所作用的资源 on/for。您可能应该有一个 Invoice
控制器,您可以在其中为 Invoice
执行 Get
、Post
、Put
、Delete
等。 GetToken
似乎它属于不同的控制器,除非它以某种方式与发票相关。
你最后的方法是正确的,但这里的问题是你混合了 2 个方案。
您提供此设置:[Route("GetInvoices/{Token}/{AcctNo}/{YearMonth}")]
然后你转身使用这样的查询参数进行测试
/api/ListItems/GetInvoices?token=ABC&acctno=1234&yearmonth=2019-12
但是如果你看你的Route
属性,它表明这个动作的路线应该在路径中完成。相反,更改您正在测试的 URL 以匹配路径,如下所示:
/api/ListItems/GetInvoices/ABC/1234/2019-12
我只使用过几个 Restful API,并且一直需要创建一个。最终我需要一个 API 并希望 Restful 方面,但那部分不是最终的焦点。
我创建了一个原型并让基本的 html 调用工作正常。然后我想转到其他类型的电话。我看过很多文章和片段,但其中 none 似乎真的能回答我的问题。我正在使用 Postman 进行测试。现在我有两个基本调用 "Get" 调用,它们都带有三个字符串参数,意识到它们具有相同的签名但名称不同。我收到与歧义相关的错误。任何帮助表示赞赏
以下是我的设置:
public class Startup
{
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "ApiByName",
routeTemplate: "api/{controller}/{name}",
defaults: null,
constraints: new { name = @"^[a-z]+$" }
);
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
config.Formatters.JsonFormatter.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
app.UseWebApi(config);
}
}
下面是我的两个方法调用
[Route("{UserId}/{Key}/{Source}", Name = "GetToken")]
[HttpGet]
public HttpResponseMessage GetToken(string UserId, string Key)
{
}
[Route("{Token}/{AcctNo}/{YearMonth}", Name = "GetInvoices")]
[HttpGet]
public HttpResponseMessage GetInvoices(string Token, string AcctNo, string YearMonth)
{
}
如果我注释掉其中一个,另一个将被调用,但我似乎无法让它工作。
------------Update------------...修改了代码如下。
"ApiByName" 已从配置启动中删除。以下是方法。我包含了一个我以前没有展示过的通用 get。
public IEnumerable<CustomListItem> Get()
{
// return new string[] { "value1", "value2" };
return _listItems;
}
[Route("GetToken/{UserId}/{Key}/{Source}")]
[HttpGet]
public HttpResponseMessage GetToken(string UserId, string Key, string Source)
{
...
}
[Route("GetInvoices/{Token}/{AcctNo}/{YearMonth}")]
[HttpGet]
public HttpResponseMessage GetInvoices(string Token, string AcctNo, string YearMonth)
{
...
}
即使进行了上述更改,调用始终转到通用 Get(显示的第一种方法)以下是来自邮递员的调用示例(以及直接粘贴在浏览器中)??
http://localhost:37788/api/listitems/GetToken?UserId=Dshadle&Key=ABC&Source=Postman
http://localhost:37788/api/listitems/GetInvoices?Token=abc&AcctNo=123&YearMonth=2019/12
如果您多次遇到此问题,那是因为您将太多操作放入单个端点。请记住将每个实体(或聚合)的操作分离到它自己的控制器中。
如果您不是这种情况,那么最简单的解决方案是使用查询参数
将所有 6 个参数放入模型中,将其作为 Get 方法的参数传递,并用 [FromQuery] 注释。
像这样:
[HttpGet]
public async Task<IActionResult> Get([FromQuery] GetRequestParameters parameters)
{
...
}
这样你就可以这样称呼它:
获取https://your_url/api/your_controller?userId=123&key=secret&source=somesource
或者
获取https://your_url/api/your_controller?token=abcd&accountNumber=secret&yearMonth=202001
请注意,您可能会同时收到无意义的参数,例如 token、key 和 userId,这些参数不符合您的要求,因此您应该验证输入
您似乎想将 api/ListItems/GetToken
映射到 GetToken()
端点,对于 GetInvoices
也是如此。根据您共享的 URL,我假设您的控制器名为 ListItems
。
实际上有两种方法可以做到这一点。无论您选择使用哪种方法,您都不需要将参数添加到您显示的 URL 的路由中。
1。 Attribute Routing
从配置中删除 ApiByName
路由。然后,您可以用完整路径(例如 [Route("api/ListItems/GetToken")]
)、 或 装饰每个动作,用 [RoutePrefix("api/ListItems")]
装饰控制器,并用 [= 装饰动作21=]。下面的示例在控制器上使用 RoutePrefix
。
[RoutePrefix("api/ListItems")]
public class ListItemsController : ApiController
{
[Route("GetToken")]
[HttpGet]
public HttpResponseMessage GetToken(string UserId, string Key, string source)
[Route("GetInvoices", Name = "GetInvoices")]
[HttpGet]
public HttpResponseMessage GetInvoices(string Token, string AcctNo, string YearMonth)
如果您想要一个看起来像 ListItems/GetToken/123/ABC/Postman
的 URL,那么只需将参数添加回路由 [Route("GetToken/{UserId}/{Key}/{Source}")]
,但是,您发布的 URL 不会匹配该格式。
Route
属性的 Name
属性 可能无法像您预期的那样工作。它实际上用于定义 API 内部的端点,而不是外部的。例如,RedirectToRoute("GetInvoices")
将 return 重定向到 GetInvoices
端点。是否需要包含它取决于您。
2。 Conventional Routing
根本不要使用 [Route]
属性。
相反,将以下路由添加到 API 路由配置(感谢 Darin Dimitrov 的 answer):
config.Routes.MapHttpRoute(
name: "ApiById",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new { id = @"^[0-9]+$" }
);
config.Routes.MapHttpRoute(
name: "ApiByAction",
routeTemplate: "api/{controller}/{action}",
defaults: new { action = "Get" }
);
然后在控制器中使用ActionName("MyAction")
属性:
[HttpGet]
[ActionName("GetToken")]
public HttpResponseMessage GetToken(string UserId, string Key, string source)
[HttpGet]
[ActionName("GetInvoices")]
public HttpResponseMessage GetInvoices(string Token, string AcctNo, string YearMonth)
我已经使用以下 URL 测试了这两种方法:
// get list of items
http://localhost:28092/api/ListItems
// get single item
http://localhost:28092/api/ListItems/1
// GetToken
http://localhost:28092/api/ListItems/GetToken?userid=123&key=ABC&source=Postman
// GetInvoices
http://localhost:28092/api/ListItems/GetInvoices?token=ABC&acctno=1234&yearmonth=2019-12
注意 1:我建议 不要 使用 /
作为URL 中的日期分隔符,因为它可能会干扰路由,请改用 -
或其他分隔符。
注2:参数必须有值,否则框架将无法找到正确的动作。如果(某些)参数应该是可选的,则在方法签名中指定默认值,例如 GetToken(string UserId, string Key, string source = "")
(source
在这里是可选的)。
但是,如果您想遵循 RESTful 模式,那么您应该真正构建端点以匹配它们所作用的资源 on/for。您可能应该有一个 Invoice
控制器,您可以在其中为 Invoice
执行 Get
、Post
、Put
、Delete
等。 GetToken
似乎它属于不同的控制器,除非它以某种方式与发票相关。
你最后的方法是正确的,但这里的问题是你混合了 2 个方案。
您提供此设置:[Route("GetInvoices/{Token}/{AcctNo}/{YearMonth}")]
然后你转身使用这样的查询参数进行测试
/api/ListItems/GetInvoices?token=ABC&acctno=1234&yearmonth=2019-12
但是如果你看你的Route
属性,它表明这个动作的路线应该在路径中完成。相反,更改您正在测试的 URL 以匹配路径,如下所示:
/api/ListItems/GetInvoices/ABC/1234/2019-12