How to get the Layout value of razor files? - asp.net-mvc

I'm doing some custom infrastructure for auto-generating specific bundles for individual views, and have a case where I need to get the Layout value for each view while iterating them as files.
I've tried var view = new RazorView(new ControllerContext(), actionView.FullName, null, true, null); but this is taking the LayoutPath as an input, and it is indeed resulting in an empty string on the LayoutPath property of the RazorView if I give null for that parameter, so it's not parsing the file for the value.
Could there be any other way to solve this in a similar manner, or would my best/only option be to just parse the text of the raw file (and _ViewStart)?
This is only done once at application start, so the performance is currently not an issue.

Alright, after a lot of source debugging and an epic battle with the internal access modifier, I have a working solution without having to render the whole page. I don't expect anyone else ever having the need for this, but anyway:
var httpContext = new HttpContextWrapper(new HttpContext(new HttpRequest("", "http://dummyurl", ""), new HttpResponse(new StreamWriter(new MemoryStream()))));
var page = Activator.CreateInstance(BuildManager.GetCompiledType(ReverseMapPath(actionView.FullName))) as WebViewPage;
page.Context = httpContext;
page.PushContext(new WebPageContext(), new StreamWriter(new MemoryStream()));
page.Execute();
var layoutFileFullName = page.Layout;
// If page does not have a Layout defined, search for _ViewStart
if (string.IsNullOrEmpty(layoutFileFullName))
{
page.VirtualPath = ReverseMapPath(actionView.FullName);
var startpage = StartPage.GetStartPage(page, "_ViewStart", new string[] {"cshtml"});
startpage.Execute();
layoutFileFullName = startpage.Layout;
}
Tada!
Ps. ReverseMapPath is a any arbitrary function to resolve the relative path of a full file name, see for example Getting relative virtual path from physical path

Related

Dart: getElementsByClassName returns a 0 element list but the data is there

I'm writing a function that will parse certain websites and fetch data from there, which will be used to create instances of a class. I'm able to successfully extract the data when it is retrieved using the getElementById() function, but for some reason, the getElementsByClassName() always returns a node list with 0 elements.
The site I'm currently parsing is here.
If you search for 'datas-nev', you will find exactly one match:
<p class="datas-nev"><b>Kutya neve: </b>Jhonny</p>
And here is the code use for parsing:
import 'package:html/parser.dart' show parse;
...
final response = await http.get(URL);
var document = parse(response.body);
var detailsContainer = document.getElementById('husky_details_container_right');
var dogName = new List<Node>();
dogName = document.getElementsByClassName('datas-nev');
The contents of the detailsContainer can be extracted successfully, for example this gives me back a string of relevant data I will use later:
var humanBehaviourValue;
try { humanBehaviourValue = detailsContainer.nodes[1].nodes[19].nodes[1].nodes[7].nodes[1].toString(); }
catch (e) { humanBehaviourValue = 'N/A'; }
But when I check the value of dogName in the debug window, I get the following:
dogName = {_growableList} size = 0
I already tried initializing the dogName 'properly' by List<Node> dogName = new List<Node>(); but it didn't help. I also tried other datas-* values, but it seems the parser can't find them. I even tried using just datas (because that is a div, while others are paragraphs), but that didn't help either.
Basically I could just hardwire the name and some data (breed, color, etc) as those never really change, but the location of the shelter can change, and keeping it up-to-date by scraping the data seems better than pushing updates out manually. That means I mostly need the value of datas-helyszin but that isn't parsed either.
As #Günter Zöchbauer pointed out, the code actually works. I was just looking for the value too soon, before it was actually fetched...

"No route in the route table matches the supplied values." Error thrown on one view only

I came across a strange problem in my project today: I use this action throughout my website to generate breadcrumbs for a given page:
#Html.Action("BreadcrumbsWithHeader2", "SharedElements", new { pageName = #Model.pageName, department = #Model.department, menuHeading = #Model.menuHeading, id = "EandTHeader" })
Where it just returns a PartialView. This works great on every page except for one, where it began throwing this error:
No route in the route table matches the supplied values.
I've checked for things like spelling errors, etc., but am not sure how to debug this any further. What could cause something in the route table to go missing?
Edit: I've just noticed that any and all ActionLinks on the website pointing to this page (not the #Html.Action shown above, but rather the view where I call this partial) are producing blank href tags. The controller for it (if this helps) is here:
[Route("JobFair/FindAJobFair/{area}")]
public ActionResult FindAJobFair(string area, string sideMenu)
{
ViewBag.sideMenu = sideMenu;
JobFairsViewModel jobFairInfo = new JobFairsViewModel()
{
department = "Foo",
menuHeading = null,
pageName = "Job Fairs"
};
return View(jobFairInfo);
}
This route is typical of what I use elsewhere on the site (attribute routing).
Do you always provide a value for sideMenu? If you don't that may cause your problem. Try to modify your controller like this:
[Route("JobFair/FindAJobFair/{area}")]
public ActionResult FindAJobFair(string area, string sideMenu = null/*default value*/)
{
ViewBag.sideMenu = sideMenu;
JobFairsViewModel jobFairInfo = new JobFairsViewModel()
{
department = "Foo",
menuHeading = null,
pageName = "Job Fairs"
};
return View(jobFairInfo);
}
Hopefully this answer helps someone in the future - the problem had to do with my variable name area that was passed into the controller. Since my project has an 'Areas' folder it was causing an issue with routing. I simply needed to change area to something like region and the issue was solved.

