Getting WebApi and Areas to play nicely - asp.net-mvc

I'm using Martin Deviller's tutorial to get MVC4's Web API working with Areas. I believe I've followed the instructions exactly, but GetControllerType throws the following exception when accessing "http://localhost/API/user":
Value cannot be null. Parameter name: controllerType
Does anyone have any ideas what could be causing this? This is what I've placed in my Area Registration file:
context.MapHttpRoute(
name: "API_default",
routeTemplate: "API/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Thanks in advance.

I see you are trying to access the route of the application without the area. Do you need areas or not?
If you are trying to follow the example then the Area registration would make the url "http://localhost/administration/API/user". Does this work?
context.Routes.MapHttpRoute(
name: "Administration_DefaultApi",
routeTemplate: "Administration/api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);

Related

Route Conflicts in web api for Get with multiple parameters

I'm using Web Api to create REST APIs that have parameters ranging from 0 to 4.
Below are examples of my APIs :
GetTaxRates()
GetTaxRatesByDate(string date, string name= "") // name is an optional parameter
GetTaxBetweenDates(string frmDate, string toDate, string name="") // name is an optional parameter
GetRecentTaxRates(string name= "") // name is an optional parameter
For these different GET calls,
i have created the following routes in the webapiconfig :
routeTemplate: "api/{controller}/{action}",
defaults: new { }
routeTemplate: "api/{controller}/{action}/{date}/{name}",
defaults: new { name= RouteParameter.Optional }
routeTemplate: "api/{controller}/{action}/{frmdate}/{toDate}/{name}",
defaults: new { name= RouteParameter.Optional }
When i am calling the APIs, it works fine for most of the routes, but there seems to be a conflict between the routes and i get the error "No action was found on the controller 'TaxRate' that matches the request." when i call the action api/TaxRate/GetTaxBetweenDates/2015-04-01/201504-10
Although i am getting the results when calling the same api with all the parameters: api/TaxRate/GetTaxBetweenDates/2015-04-01/201504-10/abc
When i change the sequence of the routes, the same issue occurs GetTaxRatesbyDate API call.
As per rule of thumb in web api routing you should register the more specific routes first. Have a look at this link Routing order. What might help here is registering more specific routes like "api/{controller}/GetTaxRatesByDate/{date}/{name}", defaults: new { name= RouteParameter.Optional }
I was able to resolve the above issue using attribute routing.

Publishing application to IIS: Web API breaks

I have built a Asp.Net MVC application, and it's worked successfully.
However, when I published it to IIS I can't access the web service.
I mean, when I enter some url of content (for example "http://localhost/MyApp/Contents/SomePage.html") it's works successfully,
but when I enter url of the api ("http://localhost/MyApp/api/SomeController/SomeMethode") I get 404.2 error.
[When I Entered such url when it was unpublish,("http://localhost:5092/api/SomeController/SomeMethode") it's showed me the result of the method]
Thanks a lot, and sorry for the bad english.
UPDATE
Thanks for the answers, I tried both of them (in the comment and in the answer) and It's didn't work. Actually, I tried to solve it 4 hours and I just couldn't. So like every angry guy I removed the publish and published it again (Just like restarting the computer when it's stuck) and I don't know why, but now it's works.
Thanks again, and sorry again for the bad English.
MVC routing is different from WebApi routing.
MVC:
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{id}",
defaults: new { id = System.Web.Http.RouteParameter.Optional }
);
WebApi
GlobalConfiguration.Configuration.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = System.Web.Http.RouteParameter.Optional }
);
In your Global.asax
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}

WebApi Routing - map url to api

