Attribute Routing with RoutingParameter - asp.net-mvc

I currently have a set of action methods in a web api controller that use Attribute Routing.
[RoutePrefix("Paper")]...
[Route("Shape/Octagon/{id:minlength(1)}]
public IEnumerable<sampleShape> PostactionName(string id){..}
[Route("Shape/Hexagon/{id:minlength(1)}]]
public IEnumerable<sampleShape> PostactionName(string id){..}
which would work for the following URIs
api/Paper/Shape/Octagon/"1,2,3"
api/Paper/Shape/Hexagon/"3,2,1"
but becomes unusable once the id parameter becomes to long. Is there anyway to have routing use the parameter id as a form data rather than part of the URI but still keep the Route attribute.

You can use FromBody attribute to let the engine know that parameter will come from post body
[RoutePrefix("Paper")]...
[Route("Shape/Octagon"}]
public IEnumerable<sampleShape> PostactionName([FromBody]string id){..}
[Route("Shape/Hexagon"}]]
public IEnumerable<sampleShape> PostactionName([FromBody]string id){..}

Related

What is the purpose of MVC passing the current "controller" and "action" as parameter values

I had to pass an extra parameter with my action links to indicate where they came from (as I needed to change a back link in the pages accordingly).
As it was a controller name, I decided to name it controller.
e.g. a sample link might be:
#Html.ActionLink(item.Name, "Options", "Questionnaire", new {
id = item.QuestionnaireId,
controller = "templates" }, null)
The receiving action in QuestionnaireController looked like:
public ActionResult Options(int id, string controller)
When the action was hit I noticed the controller value was not template, but instead was the name of the current controller (i.e. QuestionnaireController).
As an experiment I added an action parameter e.g.:
public ActionResult Options(int id, string controller, string action)
the action value was the current action too (i.e. Options).
My work-around for this was simply to rename my parameter to source, but why does MVC bother to map the names controller and action to action parameters? I assume that would apply to any/all Route Mapping values, but what is the purpose of this?
Why does MVC bother to map the names controller and action to action parameters?
I believe it's done as part of the QueryStringValueProvider or one of the other ValueProviders (maybe the RouteDataValueProvider). ASP.Net MVC uses Convention over Configuration, so the framework uses the values provided to populate method parameters. The Controller name, Action name and even the Area name are all values provided in the Url.
I assume that would apply to any/all Route Mapping values, but what is the purpose of this?
The ValueProvider is used for Routing data to determine the matching route to use, it also happens to be the same object that provides the data to populate method parameters. The side affect you are experiencing is most likely not a feature they were trying to implement.
The DefaultModelBinder.GetValue uses the ValueProviders to locate a value and bind it to the model (or method paramater).

Html.RenderAction with Route Name

I am trying to utilize the Route attribute naming (ex: [Route(Name = "Abc123")]) in a controller action, and likewise be able to call that via Html.RenderAction, but it appears that this does not support route names. I assume this is because route names are reserved only for ones requested via HTTP and not called directly, but somewhat new to MVC so I'm at a loss.
I'm using MVC Attribute Routing entirely, and I do not have routes configured otherwise. It seems that I must define the route name, and the route name has to match the action method name. In doing so, however, I am getting naming conflicts when I try to name more than one Index.
I'm basically trying to support multiple partial views, each having their own controller, which serve as plugins/widgets on my site. So ideally each would have an action called Index.
Do you have a recommendation on how I can maintain the same naming? This allows me to call Html.RenderAction("Index", [ControllerName], [Model]) without the render name changing.
You can use attribute routing with Html.RenderAction just you have to make sure that the action name in attribute is actual Name :
[Route("Home/About")]
public ActionResult About()
{
ViewBag.Message = "Your application description page.";
return View();
}
and in HTML you can have
#{Html.RenderAction("About", "home");}
It will work fine.
You should be able to do what you are trying to do with attribute routing. If you are trying to render a partial view you should be using RenderPartial instead of RenderAction.
Are you doing this between areas? I believe there are some gotcha's with making that work correctly.
Can you please post example Controller code and RouteConfig?

QueryString with MVC 5 AttributeRouting in Web API 2

I have the following code
[HttpGet]
[Route("publish/{id}")]
public IHttpActionResult B(string id, string publishid=null) { ... }
So as far as I understood,
~/..../publish/1?publishid=12
~/..../publish?id=1&publishid=12
Should work and bind both parameters but it won't work on the second case.
In the first case, publishid will not be bound.
So I do not understand why this is not working. Any idea why it is in this way?
The second case will not work because id is a required variable in the route template publish/{id}. In Web API first route template matching happens and then the action selection process.
other cases:
publish/1 - will not work as action B is saying that publishid is required. To prevent this you can change the signature of action to be something like B(string id, string publishid=null) and only id is bound
publish/1?publishid=10 - works as expected where both are bound.

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 Core 2.2 on random address goes to controller instead of 404 Not Found

If the address is well formatted everything is fine.
But when I type random string into the address bar, asp net core routes to the same controller and in particular to Index(model)
[HttpGet]
public IActionResult Index() { ... }
[HttpGet({model})]
public IActionResult Index(ViewModel model) { ... }
instead of returning 404 Not found.
Is the problem with the controller?
Your HomeController is mapped to "" or the empty route, and then this second Index action requires basically any route portion. So, /foobar literally routes to this Index action.
There's a number of problems/misunderstandings here. When you specify {model} in the route, you're telling the framework that this is a route param. There's effectively no way to actually ever bind your model, because you can't actually post a representation of ViewModel within a route path.
Second, there is no validation of route params during routing. In other words, ASP.NET Core doesn't look at you action, see that it needs to be an instance of ViewModel, realize that foobar in /foobar is not a ViewModel and then returns 404. It merely sees that there's a potential route that takes something in that route segment, and then attempts to load up the corresponding action. It's on the modelbinding phase where things will fail, but that's after the routing is already done.
You can use route constraints to add a layer of validation. For example, {foo:int} would only match if the value in that route segment was something that could be cast to an int, but you can't really do that for something like ViewModel.
Third, you shouldn't be sending an entire model via a GET. GET doesn't have a body, and complex objects should go in the body of the request. You should be using POST here instead.
Long and short, change your action to:
[HttpPost]
public IActionResult Index(ViewModel model) { ... }
And you'll be fine.

Resources