export partial view to text file - c#

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

Related

Put thousands separator in MVC

I am sending via ViewData values to my view like this.
Controller
public List<string> ListarTarjetas()
{
OpexDB db = new OpexDB();
List<string> Tarjetas = new List<string>();
using (db)
{
var listTarjetasInformativas = db.SP_TARJETASINFORMATIVAS();
foreach(var item in listTarjetasInformativas)
{
Tarjetas.Add(item.NOMBRE);
Tarjetas.Add(item.MONTO.ToString());
}
}
return Tarjetas;
}
public ActionResult Index()
{
var DatosTarjetas = ListarTarjetas();
ViewData["PrimerNombre"] = DatosTarjetas[0];
ViewData["PrimerMonto"] = String.Format(DatosTarjetas[1], new CultureInfo("es-HN"));
return View();
}
Part of my razor view:
<div class="inner">
<p>#ViewData["PrimerNombre"]</p>
<p>#ViewData["PrimerMonto"]</p>
<div class="icon">
<i class="ion ion-pull-request"></i>
</div>
</div>
Within my view, in the part of <p>#ViewData["PrimerMonto"]</p> this value 7218.19 is reflected, but I would like it to be reflected in this way, 7,218.19.
I have tried like this:
ViewData["PrimerMonto"] = String.Format(DatosTarjetas[1], new CultureInfo("es-HN"));
and other ways too. But I don't get any change.
Thank you for any help you can provide.
You can format it just as a number or as currency, but if it's a string in your view data, you need to convert it to a number.
See also https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings
[TestMethod]
public void TestNumberFormat()
{
string numberStringValue = "7891.12";
double numberNumericValue = double.Parse(numberStringValue);
string formattedValueWithSymbol = string.Format(new CultureInfo("es-HN"), "{0:c}", numberNumericValue);
string formattedValue = string.Format("{0:N}", numberNumericValue);
Console.WriteLine(formattedValueWithSymbol);
Console.WriteLine(formattedValue);
}
The output of this will be
Standard Output: 
L7,891.12
7,891.12

How send 2 List from C# controller to view with ViewBag

I am sending months (get the value from File path) and File path to the MVC view so I can show a List of the month that is linked to the File to download it like this:
OCT(that is linked to file path)
Nov (that is linked to file path)
December (that is linked to file path)
This is my Controller C# code:
public ActionResult Help()
{
var releaseNoteFiles = Directory.GetFiles(Server.MapPath("~/Content/ReleaseNotes"));
List<string> month = new List<string>();
foreach (var releaseNoteFile in releaseNoteFiles)
{
month.Add(new Regex("([^A-Z]*)([a-zA-Z]*)").Match(Path.GetFileNameWithoutExtension(releaseNoteFile).Split('.').Last()).Groups[2].Value);
}
ViewBag.releaseNoteFilesmonth = month; /Has October,Nov,...
ViewBag.releaseNoteFiles = releaseNoteFiles; /Has Path to the File
return View();
}
This is my view that I have a problem with how to send 2 lists (Filename and Path) This code shows the list 2 times.
#foreach (var item in ViewBag.releaseNoteFilesmonth)
{foreach (var item2 in ViewBag.releaseNoteFiles)
{
#item #item
<br />
}
}
It seems you want to print the month and the monthfile with hyperlink on the view, see the below code if that sorts you out.
#foreach (var item in ViewBag.releaseNoteFilesmonth)
{
var matchedmonthfile = (ViewBag.releaseNoteFiles as string[]).Where(x => x.Contains(item)).FirstOrDefault();
#item #matchedmonthfile
<br />
}

How to do the asp.net MVC equivalent of a button click like with JavaScript?

How can I for example have a button in a 'Create' view and when I click this button it calls a method in the associated controller?
My attempts so far have just resulted in sending me to a new page, e.g:
Create View
#Html.ActionLink("Get Tag", "getTag")
Controller
public void getTag()
{
// Do something
var x = 1;
var z = 2;
var e = x + z;
}
Ultimately, I plan on getting the TagId from the option that is selected when the button is clicked and storing this.
<select>
#*Iterating Tag ViewModel *#
#foreach (var item in Model.allTags)
{
<option value="item.TagId">#item.Name</option>
}
</select>
Most importantly, where can I learn about this specific type of stuff?
Thank you
In general, to call a method on your controller directly from the view without JavaScript, you could do:
Html.ActionLink("Create", // Button Title
"GetTag", // <-- ActionMethod
"Tag") // <-- Controller Name
Your controller should contain an Action method like so:
public ActionResult GetTag()
{
// Do something
var x = 1;
var z = 2;
var e = x + z;
return View();
}
In some cases, this doesn't suffice and you will need some JavaScript/jQuery to make an ajax call to your controller and return JSON data using "Json()" instead of "View()" on the return for example.
Also, you could use a different approach for your dropdown instead of a for loop. For example:
#Html.DropDownListFor(c => c.Tag.Id, new SelectList(Model.allTags, "TagId", "TagName"), "Select Tag", new { #class = "form-control" })

Passing a List from Controller to View in MVC - Can't get string using foreach

