Umbraco Razor Template Error - c#

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.

Related

In ASP.net, what kind of IF statement could I use to hide a div if the image inside it matches the current page URL?

This is within Sitefinity if that matters, and I am really new at ASP.NET and C#.
I have an image-based navigation element at the bottom of a page that links to different articles using the same template. There are 5 articles, and I would like the link to the active page/article to be hidden so there is a grid of 4 image links.
Here's a screenshot:
https://i.imgur.com/PG2Sfpo.png
Here is the code behind it:
#{
string navTitle = string.Empty;
string url = string.Empty;
if (Model.CurrentSiteMapNode != null && Model.CurrentSiteMapNode.ParentNode != null)
{
if (Model.CurrentSiteMapNode.Title == "Home")
{
navTitle = Model.CurrentSiteMapNode.ParentNode.Title;
}
else
{
navTitle = Model.CurrentSiteMapNode.Title;
}
url = Model.CurrentSiteMapNode.ParentNode.Url;
}
}
<div class="foundation-stories-container">
#foreach (var node in Model.Nodes)
{
#RenderRootLevelNode(node);
}
</div>
#*Here is specified the rendering for the root level*#
#helper RenderRootLevelNode(NodeViewModel node)
{
string[] thisPage = (node.Url).Split('/');
string thisImage = thisPage[4] + ".jpg";
<a href="#node.Url" target="#node.LinkTarget">
<div class="foundation-story-block">
<div class="hovereffect">
<img src="[OUR WEBSITE URL]/stories/#thisImage" class="img-fluid">
<div class="overlay">
<h2>#node.Title</h2>
</div>
</div>
</div>
</a>
}
So we're already getting the page URL and image file name
string[] thisPage = (node.Url).Split('/');
string thisImage = thisPage[4] + ".jpg";
Is this as easy as doing the following?
if (thisImage = thisPage)
{
foundation-story-block.AddClassToHtmlControl("hide")
}
Seems easy enough, but I don't know where to start.
I'm better at Javascript, so I do have a JS solution in place for this already, but I'd really like to find a cleaner way to do it.
<script type="text/javascript">
$(document).ready(function() {
var active = window.location.pathname.split("/").pop()
var name = active;
name = name.replace(/-/g, ' ');
jQuery.expr[":"].Contains = jQuery.expr.createPseudo(function(arg) {
return function( elem ) {
return jQuery(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >=
0;
};
});
$("h2:Contains('" + name + "')").closest(".foundation-story-block").addClass("hide");
});
</script>
This exists on the main template page.
Gets the last part of the URL
Sets that as a variable called "name"
Changes the dash to a space if there is one (most of the pages are associated with names so it's like /first-last)
Then it goes and looks at the which is where the title of the page lives, and if it equals the "name" variable, the ".hide" class is added to the block.
Thanks for any help anyone can provide.
You could bind a click event to your elements with the foundation-story-block class. The reason I use .on instead of .click is because when using UpdatePanels the click event won't fire after an UpdatePanel has it's update event triggered - you might encounter a similar problem with your dynamic binding so I used .on to avoid this.
$(".foundation-story-block").on("click", function() {
// Remove the "hide" class from any elements that have it applied
$.each($(".foundation-story-block.hide"), function(index, value) {
// Remove the class using the "this" context from the anonymous function
$(this).removeClass("hide");
});
// Add the "hide" class to the element that was clicked
$(this).addClass("hide");
});
I haven't run this though an IDE so it might not be 100% correct but it will put you on the correct path.
It is possible, yes. Here is how:
...
#{
var hiddenClass = thisImage == thisPage ? "hide" : string.Empty;
}
<div class="foundation-story-block #hiddenClass">
<div class="hovereffect">
<img src="[OUR WEBSITE URL]/stories/#thisImage" class="img-fluid">
<div class="overlay">
<h2>#node.Title</h2>
</div>
</div>
</div>

export partial view to text file

I'm writing an ASP.NET web app (university task for exam). I have a database which has columns like Id, Name, Age, SumNote. First of all I had to make a partial view with top 5 students in database:
This method to get top 5 students
public class HomeController : Controller
{
StudentContext db = new StudentContext();
public ActionResult ShowTopFive ()
{
var allStudents = db.Students.OrderByDescending(s => s.SumNote).Take(5);
return PartialView(allStudents);
}
}
This is the patrial View:
#model IEnumerable<Univercity.Models.Student>
<div id="results">
<h4>Best 5 students</h4>
<ul>
#foreach (var item in Model)
{
<li>#item.Name, Summ of notes: #item.SumNote</li>
}
</ul>
</div>
and with this one I got the list of students in my webpage
<div>
<h5>Show top 5 students</h5>
</div>
<div>
#using (Ajax.BeginForm("ShowTopFive", new AjaxOptions { UpdateTargetId = "results" }))
{
<input type="submit" value="Show"/>
}
<div id="results"></div>
</div>
the output result looks like this:
Ivanov Mikhail, Summ of notes: 16
Kozlov Pete, Summ of notes: 12
Mary Ann, Summ of notes: 11
I also need to save it as text file. Can't figure out how? May be there is a way to change something in Ajax code?
Thanks in advance. Hope someone know how to do it. Google didn't help
You could create a controller action method which uses FileStreamResult by iterating the list created from ToList() and write necessary property values into a stream, then use Controller.File() overload which accepts stream to let user download text file:
public ActionResult GetTextFile()
{
var topFiveStudents = db.Students.OrderByDescending(s => s.SumNote).Take(5).ToList();
if (topFiveStudents != null && topFiveStudents.Count > 0)
{
string fileName = "something.txt";
// create a stream
var ms = new MemoryStream();
var sw = new StreamWriter(ms);
foreach (var students in topFiveStudents)
{
// iterate the list and write to stream
sw.WriteLine(string.Format("{0}, Sum of notes: {1}", students.Name, students.SumNote));
}
sw.Flush();
ms.Position = 0;
// return text file from stream
return File(ms, "text/plain", fileName);
}
else
{
// do something else
}
}
Afterwards, create an anchor link pointed to that action method mentioned above inside partial view:
#Html.ActionLink("Export to TXT", "GetTextFile", "ControllerName")

What references should I add to this Razor based ASP.NET sample

I'm trying to learn Razor / ASP.NET. I have some sample code that I'm trying to get to run. I can't seem to figure out what references to add.
I get errors on: IsPost below
#{
ViewData["Title"] = "Home Page";
#using Newtonsoft.Json;
#using System.Net;
#using System.IO;
List<string> files = new List<string>();
if (IsPost)
{
string GetURL = "http://demo.azurewebsites.net/api/File";
WebClient client = new WebClient();
Stream dataStream = client.OpenRead(GetURL);
StreamReader reader = new StreamReader(dataStream);
var results = JsonConvert.DeserializeObject<dynamic>(reader.ReadLine());
reader.Close();
foreach (var item in results)
{
files.Add((string)item.filename);
}
}
}
It is possible that you are typing this in a view without enclosing it in #{...}. In your view, you should have it enclosed in #{...} to tell Razor the code block is a C# (or VB, whichever is the case for your project).
Having said that, inserting too much code in the View is not ideal. Views should only be responsible in presenting data, not in extracting them.
UPDATE
Your issue is likely a duplicate of this SO item:
Razor-based view doesn't see referenced assemblies
See the answers by #qes and #V.B.
Well, based on the link you provided in your comment in a prior answer, you're using ASP.Net WebPages - which is a great lightweight way of getting an ASP.Net site up using Razor syntax. It's not however MVC so for one thing you won't have things like ViewData, but that's ok - you can use Page or PageData.
This would be how an entire page would look like (though typically you'd use _layout file in combination with "content files"):
#using Newtonsoft.Json;
#using System.Net;
#using System.IO;
#{
/*
Page or PageData instead of ViewBag/ViewData
*/
Page.Title = "Hello World"; //this is typically used with a _layout.cshtml where the<title> Tag would be
//You can create/name Page properties/data as needed
Page.Whatever = "whatever I want";
Page.H1TagForSeo = "this is the h1 tag";
Page.SomeInteger = 100;
Page["MyPageData"] = DateTime.UtcNow;
List<string> files = new List<string>();
if (IsPost)
{
//IsPost test - this will only run if this page is requested via POST
for (int i = 0; i < 10; i++)
{
files.Add(i.ToString());
}
}
}
<!DOCTYPE html>
<html>
<head>
<title>#Page.Title</title>
</head>
<body>
<h1>#Page.H1TagForSeo</h1>
<p>The time is #Page["MyPageData"]</p>
<p>
You can use <code>##Page propertes/data similar to ViewBag/ViewData</code> #Page.Whatever was viewed #Page.SomeInteger times
</p>
#if (IsPost)
{
<div>Post Test</div>
<p>This entire section will only be displayed when requested via POST</p>
<p>#string.Join(",", files)</p>
}
</body>
</html>
Hth...

ASP 5 MVC 6 beta8, get Session using razor (better way)

I write that code to retrieve session values
#{
var sessionName = new Byte[20];
bool nameOK = Context.Session.TryGetValue("name", out sessionName);
if (nameOK)
{
string result = System.Text.Encoding.UTF8.GetString(sessionName);
<p> #result</p>
}
}
Is there any better way to retrieve values( using less lines etc)
A possible simplification:
At the top of your cshtml add
#using Microsoft.AspNet.Http;
This gives access to the GetString method
Context.Session.GetString("test");
I'd imagine your code simplified can then look like
#{
string sessionName = Context.Session.GetString("name");
if (sessionName != null)
{
<p>#sessionName</p>
}
}

Convert ActionResult and PartialView IEnumerable results to return json objects

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

Categories