Controller action "Index" not invoked with default setting - asp.net-mvc

I have a ASP.NET web application project, I implemented a WebApi controller and now proceeding with a MVC controller.
I've added a new MVC controller (eg. "Test") and selected to add it with "empty read and write actions".
The controller is created with various CRUD methods, however the Index action is behaving unexpectedly.
By default the Index action does not take any arguments:
public ActionResult Index()
{
return View();
}
Now if I try to invoke this method using url "/Test/Index", the method is not being called.
But if I type url "/Test/Index/1" the Index action is run.
It looks to me that its related to routing so I checked the RouteConfig class which looks like:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Id is set to optional and my understanding is I should not be required to provide a parameter value in Index method?
I created another project and checked this behavior and it works fine.
So wondering what in this project making MVC controller behaving differently?
Is mixing WebApi controllers with MVC controllers having some side effect (making it a special case)?
Let me know if you need any information to answer this question.
Update:
I did modify the WebApiConfig for making API controller work as per my requirement, it looks like this:
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{action}",
defaults: new { controller = "iclock", action = "cdata" }
);
}
I could not understand why it affect the MVC controller route? I got it now with answers provided.
Update 2:
The problem in this case is I can not (or can I?) prefix api in web api route as a third party device is sending GET and POST request using a fixed url, like following:
GET /iclock/cdata?SN=xxxxxx&options=all&pushver=2.0.2&language=XX
GET /iclock/cdata?SN=xxxxxx&type=time
POST /iclock/cdata?SN=123456&table=ATTLOG&Stamp=2011-04-05T17:40:20
I achieved above request handling functionality making changes into the WebApiConfig route. Now need a front end UI for which I am developing a MVC controller with CRUD operation.
What should be ideal approach in this case?

It could be when you navigate to Test/Index it doesn't know if it should use the web route where there is an optional "id" or the api route where there is no "id". If possible I would prefix your Web API routes, such as "api/{controller}/{action}" as described in the MVC Web API template.
For your second example, applications that access the API would simple prefix the URLs with "api/". If they are using the URLs you specified and cannot be changed, then I think you may be stuck because when the request comes in there is still the problem of not knowing which route to use.
If the URLs can be changed, as mentioned above, simple prefix with "api/".
EDIT: Updated my answer based on the extra information/code-snippet provided.
EDIT: Updated again

Did you look in WebApiConfig instead of RouteConfig in App_Start
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}

You have a conflict in your routing table. Your Web API routing table is now the same as your standard MVC routing table. Your Web API routing table (the one that is initialized with MapHttpRoute should be declared as: routeTemplate: "api/{controller}/{id}". Also, you shouldn't have modified the Web API route. It is not cast in stone that it must be api/{controller}/{id}, but there is a certain convention that you should follow. Try reseting your routes to be like the following and then try again:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
So, first reset to normal routing configuration and test. After that make changes slowly and follow the result.

Related

Creating Api controller in asp .net mvc

I have created controller called ApiConroller in MVC project. When I tried to run its Index() action method it returns the below error message:
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:60000/api/index'.
Why it is returning xml file? How to make it return a view?
/api/ is part of the default mapping for the Web Api routing, as shown here:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
If you're not using Web Api, make sure you remove those route maps by removing the WebApiConfig file from your project and/or removing WebApiConfig.Register(GlobalConfiguration.Configuration) from the Global.asax file.
If you are using Web Api somewhere, you'll need to change the routing noted above.

MVC Controller not being reached in Web API Project

I have a Web Api project which needs to return an MVC styled View. I have made my MVC Controller as such
public class MVCController: Controller
{
[HttpGet]
[Route("api/mvc/test")]
public ActionResult test()
{
return View();
}
}
However, When i try to access this controller from the web, i cant seem to reach the controller. I get the following error:
{"Message":"No HTTP resource was found that matches the request URI 'http://localhost/foo/api/mvc/test'.","MessageDetail":"No type was found that matches the controller named 'mvc'."}
After doing searches on google, people seem to be telling me to change routing properties in the webapiconfig to
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
But i still seem to be having no luck. IF HOWEVER i change my controller to an webapi controller as such
public class MVCController: ApiController
{
[HttpGet]
[Route("api/mvc/test")]
public IHttpActionResult test()
{
return Ok();
}
}
I can reach the controller.. If someone could give me some insight to as what is going on, it would be much appreciated.
UPDATE
After reading the response below, I have updated my controller to look like this:
public class MVCController: Controller
{
[HttpGet]
public ActionResult test()
{
return View();
}
}
However, localhost/MVCController/test still seems to give me a 404 error and the Controller is not being hit. Sorry for my newbieness by the way.
I bet you have a file called WebApiConfig.cs which has this code.
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 }
);
}
}
This is where the routing pattern is defined for the web api controllers. So any request coming with api/something will be considered as a request for web api endpoint because you must have invoked the WebApiConfig.Register call before registering the routes for mvc controllers. The Order of registering routes really matters.
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register); // first one
RouteConfig.RegisterRoutes(RouteTable.Routes); //second one
}
Since the order of registration matters, when a request comes with api/something, it will be matched against the route registration for web apis and framework will try to look for matching web api controller.s
If you swap the order of calling the route registration method, your request will work. but that might affect other parts when you try to access web api controllers.
BTW, Are you sure you want to have api/ in the route pattern for your MVC controller ? Unless you really want some different url patten than the normal convention(*controllername/action*), just remove the Route attribute it self. With the default route definition, it will work for yourSite/mvc/test request.

Can't access (404) ASPX from a View directory while HTML and (normal) ASPX are accessible

