ActionLink helper passes param without param name - asp.net-mvc

I have an asp.net MVC app created using VS2015.
In my razor view, I have the following:
#Html.ActionLink(linkText: "Detail",
actionName: "Index",
controllerName: "SupportNotificationDetail",
routeValues: new { id = item.DetailFilename },
htmlAttributes: null)
The definition for my controller method is as follows:
public class SupportNotificationDetailController : Controller
{
// GET: SupportNotificationDetail
public ActionResult Index(string id)
I have made no changes to the default routing configuration.
My problem is, the action link is producing the following URL:
ESBAMPortal/SupportNotificationDetail/Index/%7B43794F0E-23AD-4A70-AF39-3364E93F5832%7D.html
For this, I get a 404 error. If I manually edit the url in the browser address bar so that the id parameter is named - then the correct page is loaded:
ESBAMPortal/SupportNotificationDetail/Index?id=%7B43794F0E-23AD-4A70-AF39-3364E93F5832%7D.html
If I can find an answer to either of the following then I will be able to sleep tonight:
Why does the url without the named id parameter give a 404?
or
How can I make the ActionLink helper give the required URL?

When you request the url yourSiteName/SupportNotificationDetail/Index/somefile.html, The request will be handled by IIS because the request url is looking for a static content html file ( The request specifically has a file extension in it). So iis will try to serve it directly without the request going through the MVC request pipeline.
But when you request yourSiteName/SupportNotificationDetail/Index?id=somefile.html, somefile.html is a querystring value. So IIS won't directly serve the response. It will be send to the MVC pipeline and since the request matches the route definition registered with the route table, it will be forwarded to the Index action method with the parameter id and it's value.
The default MVC route definition has a request url pattern of {controller}/{action}/{id} where id is an optional parameter to the action method. For this reason, the helper method generates the link to match with the above mentioned pattern , hence you are getting the url without the id parameter in it.
You can change the parameter name from Id to something else and then the ActionLink helper method will generate the target url with explicit querystring parameter name.
public class SupportNotificationDetailController : Controller
{
public ActionResult Index(string fildId)
{
return Content(fildId);
}
}
and in the view,
#Html.ActionLink("Detail", "Index", "SupportNotificationDetail",
new { fildId = Model.DetailFilename }, null)

Related

MVC 4 routing to a controller

I am new to MVC and I am trying to mess around by creating a practice site which will be a gallery site for viewing and uploading images. The problem I encountered is that I cannot get the routing to work correctly.
Here is a link to my routing code and solution tree:
https://imgur.com/a/Oc1Tt?
Did I set the views and controller up incorrectly?
The error I get is: The view 'Index' or its master was not found or no view engine supports the searched locations. The following locations were searched:
Thanks for any input
Routing works by converting an incoming request to route values or by using route values to generate a URL. The route values are either set as parameters in the URL itself, as default values, or both (in which the defaults make the URL parameters optional).
You have not set any route values in your route. Since you don't have route parameters in the URL, you need to set defaults (controller and action are required by MVC).
routes.MapRoute(
name: "Gallery",
url: "Gallery/Index",
defaults: new { controller = "Gallery", action = "Index" }
);
That said, your Default route already covers this URL. You only need to add custom routes if you desire behavior that the Default route doesn't cover.
Also, if you change the view names so they don't match the name of the action method, you have to specify the name explicitly from the action method.
public ActionResult Index()
{
return View("~/Views/Gallery/GalleryView.cshtml");
}
By default MVC uses conventions. It is much simpler just to name the view Index.cshtml instead of GalleryView.cshtml so you can just return View from the action method.
public ActionResult Index()
{
return View();
}

asp.net mvc routing url.action issue