I've been googling for about an hour and not found an example so I thought I'd ask here.
I am replacing a standard mvc controller with a webapi and having problems with the routing, I've changed the names because of the organisation but they are still valid.
my webapi is currently called SystemAPI in the controllers folder - I want it to have a different name that the url that points to it ideally.
The url I need to point to it is /v1Controller/{id}
I cant change the v1Controller url as it is a fixed point with apps I have no control over
my current coding attempt is
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DocumobiApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "V1Controller",
routeTemplate: "v1Controller/{id}",
defaults: new { id = RouteParameter.Optional }
);
// Uncomment the following line of code to enable query support for actions with an IQueryable or IQueryable<T> return type.
// To avoid processing unexpected or malicious queries, use the validation settings on QueryableAttribute to validate incoming queries.
// For more information, visit http://go.microsoft.com/fwlink/?LinkId=279712.
//config.EnableQuerySupport();
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().FirstOrDefault();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
}
}
to which I get the response
"message":"No HTTP resource was found that matches the request URI 'http://localhost:38685/v1Controller'.","messageDetail":"No route providing a controller name was found to match request URI 'http://localhost:38685/v1Controller'"}
I'm sure its something fairly obvious but cant for the life of me figure it out.
Cheers,
Steven
As the following error message says, a route match should result in providing value for the controller route variable which Web API depends on for selecting a controller.
No route providing a controller name was found to match request URI 'http://localhost:38685/v1Controller
So you could modify the route like below(notice the default value for controller variable):
config.Routes.MapHttpRoute(
name: "V1Controller",
routeTemplate: "v1Controller/{id}",
defaults: new { id = RouteParameter.Optional, controller="SomeControllerHere" }
);
Make sure your action method on your controller has an id with a default value.

Non Api routing with SPA and Web Api

I have been trying for a few days to solve this problem so I may in fact be trying to solve the wrong problem or don't know the right terms to search so here goes.
I'm creating a SPA with AngularJS and Web Api (4.5). All of my views are client side. So the server doesn't know all the possible routes that may become present in the URI. This isn't a problem until a user uses one of the browser controls (back, forward, refresh, history) and the server attempts to route the requested URI.
My thoughts on dealing with this have centered around mapping all non API routes to the root of the application.
So I would like to either, know the correct syntax for MapHttpRoute to pick up any route that does not attempt to reference controllers (API's) or if there is a better method for dealing with this problem.
public static void Register( HttpConfiguration config )
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//
// This doesn't work
//
config.Routes.MapHttpRoute(
name: "Default",
routeTemplate: "{*catchall}"
);
}
This XML file does not appear to have any style information associated with it. The document tree is shown below.
No HTTP resource was found that matches the request URI 'http://localhost:9234/login'.
No route providing a controller name was found to match request URI 'http://localhost:9234/login'
Not a good idea, just workaround
config.Routes.MapHttpRoute(
name: "Default",
routeTemplate: "{*catchall}",
defaults: new { controller = "Spa"}
);
[AllowAnonymous]
public sealed class SpaController : ApiController
{
public HttpResponseMessage Get()
{
var indexHtml = HostingEnvironment.MapPath("~/index.html");
var stringContent = new StreamContent(File.OpenRead(indexHtml));
var response = new HttpResponseMessage(HttpStatusCode.OK) {Content = stringContent};
return response;
}
}

Asp.net MVC/Web Api Routing: Need to route a little different

I have setup a asp.net web api project (it works exactly the same as a Mvc Project) using routing - hence i have the following
routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
So everything works just the way i want it .... I enter api/Products/15 it it arrives in my Products Controller passing in 15 as the id.
Great.
I also have 2 controllers more, 1 called UploadsController and 1 called DownloadsController. These offer Uploads and Downloads (GET / PUT etc)
Now i don't want them to be picked up by the original rule (see above)
But what i would like is to use these 2 urls to access them
/api/Transport/Uploads/15
/api/Transport/Downloads/15
I have passed in 15 as the ID, probably wouldn't happen in real life... just its good for demonstration :-)
Now Transport doesn't exist so i could do the following
routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/Transports/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
which i believe works...
but the problem is that if i do
/api/Uploads/15 - this would also be caught by the original rule which i don't want..
I want the Uploads and DOwnloads controller to be accessed through the fake "Transports" and not without the Transports
Can anyone help?
Thanks in advance
You could use route constraints and define 2 API routes in the following order:
// matches /api/transports/downloads/id or /api/transports/uploads/id only
// and no other possible controller
routes.MapHttpRoute(
name: "API Transport",
routeTemplate: "api/transports/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new { controller = "uploads|downloads" }
);
// matches anything in the form /api/{controller}/id where {controller}
// could be anythnig different than "downloads" or "uploads" because we don't
// want to allow the following urls: /api/downloads/id and /api/uploads/id
routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new { controller = #"^((?!(downloads|uploads)).)*$" }
);

Resources