9

I am trying to expose a MVC route in Sitecore 9.2 for a web api I am creating.

I followed the steps describe here but it only works when my controller inherits from controller. If I inherit it to ServicesApiController I receive the following error.

The controller for path '/api/messages' was not found or does not implement IController.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: Sitecore.Mvc.Diagnostics.ExceptionWrapper: The controller for path '/api/messages' was not found or does not implement IController.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:


    [ExceptionWrapper: The controller for path '/api/messages' was not found or does not implement IController.]

    [ControllerCreationException: Could not create controller: 'Messages'. 
    The current route url is: 'api/messages'. ]
       Sitecore.Mvc.Controllers.SitecoreControllerFactory.CreateController(RequestContext requestContext, String controllerName) +171
       System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory) +261
       System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +77
       System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +1128
       System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step) +220
       System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +134

UPDATE I checked the Sitecore.Mvc.Controllers.SitecoreControllerFactory and notice that inside the method ResolveController factory has a cast to IController.

protected virtual IController ResolveController(Type type)
    {
        return (DependencyResolver().GetService(type) as IController) ?? TypeHelper.CreateObject<IController>(type, Array.Empty<object>());
    }

protected virtual IController CreateSitecoreController(RequestContext requestContext, string controllerName)
    {
        IController controller = PipelineService.Get().RunPipeline("mvc.createController", new CreateControllerArgs(requestContext, controllerName), (CreateControllerArgs args) => args.Result);
        if (controller == null)
        {
            throw new InvalidOperationException("Could not create a Sitecore controller: '{0}'".FormatWith(controllerName));
        }
        return controller;
    }

Does this mean that you can no longer inherit from ServiceApiController in Sitecore 9.2 like what I am trying to do since the ServiceApiController inherits from APIController and not on Controller or IController?

It would be helpful if you guys can confirm as well.

UPDATE 2

I tried inheriting from the IController, the error disappears but the action is not called or executed.

Below are my codes:

Config:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <initialize>
        <processor type="SAIF.Foundation.Bot.Pipeline.BotLoadProcessor,SAIF.Foundation.Bot" patch:after="processor[@type='Sitecore.Pipelines.Loader.EnsureAnonymousUsers, Sitecore.Kernel']" />
      </initialize>
    </pipelines>
  </sitecore>
</configuration>

RouteConfig.cs

namespace SAIF.Foundation.Bot
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.MapRoute("botroutes", "api/messages", new { controller= "Messages", action="index" });
        }
    }
}

BotLoaderProcessor.cs

namespace SAIF.Foundation.Bot.Pipeline
{
    using Sitecore.Diagnostics;
    using Sitecore.Pipelines;
    using System.Web.Routing;

    public class BotLoadProcessor
    {
        public void Process(PipelineArgs args)
        {
            Log.Info("Sitecore is starting", this);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
        }
    }
}

MessagesController.cs

 public class MessagesController : ServicesApiController
    {
        // GET: Bot
        private readonly IBotFrameworkHttpAdapter Adapter;
        private readonly IBot Bot;


        public MessagesController()
        {
            Adapter = new BotFrameworkHttpAdapter();
            Bot = new SimpleBot();
        }


        [System.Web.Http.HttpPost]
        [AcceptVerbs("Post")]
        public async Task<HttpResponseMessage> Index()
        {
            var response = new HttpResponseMessage();
            await Adapter.ProcessAsync(Request, response, Bot);
            return response;
        }
    }

3 Answers 3

14
+100

You have most of the pieces you need, but not all.

You need a patch config

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
    <sitecore>
            <initialize>
                <processor patch:before="processor[@type='Sitecore.Mvc.Pipelines.Loader.InitializeRoutes, Sitecore.Mvc']"
                           type="SAIF.Foundation.Bot.Pipeline.BotLoadProcessor, SAIF.Foundation.Bot" />
            </initialize>
        </pipelines>
    </sitecore>
</configuration>

You need the route configurator that you patched in

Notice that it inherits from nothing.

public class BotLoadProcessor
{
    public void Process(PipelineArgs args)
    {
        Configure(RouteTable.Routes);
    }

    protected void Configure(RouteCollection routes)
    {
        routes.MapHttpRoute("botloadapi_message", "sitecore/api/botloadapi/messages", new
        {
            controller = "Messages",
            action = "Index"
        });
    }
}

And you need your controller