Use Content instead of Document in Umbraco (v6)

I would like to update some obsolete code from umbraco v4 in the updated to v6 solution.
I have
entitiesFolder = new umbraco.cms.businesslogic.web.Document(folderId);
entitiesFolder.ReorderChildren(
entitiesFolder.Children.OrderBy(fdoc => fdoc.Text),
refreshEntireCache);
Now the recomendation instead of obsolete Document is to use Umbraco.Core.Models.Content. How? Didn't find (as usual for Umbraco) any documentation about... (
// new version
var toto = new Umbraco.Core.Models.Content(??)
toto.SoirtChildren(???)
Are you doing this from a razor view? If so you can do:
var nodeId = 123;
var myNode = Umbraco.TypedContent(nodeId);
var property = myNode.GetPropertyValue<string>("myStringAlias");
If you're doing it from a class or something you'll have to use something like:
var helper = new UmbracoHelper(UmbracoContext.Current);
var nodeId = 123;
var myNode = helper.TypedContent(nodeId);
(This is untested but it should work..)
If you are just querying data and need to sort it, using the umbracoHelper is a great way to go. It only hits the xml cache in App_Data/umbraco.config, so you don't hit the database.
However, if you are attempting to programatically sort some of the nodes in the content tree, you will need to use the ContentService. You will need to use the ContentService whenever you actually want to programatically modify content nodes. You will also find a similar MediaService for media.
https://our.umbraco.org/Documentation/Reference/Management-v6/Services/ContentService
ApplicationContext.Current.Services.ContentService.Sort(...)

Creating HtmlSelectOneMenu dynamically - assigning SelectItem list

I have a JSF application where I need to create almost all of the UIComponents dynamically based on certain parameters to the page. The components are created and added to an HtmlPanelGrid. I've been successfully creating HtmlLabel, HtmlInputText, UISelectBoolean, and HtmlCommandButton. Now I need to create an HtmlSelectOneMenu and add it, and I'm having a hard time finding examples that show how to attach the list of items to select.
The selection list is this, where I've made cfaItems a property of my backing bean:
SelectItem[] cfaItems = {
new SelectItem(1, "1"),
new SelectItem(2, "2"),
new SelectItem(3, "3"),
new SelectItem(4, "4"),
new SelectItem(5, "5")
};
The creation of the HtmlSelectOneMenu:
HtmlSelectOneMenu cfaMenu = (HtmlSelectOneMenu)
getApplication().createComponent(HtmlSelectOneMenu.COMPONENT_TYPE);
cfaMenu.setId("cfaMenu");
grid.getChildren().add(cfaMenu);
As best as I can figure it out, I need to create a ValueExpression that would bind the cfaItems list to the cfaMenu but not finding any examples is a problem. I think that I need to do something like this
String menuBinding =
"#{" + beanName + ".cfaItems}";
ValueExpression menuVE = getApplication().getExpressionFactory().
createValueExpression(FacesContext.getCurrentInstance().
getELContext(), menuBinding, String.class);
cfaMenu.setValueExpression("value", menuVE);
But I don't think that's correct. Any suggestions?
You need to create an UISelectItems instance with the given select item array as value and then add it as child of the menu, exactly as you'd do with <f:selectItems> in the view side.
UISelectItems selectItems = new UISelectItems();
selectItems.setValue(cfaItems);
cfaMenu.getChildren().add(selectItems);

How to get the url to the current action (after modifying some route data)?

I'm localising a site via a Change Language control in the master page. I need to render the control with the current url you're on in each of the different languages.
So if you're on http://site.com/en/Home/About and you change the language to french, I need to direct you to http://site.com/fr/Home/About.
The localisation code works on the route data language property, so I've been trying to figure out how I can:
Get access to the current action (with all original parameters)
Get the url to the current action (with all original parameters) with the route data changed.
Can anyone point me in the right direction?
I've tried passing the ViewContext from the parent into the UserControl, which gives me access to the route data but I can't figure out how to get the language routed url from that.
I ran this on the site I'm working on locally and it seemed to work. There's probably a cleaner way.
HttpRequestBase hrb = HttpContext.Request;
System.Uri url = hrb.Url;
string[] test = url.AbsoluteUri.Split('/');
int nIndex = 0, nCounter = 0;
foreach(string str in test)
{
if (str.Contains("site.com"))
{
nIndex = nCounter;
break;
}
nCounter++;
}
string strLanguage = test[nIndex + 1];
Obviously the +1 can even go in the IF statement, but I didn't think it looked good there. Hope this helps some.
I'm not 100% happy with this, I haven't got to a stage where I can fully test the impact of this but this is what I'm going for so far. Please do answer if you have a better solution.
I pass the ViewContext from the masterpage so I get the ViewContext with route data from whatever url you're currently on.
private string GetLocalisedUrl(ViewContext viewContext, string language)
{
viewContext.RouteData.DataTokens[LANGUAGE_ROUTEDATA_KEY] = language;
UrlHelper helper = new UrlHelper(viewContext.RequestContext);
return helper.Action(viewContext.RouteData.Values["action"].ToString(), viewContext.RouteData.Values["controller"].ToString(), viewContext.RouteData.DataTokens);
}

Resources