简体   繁体   English

ASP.NET WebApi-具有类似操作方法的两个控制器

[英]ASP.NET WebApi - Two Controllers With Similar Action Methods

I have a scenario where I have 2 different controllers that each have multiple Get methods. 我有一个场景,其中有2个不同的控制器,每个控制器都有多个Get方法。 I have the methods decorated with the ActionName attribute, but the Routing isn't working as I think it should. ActionName属性修饰的方法,但是路由没有按我认为的那样工作。

ContactController ContactController

public ContactModel GetContactByID(string id)
{
    ...
}

[ActionName("username")]
public ContactModel GetContactByUserName(string text)
{
    ...
}

PaymentController PaymentController

public PaymentModel Get(Guid id)
{
    ...
}

[HttpGet, ActionName("sale")]
public PaymentActivityModel Sale(Guid id)
{
    ...
}

Routes 路线

config.Routes.MapHttpRoute(
    "PaymentControllerActionId", 
    "api/client/{clientId}/{controller}/{action}/{id}", 
    defaults: null 
);

config.Routes.MapHttpRoute(
    "ContactControllerActionText", 
    "api/client/{clientId}/{controller}/{action}/{text}", 
    defaults: null
);

config.Routes.MapHttpRoute(
    "ClientControllerId", 
    "api/client/{clientId}/{controller}/{id}", 
    new { id = RouteParameter.Optional }
);

When I navigate to a Payment, it works fine. 当我导航到“付款”时,它可以正常工作。 But when I navigate to a Contact, I receive: 但是,当我导航到“联系人”时,会收到:

No HTTP resource was found that matches the request URI, .../api/client/.../contact/username/exampleUserName 找不到与请求URI匹配的HTTP资源... / api / client /.../ contact / username / exampleUserName

No action was found on the controller 'Contact' that matches the request. 在控制器“联系人”上未找到与请求匹配的操作。

I was under the impression that the parameter name would be matched up with the action name ( text vs. id ). 我的印象是参数名称将与动作名称( textid )匹配。

Is the problem that one uses a Guid id and one uses a string id? 是一个人使用Guid ID,一个人使用string ID的问题吗?

This is a client-facing API, and I have a client-friendly ContactID that is a string. 这是一个面向客户端的API,我有一个字符串的客户端友好型ContactID。 Whereas the PaymentID is a Guid. 而PaymentID是Guid。

First I want to point out your routes don't make a lot of sense. 首先,我想指出您的路线没有多大意义。

This route says it is for PaymentControllerActionId, however you left the routing open to use any controller instead of specifying it is only for the Payment Controller. 此路由说它是用于PaymentControllerActionId的,但是您将路由保留为打开状态以使用任何控制器,而不是指定仅用于Payment Controller。

config.Routes.MapHttpRoute(
    "PaymentControllerActionId", 
    "api/client/{clientId}/{controller}/{action}/{id}", 
    defaults: null 
);

To answer your question. 回答您的问题。 You likely need to specify {text} as an optional RouteParameter. 您可能需要指定{text}作为可选的RouteParameter。 Otherwise the framework usually expects that you have defined a custom routing constraint (and you should have a routing constraint on {clientId} IMO). 否则,框架通常期望您已定义了自定义路由约束(并且您应该在{clientId} IMO上具有路由约束)。

Also, if one of your actions expects a GUID. 另外,如果您的一项操作需要GUID。 Put it as a Guid argument type, and WebAPI will match it correctly. 将其作为Guid参数类型,WebAPI将正确匹配它。 Alternatively, since both functions are expecting either a name or a guid, you could just have only 1 function that takes a string, and in your db do a select statement matching the GUID or the NAME and return the contact. 或者,由于两个函数都期望使用名称或guid,因此您可能只有一个带有字符串的函数,然后在数据库中执行与GUID或NAME匹配的select语句并返回联系人。 Much less code, easier to read, makes more sense. 更少的代码,更易于阅读,更有意义。

If you are using Web API 2, then you could use attribute routing for this purpose. 如果您使用的是Web API 2,则可以为此目的使用属性路由。

In the below example, the controllers use a mix of conventional + attribute routing, but you can change this to only go by attribute routing if you need. 在下面的示例中,控制器混合使用常规+属性路由,但是您可以根据需要将其更改为仅通过属性路由进行。

Example: 例:

Route Configuration 路由配置

config.MapHttpAttributeRoutes();

config.Routes.MapHttpRoute(
    "ClientControllerId", 
    "api/client/{clientId}/{controller}/{id}", 
    new { id = RouteParameter.Optional }
);

ContactController ContactController

[RoutePrefix("api/client/{clientId}/Contact")]
public class ContactController
{
    // this uses conventional route
    public ContactModel GetContactByID(string id)
    {
        ...
    }

    [Route("username/{userName}")]
    public ContactModel GetContactByUserName(string userName)
    {
        ...
    }
}

PaymentController PaymentController

[RoutePrefix("api/client/{clientId}/Payment")]
public class PaymentController
{
    // this uses conventional route
    public PaymentModel Get(Guid id)
    {
        ...
    }

    [HttpGet, Route("sale/{id}")]
    public PaymentActivityModel Sale(Guid id)
    {
        ...
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM