Trouble getting a response from an asp.NET WebAPI in an Area - asp.net-mvc-4

I'm trying to add a ASP.NET Web API ( from MVC 4 ) to my project..... But I'm having some trouble getting any response from the Area/WebAPI/Controller ( not quite sure where it's going wrong...)
I installed the Route Debugger, and if I go to my main page... I see the routes...
Matches Current Request Url Defaults Constraints DataTokens
False api/{controller}/{action}/{id} action = Index, id = UrlParameter.Optional (empty) Namespaces = OutpostBusinessWeb.Areas.api.*, area = api, UseNamespaceFallback = False
False {resource}.axd/{*pathInfo} (null) (empty) (null)
True {controller}/{action}/{id} controller = Home, action = Index, id = UrlParameter.Optional (empty) (empty)
True {*catchall} (null) (null) (null)
So it seems like the route is setup
Next I have a PlansController in the "api" Area, It's just the default apiController generated by "Add New"...
public class PlansController : ApiController
{
// GET /api/<controller>
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET /api/<controller>/5
public string Get(int id)
{
return "value";
}
// POST /api/<controller>
public void Post(string value)
{
}
// PUT /api/<controller>/5
public void Put(int id, string value)
{
}
// DELETE /api/<controller>/5
public void Delete(int id)
{
}
}
Now When I go to http://localhost:2307/api/Plans/1
I get
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /api/Plans/1
Any ideas why? Is there something I need to configure?

ASP.NET MVC 4 doesn't support WebApi in areas out of the box.
Martin Devillers proposed a solution: ASP.NET MVC 4 RC: Getting WebApi and Areas to play nicely
You can also have more details in my response on a similar question (especially for support with portable areas):
ASP.Net WebAPI area support

Change it to:
// GET /api/<controller>
public IEnumerable<string> GetMultiple(int id)
{
return new string[] { "value1", "value2" };
}
Call it with:
http://localhost:2307/api/Plans/GetMultiple/1
This is my Global.asax:
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
My Controller:
public class MyApiController : ApiController
{
public IQueryable<MyEntityDto> Lookup(string id) {
..
}
I called it as follows:
http://localhost/MyWebsite/api/MyApi/Lookup/hello
Works perfectly.

Related

Web API One action works while a nearly identical one doesn't?

Error Message
{
"Message": "No HTTP resource was found that matches the request URI 'https://localhost:44390/api/UserRoutes?effectiveDate=3/29/2019'.",
"MessageDetail": "No type was found that matches the controller named 'UserRoutes'."
}
Working Action
public class AdvanceOrderApiController : BaseApiController
{
[HttpGet, Route("api/AdvanceOrders")]
public AdvanceOrdersResult GetAdvanceOrdersForRouteDate(string route, DateTime effectiveDate)
{
...
}
}
// JavaScript Usage: route="0100" and effectiveDate="03/29/2019".
API.SendRequest("/api/AdvanceOrders", "GET", { route: route, effectiveDate: effectiveDate }, success, failure);
Not Working Action
public class UserApiController : BaseApiController
{
[HttpGet, Route("api/UserRoutes")]
public IEnumerable<string> GetUserRoutes(DateTime effectiveDate)
{
...
}
}
// JavaScript Usage: effectiveDate="03/29/2019"
API.SendRequest("/api/UserRoutes", "GET", { effectiveDate: effectiveDate }, success, failure);
WebApiConfig
Not sure that it's relevant since I'm just declaring the route for each action, but...
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
...
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
API.SendRequest
This function is just a wrapper around jQuery's $.ajax function, nothing fancy. If the code is necessary I'll present it, but it works for all my other API calls so I can't imagine it would be the source of the problem.
These actions are nearly identical, why does one work and the other doesn't?
Passing the date in as Igor said in the comments presented an error message that revealed that I had an Api controller in my Permissions area that had a route also named api/UserRoutes.
Once I changed the name of the route the problem resolved.
I just wish it could have just told me this error message from the start.

ASP MVC default route is not applying for root site url

I'm having trouble getting ASP.net MVC to serve up the default controllers index view for the root site url http://mysite:8080/. All I get back is a 404 with The resource cannot be found. It works fine if I specify the full route path in the url : http://mysite:8080/Default/Index, however, I want the default route to apply even if the user doesn't specify the route path though. It seems that this should just work out of the gate. This is a fresh project from the VS2013 MVC 4 template.
I've tried both route mappings below and neither seems to work. How can this be achieved?
routes.MapRoute(
"Root",
"",
new { controller = "DefaultController", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "DefaultController", action = "Index", id = UrlParameter.Optional }
);
Here is a solution to this problem. It's disappointing that the default route's defaults do not apply for the root site url though.
routes.Add(new Route("", new SiteRootRouteHandler("~/Default/Index")));
public class SiteRootRouteHandler : IRouteHandler
{
private readonly string _redirectUrl;
public SiteRootRouteHandler(string redirectUrl)
{
_redirectUrl = redirectUrl;
}
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new SiteRootHandler(_redirectUrl);
}
}
public class SiteRootHandler: IHttpHandler
{
private readonly string _redirectUrl;
public SiteRootHandler(string redirectUrl)
{
_redirectUrl = redirectUrl;
}
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
context.Response.RedirectPermanent(_redirectUrl);
}
}

MVC 4 - getting a 404 on a certain area's controllers

