Hi,
As strange as this may sound, reordering your actions to put the index action first should resolve the issue.
Thanks for the input. But how can I then have partial classes of StartPageController ?
Ah. I see the problem. I'd missed the "partial" bit when I read the original question. To summarise, you can't control the order of the methods as they exist in partial classes in different files and so you can't ensure the index method comes first.
I've recreated the issue and it looks as though both actions are matching the same route:
{controller=Home}/{action=Index}/{id?}
I think, to resolve the issue, you'll need to override the mechanism to select the appropriate action. You could do this with an action constraint which, for each action, would allow you to determine whether it's the most appropriate one to handle your request. I've done that by attaching a "priority" to each action and picking the action with the lowest value here:
[AttributeUsage(AttributeTargets.Method)]
public class ActionPriorityAttribute : Attribute, IActionConstraint
{
public ActionPriorityAttribute(int priority = 0)
{
Priority = priority;
}
public int Priority { get; set; }
public int Order => 0;
//Return a bool indicating whether to use this action
public bool Accept(ActionConstraintContext context)
{
//if the priority is 0, we can't beat that so use this action
//similarly, if this is the only action, just use it
if (Priority == 0 || context.Candidates.Count == 1)
return true;
//If this action has the lowest "priority" value of all actions, return true to use this action
//otherwise return false so we can choose the action with the lower value when we get to it
return !context.Candidates.Any(x => ((x.Action.ActionConstraints.FirstOrDefault(f => f.GetType() == typeof(ActionPriorityAttribute)) as ActionPriorityAttribute)?.Priority ?? 10000) < Priority);
}
}
You can then apply it to your controller like this:
public class HomeController : PageController<HomePage>
{
[ActionPriority(10)]
[HttpGet("getdto")]
public IActionResult GetDTO(string id)
{
return Json(new { id });
}
[ActionPriority(0)]
[HttpGet()]
public IActionResult Index(HomePage currentContent) => View(ContentViewModel.Create<HomePage>(currentContent));
}
Hi Paul,
Thank you for sharing it. I just modified the code a bit to validate for nulls of `ActionConstraints`
[AttributeUsage(AttributeTargets.Method)]
public class ActionPriorityAttribute : Attribute, IActionConstraint
{
public ActionPriorityAttribute(int priority = 0)
{
Priority = priority;
}
public int Priority { get; set; }
public int Order => 0;
//Return a bool indicating whether to use this action
public bool Accept(ActionConstraintContext context)
{
//if the priority is 0, we can't beat that so use this action
//similarly, if this is the only action, just use it
if (Priority == 0 || context.Candidates.Count == 1)
return true;
//If this action has the lowest "priority" value of all actions, return true to use this action
//otherwise return false so we can choose the action with the lower value when we get to it
return !context.Candidates.Any(x => ((x.Action.ActionConstraints?.FirstOrDefault(f => f.GetType() == typeof(ActionPriorityAttribute)) as ActionPriorityAttribute)?.Priority ?? 10000) < Priority);
}
}
Hi
After upgrading from CMS 11 to 12, we noticed that URL.Action didn't work anymore for action methods on the page controller. We then implemented the workaround described here: https://world.optimizely.com/forum/developer-forum/cms-12/thread-container/2022/8/url-action-does-not-work-in-cms-12/ .
However, after a few months (!), we ran into the same issue you described here: all of a sudden, on page load, the index method wasn't called, but some random action method on that page controller was, which resulted in nullreference exceptions. For more info: see my post in the linked thread.
Our current conclusion is that there's a reason Url.Action doesn't work out of the box anymore for methods on content controllers: you're supposed to put the action methods on a separate controller.
If there's any feedback on this, please share. It was a tricky issue to debug, hope to save someone else the time :).
Kr
Lander
Hi,
In our current EpiServer ver. 11 we are having partial classes of startpage controller. Each partial class contains different action methods and some only returns JSON.
After migrating to Optimizely 12 the index method is not get called as default ->
https://localhost:5001 should call index method of startpage but its calling some other action method of the same controller which return Json
If i write https://localhost:5001/index then the index method is called
Or said in other words, how can I make following code work ->
Any help would be appreciated