Need To use Identical Controllers in Web API 2 - c#

How can i use two identical Controllers in Web API 2.
I need to use URL as follows.
mysite/api/Contacts/get/2
and
mysite/api/v1/Contacts/get/2
but if i use seperate folder for this it gives an error.
my WebApiConfig.cs like this
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi2",
routeTemplate: "api/v1/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
This is the Error
Multiple types were found that match the controller named 'default'.
This can happen if the route that services this request
('api/v1/{controller}/{id}') found multiple controllers defined with
the same name but differing namespaces, which is not supported. The
request for 'default' has found the following matching controllers:
TestWebAPI.Controllers.DefaultController
TestWebAPI.Controllers.v1.DefaultController
How Can i Achieve this?... Basically I need this for Versioning.

This can happen if the route that services this request ('api/v1/{controller}/{id}') found multiple controllers defined with the same name but differing namespaces, which is not supported.
This means that you have two distinct controllers named DefaultController (as you mentioned).
If you want to serve both urls with the same controller, just delete the one in v1 folder. If you want to serve each url with each controller you should specify the namespace for each one.
var r = routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
r.DataTokens["Namespaces"] = new string[] {"Foo"};
More info in this blog post.

Related

How do I not generate the default endpoints when using attribute routing?

I'm using attribute routing in a Web API controller (.NET Framework 4.5.2 - don't ask, I'm trying to get approval for time to move everything forward).
I have applied a [RoutePrefix] attribute to my ApiController.
I have two controller actions, both HttpGets. Each has a [Route] attribute applied.
I'm using Swagger to auto-generate docs. In the docs for this controller I see three endpoints listed - two for my controller actions, and another HttpGet with the bare controller route.
That is what I have is this:
[RoutePrefix("api/test/Tickets")]
public class TestTicketsController : ApiController
{
[HttpGet, Route("")]
public HttpResponseMessage GetTickets()
{
....
}
[HttpGet, Route("since")]
public HttpResponseMessage GetTicketsSince(string since)
{
....
}
}
And In the generated Swagger docs I see three endpoints:
GET api/test/Tickets
GET api/test/Tickets/since
GET api/TestTickets
This third endpoint, api/TestTickets, seems to be derived from the class name of the controller, ignored my routing attributes. And when I call it, I get an HTTP 200 with an empty body, despite not having defined an action for it.
Where is this coming from? And how can I stop it from being generated?
===
It was suggested that I remove the [HttpGet, Route("")] attribute. If I do, I get an error:
Multiple operations with path 'api/TestTickets' and method 'GET'.
It was also suggested that I include my WebApiConfig:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "swagger_root",
routeTemplate: "",
defaults: null,
constraints: null,
handler: new RedirectHandler((message => message.RequestUri.ToString()), "api/docs/index"));
var mediaType = new MediaTypeHeaderValue("application/json");
var formatter = new JsonMediaTypeFormatter();
formatter.SupportedMediaTypes.Clear();
formatter.SupportedMediaTypes.Add(mediaType);
config.Formatters.Clear();
config.Formatters.Add(formatter);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
If I comment-out the config.Routes.MapHttpRoute, the extra endpoint goes away.
Now it's just a matter of determining whether we have any controllers that expect this default endpoint to be there.
Thanks.
abdulg pointed out in a comment, rather than in an answer - default routes are configured in WebApiConfig.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);

Exposing a Web Api Rest Service, without controller name to access its methods

I have a rest service developed with ASP.NET Web Api.
The controller in this example is MyTestController.
In the route template, I set "api/{controller}/{action}/{id}" . It has a simple GET method "hello", that returns a string.
So if I try to call this service while it is running, I should do a GET http://localhost/api/MyTest/hello .
What I would like to obtain instead is to be able to call it as GET http://localhost/hello , so removing the api/controller part.
Is that possible?
I have already tried to set routeTemplate: "/{action}/{id}" but it obviously does not work.
This is an example of service
public class MyTestController : ApiController
{
[HttpGet]
public string Hello()
{
return "service is online";
}
}
And this is the code extract with the routing settings:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
You can try something like this, bellow
// Register the static hello route
config.Routes.MapHttpRoute(
name: "HelloRoute",
routeTemplate: "api/hello",
defaults: new { controller = "MyTest", action = "Hello" }
);
// If it does not match, then fallback to the generic matcher
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Take a look at the microsoft routing guide for web api to see how the matching happens and what default options you have.
Bear in mind that you choose wisely the reason why you want something like this. In case of rest apis we want to have routes like hostname/resource/id/sub-resource/id
You can read about rest api (which are resource based) here

