After running the 7.5.11 upgrade on our Umbraco web site I am getting an exception in one of my Partial View Macro Files (cshtml):
System.NullReferenceException: Object reference not set to an instance of an object.
at Umbraco.Web.PublishedContentExtensions.GetPropertyValue(IPublishedContent content, String alias)
The exception is pointing to this line:
var mediaItem = Umbraco.TypedMedia(item.GetPropertyValue("propAliasString"));
The line is in this foreach loop:
#foreach (var item in news.Where(x => x.GetPropertyValue<int>("group") == year.Key).OrderByDescending(y => y.GetPropertyValue("date")))
{
var mediaItem = Umbraco.TypedMedia(item.GetPropertyValue("announcement"));
<div class="panel-body">
<span class="glyphicon glyphicon-file" aria-hidden="true"></span> #item.GetPropertyValue("headline")
<p style="margin-left:16px;" class="date">#( Convert.ToDateTime(item.GetPropertyValue<string>("date")).Date.ToString("d. MMMMM yyyy"))</p>
</div>
}
I have tried to browse the Umbraco documentation for changes in the api from 7.4 to 7.5 regarding this issue.
Before the upgrade this worked.
Has any of you experienced this kind of error? - and more important found a solution?
best regards
Jesper
Found the solution - kind of embarrasing.
A check on the property for null value is needed:
var mediaItem = Umbraco.TypedMedia(item.GetPropertyValue(".."));
if(mediaItem != null)
{
....
}
Anyways my excuse is that it worked before the upgrade. :-)
/Jesper
Related
I was testing WebBrowser, but there's no method to getElemments by class, but by tag.
I have something like this.
html:
<div class="Justnames">
<span class="name">Georgia</span>
</div>
So i'd like to get the string "Georgia", which is inside of that span.
I tried:
Var example = Nav.Document.GetElementsByTagName("span");
But it return null, and I've no idea why.
Sorry my english and thanks a lot of the help! :)
This may help:
var elementCollection = default(HtmlElementCollection);
elementCollection = webBrowser1.Document.GetElementsByTagName("span");
foreach (var element in elementCollection)
{
if (element.OuterHtml.Contains("name"))
// we reach here, we get <span class="example"
}
Or:
foreach (var element in elementCollection)
{
if (element.GetAttribute("className") == "name")
// we reach here, we get <span class="example"
}
You can do this using jquery :
var test = $(".name").text();
alert(test):
Because you tagged "C#" and ".net" i assume you have a aspx page and try to access it from server code. To access it from server side you have to add the runat="server" tag to the span:
<span class="name" runat="server">Georgia</span>
Otherwise you only can access it from client side (JavaScript)
I have two classes: Store and Machine.
Right now I have constructed a view where I show the Stores associated to the logged user:
public async Task<IActionResult> Index()
{
var Tiendas = await _context.Stores.Where(t => t.Usuario == User.Identity.Name).Include(t => t.Machines).ToListAsync();
LiqIndexData Liquid = new LiqIndexData()
{
StoreL = Tiendas,
};
return View(Liquid);
}
In this code I also added the Machines asociated to each Store.
The View:
In my View I would like to present, for each Store, all of the Machinesregistered. For this I'm using nav-tabs
Nav Tab based on the number of Stores
<ul class="nav nav-pills">
#foreach (var item in Model.StoreL)
{
<li>#item.StoreName</li>
}
</ul>
<div class="tab-content">
#foreach (var item in Model.StoreL)
{
<div class="tab-pane fade in active" id="#item.StoreID"></div>
}
The Problem:
Info shown in the body of each Nav-tab:
I'm trying to access the information of each Machine associated with each Store. For this I'm trying to use:
#foreach (var item in Model.StoreL)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Machines
.Where(m=>m.StoreID==item.StoreID))
</td>
But I don't know how to access the property. If I try:
#Html.DisplayFor(modelItem => item.Machines
.Where(m=>m.StoreID==item.StoreID).PropertyXYZ)
I get:
'IEnumerable' does not contain a definition for 'PropertyXYZ' and no extension method 'PropertyXYZ' accepting a first argument of type 'IEnumerable' could be found (are you missing a using directive or an assembly reference?)
Any advice?
As the error is trying to tell you, your collection of Machines has no PropertyXYZ.
Depending on what you actually want to do, you can either use First() to get only one Machine (and no others), or use a loop to go through all of them.
What is the best approach to take when converting a basic ActionResult to JSON objects and rendering them in a PartialView? My objective is to modify the application so that instead of the page rendering only the comments in the db at the time of the page request to a type of data service that updates thePartialView to add any incoming comments that may have been posted since the last page request. I think the solution I am looking for will use OData in json format and then bind that data using knockout.js, but not sure.
Here is the Controller ActionResult which returns an IEnumerable list of objects from the repository to a PartialView:
[ChildActionOnly]
public ActionResult GetCommentsById(int AId = 0)
{
if (AId == 0)
return HttpNotFound();
return PartialView("_CommentsPartial",
_unitOfWork.ArticleRepository.GetCommentsByArticleId(AId));
}
Here is a snippet of the PartialView to keep things short:
#model IEnumerable<BlogSite.Models.Comment>
#using BlogSite.Helpers;
<ul id="comments-list">
#{
foreach (var comment in Model)
{
<!--Grabs Parent Comment and then all replies w/ParentCommentId b4 grabs new Parent Comment -->
if (comment.isRoot && comment.ParentCommentId == null)
{
<!-- Comment -->
int counter = 0; foreach (var c in Model) { if (c.ParentCommentId == comment.CommentId) { counter += 1; } }
<li id="#comment.CommentId" itemscope itemtype="http://schema.org/UserComments" class="comment-container" tabindex="#comment.CommentId">
Then I call it from the Details view:
<div id="comments-panel" class="panel-box">
<div class="show-comments"><div id="upNdown"></div><span id="showNhide">Show Comments</span></div><br /> <br />
<div id="comments-partial" style="display:none;">
#Html.Action("AddComment", "Comment", new { AId = Model.ArticleId })
#Html.Action("GetCommentsById", "Article", new { AId = Model.ArticleId })
</div>
</div>
How can I make this conversion as painless as possible? Thanks in advance!
I think I gather from your question that the controller already did its work and that you simply want to "consume" the data output from it as if it were an AJAX request using the same js code. You can do this fairly easily by just serializing the data in the model using the Newtonsoft Json.NET api and extensions provided by Forloop.HtmlHelpers. These can be installed as nuget packages if you haven't already.
First, you would place this in your partial view
Note: If you don't want to install the Newtonsoft package you can replace JsonConvert.SerializeObject with the System.Web.Helpers method Json.Encode
#{
using (var context = Html.BeginScriptContext())
{
Html.AddScriptBlock("var jsonData=" + JsonConvert.SerializeObject(Model) + ";");
}
}
Then in your layout page, to ensure that your script block is rendered at the appropriate time, add this call to Html.RenderScripts
#Scripts.Render("~/bundles/jquery")
#*Add any other dependency scripts*#
#Html.RenderScripts()
#RenderSection("scripts", required: false)
This is why you need the Forloop.HtmlHelpers package, these extension methods help mitigate out-of-order script code getting rendered in the partial view before jQuery or anything else has started up.
Hope that helps
I am facing problem in retrieving Subject title of a mail from Unread mails using Selenium webdriver-C#.
Here's the HTML code :
<div class="ae4 UI UJ" gh="tl">
<div class="Cp">
<div>
<table id=":8e" class="F cf zt" cellpadding="0">
<colgroup>
<tbody>
<tr id=":8d" class="zA zE">
<td class="PF xY"></td>
<td id=":8c" class="oZ-x3 xY" style="">
<td class="apU xY">
<td class="WA xY">
<td class="yX xY ">
<td id=":87" class="xY " role="link" tabindex="0">
<div class="xS">
<div class="xT">
<div id=":86" class="yi">
<div class="y6">
**<span id=":85">
<b>hi</b>
</span>**
<span class="y2">
</div>
</div>
</div>
</td>
<td class="yf xY "> </td>
<td class="xW xY ">
</tr>
I am able to print 'emailSenderName' in console but unable to print 'text' (subject line i.e. "hi" in this case) as it is between span tags. Here's my code.
//Try to Retrieve mail Senders name and Subject
IWebElement tbl_UM = d1.FindElement(By.ClassName("Cp")).FindElement(By.ClassName("F"));
IList<IWebElement> tr_ListUM = tbl_UM.FindElements(By.ClassName("zE"));
Console.WriteLine("NUMBER OF ROWS IN THIS TABLE = " + tr_ListUM.Count());
foreach (IWebElement trElement in tr_ListUM)
{
IList<IWebElement> td_ListUM = trElement.FindElements(By.TagName("td"));
Console.WriteLine("NUMBER OF COLUMNS=" + td_ListUM.Count());
string emailSenderName = td_ListUM[4].FindElement(By.ClassName("yW")).FindElement(By.ClassName("zF")).GetAttribute("name");
Console.WriteLine(emailSenderName);
string text = td_ListUM[5].FindElement(By.ClassName("y6")).FindElement(By.TagName("span")).FindElement(By.TagName("b")).Text;
Console.WriteLine(text);
}
I had also tried by directly selecting the Text from tag of 5th Column (td), which contains the subject text (in my case), but no results.
I might went wrong somewhere or may be there is some other way of doing it.
Please suggest, Thanks in advance :)
The 'getText' method available in the Java implementation of Selenium Web Driver seems to do a better job than the equivalent 'Text' property available in C#.
I found a way of achieving the same end which, although somewhat convoluted, works well:
public static string GetInnerHtml(this IWebElement element)
{
var remoteWebDriver = (RemoteWebElement)element;
var javaScriptExecutor = (IJavaScriptExecutor) remoteWebDriver.WrappedDriver;
var innerHtml = javaScriptExecutor.ExecuteScript("return arguments[0].innerHTML;", element).ToString();
return innerHtml;
}
It works by passing an IWebElement as a parameter to some JavaScript executing in the Browser, which treats it just like a normal DOM element. You can then access properties on it such as 'innerHTML'.
I've only tested this in Google Chrome but I see no reason why this shouldn't work in other browsers.
Using GetAttribute("textContent") instead of Text() did the trick for me.
Driver.FindElement(By.CssSelector("ul.list span")).GetAttribute("textContent")
Try this
findElement(By.cssSelector("div.y6>span>b")).getText();
I had the same problem. Worked on PhantomJS. The solution is to get the value using GetAttribute("textContent"):
Driver.FindElementsByXPath("SomexPath").GetAttribute("textContent");
Probably too late but could be helpful for someone.
IWebElement spanText= driver.FindElement(By.XPath("//span[contains(text(), 'TEXT TO LOOK FOR')]"));
spanText.Click();
IWebElement spanParent= driver.FindElement(By.XPath("//span[contains(text(), 'TEXT TO LOOK FOR')]/ancestor::li"));
spanParent.FindElement(By.XPath(".//a[contains(text(), 'SIBLING LINK TEXT')]")).Click();
bonus content here to look for siblings of this text
once the span element is found, look for siblings by starting from parent. I am looking for an anchor link here. The dot at the start of XPath means you start looking from the element spanParent
<li>
<span> TEXT TO LOOK FOR </span>
<a>SIBLING LINK TEXT</a>
</li>
This worked for me in Visual Studio 2017 Unit test project. I'm trying to find the search result from a typeahead control.
IWebElement searchBox = this.WebDriver.FindElement(By.Id("searchEntry"));
searchBox.SendKeys(searchPhrase);
System.Threading.Thread.Sleep(3000);
IList<IWebElement> results = this.WebDriver.FindElements(By.CssSelector(".tt-suggestion.tt-selectable"));
if (results.Count > 1)
{
searchResult = results[1].FindElement(By.TagName("span")).GetAttribute("textContent");
}
I'm new to Razor templates in Umbraco (and in general), but I prefer using it over XSLT files. However, I have run into a problem that I don't know how to solve. I am getting the following message:
An unknown error occured while rendering the following code:
System.NullReferenceException: Object reference not set to an instance of an object.
at RazorEngine.Dynamic.baeffbebc.Execute()
at RazorEngine.Templating.TemplateService.Parse[T](String template, T model, String name)
at umbraco.MacroEngines.RazorEngine.GetResult(String cacheIdentifier, String template, INode currentPage, String& result)
My macro looks like this:
#using System
#using uComponents.Core
#using uComponents.Core.uQueryExtensions
#using System.Linq
#using umbraco.NodeFactory
#helper NoPictures()
{
<li>Pictures coming soon!</li>
}
#helper Pictures(String crop)
{
<li><a rel="photos" href="#crop" title="test">
<img src="#crop" class="shadow hovershadow"></a></li>
}
#{
var n = Node.GetCurrent();
var pictures = n.GetProperty("pictures").Value;
if(pictures.Length <= 0)
{
NoPictures();
}
else
{
var pictureNodes = pictures.Split(',');
foreach (var pictureNode in pictureNodes)
{
var node = new Node(Convert.ToInt32(pictureNode));
var photoId = node.GetProperty("picture").Value;
var photo = uComponents.Core.uQuery.GetMedia(Convert.ToInt32(photoId));
var crop = MediaExtensions.GetImageCropperUrl(photo, "umbracoFile", "wide");
Pictures(crop);
}
}
}
I really appreciate any help that anyone can offer... even if it is giving me an idea how to debug this within Umbraco. Thanks!
Edit: The version of Umbraco 4.6.1
Okay, my final code was this:
#using System
#using uComponents.Core
#using uComponents.Core.uQueryExtensions
#using System.Linq
#{
var n = uQuery.GetCurrentNode();
var pictures = n.GetProperty("pictures").Value;
if(pictures.Length > 0)
{
var pictureNodes = pictures.Split(',');
foreach (var pictureNode in pictureNodes)
{
var node = uQuery.GetNode(Convert.ToInt32(pictureNode));
var photoId = node.GetProperty("picture").Value;
var photo = uQuery.GetMedia(Convert.ToInt32(photoId));
var crop = photo.GetImageCropperUrl("imageCropper", "wide");
<li><a rel="photos" href="#crop" title="#node.GetProperty("title").Value">
<img src="#crop" height="150px" width="150px" class="shadow hovershadow"></a></li>
}
}
else
{
<li>Pictures coming soon!</li>
}
}
The code didn't change much, but apparently when running the macro before, I had an error somewhere. No matter what I did to change the script, the error persisted. It turns out that the Umbraco's Razor caching is too aggressive or has a bug, so the cache was not being invalidated when a change was made to the script. To work around it, I had to recycle the Application Pool in IIS. All is working now.