I'm trying to pass a List from my controller to a view.
The model as defined in my view is:
#model List<prismic.starter.Models.ResourceModel>
I am passing a List<ResourceModel> from my controller to the view:
public async Task<ActionResult> resources()
{
var docArray = await new Prismic_Connect().getAllByType("resource");
List<ResourceModel> resourceList = new List<ResourceModel>();
foreach(var doc in docArray)
{
resourceList.Add(new ResourceModel(doc));
}
return View(resourceList);
}
I can get the string value I am trying to display by writing the following:
#Model.First().getTitle();
However, when I try to loop through the list using foreach , the "title" string is not displayed.
#{
foreach (var doc in Model)
{
doc.getTitle();
}
}
What am I doing wrong here?
You missing the leading # which tells the razor engine to output the value
#foreach (var doc in Model)
{
#doc.getTitle(); // add #
}

Extension Method in ASP.NET MVC 4 HttpPost ActionResult

I've got a simple HomeController with one overloaded (GET/POST) Index method which displays data from a list of Person objects in an HTML table and gives the user a form in which they can type a sheet name and a file name and download an Excel file of the results (EPPlus Excel library) and download them. To encapsulate the information needed to save the Excel File I created the following view model:
public class ExcelDownloadView
{
public List<Person> Persons { get; set; }
//ConvertToDataTable is a List extension method return converts the list and its properties
//into a table where columns are the properties
public DataTable DataTable { get { return Persons.ConvertToDataTable(); } }
public string SheetName { get; set; }
public string FileName { get; set; }
}
Here's what my view looks like, and on the initial GET request, everything comes out fine:
#model ExportToExcel.Models.ExcelDownloadView
#using ExportToExcel.Helpers
#{
ViewBag.Title = "Index";
}
<div id="grid">
#Html.ListToTable(Model.Persons)
</div>
<div>
This is the number of rows: #Model.DataTable.Rows.Count (correct)
</div>
#using (Html.BeginForm())
{
<input name="sheetName" type="text" /><br />
<input name="fileName" type="text" /><br />
<input type="submit" value="Click to download Excel file..." />
}
When I try to submit the form I get an error in my ConvertToDataTable method:
public static DataTable ConvertToDataTable<T>(this List<T> data)
{
DataTable dt = new DataTable();
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
for (int i = 0; i < props.Count; i++)
{
PropertyDescriptor prop = props[i];
dt.Columns.Add(prop.Name, prop.PropertyType);
}
object[] values = new object[props.Count];
//*****error is at the start of the foreach loop
foreach (T item in data)
{
for (int i = 0; i < values.Length; i++)
{
values[i] = props[i].GetValue(item);
}
dt.Rows.Add(values);
}
return dt;
}
Controller:
[HttpGet]
public ActionResult Index()
{
ExcelDownloadView model = new ExcelDownloadView();
model.Persons = Person.GetPersons().ToList();
var dataTable = model.Persons.ConvertToDataTable();
return View(model);
}
[HttpPost]
public ActionResult Index(ExcelDownloadView viewModel)
{
//DataTable property takes the List<Person> of the view model and turns it into
//a datable for use in the following Excel-file-creating function
/*--> if nonWorkingVersion is commented out, the program programs with a NullReferenceException*/
//DataTable nonWorkingVersion = viewModel.DataTable;
//if a re-seed the DataTable, everything works fine
DataTable dt = Person.GetPersons().ToList().ConvertToDataTable();
using (ExcelPackage pck = new ExcelPackage())
{
//Create the worksheet
ExcelWorksheet ws = pck.Workbook.Worksheets.Add(viewModel.SheetName);
//Load the datatable into the sheet, starting from cell A1. Print the column names on row 1
ws.Cells["A1"].LoadFromDataTable(dt, true);
//Format the header for column 1-3
using (ExcelRange rng = ws.Cells["A1:C1"])
{
rng.Style.Font.Bold = true;
rng.Style.Fill.PatternType = ExcelFillStyle.Solid; //Set Pattern for the background to Solid
rng.Style.Fill.BackgroundColor.SetColor(Color.FromArgb(79, 129, 189)); //Set color to dark blue
rng.Style.Font.Color.SetColor(Color.White);
}
//Example how to Format Column 1 as numeric
using (ExcelRange col = ws.Cells[2, 1, 2 + dt.Rows.Count, 1])
{
col.Style.Numberformat.Format = "#,##0.00";
col.Style.HorizontalAlignment = ExcelHorizontalAlignment.Right;
}
//Write it back to the client
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment; filename=" + viewModel.FileName);
Response.BinaryWrite(pck.GetAsByteArray());
}
return View(viewModel);
}
In the GET version of Index method the data is there and correct. Why is the data not showing up correctly in my POST version? If I modify the view and remove references to the Persons property, a diaglog box will pop up and I can download the file I want. Why isn't the POST version receiving the data for Persons from the GET version?
First thing is to realize that these actions are called for two separate requests. First is called when user navigated to the page, and second is called when user saw the page, filled out the form and submitted it.
Next is the fact that in ASP.NET MVC you do not have state. The only info you have is the one posted form client. So even though there was some object created on the previous request, this is object has nothing to do with current request. In your form has two inputs - these are the pieces you get in request.
The correct way to handle this is what you have already implemented. That is if you need some data base querying during the request - generally you need to do it on every request.

Categories