Web API route not getting called

This is my web API config:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "ReaderTags",
routeTemplate: "Reader/{readerID}/Tags"
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
I want that when I call my URL /Reader/abc/Tags it should call my ReaderController's Tags action and pass abc as the string parameter.
But somehow it is using the DefaultAPI's route and trying to find abc as an action in ReaderController.
What am I missing?
The route mapping is missing defaults that would let the route table know what controller and action to invoke for routes matching the template
config.Routes.MapHttpRoute(
name: "ReaderTags",
routeTemplate: "Reader/{readerID}/Tags",
defaults: new { controller = "Reader", action = "Tags" }
);
The route template also assumes that the string parameter on the action shares the same name: i.e: readerID.
public IHttpActionResult Tags(string readerID) {
//...
}
And since config.MapHttpAttributeRoutes(); is also configured, then the same can be achieved via attribute routing instead of convention-based routing like this
//GET Reader/abc/Tags
[HttpGet]
[Route("Reader/{readerID}/Tags")]
public IHttpActionResult Tags(string readerID) {
//...
}

ASP MVC 5 and Web Api 2 can't view page on complete links

I have 2 controllers, 1 is an MVC and 1 is Web Api 2.
The latter seems to work correctly, but the first can't display HTML pages only when I write the full address.
This is my simple RouteConfig.cs
routes.MapRoute(
name: "Default",
url: "{controller}/{action}",
defaults: new {
controller = "Base",
action = "Main"
}
);
)
Let's take the default as example, so controller is Base and action is Main, the code is straightforward
public ActionResult Main() {
return View();
}
http://localhost/miApps --> work and display content of /View/Base/Main
http://localhost/miApps/Base --> work and display content of /View/Base/Main
http://localhost/miApps/Base/Main --> doesn't work, the error is
{"Message":"No HTTP resource was found that matches the request URI 'http://localhost/miApps/Base/Main'.","MessageDetail":"No type was found that matches the controller named 'Base'."}
I post also WebApiConfig.cs, maybe there is an interaction?
config.MapHttpAttributeRoutes();
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{action}",
defaults: new {
//id = RouteParameter.Optional
}
);
}
The route to API controllers should have a prefix (usually '/api/') in order to make a distinction from ordinary controllers.
try updating your WebApiConfig.cs to this:
config.MapHttpAttributeRoutes();
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}",
defaults: new {
//id = RouteParameter.Optional
}
);
}

How to route url for adding associated entity with asp.net webapi

I have a model looks like below:
class File{
public IList<Tag> Tags;
};
According to REST guideline, if I want to add a tag to a file. The URL should looks like this:
http://service.com/File/Id/Tags/ with a PUT method.
Since I'm just beginner of ASP.net MVC WebAPI. My question is how do I route this url to my APIController?
Thanks,
By default all API controllers have a route of /api/SomeApi/ where SomeApiController is an ApiController. There is a seperate route file App_Start\WebApiConfig.cs which you can modify to get the routes you need.
You can have routes like the one below
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" }
);
You can then have an action named "UpdateSomething", which can be accessed by using somewebsite.com/api/someapi/updatesomething I hope the above information will be useful to start off with.
Update:
for route /File/Id/Tags you can have the following route defined
config.Routes.MapHttpRoute(
name: "MySpecialRoute",
routeTemplate: "/File/Id/Tags",
defaults: new { controller = "AbcController", action = "XyzAction" }
);
Note: Have not tested the above code

Categories