Null exception in GetUrl in search provider indexer

Vote:
 

I'm trying to use GetUrl() in a commerce search provider indexer and GetUrl throws a null exception.

Doing this:

var urlResolver = ServiceLocator.Current.GetInstance<UrlResolver>();
urlResolver.GetUrl(node.ContentLink)


Gives me

Value cannot be null.
Parameter name: httpContext

   at System.Web.HttpContextWrapper..ctor(HttpContext httpContext)
   at EPiServer.Framework.FrameworkInitialization.<ConfigureContainer>b__1()
   at EPiServer.Commerce.Routing.RequestCacheUrlResolver.GetVirtualPath(ContentReference contentLink, String language, ContextMode contextMode, Func`1 getVirtualPathAction)
   at EPiServer.Commerce.Routing.RequestCacheUrlResolver.GetUrl(ContentReference contentLink)
   .
   (private code)
   .
   at Mediachase.Search.SearchManager.BuildIndex(Boolean rebuild)

#79015
Dec 06, 2013 13:56
Vote:
 

In which context does the search provider indexer execute? There is code which should avoid using the RequestCacheUrlResolver if the context is not a web context but apparently the check is buggy.

#79215
Dec 11, 2013 9:54
Vote:
 

Until the bug is fixed, you can work around this issue by changing the container configuration using a initializable/configurable module (or append the container config to one you already have):

[ModuleDependency(typeof(EPiServer.Commerce.Initialization.InitializationModule))]
public class FixUrlResolverHttpContext : IConfigurableModule
{
  public void Initialize(InitializationEngine context) {}
  public void Preload(string[] parameters) {}
  public void Uninitialize(InitializationEngine context) {}
  public void ConfigureContainer(ServiceConfigurationContext context)
  {
  context.Container.Configure(
    c =>
    c.For<ServiceAccessor<HttpContextBase>>()
      .Use(() => HttpContext.Current != null ? new HttpContextWrapper(HttpContext.Current) : null));
  }
}

#79226
Dec 11, 2013 11:11
Vote:
 

I run it using the Build/Rebuild Index buttons i Commerce Manager. I'll try your fix.

#79404
Dec 16, 2013 15:23
Vote:
 

I tried your fix and I no longer get an exception. However, GetUrl always returns null run in commerce manager context.Is this not the correct way to get the url for a product or category page?

var urlResolver = ServiceLocator.Current.GetInstance<UrlResolver>();
var url = urlResolver.GetUrl(content.ContentLink, "sv-SE");

#79453
Dec 17, 2013 16:38
Vote:
 

Do you get something out of GetUrl if you run it in the front end site context?

Are you really using a language branch for the specific culture sv-SE? Generally the neutral culture sv is used, that is what is set up out of the box. Check the website language settings in CMS admin and the language setup of your catalog.

Also, does the content you want to get the URL for have a matching render template? If it does not, GetUrl returns null.

#79466
Dec 18, 2013 8:18
Vote:
 

It works in front end site context but in commerce manager context GetUrl returns null.

#79472
Dec 18, 2013 11:36
Vote:
 

We use sv-SE since we have multiple locales for some countries. For example fi-FI and sv-FI

#79473
Dec 18, 2013 11:37
Vote:
 

I think I know why now... Your render templates are in your template project, which is not deployed in the manager site. Then no renderer is found for the content and no URL is returned. It could perhaps be solved by deploying the assemblies containing the renderers and content types to the manager site but I don't know if that could cause other side effects. Perhaps deploying an assembly containing a dummy renderer which works for any CatalogContentBase would be an alternative but that is completely untested.

I think we may have a gap in the UrlResolver functionality here. What is it that you need the URL for in the search provider? Would it be sufficient to have permanent links (which you can get from a IPermanentLinkMapper service)?

#79478
Dec 18, 2013 11:52
Vote:
 

This is probably a better solution than deploying assemblies:

var requestContext = new RequestContext {RouteData = new RouteData()};
var contentRouteValues = new RouteValueDictionary
{
    {RoutingConstants.NodeKey, contentLink},
    {RoutingConstants.LanguageKey, language},
};

var virtualPath = RouteTable.Routes.GetVirtualPath(requestContext, contentRouteValues);
var url = virtualPath.GetUrl();

#79480
Dec 18, 2013 12:16
Vote:
 

We're indexing the url's since we're using Apptus eSales and don't want to fetch information from several sources.


GetVirtualPath() needs a HttpContext to get the application path so I setup a fake HttpContext. However, for any of our product types the url looks the same except for the id. I tried adding contextmode default to the route data tokens but that didn't change anything.

/ProductInCartOrWishList/Edit?node=90__CatalogContent&amp;language=sv-SE


I think we'll have to get the url front end for now.

#79484
Dec 18, 2013 13:50
Vote:
 

Sorry about this, the UrlResolver should be able to work even when there is no template but there's a bug which prevents it. The strange URL you got is because there are more routes registered that apparently can be applied. You should filter by content route, to do something like:


var requestContext = new RequestContext {RouteData = new RouteData()}; //Also set the fake HTTP Context if required
foreach (RouteBase route in RouteTable.Routes.Where(r => r is ContentRoute))
{
  // Create new route values for each route in case they are manipulated by the route
  var contentRouteValues = new RouteValueDictionary
  {
    {RoutingConstants.NodeKey, contentLink},
    {RoutingConstants.LanguageKey, language},
  };
  var virtualPath = route.GetVirtualPath(requestContext, contentRouteValues);

  if (virtualPath != null)
  {
    return virtualPath.GetUrl();
  }

}
return null;

#79488
Dec 18, 2013 15:21
Vote:
 

We never got this working.

We now run the indexer using the scheduled job instead which makes it run in the correct context

However it's giving us another error. Note that we don't use the SeoUri routing but the "Uri name" alternative.

ArgumentNullException: "The provided content link does not have a value.\r\nParameter name: contentLink"

 

at EPiServer.DataFactory.Get[T](ContentReference contentLink, ILanguageSelector languageSelector)
at EPiServer.DataFactory.Get[T](ContentReference contentLink)
at EPiServer.Web.Routing.Segments.NodeSegment.GetVirtualPathSegment(RequestContext requestContext, RouteValueDictionary values)
at EPiServer.Web.Routing.Segments.NodeSegment.GetVirtualPathSegment(RequestContext requestContext, RouteValueDictionary values, HashSet`1 usedValues)
at EPiServer.Web.Routing.ContentRoute.AddVirtualPathFromSegments(StringBuilder virtualPath, RequestContext requestContext, RouteValueDictionary values, HashSet`1 usedValues, Int32 lastNonDefaultIndex)
at EPiServer.Web.Routing.ContentRoute.GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
at EPiServer.Web.Routing.UrlResolver.GetUrlFromRoute(ContentReference contentRefernce, String language, RouteValueDictionary routeValues, RequestContext requestContext)
at EPiServer.Web.Routing.UrlResolver.GetVirtualPath(ContentReference contentLink, String language, ContextMode contextMode, RouteValueDictionary routeValues, RequestContext requestContext)
at EPiServer.Web.Routing.UrlResolver.GetVirtualPath(ContentReference contentLink, String language, VirtualPathArguments virtualPathArguments)
at EPiServer.Web.Routing.UrlResolver.GetUrl(ContentReference contentLink, String language)
at EPiServer.Commerce.Routing.RequestCacheUrlResolver.GetVirtualPath(ContentReference contentLink, String language, ContextMode contextMode, Func`1 getVirtualPathAction)
at EPiServer.Commerce.Routing.RequestCacheUrlResolver.GetUrl(ContentReference contentLink, String language)
at EPiServer.Commerce.Routing.RequestCacheUrlResolver.<>c__DisplayClass1.<GetUrl>b__0()
at EPiServer.Commerce.Routing.RequestCacheUrlResolver.GetVirtualPath(ContentReference contentLink, String language, ContextMode contextMode, Func`1 getVirtualPathAction)
at EPiServer.Commerce.Routing.RequestCacheUrlResolver.GetUrl(ContentReference contentLink)
...
private code
...
at Mediachase.Search.SearchManager.BuildIndex(Boolean rebuild)

#79941
Jan 10, 2014 13:21
Vote:
 

I suggest you register a support case for this. If possible it would be great if you could include the code for your search provider, or even better some stripped-down repro code which demonstrates the problem on a sample site / catalog.

Thanks in advance!

#79988
Jan 13, 2014 11:49
Vote:
 

We saw a similar problem with "contentLink", when trying to use the UrlResolver on catalog content in a scheduled job.

It was solved by adding a wildcard hostname (*) to the site definition.

 

#83648
Mar 30, 2014 15:54
Vote:
 

Mads's solution works like a charm. This issue was raised in 2013, and still exists in the version 9.6

#143898
Feb 03, 2016 3:15
Vote:
 

Unfortunatley the "*" doesn't work if you have multiple sites setup, as you can only have one wildcard set for all of your sites.  Now what. 

#152230
Aug 19, 2016 21:37
Vote:
 

Can confirm this is still an issue with CMS 9.12 + Commerce 9.22.

#172655
Dec 07, 2016 12:43
Vote:
 

Is the issue identical (calling GetUrl from a custom search indexer)? I don't think we ever got the bug report I requested three years ago so there was perhaps never any follow up on this. I'll log the bug myself, just want to make sure I have the correct repro steps.

#172699
Dec 08, 2016 11:40
Vote:
 

Not from a search indexer, but from a scheduled job, at least (so no normal HttpContext).

#172700
Dec 08, 2016 11:48
Vote:
 

I have registered bug COM-3514 for this.

#172708
Dec 08, 2016 13:21
Vote:
 

The bug appears to be fixed in our latest version (Commerce 10.1.0). So if possible I suggest you to try and upgrade.

/Q

#172716
Dec 08, 2016 16:47
Vote:
 

For future visitors: This might help you http://vimvq1987.com/2017/02/find-indexing-job-hierarchicalcatalogpartialrouter-note/, (There is no guarantee this will fix it for you, as the underlying problem can be different, but you you are registering custom root for hierarchicalcatalogpartialrouter, then it would be worth checking).

#175602
Edited, Feb 24, 2017 1:54
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.