1

I'm working on an upgrade from Sitecore 8.2 to 10.1, and I've got some API Controllers. These worked in the 8.2 site but I'm encountering dependency injection issues now, getting the following error when trying to call the APIs:

{"Message":"An error has occurred.","ExceptionMessage":"An error occurred when trying to create a controller of type 'MapSearchController'. Make sure that the controller has a parameterless public constructor.","ExceptionType":"System.InvalidOperationException","StackTrace":" at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.d__15.MoveNext()","InnerException":{"Message":"An error has occurred.","ExceptionMessage":"Type 'MySite.Domain.MapSearchController' does not have a default constructor","ExceptionType":"System.ArgumentException","StackTrace":" at System.Linq.Expressions.Expression.New(Type type)\r\n at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"}}**

Here is all of the code I have related to the controller and DI setup

namespace MySite.Domain.Controllers
{
    [Route("services/api/MapSearch")]
    public class MapController : ApiController
    {
        private readonly IMapSqlSearchService _sqlSearchService;
        private readonly IMapSolrSearchService _SolrSearchService;
        public MapSearchController(IMapSqlSearchService sqlSearchService, IMapSolrSearchService SolrSearchService)
        {
            _sqlSearchService = sqlSearchService;
            _SolrSearchService = SolrSearchService;
        }

        [HttpGet]
        public IHttpActionResult Get()
        {
            var allUrlKeyValues = ControllerContext.Request.GetQueryNameValuePairs();
            var filters = iSearchHelper.GetRequestFilters(allUrlKeyValues);
        
            var SolrSearchResults = _SolrSearchService.GetResults(filters.CropFilters, filters.OtherFilters);
            var formattedResults = _sqlSearchService.GetResults(filters, SolrSearchResults);

            return Json(formattedResults, new JsonSerializerSettings
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            });
        }
    }
}

I have a Registrar that registers the services:

public class MapServicesRegistrar
{
    public static void RegisterMapServices(ContainerBuilder builder)
    {
        builder.RegisterType<MapSqlSearchService>().As<IMapSqlSearchService>();
        builder.RegisterType<MapSolrearchService>().As<IMapSolrSearchService>();
        builder.RegisterType<TrialResultsFormatter>().As<ITrialResultsFormatter>();
    }
}

In AutofacStartup.cs, the registrar is called:

MapServicesRegistrar.RegisterMapServices(builder);

It's also called in a custom registration class:

public class RegisterCustomDependencies : IProcessor<RegisterAutofacDependenciesPipelineArgs>
{
    public void Process(RegisterAutofacDependenciesPipelineArgs pipelineArgs)
    {
        CustomDependenciesRegistrar.RegisterDependencies(pipelineArgs.ContainerBuilder);
    }
}
public static class CustomDependenciesRegistrar
{
    public static void RegisterDependencies(ContainerBuilder builder)
    {
        SiteServicesRegistrar.RegisterSiteServices(builder);
        DstServicesRegistrar.RegisterDstServices(builder);
        MapServicesRegistrar.RegisterMapServices(builder);

The services and controllers are registered in RegisterServicesConfigurator:

public class RegisterServicesConfigurator : IServicesConfigurator
{
    public void Configure(IServiceCollection serviceCollection)
    {
         serviceCollection.AddTransient<IMapSqlSearchService, MapSqlSearchService>();
         serviceCollection.AddTransient<IMapSolrSearchService, IMapSolrSearchService>();
         serviceCollection.AddTransient<MapSearchController>();

...and finally, there's a patch that tells it to check the proper dll for DI:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
    <services>
      <configurator type="Jabberwocky.DependencyInjection.Sc.Configuration.AggregateServiceConfigurator, Jabberwocky.DependencyInjection.Sc" />
  <Jabberwocky.ScannedAssemblies>
    <!-- Add Assembly Patterns here that will automatically be scanned for services -->    
      <Domain>MySite.Domain</Domain>
      <Site>MySite</Site>
  </Jabberwocky.ScannedAssemblies>
    </services>
</sitecore>
</configuration>

...which is also referenced in AutofactStartup.cs:

    private const string WebsiteDll = "MySite";
    private const string DomainDll = "MySite.Domain";

    public static void RegisterDependencies()
    {
        var builder = new ContainerBuilder();
        builder.AutowireDependencies(assemblyNames: new[] {  WebsiteDll, DomainDll });
3
  • This looks like an issue in DI configuration.
    – Ghanendra
    Nov 3 at 16:01
  • 1
    I would guess this is a conflict between autofac and the MS DI framework used in Sitecore. This article might help with chaining those: seanholmesby.com/… - Ultimately, your MapSearchController is not registered with the DI container so when it's being created the container doesn't know about it and doesn't resolve the dependencies. Also, WebApi controllers need some extra work to std MVC controllers IIRC.
    – Richard Seal
    Nov 3 at 16:11
  • 1
    If you go to https://<your-domain>/sitecore/admin/ShowServicesConfig.aspx does it show both your dependencies listed correctly? Nov 3 at 23:25

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.