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/
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.
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()
{
}
}
}
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 have two Web API projects and I have a MarketController and I need to extend the Api controller so I did it.
I created a BaseController class and inherit from ApiController like this:
public class BaseController:ApiController { }
so far so good, it's working fine:
public class MarketController : BaseController
{
public MarketController() : base()
{
}
// GET api/<controller>
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
But I wanted to do it in another class library called BLL, so I moved the BaseController class to the BLL class library and I referenced it in the Web API project.
When I did this, the api stopped working.
The response is :
{
"Message": "No HTTP resource was found that matches the request URI someurl/api/market.",
"MessageDetail": "No type was found that matches the controller named 'market'."
}
No need to implement custom ControllerFactory or AssemblyResolver classes.
This scenario will "just work" provided you add the Microsoft.AspNet.WebApi.Core nuget package to the assembly containing the base class.
In my case I'd just added a reference to the System.Web.Http.dll which will compile, but the controllers will not load properly. Adding the Nuget package got everything working with no code changes.
By default MVC looks for all controllers in same assembly of mvc application. The default controller factory creates controller instance based on string 'ControllerName+Controller' like MarketController where market comes from url market/actionname.It will look for MarketController in the same assembly as mvc application.
To put controller in separate assembly you will have to create your own controller factory or you will have to specify assembly name is app start.
Once you've created your own custom ControllerFactory, you add the following line to Application_Start in global.asax to tell the framework where to find it:
ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory());
Or for simple cases like yours you can do this :
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" },
new[] { "BLLAssembly.Controllers" }
);
Here BLLAssembly.Controllers is namespace for your BaseController in BLL assembly.
There is one more advanced way using custom assembly resolver ,i.e IAssembliesResolver
The below article tells how to do this with Web Api also,
http://www.strathweb.com/2012/06/using-controllers-from-an-external-assembly-in-asp-net-web-api/
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