November Happy Hour will be moved to Thursday December 5th.
November Happy Hour will be moved to Thursday December 5th.
Something like this?
var linkRepository = ServiceLocator.Current.GetInstance<ContentSoftLinkRepository>(); var blockLink = (currentBlock as IContent).ContentLink; var referencingContentLinks = linkRepository.Load(blockLink, true) .Where(link => link.SoftLinkType == ReferenceType.PageLinkReference && !ContentReference.IsNullOrEmpty(link.OwnerContentLink)) .Select(link => link.OwnerContentLink) .ToList();
My problem is deeper. Actually, I simplified description because on block controller I have the same situation.
Actually task is processing block's attributes in some attribute helper when HTML control is creating. In this situation I don't know what block I'm processing exactly. So, I'm getting page as:
EPiServer.ServiceLocation.ServiceLocator.Current.GetInstance<EPiServer.Web.Routing.PageRouteHelper>().Page
and recursively checks attributes for each block that current page contains. But it works only in case if I render block from PAGE controller. If I have specific BLOCK controller with action to render block - Page property returns StartPage. Can somebody explain the reason of this behaviour?
If you set breakpoint in controller does RouteData contains key named "node"?
From page controller action I really have correct(ContentLink=34) "node" key into RouteData
RouteData.DataTokens["node"] {34} object {EPiServer.Core.PageReference}
But on block controller action I
RouteData.DataTokens["node"] null object
As temporary solution I found that it's possible to manually register current page inside each block controller into OnActionExecuting:
Request.RequestContext.SetCustomRouteData("node", Configuration.MyPage);
But this means that each block will be hard-related with only one page. And for my purpose there is another negative effect - model validation works before OnActionExecuting. And if model has invalid state my Attribute helper start processing validation error message before OnActionExecuting. So, this solution is absolutely unacceptable.
Hi,
Can you please explain once again a bit more about your statement "If I have specific BLOCK controller"? What does really mean? You have controller inheriting from BlockController<T> that is used alone without any parent page controller? Because basically when your content item is being rendered you should get the same routing dictionary that was available while page was rendered - route data is held inside HtmlHelper and before proceeding further with content rendering (this happends in MvcContentRenderer class) route data is merged together with some additional route data.
Hi, Valdis,
Yes, exactely. My controller inherited from BlockController<T> and it's really independent controller. It's processing only current block actions, for example GetBlock() which render view for block content displaying and then return JsonResult which is processing on client side.
I was googling this issue and saw several posts where Page from PageRouteHelper return correct current page. I have guess that maybe problem is that I render each block and then return view as JSON view(and it's a reason why I lost my route data):
var result = new { html = RenderPartialViewToString("viewName", viewModel) }; return BuildJson(result);
Checked the same RenderPartialViewToString/return JSON combination onto my page controller. And there I got correct current page. So, it's very similar that my guess is wrong.
How are you invoking that block controller? I'm trying to understand your usage case - do you have page where block is placed inside content area and controller is invoked when block is being rendered? Or you are somehow manually sending request to that controller (direct route?) and getting Json back for client-side?
Any code fragment used in your solution would make more sense..
I couldn't get full picture of your setup but my speculations is that when you submit request to block controller through ajax - EPiServer actually does not have enough information to write down routing data - like to which page currently request is sent.
Here are just few of my observations:
* What excatly "$tools.data.get" does? Where it send request?
* How block controllers are setup? If you just type n browser "http://{site}/{blockcontroller}/" - without any additional route registration, it should give 404.
So the missing part for me currently - is how excatly are you invoking block's controller from client-side? Where request ends up and how EPiServer knows where to route this incoming request and how to properly forward it to block's controller.
Also, not wondering why sometimes current page may point to start page. There is similar code in routing helper:
pageLink = pageData != null ? pageData.PageLink : ContentReference.StartPage;
It means if routing helper fails to find page for current request - StartPage may be returned instead.
I know this thread gets a bit longly, but hope all this will give you some value.
I think I got all missing pieces together. And here are my recommendations:
* In general I think if your blocks are producing Json responses - I would consider to switch to some Json services, like WebApi if possible.
* Second, if you are using blocks as server-side producers of data - what would happen if the same block is placed on more than one page instance? By invoking just controller of the block - neither EPiServer nor block controller will know which page to use as hosting page.
* As in your setup as far as I can understand blocks are used similar as shared blocks - I would re-conisder to rely on page where particular block is placed (the original purpose why you created this thread at all). This makes overall data architecture fragile.
As block controllers are special piece of code (child actions that can't be invoked directly) that is treated differently as ordinary page controllers, I give you sample code of how to invoke block controller from page controller with placeholders for you to fill out. For this to work properly - you anyway will need some page controller that will be responsible for invoking further block controller. Look at that page controller as nothing more as Json data provider hosting controller that has no results by itself.
Code to invoke block controller directly from page controller:
var repo = ServiceLocator.Current.GetInstance<IContentRepository>(); // there is a block with ID 169 - you can just create shared block var blockData = repo.Get<SampleBlock>(new ContentReference(169)); var writer = new StringWriter(); var routeData = new RouteData { Values = { { "controller", typeof(SampleBlock).Name } } }; var controllerContext = new ControllerContext(HttpContext, routeData, this); var partialView = ViewEngineCollection.FindPartialView(controllerContext, "Index"); var viewContext = new ViewContext(ControllerContext, partialView.View, ViewData, TempData, writer); var htmlHelper = new HtmlHelper(viewContext, new ViewDataDictionaryProvider(this)); htmlHelper.RenderContentData(blockData, false); // this will be result of block's view execution var resultOfBlock = writer.ToString();
Anyway - I could be wrong and lacking more details about your solution - but from 1000 feet it looks like blocks maybe are not the best choice for Json data production (especially when Json data is produced in view and not in controller) in this case. I would look for some alternatives - like WebApi or similar.
Thank you for your answers, Valdis
It's really usefull advice. And I think you are right about block controller can't recognize page for simple call from client side. I thought about this too. And I'm sure your idea request block controller from page controller will work because routing works correctly in case of usage page controller. But for this moment I can't use variant that you proposed and will try to find some solution in future. If I would be successfull I write my variant here. Thank you anyway.
I use following code:
to get page which contains my block. But it works only in case if request for rendering block processing by page controller.
In the same time I have several controllers only for processing blocks. And there I get StartPage instead of real page which block belongs.