November Happy Hour will be moved to Thursday December 5th.
November Happy Hour will be moved to Thursday December 5th.
The same issue came up in this thread: http://world.episerver.com/Modules/Forum/Pages/Thread.aspx?id=79015
I suggested a workaround but apparently it was not enough in that case, but maybe it is for you?
We need to dig a bit deeper into the issue from that thread and it is now handled as a support case.
Thanks for the help Magnus, I will try out your suggestions monday, the context fix could be a good and easy way to go.
Hi Magnus
I solved my issue with parts of the suggestions you linked to and a bit of debugging and write custom handling.
I started by configuring the HttpContextBase registration as you pointed out in the thread you linked by adding the following module
[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));
}
}
In the code below I try to write the url with the normal handling if that fails i revert to resolving the url with the PartialRouter
this means that I am able to use the normal handling of url's in when I am on EPiServer pages, but revert to custom handeling when out of the EPiServer context.
public class CustomUrlResolver
{
public Url GetUrl<TContent>(TContent content) where TContent : IContent, ILocalizable
{
Url resultUrl = null;
var urlResolver = ServiceLocator.Current.GetInstance<UrlResolver>();
var httpContext = ServiceLocator.Current.GetInstance<HttpContextBase>();
var siteDefinitionRepository = ServiceLocator.Current.GetInstance<SiteDefinitionRepository>();
string urlString = urlResolver.GetUrl(content.ContentLink, content.Language.Name, new VirtualPathArguments
{
ContextMode = ContextMode.Default,
RequestContext =
new RequestContext
{
HttpContext = httpContext,
RouteData = new RouteData()
},
RouteValues = new RouteValueDictionary()
});
if (string.IsNullOrEmpty(urlString) && content is CatalogContentBase)
{
var routeHandler = ServiceLocator.Current.GetInstance<PartialRouteHandler>();
var routers = routeHandler.GetOutgoingRouters(typeof(CatalogContentBase));
foreach (var partialRouter in routers)
{
var partialRouteData = partialRouter.GetPartialVirtualPath(content, content.Language.Name,
new RouteValueDictionary
{
{RoutingConstants.NodeKey, content.ContentLink.ToReferenceWithoutVersion()},
{RoutingConstants.LanguageKey, content.Language.Name},
}, new RequestContext
{
RouteData = new RouteData(),
HttpContext = httpContext
});
if (partialRouteData != null)
{
//NOTE: EPiServer can't find StartPage of site when out of context so we set the correct start page
if (ContentReference.IsNullOrEmpty(partialRouteData.BasePathRoot))
partialRouteData.BasePathRoot = siteDefinitionRepository.List().First().StartPage;
if (!string.IsNullOrWhiteSpace(partialRouteData.PartialVirtualPath))
{
//NOTE: we dont want edit urls' in our index so we use ContextMode.Default
var baseUrl = urlResolver.GetUrl(partialRouteData.BasePathRoot, content.Language.Name, new VirtualPathArguments
{
ContextMode = ContextMode.Default,
RequestContext =
new RequestContext
{
HttpContext = httpContext,
RouteData = new RouteData()
},
RouteValues = new RouteValueDictionary()
});
// combine base url with virtualPath
urlString = baseUrl + partialRouteData.PartialVirtualPath;
break;
}
}
}
}
if (!string.IsNullOrWhiteSpace(urlString))
{
// remove hostname and protocol if included, this can be skipped if you want to use absolute urls
resultUrl = new Url(new Url(urlString).GetComponents(UriComponents.PathAndQuery, UriFormat.SafeUnescaped));
}
return resultUrl;
}
}
There are quite a lot of places in the Routing that EPiServer used HttpContext.Current and reverts to default values if current is null
Couldn't all HttpContext.Current be replaced by ServiceLocator.Current.GetInstance<HttpContextBase>() I think that could solve the issue, or at least make i possible to fake the HttpContext when something failes in routing.
Best Regards
Thomas.
Thanks for posting your workaround so it can benefit others, and demonstrate to us how cumbersome it is to do this so we can improve. We have both the ServiceAccessor<HttpContext> issue and the get-URL-without-template issue registered as bugs and I hope they will be fixed soon.
I haven't looked at the usages of HttpContext.Current but I know that there may be some heavily used execution paths where the container lookup actually impacts performance to such a degree that it motivates using the static accessor directly, however I doubt that that is the case everywhere if it is used in many places.
Hi
I have run into some issues with writing product urls
in my setup I have a async EPiServer scheduled task, that handles indexing content and products,
in this task I would like to write urls onto my index so that I dont have to write the end user urls everytime I search.
But I get a HttpContext can not be null exception when trying to write the urls with UrlResolver.GetUrl()
I have tried all the different options on the UrlResolver for writing urls but all with the same result.
Then I reverted to storing the ContentReference in my index and tried to handle the url writing in my ServiceStack service that handles searches.
This time around all content urls are written correctly but I can't get it to write product urls correctly.
I use the same ContentReference from the index for getting the product on EPiServer pages and there it works perfectly but I cant get it to write urls in the ServiceStack Service
Anybody else tried something similar?