I think the one you have will work as-is.

 public class MessagesController : ServicesApiController
    {
        // GET: Bot
        private readonly IBotFrameworkHttpAdapter Adapter;
        private readonly IBot Bot;


        public MessagesController()
        {
            Adapter = new BotFrameworkHttpAdapter();
            Bot = new SimpleBot();
        }


        [System.Web.Http.HttpPost]
        [AcceptVerbs("Post")]
        public async Task<HttpResponseMessage> Index()
        {
            var response = new HttpResponseMessage();
            await Adapter.ProcessAsync(Request, response, Bot);
            return response;
        }
    }

In summary

From what you've shown, I don't think you're registering the routes correctly. Follow these 3 steps, and you should be good to go.

I can't be sure if your controller action Index actually works, since it's just a facade to some code deeper inside your setup. For completeness, here is a [HttpPost] method I know works.

[HttpPost]
public async Task SetProfileImage([FromBody] Base64ProfilePicture profilePicture)
{
    Assert.IsNotNull(profilePicture, nameof(profilePicture));

    var user = Sitecore.Context.User;
    await _profileProvider.SetProfilePictureForUser(user.Name, new ProfilePicture(profilePicture));
}
1
  • 1
    Another thing worth mentioning is that you shouldn't be using the System.Web.Mvc namespace whatsoever in this configuration, but should be exclusively pulling from System.Web.Http. Many of the names overlap (e.g. HttpGet, HttpPost), and you will run into runtime errors if you mix the two up.
    – raterus
    May 21, 2020 at 18:16
4

MapRoute is meant for MVC controllers whereas MapHttpRoute is meant for Web API controllers.

ServiceApiController is ApiController, and you should register your route with MapHttpRoute instead of MapRoute.

Just register your route with:

GlobalConfiguration.Configure(config =>
{
     config.Routes.MapHttpRoute("botroutes", "api/messages", new
     {
         controller = "Messages",
         action = "Index"
     });
});
-1

You need to register your custom route using a patch config. enter image description here

Make the changes to your BotLoaderProcessor class as follows:

BotLoaderProcessor.cs

namespace SAIF.Foundation.Bot.Pipeline
{
    using Sitecore.Diagnostics;
    using Sitecore.Mvc.Pipelines.Loader;
    using System.Web.Routing;
    using System.Web.Mvc;

    public class BotLoaderProcessor : InitializeRoutes
    {
        public void Process(PipelineArgs args)
        {
            Log.Info("Sitecore is starting", this);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
        }
    }
}

Create a config patch file for BotLoaderProcessor class and add the following.

z.BotLoaderRoute.config

<?xml version="1.0"?> <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"> <sitecore> <pipelines> <initialize> <processor type="SAIF.Foundation.Bot.BotLoaderProcessor, SAIF.Foundation.Bot" patch:before="*[@type='Sitecore.Mvc.Pipelines.Loader.InitializeRoutes, Sitecore.Mvc']" /> </initialize> </pipelines> </sitecore> </configuration>

5
  • Does not work. Firstly the RouteConfig is not a processeor so I could not register it.
    – Pinoy2015
    Oct 27, 2019 at 13:33
  • Have updated. You need to create the patch file for BotLoaderProcessor and not RouteConfig class. Also, make sure that the BotLoaderProcessor inherits from InitializeRoutes class in Sitecore.Mvc.Pipelines.Loader Oct 28, 2019 at 3:38
  • It works only if my controller inherits from Controller but when I change the inheritance to ServiceApiController, the same error occurs.
    – Pinoy2015
    Oct 28, 2019 at 4:40
  • I checked the Sitecore.Mvc.Controllers.SitecoreControllerFactory where the error is being thrown and notice that inside the method ResolveController, there is a cast to IController. Please see the update section in my question for more details.
    – Pinoy2015
    Oct 28, 2019 at 4:41
  • Did you try <processor type="SAIF.Foundation.Bot.BotLoaderProcessor, SAIF.Foundation.Bot" patch:before="*[@type='Sitecore.Mvc.Pipelines.Loader.InitializeRoutes, Sitecore.Mvc']" /> instead of <processor type="SAIF.Foundation.Bot.Pipeline.BotLoadProcessor,SAIF.Foundation.Bot" patch:after="processor[@type='Sitecore.Pipelines.Loader.EnsureAnonymousUsers, Sitecore.Kernel']" /> in Config? Oct 28, 2019 at 15:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.