How to create controller action for details view - sitefinity

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");
}

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

Umbraco with MVC Controller

I am working on MVC and i started learning Umbraco, I didn't get how to bind the umbraco page with mvc controller get method to show the database values. can anyone suggest any url or video?
Thansk...
What you're looking for is Umbraco route hijacking.
You can read about it here.
https://our.umbraco.org/documentation/reference/routing/custom-controllers
It's easiest to demonstrate with an example : let's say you have a Document Type called 'Home'. You can create a custom locally declared controller in your MVC web project called 'HomeController' and ensure that it inherits from Umbraco.Web.Mvc.RenderMvcController and now all pages that are of document type 'Home' will be routed through your custom controller! Pretty easy right :-) OK so let's see how we can extend this concept. In order for you to run some code in your controller you'll need to override the Index Action.
So, basically, you "simply" need to create a controller named after your document type, so for example, a document type with the name "TextPage" would need a controller called "TextPageController". Now, if you read through the documentation, you'll find that your "TextPageController" will need to inherit from the RenderMvcController. Here's an example how to achieve this.
public class TextPageController : RenderMvcController
{
public ActionResult Index()
{
return View("~/Views/TextPage.cshtml");
}
}
This forum link may help you:
https://our.umbraco.org/forum/developers/razor/38242-Umbraco-MVC4111-Surface-controller-using-an-AJAX-form

Can Umbraco pass a model to view

I am quite new to this Umbraco MVC.
I need to pass some data bound to a model to my partial view from the GET action method.
This simply is not working in a regular MVC way.
[httpget]
public ActionResult Membership()
{
SupplierMembershipInfoModel mm = new SupplierMembershipInfoModel();
mm.ProductPackage = "sssssssss";
ViewBag.status = Request.QueryString["status"];
return PartialView("MembershipPartial", mm);
}
my view:
#model Umbraco.Web.Models.SupplierMembershipInfoModel
some html.....
<td>#Model.ProductPackage</td>
I don't get data here...and the debug never hits the action. But it hits any POST action method.
I know i am doing something wrong...but just don't know what the mistake is??
Any ideas??
As #Sebastiaan points out, the best place to start is the Umbraco community site. There is documentation specific to your issue here: http://our.umbraco.org/documentation/Reference/Templating/Mvc/child-actions
In a nutshell, you want to display a child action on your page and Umbraco uses SurfaceControllers for this. A SurfaceController is simply a Controller that inherits from Umbraco.Web.Mvc.SurfaceController. This provides you Controller with access to the Umbraco context - see here (http://our.umbraco.org/documentation/Reference/Templating/Mvc/surface-controllers).
Either way, you should read the whole documentation section on templating as it will give you a lot of insight into how Umbraco MVC is managed.

Html.RenderAction uses Post instead of Get

I have a simple form on my page. When submitted, it checks if ModelState.IsValid and returns the View with the same model if it's not valid.
On the same page, I'm rendering an action that contains another form like so:
Html.RenderAction("AccountNote", new { id = Model.ID });
Everything works fine until I submit the form on my page and the validation fails. When it shows the page again, the AccountNote action's Post event fires when I'd expect the Get event to fire. I guess it makes sense why it's happening since it's the post that action that's rendering the view, but I want the Get event to fire instead.
public ActionResult AccountNote(int id)
{
//code goes here...
return PartialView(model);
}
[HttpPost]
public ActionResult AccountNote(AccountNoteViewModel model)
{
//code goes here...
return PartialView(model);
}
Am I doing something incorrect? Or is there some trickery I have to do to make this work? I would expect the Html.RenderAction to always assume GET instead of POST.
One solution would be to have only one AccountNote() action method. Then it will be called regardless of GET or POST. You might have to modify your logic a bit if you were using POST version of AccountNote().
And you can decorate it with [ChildActionOnly] attribute.
Since I know, there is not any solution for this problem out of the box. RenderAction and Action methods, consider the current request for deciding on to use which verb.
But you can rename them. For example rename the one that is restricted to HttpPost to AddAccountNote and leave the other one with the current name and without specifying its verb.
Would RenderPartial be an option for you?
More discussion on this topic can be found here: RenderAction calls wrong action method

Creating a new view results in 404 Page

I am trying to do something very simple and I seem to be missing something. I tried to scour the internet for results but haven't gotten anywhere so I was wondering if someone can please advise on this seemingly easy and straightforward task.
I have a working MVC Application and have created Models, Controllers, Views using the defaults (scaffolding).
Now I want to create a new view for one of my controller actions:
public ActionResult Index()
{
return View(db.Blog.ToList());
}
So I right click on Action Result and click Add View.
This gives me a dialog box where I specify a view name of "Test", I click "Create a Strongly Typed View" check box and select model class of Blog.
For scaffold template, I leave empty (note I have tried index without any good result)
Now I click the Add button.
As expected this creates a new view test.cshtml under Views/Blogs
Now when I begin without debugging and go to url: localhost:12341/Blog/Test
I get the following error:
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /Blog/test
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.17929
There could be a lot of issues with why it doesn't work. It is probably worth your while to look into ASP.NET MVC routing. For now, Mystere Man's solution might be a "quick fix" assuming you have everything else set up to their defaults.
In particular, when you tell your browser to go to localhost:12341/Blog/Test then it will (probably) look for a Controller called BlogController and then perform the Test action. In your case, your action is called Index so you would want to go to localhost:12341/Blog/Index (though you may be able to omit Index since it's the default action). Lastly, since your action is called Index then the View() function will automatically look for Index.cshtml. This is detailed somewhat in the msdn documentation:
http://msdn.microsoft.com/en-us/library/dd492930(v=vs.100).aspx
In particular:
If the ViewName property is empty, the current action name is used in place of the ViewName property.
Your action method is called Index, not Test. If you want the url to be /Test, then you need to name the action method Test (there are other ways to do it, but this is the best way)
If you want to use the view Test, then you need to specify it in your View() method.
return View("Test", db.Blogs.ToList());
However, you will still need to use the Index url /Blogs/Index because your action method is Index.