简体   繁体   中英

WebApi attribute routing defined on interface

I'm trying to convert a WCF/REST service project to MVC/WebAPI. The service layer is implemented multiple times as a wrapper for different end systems, and all implementations observe a common contract defined in an interface ( IContract ). With WCF, we defined [WebInvoke] and [OperationContract] attributes on each of the methods which were exposed as web service methods. In WebAPI, this can be simplified with attribute routing defined on the controller. However, I would like to keep the route attributes defined on the interface, so all the implementations behave similarly.

Here's a sample of the old interface:

[ServiceContract]
public interface IContract
{
    [WebInvoke(UriTemplate = "Version", Method = "GET", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)]
    [OperationContract]
    string GetVersion();
}

Here's what I was hoping to get working:

public interface IContract
{
    [Route("Version")]
    [HttpGet]
    string GetVersion();
}

I would also consider creating an abstract base class, but this other StackOverflow question makes me think there isn't a suitable replacement for [WebInvoke(UriTemplate)] using WebAPI attribute routing. Is that the case, or can someone point me to a similar, supported technique?

Thanks

After some more research into what is coming out from the ASP.NET team, it looks like the System.Web.Http.Routing.IDirectRouteProvider extensibility will hopefully meet our needs. As of this writing, this is only available using the ASP.NET nightly builds, but will hopefully reach RTM or at least CTP by the time we're ready to roll it out.

The following code shows how to implement this for my example above (original source: https://aspnetwebstack.codeplex.com/workitem/1464 )

In Application_Start or WebApiConfig.Register() pass a new IDirectRouteProvider to the MapHttpAttributeRoutes() method.

config.MapHttpAttributeRoutes(new CustomDirectRouteProvider());

Define the Route Provider as follows. This basically just turns on attribute inheritance so it will read routes from the base class (but not the interface).

public class CustomDirectRouteProvider : DefaultDirectRouteProvider
{
    protected override IReadOnlyCollection<IDirectRouteFactory> GetActionRouteFactories(HttpActionDescriptor actionDescriptor)
    {
        return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>(inherit: true);
    }
}

In my case, we created an abstract BaseApiController that provides [Route] attributes to the WebAPI methods.

public abstract class BaseApiController : ApiController, IContract
{
    [Route("Version")]
    [HttpGet]
    public abstract string GetVersion();

}

Our end systems were formerly WCF REST service endpoints which implemented an IContract interface. For WebAPI, the controllers now derive from the BaseApiController. (We also had to change the name from ContractService to ContractServiceController.) We kept IContract around for backwards compatibility, but it's now implemented on BaseApiController. The [RoutePrefix] attribute is defined on the controller, which is our root URL in this case.

[RoutePrefix("")]
public class TestController : BaseApiController
{
    public override string GetVersion();
    {
        return "Version 1.0.0.0";
    }
}

You cannot decorate the interface with a Route attribute. This is because Web API works within its own framework... It inspects all objects that are of type ApiController in order to determine what to route. It basically interrogates your custom controller's methods' attributes in order to create the routing. It does not look for your custom IContract interface, so it would not care to do such routing.

Even if you change the code-base of Web API to read and process Route attributes from interfaces, how would this work? An interface is a contract and does not contain functionality. So, if it saw a route for "Version" , what controller implementation/instance would it map it to? The first one it arbitrarily finds which can be assigned to IContract ? The last one? All of them? And if all of them, how do you execute N controller methods at once?

I believe you need to evaluate your understanding of attribute routing. It tells the Web API framework to use THIS method on THIS controller for THIS route. You could not abstract this to interface because it would not be able to determine what deriving class to execute.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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