ASP.NET MVC new Routes not working - c#

I am using ASP.NET MVC and I am trying to create a new route for a parameter like so:
config.Routes.MapHttpRoute(
name: "MarkOnline",
routeTemplate: "api/{controller}/{id}",
defaults: new { offline = RouteParameter.Optional }
);
and here is my method call I am trying to use inside my API Controller
public void MarkOnline(string offline)
{
}
however what gets returned is my Entity Framework GetData method in the API Controller, which is this:
public IQueryable<VistaLCPreview> GetData()
{
return db.Data;
}
What am I doing wrong?

In this context, GetData is being called due to the fact that it has a prefix of Get. There's a convention that maps HTTP GET to functions prefixed with Get, HTTP POST to PostXXX, etc. GetData is being resolved by the default HTTP route, which specifies an optional id parameter and is not present in your expected GetData URL example (which is what you want there).
The MapHttpRoute from your example is not going to match, due to the id parameter in the routeTemplate, which has not been defaulted to RouteParameter.Optional. This route is actually unnecessary - You do not need to include query-string parameters in this route definition. Query-string parameters are simply mapped into the arguments passed into the actions (offline in your case).
Because MarkOnline is not prefixed with one of the HTTP Verbs as I mentioned above, it is not being matched by the default HTTP route. To fix your problem you simply need to do two things:
Remove the MapHttpRoute that you added. This is not needed as the default HTTP route I've already mentioned will cover your use-case.
Add the HttpGet attribute to your MarkOnline method. This will cause the routing to pick up MarkOnline when an offline query-string parameter is found, but call GetData when it is not.

Your route is not configured correctly, you are not specifying the default action on your controller.
It should be something like this:
routes.MapRoute(
name: "MarkOnlineRoute",
url: "api/{controller}",
defaults: new { action = "MarkOnline" }
);
But also notice that the order which you configure your routes is important, it should be located before the default route configuration:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
And as a reference, this is my test controller:
public class AvailabilityController : Controller
{
// GET: MarkOnline
public void MarkOnline(string offline)
{
//return Json(new { isOnline = true, name=offline }, JsonRequestBehavior.AllowGet);
}
}
And it is called with: http://localhost/api/availability?offline=xxx#xxx.com

Related

Multiple controllers, same same controller name