I can access Ping.HTML and Ping.ASPX but when I try to access the view from my MVC (4.0) project (deployed to the same server, the bogus one, by F5), I get 404.
It's a vanilla project created from the template for MVC 4 with a very default view and controller (no model).
Hints on how to resolved it? I'm out of ideas...
EDIT
My RouteConfig.cs is like this
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new {
controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
Controllers folder contains only one, single file called ÄDefault1Controller.cs*. It only does this:
public class Default1Controller : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Test()
{
return View();
}
}
EDIT
The exact URLs typed in (besides the server name alone, of course) are:
> http://localhost:49642/Index
> http://localhost:49642/Index.aspx
> http://localhost:49642/Home/Index
> http://localhost:49642/Home/Index.aspx
> http://localhost:49642/Default/Index
> http://localhost:49642/Default/Index.aspx
Based on the information you've given, it sounds like a routing problem. The URL you are requesting isn't firing a controller.
EDIT
MVC works by convention, so by naming your controller Default1Controller the matching URL would start with /Default1.
In the example you've given, you can only access the Test() method by navigating to http://localhost:49642/Default1/Test, which will return the view typically located at /Views/Default1/Test.aspx (or /Views/Default1/Test.cshtml for razor-based views).
Please check out the routing overview at ASP.NET for more information about how the route table maps to controllers and actions. I should point out that the link is for the older versions of MVC, but you should get the idea.
Let me know if I can help further.
Matt

WEB API : Single parameter get methods on different controllers

How do I form routes to use the same method on different controllers in ASP.Net Web API?
Here's What I've tried :
var config = new HttpSelfHostConfiguration(strUrl);
config.Routes.MapHttpRoute(
"Scripts", "{controller}/{Name}",
new { controller = "Scripts",strScriptId=""});
config.Routes.MapHttpRoute(
"Images", "{controller}/{strParam}",
new { controller = "Images", strImageId= "" });
Thanks.
Edit: Same method in the sense..for example, a method accepting just one parameter on with a different name on two controllers.
Example :
ScriptsController has GetScripts(string strScriptId) method
ImagesController has GetImages(string strImageId) method.
I need to access it like
1. http://localhost/GetScripts/ScriptId123
2. http://localhost/GetImages/ImageId223
I'm unable to figure out the routes for this. I have tried the above routes (edited them to make it clearer.)
I have many more such controllers with different getsomething methods accepting just one parameter.
You could just have one single route like below:
config.Routes.MapHttpRoute("DefaultApi", "{controller}/{id}", new {id = RouteParameter.Optional});
and you could have your actions like below:
GetImages([FromUri(Name="id")] string strImageId);
GetScripts([FromUri(Name="id")] string strScriptId);
Please refer to this tutorial for routing options.
For Id parameter it's the easiest. Routing should be:
config.Routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
and the controller method (it doesn't matter on which controller!):
public MyData Get(int id)
{
...
}
If you really want string for Id, you can just use it as follows:
public MyData Get(string id)
{
...
}
Do you really need a different name for the parameter?
If you do, you can simply try the following routing (I am not sure, though):
routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/{controller}"
);
Also please note that the routing routes you wrote are conceptually wrong for WebApis:
Instead of
.../GetScripts/ScriptId123
.../GetImages/ImageId223
Consider the following (For Get requests):
.../Scripts/123
.../Images/123
The default route:
routes.MapHttpRoute(
name: "default",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Should work for you. Make sure your action methods matches the signature (use id instead of strImageId and strScriptId)
EDIT:
#Josh the parameters in the route SHOULD match the parameters in your actions.
As I said before, there is NO NEED to create alternate routes but if you are required to preserve those names on the ids, you can create a route to accommodate them:
routes.MapHttpRoute(
name: "scriptsRoute",
routeTemplate: "{controller}/{strScriptId}",
defaults: new { controller="Scripts" }
);
routes.MapHttpRoute(
name: "imagesRoute",
routeTemplate: "{controller}/{strImageId}",
defaults: new { controller="Images" }
);
Please NOTE in the routes above the ids are not optional, you can add the constrain if needed.
Also what #liel is recommending in terms of naming your controllers/actions is good advise.
AS We all know REST is resource based and this identify the resource with the URL, so that not more than one method with same parameter will be allowed in the REST service but there is work around in MVC 5 Web Api method level routing.
Here is the example you can do that:
[HttpGet]
[Route("api/search/FindByName/{name}")]
FindByName(string name)
{
}
[HttpGet]
[Route("api/search/FindById/{name}")]
FindById(int searchId)
Note:"search" is the controller name.
Please let know if need more clarification.

How to put all my Controllers in a own classlibrary

Can I configure MVC to directly look into a class library ("MyApp.Controllers" for example) instead of the foder Controllers?
Yes, you can. The easiest way is to add the namespace of your class library to the routers.MapRoute call in global.asax. This is how one of our configurations look like:
public static void RegisterRoutes(RouteCollection routes, IEnumerable<string> controllerNamespaces)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{resource}.ashx/{*pathInfo}");
routes.IgnoreRoute("{*favicon}", new { favicon = #"(.*/)?favicon.ico(/.*)?" });
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" }, // Parameter defaults
controllerNamespaces.ToArray()
);
}
Notice that we use an overload of MapRoute that allows us to supply a string array of controller namespaces.
Another option is to implement a custom IControllerFactory, but that's more work and usually not necessary.
The ASP.NET MVC runtime knows nothing about a folder named 'Controllers', that is just a project structure convention. You can have your controllers on any assembly, on any namespace, and it should work without any special configuration.

Resources