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,
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