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

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>
}
}

Related

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")

Pass a generic list from controller to view mvc

I've racked my brain over this for way to long now to I'm deferring to the experts. I know this question has been asked and answered several times but I can't seem to get ANYTHING to work. Here's the scenario: As the title says, I'm trying to pass a list from the controller to the view. I'm using an API that has a method, "GetInventoryLocations" whose base type is List<string>. In the example below I instantiate a new list and use a foreach to loop through the "InventoryLocation" programatically casting each item in the collection to a string and adding it to the list I created "locationlist". Finally I assign the list to the viewdata. From there I've tried all kinds of things in the view but still can't get it to work. Thanks for any help. Be kind to a junior developer.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Moraware.JobTrackerAPI4;
using Evolveware1_0.Models;
namespace Evolveware1_0.Controllers
{
[Authorize]
public class InventoryController : Controller
{
//./Inventory/Locations
[HttpGet]
public ActionResult Index()
{
//declare variables for connection string to JobTracker API Service
var DB = "databasename"; // your DB name here
var JTURL = "https://" + DB + ".somecompany.net/" + DB + "/";
var UID = "****"; // your UID here - needs to be an administrator or have the API role
var PWD = "password"; // your PWD here
//connect to API
Connection conn = new Connection(JTURL + "api.aspx", UID, PWD);
conn.Connect();
//declaring the jobtracker list (type List<InventoryLocation>)
var locs = conn.GetInventoryLocations();
//create a new instance of the strongly typed List<string> from InventoryViewModels
List<string> locationlist = new List<string>();
foreach (InventoryLocation l in locs) {
locationlist.Add(l.ToString());
};
ViewData["LocationsList"] = locationlist;
return View();
}//end ActionResult
}
};
And in the view:
#using Evolveware1_0.Models
#using Evolveware1_0.Controllers
#*#model Evolveware1_0.Models.GetLocations*#
#using Evolveware1_0.Models;
#{
ViewBag.Title = "Index";
}
<h2>Locations</h2>
#foreach (string l in ViewData["LocationList"].ToString())
{
#l
}
You are doing a toString() to a list, this will not work. You will need to cast your ViewData to it's proper type, a list of InventoryLocation.
Being that you are using Razor and MVC, I suggest using ViewBag instead, no casting necessary.
In your controller instead of ViewData["LocationList"] = locationlist, initialize a ViewBag property to pass to your view.
ViewBag.LocationList = locationlist;
Then in your view in your loop just access your ViewBag.LocationList object.
#foreach (string l in ViewBag.Locationlist)
{
#l
}

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...

HTML is being rendered as literal string using RazorEngine. How can I prevent this?

I'm trying to generate a HTML document with RazorEngine (http://razorengine.codeplex.com/). Everything is mostly working, but the problem I have now is some of the HTML is being rendered correctly, and HTML that I have nested in that is being rendered as literal HTML, so rather than the browser displaying the tables & divs as expected, it's displaying e.g.
"<table></table><div></div>"
I kick off this process by calling the following:
string completeHTML = RazorEngine.Razor.Parse("InstallationTemplate.cshtml", new { Data = viewModels });
The completeHTML is then written to a file.
"InstallationTemplate.cshtml" is defined as:
#{
var installationReport = new InstallationReport(Model.Data);
}
<!DOCTYPE html>
<html>
<head></head>
<body>
<div>
<!-- I would expect this to write the rendered HTML
in place of "#installationReport.DigiChannels()" -->
#installationReport.DigiChannels()
</div>
</body>
</html>
Where InstallationReport and DigiChannels are defined as follows:
public static class InstallationReportExtensions
{
public static string DigiChannels(this InstallationReport installationReport)
{
return installationReport.GetDigiChannelsHtml();
}
}
public class InstallationReport
{
public string GetDigiChannelsHtml()
{
// the following renders the template correctly
string renderedHtml = RazorReport.GetHtml("DigiChannels.cshtml", GetDigiChannelData());
return renderedHtml;
}
}
public static string GetHtml(string templateName, object data)
{
var templateString = GetTemplateString(templateName);
return RazorEngine.Razor.Parse(templateString, data);
}
After GetDigiChannelsHtml() runs and returns renderedHtml, the line of execution returns to TemplateBase.cs into the method ITemplate.Run(ExecuteContext context), which is defined as:
string ITemplate.Run(ExecuteContext context)
{
_context = context;
var builder = new StringBuilder();
using (var writer = new StringWriter(builder))
{
_context.CurrentWriter = writer;
Execute(); // this is where my stuff gets called
_context.CurrentWriter = null;
}
if (Layout != null)
{
// Get the layout template.
var layout = ResolveLayout(Layout);
// Push the current body instance onto the stack for later execution.
var body = new TemplateWriter(tw => tw.Write(builder.ToString()));
context.PushBody(body);
return layout.Run(context);
}
return builder.ToString();
}
When I inspect builder.ToString(), I can see it contains proper HTML for the InstallationTemplate.cshtml stuff, and escaped HTML for the DigiChannels.cshtml stuff. For example:
How can I get #installationReport.DigiChannels() to include the correct HTML instead of the escaped HTML that it's currently doing?
Have you tried:
#Raw(installationReport.DigiChannels())
Edit : I could use it in following way (MVC3)
#Html.Raw(installationReport.DigiChannels())
The alternative to #Raw is to change your API to return HtmlStrings in appropriate places
Represents an HTML-encoded string that should not be encoded again.
The default razor behaviour is to encode strings.

Umbraco Razor Template Error

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.

Categories