I am using attribute routing for Web Api. What I am trying to accomplish is to write a controller selector so that controller classes sharing the same name but that reside under different namespaces will be reached using their different attribute routes (as Web Api does not allow this by default).
I have searched the web for examples and found the following:
https://github.com/WebApiContrib/WebAPIContrib/pull/111/files
http://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/NamespaceControllerSelector/NamespaceHttpControllerSelector.cs
But as far as I can understand, they seem to be modifications for the default {controller}/{action}/{id} style convention based routing. Because they use routeData.Values.TryGetValue(ControllerKey, out controllerName) to get the controller name from the request route data in the controller selector. But since I am using attributes, I guess I cannot use this.
Is there a sample or a guide that shows how to accomplish this using attribute routing?
EDIT1:
Here is a simple example of the scenario I described as requested in a comment:
namespace NS1
{
public class Class1 : ApiController
{
[HttpGet]
[Route("dosomething1")]
public object DoSomething()
{
}
}
}
namespace NS2
{
public class Class1 : ApiController
{
[HttpGet]
[Route("dosomething2")]
public object DoSomething()
{
}
}
}
Related
I would like to list all the available endpoints a controller provides.
Is it possible to access the component(s) .NET uses to generate these routes (by, for instance providing it a type or controller name (string))?
The methods/verbs (so, POST, GET) are not even that important for my scenario, just the routes themselves.
Example
Please, take a look on the below ASP.NET Core code.
[ApiController]
[Route("[controller]")
public class HomeController : ControllerBase
{
[HttpGet("additional")]
public async Task<IActionResult> Whatever()
{
// ...
}
}
So, the method will be exposed as a GET endpoint on the URL of Home/additional.
Why this doesn't work? I get error: System.InvalidOperationException: Multiple controller types were found that match the URL. This can happen if attribute routes on multiple controllers match the requested URL.
public class ConfigUpdateController: ApiController
{
[HttpPut]
[Route("api/device/{serial}/config")]
public IHttpActionResult Update(
[FromUri] string serial,
[FromBody] Configuration configuration)
{
}
}
public class ConfigQueryController: ApiController
{
[HttpGet]
[Route("api/device/{serial}/config")]
public IHttpActionResult Get(
[FromUri] string serial)
{
}
}
The reason why i want to have methods for same resource in separate controllers is decoupling queries from commands.
EDIT
To be honest, it's ample code to illustrate my problem, so please don't bother commenting controllers naming ect. It's not important in context of my question.
EDIT 2
I've found here web-api overview thet routing has 3 phases:
Routing has three main phases:
Matching the URI to a route template.
Selecting a controller.
Selecting an action.
So it seems this does not work because controller can't be resolved and method verb (PUT, GET) are not even checked? O_o
Read the error carefully, then look at your attribute routing. You have identical URLs for two different actions.
Program would have no idea which action to execute.
use [FromRoute] instead of [FromUri] annotations
I want to remove controller name from URL for specific Controller.
My Controller name is Product
I found some link to do this
Routing with and without controller name
MVC Routing without controller
But all the above links done in route config file. and those are affecting other controller too. I want to do it using Attribute Routing.
Can it is possible? As I want to do this for only Product controller.
I have tried to do it on action like this
[Route("Sample/{Name}")]
but it is not working.
Gabriel's answer is right, however, it can be a bit misleading since you're asking for MVC and that answer is for Web API.
In any case, what you want is to put the annotation over the class definition instead of an action method. MVC example would be like:
[RoutePrefix("SomethingOtherThanProduct")]
public class ProductController : Controller
{
public ActionResult Index()
{
...
return View();
}
}
I'm also dropping this as an answer since you may find the following article helpful: [Attribute] Routing in ASP.NET MVC 5 / WebAPI 2
Make sure you set the RoutePrefix attribute on the whole controller class, as well as using the Route attribute on the action.
[RoutePrefix("notproducts")]
public class ProductsController : ApiController
{
[Route("")]
public IEnumerable<Product> Get() { ... }
}
I'm having a problem with splitting my web-api application into different areas (not mvc areas), using namespaces and RoutePrefix
The application is hosted using Owin Self Host, and in my Startup class I have the following.
HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
app.UseWebApi(config);
And my two controllers that I tested with
[RoutePrefix("api/test")]
public class TestController : ApiController
{
[Route("")]
public IHttpActionResult Get()
{
return Ok("api");
}
}
[RoutePrefix("sync/test")]
public class TestController : ApiController
{
[Route("")]
public IHttpActionResult Get()
{
return Ok("sync");
}
}
These two controllers live in two different namespaces, Api and Sync.
When I try to access the two controllers with
http://localhost/api/test and http://localhost/api/sync I get a 404.
But If I rename one of the controllers to e.g. TestApiController then both works.
Someone having a good idea if it's possible to do what I want?
Unfortunately, Web API finds controllers by class name, ignoring the namespace. This is a known issue and is not unique to attribute-based routing.
The easiest work-around by far is to avoid the problem and use unique controller names. But if you don't mind getting a little fancy, here's a solution:
https://blogs.msdn.microsoft.com/webdev/2013/03/07/asp-net-web-api-using-namespaces-to-version-web-apis/
I have Controller with some method GET :
public class TestController : ApiController
{
public List<T> Get(){...}
[ActionName("GetById")]
public T Get(int id){...}
}
Can i access second Get method as /Get?id=1 even if i have different ActionName?
ActionName for generating cache with different names
Updated because my previous answer was related to standard MVC controllers not Web API because that is what the ActionName attribute is for. I am not sure what if anything it would do on a web api controller. Without attributes or a change from the deault routing your actions would have the following routes "/api/test/" Get() "/api/test/id" Get(int id) where id is an int.
If you want more flexibility MVC5 supports attribute routing