Simple lack of understanding - MVC Routing - asp.net-mvc-4

I want to call a method in the controller. To do this, assuming default routing, I have to have a view that matches the controller I'm calling.
So if I have a contoller action
public ActionResult Edit(booking booking)
then I must have a view called Edit.
Is that right?
What I want to do is call any action in my controller from a given page without there being a view of the same name.
So if I'm on the Edit page, I should be able to call an action named createproduct, without there being a createproduct view.

You don't need to have a view for every controller action. You can just call an action by calling the correct URL, that's one of the advantages of MVC and routing. Routes don't have to represent a physical location. You should be able to do the following /Controller/Edit/booking

A controller action doesn't have to return a View. You tend to see the action method return View(), which renders a view with the same name as the action method by default. But you can return View("SomeOtherViewName"). You can also return various other results, such as FileResult (returns a file), HttpStatusCodeResult (returns an HTTP response code with no content), JsonResult (returns Json), Content (returns some string) etc. The Controller class has methods to help return some of these result types: File, Json, Content.

Related

Why is mandatory the "Route" attribute on methods of a custom-routed controller?

Consider a fresh Asp.Net Core 2.1 MVC Web app created via the Visual Studio 2017 template. Now, consider a custom view (MyView) and also a controller (ActualController) so that the project structure looks similar to this picture:
The MyView shows nothing special, and it's off the point. However, the page should appear when the user enters an URL like http://(domain)/desired/myview or also via a hyperlink in the home page:
<a asp-area="" asp-controller="Desired" asp-action="MyView">MyView</a>
Now let's focus on the controller, which is a class named differently from what the routing expects:
[Route("desired")]
public class ActualController : Controller
{
[Route("MyView")] //without this the method won't be called
public IActionResult MyView()
{
return this.View();
}
}
From what I know, by decorating the controller with a Route attribute tells the URL resolver to match this class. However, the mapping works only if I explicitly add a (redundant) Route attribute on the target method/action. If I remove it, the path won't be found, and the server returns a 404-error.
The question is: why should be mandatory to decorate with Route the method, even the action is implicitly defined by the method name (as usual)?
NOTE: is rather simple for me to rename the controller class, but I'd like to know what are the reasons behind this behavior.
You are overriding the default route of [controller]/[action] with [Route("desired")]. Since you don't define an action parameter on controller level, all other routes have to be done explicitly.
Changing the top route parameter to [Route("desired/[action]")] should solve it and the method name will be used as parameter. You can still override single actions if you want to name them differently by adding the [Route("")] attribute to them.
Also see the docs (Token replacement in route templates) for further description on the route parameters

How to create controller action for details view

Inherited a Sitefinity site. Need to add a MVC widget for the details view on the news pages.
I found this documentation but I can't make heads or tails of it - maybe it was for a different version. I finally found the UrlkeyPrefix buried deep in the news widget options, but following the instructions of the documentation added "!content" in the middle of my details page URL (which I can't have happening) and still did not display my custom widget.
Does anyone know how to correctly configure the controller to get the widget to show up for the details pages?
I sort of got the example in the documentation to work, except that there's this very annoying "!content" in my URL still
https://mysite/news/!content/2017/08/24/my-article-title
[ActionName("!content")]
public ActionResult Filter()
{
return View("index", InitializeModel());
}
Navigating to the URL sans "!content" just shows the list page.
The nature of MVC is such that you're only able to invoke one action at a time.
Assuming that you're invoking the Details action on the NewsController, the other widget you've placed on the page won't understand how to respond to a Details action unless you do one of two things:
Create a corresponding Details action in your own controller OR
Override HandleUnknownAction to handle what you want to happen when another widget's method is invoked. (better, as it reduces ambiguity)
If you want to invoke your Index action on your custom widget when the Details action is invoked on News:
protected override void HandleUnknownAction(string actionName)
{
this.ActionInvoker.InvokeAction(this.ControllerContext, "Index");
}

Web API return Helper Page

I have a ASP.NET WebPage and like to use the Helper Pages located under App_Code. Now I don't have any clue how to solve this problem: I post data from a html form to my Controller (WebApi 2 HttpPost method) with $.ajax. As a result, I wan't the content of my helper page, whose binding data comes from my controller web api method.
I would like to maintain my form data encapsulated in my model class, because it seems cleaner to me to handle with the data. I also want to access my model in my view.
[HttpPost]
[Route("api/{ClassID}/AddUsers")]
public IHttpActionResult AddUsers([FromUri] int ClassID, [FromBody] Models.UserInfo userInfo)
{
Foo result = new Foo();
result = doSometStuff(userInfo);
return ???(HelperPages.FooHelper.Get(result));
}
I have to answer my question myself. Web API only returns data, not any view. So I just have to use a mvc controller to do so.

GetPdfBytesFromUrl sent from within controller still needs authentication

I am using EVOPdf converter in my MVC4 project.
I am using the method pdfConverter.GetPdfBytesFromUrl to hit another controller action to return the rendered HTML and have that get converted into a PDF.
My problem is that I now have an [Authorize] attribute on the controller, now that same method only renders a log-in page.
Since I'm requesting the URL from within the same controller (but a different actionresult), is there any way to pass authentication?
string myOwnAddress = System.Configuration.ConfigurationManager.AppSettings["local-address"];
//THIS WILL NEED THE PARAMETERS SENT VIA THE GET URL
byte[] pdfBytes =
pdfConverter.GetPdfBytesFromUrl(myOwnAddress + "/ClinicianReportPDFRendered?PID=" + PID);
Unless somebody can come up with a better solution, I'm going to create a unique key in the requesting action to be passed/used one time and authenticate using that code in the other action.
The only downside is I'll have to take off the blanket [Authorize] on the top of the controller and apply it individually to each action result.

How can I use asp.net mvc routing to call a different ActionResult method and display a different URL than what is actually there?

Lets say I have a Controller class called ProductController.
I'll use Samsung as a hypothetical product category.
I have an Html.ActionLink on a page that looks like this
~/Product/Samsung?t=Sony
Now lets say I don't have an ActionResult method named Samsung.
But lets say I have more links like the one above like
~/Product/Toshiba?t=LG
~/Product/Sony?t=Dynex
Never mind the t=? part.
Is there a way that I can make all of these ActionLinks hit the same ActionResult method in my Product Controller?
public ActionResult TelevisionCategory()
{
}
Like some sort of URL routing so that any URL in a specific format will hit the TelevisionCategory method?
Sounds like you just need a custom route that takes an identifier as a second URL segment instead of an action name.
Something like the following should suffice (you'll need to add this above the default route in your route config):
routes.MapRoute(
"Products",
"Product/{category}",
new { controller = "Product", action = "TelevisionCategory" }
);
Then, your action method should look like this:
public ActionResult TelevisionCategory(string category)
See here for more on creating custom routes.
If using MVC5 is an option, you can also use attribute routing, which is a little more intuitive and succinct.