My problem is regarding setting up my app's access for internal users and external users.
Based on MS TechKB: AREAS in ASP.NET I went with AREAS. I have an Areas/Internal and Areas/External. Areas/External has the actual functionality and controllers for the app. All Areas/Internal does is check server variables and sets your identity as your domain name if it checks out in active directory.
The problem is, I can get to the Areas/External controllers/pages just fine but when I try to browse to the Areas/Internal area controller I get a 404. My controller is named Intranet (excluding the "Controller" in the name) and this is what my InternalAreaRegistration.cs file looks like:
public override void RegisterArea(System.Web.Mvc.AreaRegistrationContext context)
{
context.MapRoute(
"Internal_default",
"Intranet/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional });
}
public override string AreaName
{
get
{
return "Internal";
}
}
Can anyone tell me why I would be getting a 404 on the internal controllers?
It seems you are missing controller segment after Area in the code you wrote above. It should be something like:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Internal_default",
"Intranet/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "Your Controller Namespace" }
);
}
A related question at below link is answered, hope that will help too:
Controller with same name as an area - Asp.Net MVC4

Add Web Api controllers to an existing ASP.NET 4 web application

Following the steps from this question How to add Web API to an existing ASP.NET MVC 4 Web Application project? , I have added web api support to my application.
In my original scenario I have the following web mvc controller:
public class FranchiseController : Controller
{
public ActionResult List()
{
return View();
}
[DataContext]
public ActionResult GetAllFranchises()
{
var franchiseInfoViewModelList = new List<FranchiseInfoViewModel>();
var franchiseInfoList = _franchiseService.GetAll();
foreach (var franchiseInfo in franchiseInfoList)
{
franchiseInfoViewModelList.Add(new FranchiseInfoViewModel(franchiseInfo, p => p.IsImportant));
}
var jsonNetResult = new JsonNetResult
{
Formatting = Formatting.Indented,
Data = franchiseInfoViewModelList
};
return jsonNetResult;
}
}
When the user navigates to the List view, I am calling
$.getJSON("/franchise/GetAllFranchises")
.done(function (data) {
});
to go to the GetAllFranchises action method and return the json data. So far so good.
I have created the following web api controller:
public class FranchiseController : ApiController
{
public IEnumerable<FranchiseInfoViewModel> GetAllFranchises()
{
var allFranchises = new List<FranchiseInfoViewModel>();
var franchiseInfoList = _franchiseService.GetAll();
foreach (var franchiseInfo in franchiseInfoList)
{
allFranchises.Add(new FranchiseInfoViewModel(franchiseInfo, p => p.IsImportant));
}
return allFranchises;
}
}
and I am trying to get to its action method like this:
$.getJSON("api/franchise")
.done(function (data) {
});
I am getting 404 error and the app is trying to reach the following url:
/Franchise/api/franchise
instead of api/franchise.
Global Asax:
protected void Application_Start()
{
Log.StartSession();
ElmahExtension.SetCurrentApplication(this);
ViewEngines.Engines.Add(new OmegaViewEngine());
AreaRegistration.RegisterAllAreas();
SerializerConfig.Register(GlobalConfiguration.Configuration);
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
Bootstrapper.Initialise();
FluentValidationModelValidatorProvider.Configure();
}
Default route:
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
In my Controllers folder I have my web mvc controller:
Controller\FranchiseController
and I have made a new folder WebAPI to hold my web api controller
Controller\WebAPI\FranchiseController
What am I doing wrong ? Thanks!
I'm not sure if it's the right move to name "FranchiseController" both to the MVC Internet Application Controller and to the MVC Web API Controller (totally different things). After renaming one of them I think you should put the Web Api Controller in the root of the directory (Controller).

How to create ASP.NET Web API Url?

In ASP.NET MVC, we have #Url.Action for actions. Is there something similar like #Url.Api which would route to /api/controller?
The ApiController has a property called Url which is of type System.Web.Http.Routing.UrlHelper which allows you to construct urls for api controllers.
Example:
public class ValuesController : ApiController
{
// GET /api/values
public IEnumerable<string> Get()
{
// returns /api/values/123
string url = Url.Route("DefaultApi", new { controller = "values", id = "123" });
return new string[] { "value1", "value2" };
}
// GET /api/values/5
public string Get(int id)
{
return "value";
}
...
}
This UrlHelper doesn't exist neither in your views nor in the standard controllers.
UPDATE:
And in order to do routing outside of an ApiController you could do the following:
public class HomeController : Controller
{
public ActionResult Index()
{
string url = Url.RouteUrl(
"DefaultApi",
new { httproute = "", controller = "values", id = "123" }
);
return View();
}
}
or inside a view:
<script type="text/javascript">
var url = '#Url.RouteUrl("DefaultApi", new { httproute = "", controller = "values", id = "123" })';
$.ajax({
url: url,
type: 'GET',
success: function(result) {
// ...
}
});
</script>
Notice the httproute = "" route token which is important.
Obviously this assumes that your Api route is called DefaultApi in your RegisterRoutes method in Global.asax:
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
It works with the simpler form of Url.Action thus you don't have to reference any Routing names:
Url.Action("ActionName", "ControllerName", new { httproute = "DefaultApi" })
You might want to add an area = "" if the URL is needed within an Area. (Api controllers are outside of Areas by default.) I'm using MVC 4.
Want to be able to generate links in a typesafe manner, without hardcoded strings (controller names)?
There's a nuget for that! (and it's written by Mark Seeman)
https://github.com/ploeh/Hyprlinkr
Works like this:
Routes, as usual:
name: "API Default",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
Get an URL:
var linker = new RouteLinker(request);
var uri = linker.GetUri<FooController>(r => r.GetById(1337));
Result:
http://localhost/api/foo/1337
Here is the KISS method for answering the question:
If this is the code that you would use to create a MVC controller URL
#Url.Action("Edit", "MyController")
In order to get a URL for the API version of the controller (assuming you use the same controller name) you can use
#Url.Action("Edit", "api/MyController")
All the Url.Action method is doing is appending the root path of the application, with the controller name, followed by the action name (unless it is "Index" in which case it is not appended. if the route values object has an id property the value is also appended to the URL.