I was wondering if this is possible. Say I have a monolithic Controller, ReportController.cs.
I want to make a totally separate controller file but still keep the /Report/ in the url that we've some to know and expect.
What I tried was this in my global asax:
routes.MapRoute(
"Testing", // Route name
"{test}/{action}/{id}" // URL with parameters
);
and I added a new Controller named ReportTest.cs
the original route looks like this:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "LandingPage", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
Every time I try to call the simple action I have in ReportTest.cs I get this error: "Value cannot be null or empty. Parameter name: controllerName"
Am I misunderstanding how this works. When you have "{controller}/.." is this not saying 'look for any controllers named + controller and use that'. So if I go to .../Report/DoStuff it'll look for the method DoStuff on ReportController right?
So wouldn't my other route just append a search sequence? So if I put .../Report/DoStuff it'll look for the method DoStuff on ReportController and ReportTest right?
The routing format string:
{controller}/{action}/{id}
Means: the first part ("part" being "element after splitting on /") of the request URI is the controller name, the next part the action method and the last part the ID.
The placeholders {controller} and {action} are special. So your route {test}/{action}/{id} will not find any controller, as none is specified, and {test} doesn't mean anything. (Well it does, it'll get added as a route attribute named "test", and assigned a value representing that part of the request URI, so that is irrelevant for this scenario).
If you want to route an URI to a controller that is not mentioned in the URI, then you must literally specify the prefix, and the controller it should be routed to.
So your routing will look like this:
routes.MapRoute(
"SecondReportController",
"Report/NotOnReportController/{id}",
new { controller = "NotAReportController" }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "LandingPage", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
Then you can use the following controller:
public class NotAReportController : Controller
{
public ActionResult NotOnReportController(int id)
{
// ...
}
}
You can of course also use attribute routing instead:
public class NotAReportController : Controller
{
[Route("Report/NotOnReportController/{id}")]
public ActionResult NotOnReportController(int id)
{
// ...
}
}

ASP.NET MVC Routes: How do I omit "index" from a URL

I have a controller called "StuffController" with a parameterless Index action. I want this action to be called from a URL in the form mysite.com/stuff
My controller is defined as
public class StuffController : BaseController
{
public ActionResult Index()
{
// Return list of Stuff
}
}
I added a custom route so the routes are defined like this:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// Custom route to show index
routes.MapRoute(
name: "StuffList",
url: "Stuff",
defaults: new { controller = "Stuff", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
But when I try to browse to mysite.com/stuff I get an error
HTTP Error 403.14 - Forbidden
The Web server is configured to not list the contents of this directory.
The URL mysite.com/stuff/index works fine. What I am doing wrong?
HTTP Error 403.14 - Forbidden The Web server is configured to not list the contents of this directory.
The error indicates that you have a virtual directory (probably a physical one) in your project called /Stuff. By default, IIS will first reach this directory and look for a default page (for example /index.html), and if no default page exists will attempt to list the contents of the directory (which requires a configuration setting).
This all happens before IIS passes the call to .NET routing, so having a directory with the name /Stuff is causing your application not to function correctly. You need to either delete the directory named /Stuff or use a different name for your route.
And as others have mentioned, the default route covers this scenario so there is no need for a custom route in this case.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// Passing the URL `/Stuff` will match this route and cause it
// to look for a controller named `StuffController` with action named `Index`.
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
It seems that your scenario is covered fine by default route, so there is no need for a custom Stuff one.
As to why the error is thrown, the fact that action is listed in defaults does not mean that it is actually becoming a part of a route. It should be mentioned in the route, otherwise it appears as there is no action at all. So what I think happens here is that first route is matched, but it cannot be processed as there is no action specified, so MVC passes request on to IIS, which throws the named error.
The fix would be simple:
// Custom route to show index
routes.MapRoute(
name: "StuffList",
url: "Stuff/{action}",
defaults: new { controller = "Stuff", action = "Index" }
);
But again, you shouldn't need that at all.

.NET Web API custom return value

I am having some issues with Web API, and standard documentation didn't help me much..
I have a ProductsController, with a default method GetAllProducts(), which accepts several GET parameters (it was easier to implement that way) for querying.
Now, in another part of the application, I use a jQuery autocomplete plugin, which has to query my webservice and filter the data. Problem is, it expects results in a custom format, which is different than that returned by Web API. I procedeed creating another method, GetProductsByQuery(string query), which should return the data in that format.
Is there any way I can enforce WebAPI to return the data as I want it, without making another Controller?
I am also having problems with the routing table, because all the GETs go straight to the first method, even if I routed the second one to url: "{controller}/query/{query}"
Here is some code:
public class ProductsController : ApiController
{
public IEnumerable<Product> GetAllProducts()
{
NameValueCollection nvc = HttpUtility.ParseQueryString(Request.RequestUri.Query);
// Querying EF with the parameters in the query string
return returnQuery;
}
[System.Web.Mvc.HttpGet]
public dynamic GetProductsByQuery(string query)
{
return SomeCustomObject;
}
And the routing:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Query",
url: "{controller}/query/{query}");
You need to swap your routes around - any request that matches your second route will match your first route first.
Secondly, look into custom media formatters if you need specific return formats for your data:
http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters

asp.net-mvc routing issue : parameters dictionary contains a null entry for parameter

I am trying to set up custom routing with the following mapped route
edit: my full route config
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
#region FixtureAdmin
routes.MapRoute(
name: "FixtureEdit",
url: "{controller}/{action}/{id}",
defaults: new { controller = "FixtureAdmin", action = "Edit", id = UrlParameter.Optional }
);
#endregion
#region Results
routes.MapRoute(
name: "ResultAdd",
url: "{controller}/{action}/{fixtureId}",
defaults: new { controller = "Result", action = "Add", fixtureId = UrlParameter.Optional }
);
#endregion
And my controller code
public ActionResult Add(int fixtureId)
{
// return model to view etc..
}
This is coming up with the exception, even though I have specified the parameter as optional.
The parameters dictionary contains a null entry for parameter 'fixtureId'
The strange thing is, if I change the parameter of the Add action to just 'Id' then the following URL will work Result/Add/1. I'm confused, is there some default routing that is overriding my custom one? Why would changing the parameter to just 'Id' work?
Edit
Just to test, I added another parameter to the action
public ActionResult Add(int? fixtureId, int? testId)
I then edited the route accordingly and now it works, so I reckon it is an issue with default routing.
Use a nullable int in your Controller Action.
public ActionResult Add(int? fixtureId)
{
// return model to view etc..
}
But the question is, if that is indeed an ID, how would it react if a null/blank ID is requested by the user? Is that ID a key in your DB? You can make it nullable if you are able to handle or provide a default page if the ID is blank/null.
EDIT:
This is because ASP.NET will assume that an unidentified parameter in your request is the id, in your case, Results/Add/1, 1 is unidentified. If you want to make that code work with using fixtureId, you should use Results/Add?fixureId=1. So ultimately, it's not because of the routing, but instead, it's because of the parameter in the Action that you have.
EDIT2:
Also, what you are experiencing there is called a routing conflict. Your routes are conflicting with the Default. You can try to apply constraints.
2,
from your post i think your problem is putting your custom route after default, like this:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
name: "ResultAdd",
url: "{controller}/{action}/{fixtureId}",
defaults: new { controller = "Home", action = "Add", fixtureId = UrlParameter.Optional }
so:
1/ exception "The parameters dictionary contains a null entry for parameter 'fixtureId'" will come if you dont give the specific route name for any action link or route form because MVC will use default route to routing. So you need to give specific route name to your custom route can be worked, like this:
#Html.ActionLink("Test custom Route", "Add", "Home", new { fixtureId = 1 }, "ResultAdd")
Cheer
Look at this method of adding what the developer calls a 'NullableConstraint' clicky link So if the optional parameter is supplied you can do some checking on it's value.
And also look at the answer following the accepted answer for what seems a simpler, cleaner solution.

Defining two get function in WebAPI

I am getting to following exception when i am trying to call a GET function in MVC WebAPI
{"$id":"1","Message":"An error has occurred.",
"ExceptionMessage":"Multiple actions were found that match the request:
\r\nSystem.Xml.XmlNode Get(Int32, System.String)
I think the problem is cause due to two get function
I have defined two functions:
One:
[HttpGet]
public XmlNode Get(int id, string Tokken)
{
//Do something
}
Second One
[HttpGet]
public List<UsersAnswers> GetUsersInteractions(int? activityID, string Tokken)
{
// Do Something
}
The route configuration
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Now i am getting the exception when i try to call to the second function:
{SiteURL}/api/Activities/GetUsersInteractions?activityID=32&Tokken=r54e54353
As you can see the route engine sent the request to the first function instead of the second.
How can i define two get operation and to call each one separately?
With the default routing template, Web API uses the HTTP method to select the action. However, you can also create a route where the action name is included in the URI:
routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
In this route template, the {action} parameter names the action method on the controller. With this style of routing, use attributes to specify the allowed HTTP methods. For example, suppose your controller has the following method:
public class ProductsController : ApiController
{
[HttpGet]
public string Details(int id);
}
In this case, a GET request for “api/products/details/1” would map to the Details method. This style of routing is similar to ASP.NET MVC, and may be appropriate for an RPC-style API.
You can override the action name by using the ActionName attribute. In the following example, there are two actions that map to "api/products/thumbnail/id. One supports GET and the other supports POST:
public class ProductsController : ApiController
{
[HttpGet]
[ActionName("Thumbnail")]
public HttpResponseMessage GetThumbnailImage(int id);
[HttpPost]
[ActionName("Thumbnail")]
public void AddThumbnailImage(int id);
}
You are not calling the second function - the second function is named InsertUserRecord and is a POST method. The function you're calling via GET is GetUserInteractions. As there's no such function for GET, the engine may map this to the only GET function there is, but actually it should throw a "no such function" error.

Categories

Resources