In my view I'm using a
<img src="#Url.Action("Method", new { Model.Url })" ...
<img src="#Url.Action("Method", new { Model.Url })/1" ...
And in that method I have params:
public ActionResult Method(string url, int ids=0)
With
var book = GetBookByUrl(url);
...
switch (ids)
{
case 1:
In my global.asax I have:
routes.MapRoute(null,
"{controller}/{action}/{url}/{ids}",
new { controller = "Controller", action = "Method", url = "", ids = #"\d+" });
My view returns the correct URL's (with /1 and /2 appended), but I can't seem to get my method to retrieve the value of ids so that I can manipulate them in my action method to retrieve different results based on the Url.Action URL provided within my view, what gives?
The ids parameter seems to always be 0 (not being routed data) and the url parameter has the entire url "bla-bla/2", which I do not want.
Please note that although there are plenty of routing resources, I've read over them and can't seem to get this to work - also is this the standard way of routing data from a request to a controller?
Please show me by way of example how to solve, many thanks!

ASP.NET MVC catch URL parameter in Controller

I've defined such a controller ViewProfile.
I want to use it for the next syntax to access public user info in my project.
/ViewProfile/Sammy
/ViewProfile/Billy
etc...
But I don't know how to handle the 2-nd parameter in URL.
I've tried to use:
[HttpGet]
public ActionResult Index(string query)
{
...
return View();
}
But in the debugger, string query is always empty.
I have read about routines mapping, but really don't understand how would it help me with the determination of id or other parameters.
I read in ASP.NET MVC Book that to get the parameter directly in the controller action just name it as ID.
ASP.NET MVC lets you easily do this without having to confi gure
anything extra. ASP .NET MVC’s default routing convention is to treat
the segment of a URL after the action method name as a parameter named
ID. If your action method has a parameter named ID, then ASP.NET MVC
will automatically pass the URL segment to you as a parameter.
I just tried a sample app and it worked fine for me. The string i entered in the URL did get passed on to the ID parameter in the action.
Also what i noticed is that you should provide your URL as viewprofile/index/1 or
viewprofile/index/somestring.
YOu seem to be skipping the action part.

ASP.NET MVC throws error when id is null

I have a publicly available controller (The action cannot be hidden under any security attribute) . The controller has an action which is available publicly as well.
Following is a sample structure of the controller :
public SomeController : Controller {
[HttpGet]
public ActionResult show(int id){
}
}
The action has a id field which is required. However throws an error which unnecessary adds to the logs when someone enters a malformed URL without the required id (or when search engine bots hit the a URL with the required id).
What should be the ideal solution to deal with this solution.
Possible solutions that come to my mind are :
Set the id as Nullable (int? id) and explicitly handle the case of not having a value by redirecting the caller to some other page showing appropriate errors
explicitly send a 404 error
Is there a generic way using Attributes to do this?
P.S : (to be specific) by explicit I mean writing if else conditions to handle such cases per controller.
I would appreciate any hints in the right direction.
You need a route constraint. This will help the router throw out URLs earlier (resulting in a 404) rather than later (the route is valid, goes to action, action barfs because a parameter is missing).
http://www.asp.net/mvc/tutorials/controllers-and-routing/creating-a-route-constraint-cs
Example default route (potentially replacing the existing one in your global.asax.cx):
// order is important; more specific routes to less specific routes is what you want
//
// default index action, with no ID
routes.MapRoute(
"Default_Index",
"{controller}/",
new {controller="Home", action="Index"}
);
// default create action, with no ID
routes.MapRoute(
"Default_Create",
"{controller}/Create",
new {controller="Home", action="Create"}
);
// default action requiring an ID (such as EDIT)
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new {controller="Home", action="Index"},
new {id = #"\d+" }
);
I would suggest to return 404 status with a custom error page because some one is requesting a resource that doesn't exists.
You can make it as a Nullable type, if it can return a result which represents that request otherwise return 404 status.
For e.g. action method Index(int? id) could return list of items, if id is null or return that specific item. Depending on your business scenario.

Why does MVC 4 Web API match action parameters from a GET request body?

I have a API method that returns a user object by specifying a user id in a request url the restful way, like this:
http://www.myapi.com/users/1
My route looks like this:
routes.MapHttpRoute(
"GetUserByUserId",
"users/{id}",
defaults: new { Controller = "User", Action = "GetUserByUserId" },
constraints: new { httpMethod = new HttpMethodConstraint(new string[] { "GET" })
});
The controller is named UserController and the method is named GetUserByUserId, and looks like this:
[HttpGet]
public User GetUserByUserId(int id)
{
... returns a User object ....
}
If I call the method it responds with the user object, as expected. The id "1" in the url is automatically matched as the GetUserByUserId attribute "id" by the route.
But(!!), if I accidently also provide a JSON serialized object of any kind in the request body, like this:
{"Id":6,"PermissionId":0,"UserId":3}
MVC is automatically mapping the "Id" property in the request body object to my "id" attribute of the GetUserByUserId method, ignoring the "1" id in my url!
To me, this looks very strange. I know Web API automatically maps the request url and the request body to appropriate attributes in the routed method, but the "Id" in the request body in my example is NOT a simple stand-alone integer, it is a property in a complex type and should not be interpretated as the method attribute "id".
Is this a bug, or am I missing something?
asp.net mvc uses ValueProviderFactories to extract values from request for model binding. You can see configured providers by inspecting ValueProviderFactories.Factories Property. With default configuration, this collection consists of
ChildActionValueProviderFactory
FormValueProviderFactory
JsonValueProviderFactory
RouteDataValueProviderFactory
QueryStringValueProviderFactory
HttpFileCollectionValueProviderFactory
This collection is sorted, and as JsonValueProviderFactory appears higher in list, it is used as value provider for id, rather than RouteDataValueProviderFactory.

Resources