How to change below code from asp.net to razor page - asp.net-mvc

I am new to Razor page but have been working in aspx. This below is my code - please help me convert this to a Razor page:
void Page_Load(object sender, EventArgs e)
{
foreach(string f in Request.Files.AllKeys)
{
HttpPostedFile file = Request.Files[f];
file.SaveAs("C:\\e_data\\WorkPage\\IMS18\\ALBAB_Dynamic\\20008\\Case_Manager\\" + file.FileName);
}
}
I want to change to razor page code.

Here's what I use for uploading a single file and storing the path to the file in a database. It'll explain the bits that Microsoft left out of it's docs (for instance the path to the base directory in .netcore2.2) Note that security is not much of a concern for me as this is a small company intranet... but there's bits in there about getting filename without extension, and you may want to store without the file extension for security reasons (or remove and then add your own extension):
public async Task<IActionResult> OnPostAsync()
{
if (id == null)
{
return NotFound();
}
Kit = await _context.Kits.FirstOrDefaultAsync(m => m.ID == id);
if (Kit == null)
{
return NotFound();
}
if (Request.Form.Files.Count > 0)
{
IFormFile file = Request.Form.Files[0];
string folderName = "UploadedOriginalBOMs";
string OrgBOMRootPath = Path.Combine(AppContext.BaseDirectory, folderName);
if (!Directory.Exists(OrgBOMRootPath))
{
Directory.CreateDirectory(OrgBOMRootPath);
}
string sFileExtension = Path.GetExtension(file.FileName).ToLower();
string fullPath = Path.Combine(OrgBOMRootPath, file.FileName);
// StringBuilder sb = new StringBuilder();
if (file.Length > 0)
{
String cleanFilename = Path.GetFileNameWithoutExtension(file.FileName);
using (var stream = new FileStream(fullPath, FileMode.Create))
{
file.CopyTo(stream);
}
Kit.PathToOriginalBOM = "UploadedOriginalBOMs/" + file.FileName;
_context.Kits.Attach(Kit).State = EntityState.Modified;
await _context.SaveChangesAsync();
}
}
else
{
if (!ModelState.IsValid)
{
return Page();
}
}
return RedirectToPage("./Index");
}
You'll notice that you can just use the same forloop as in your .aspx file.

Related

how to Upload a single file in the list

I have a list where I upload a file for each record and send them all together to the controller. The code works correctly, but if I don't upload a file for one of them and an empty record is sent, an error occurs.
[HttpPost]
public async Task<IActionResult> SabtEditTaxParvanedAsync([FromForm]IEnumerable<TaxParvande> taxParvandes)
{
if (taxParvandes == null)
{
return Content("File not selected");
}
foreach (var item in taxParvandes)
{
var path = Path.Combine(_environment.WebRootPath, "ListUpload", item.prosessMastand.FileName);
using (FileStream stream = new FileStream(path, FileMode.Create))
{
await item.prosessMastand.CopyToAsync(stream);
stream.Close();
}
var taxDomainModel = new TaxDomainModel
{
prosessId =item.prosessId,
prosessName = item.prosessName,
state = item.state,
FilePath = path,
};
_context.Add(taxDomainModel);
await _context.SaveChangesAsync();
}
return View();
}
But if I don't upload a file for one of them and an empty record is
sent, an error occurs.
Well, in this scenario, you might encounter null reference exception. To overcome this error you could set item.prosessMastand == null then to continue loop which will skip the error upon empty insertion.
public async Task<IActionResult> SabtEditTaxParvanedAsync([FromForm] IEnumerable<TaxParvande> taxParvandes)
{
if (taxParvandes == null)
{
return Content("File not selected");
}
foreach (var item in taxParvandes)
{
if (item.prosessMastand == null)
{
continue;
}
var path = Path.Combine(_environment.WebRootPath, "ListUpload", item.prosessMastand.FileName);
using (FileStream stream = new FileStream(path, FileMode.Create))
{
await item.prosessMastand.CopyToAsync(stream);
stream.Close();
}
var taxDomainModel = new TaxDomainModel
{
prosessName = item.prosessName,
state = item.state,
filePath = path,
};
_context.Add(taxDomainModel);
await _context.SaveChangesAsync();
}
return RedirectToAction("Index");
}
Output:

How can I do to Edit a record with losing the actual data of it?

The error I'am receiving when I try to upload a File on a record already existed, is this:
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
public ActionResult Edit(Project mcs, HttpPostedFileBase file, [Bind(Include
= "ProjectID,NumberMCP,EngineerID,SiteLocationID,nameProject,Ptype,Pyear,
Fr,
Fc, MCPcontent, Proj, ContentType")] Project project)
{
try
{
if (ModelState.IsValid)
{
if (file != null && file.ContentLength > 0)
{
System.IO.File.Delete(Path.Combine(Server.MapPath("~/UploadFiles/"), mcs.Proj));
string ds =
file.FileName.Substring(file.FileName.Length - 3);
string p = string.Empty;
p = Server.MapPath("~/UploadFiles/");
file.SaveAs(p + file.FileName);
BinaryReader br = new BinaryReader(file.InputStream);
byte[] buffer = br.ReadBytes(file.ContentLength);
using (db)
{
mcs.Proj = file.FileName;
mcs.ContentType = file.ContentType;
mcs.MCPcontent = buffer;
db.Projects.Add(mcs);
db.SaveChanges();
}
ViewBag.EngineerID = new SelectList(db.Engineers, "EngineerID", "eName", project.EngineerID);
ViewBag.SiteLocationID = new SelectList(db.SiteLocations, "SiteLocationID", "nameSL", project.SiteLocationID);
return RedirectToAction("Index");
}
else
{
TempData["Message"] = "No se elegió ningún
archivo.";
return RedirectToAction("Edit");
}
}
}
else
{
return View();
}
}
catch /*(Exception ex)*/
{
ViewBag.Message = "Upload failed";
return RedirectToAction("Edit");
}
}
I need some logic help in here please.

How to read into memory the lines of a text file from an IFormFile in ASP.NET Core?

Say you have this Action:
public List<string> Index(IFormFile file){
//extract list of strings from the file
return new List<string>();
}
I've found plenty of examples of saving the file to the drive, but what if I instead want to skip this and just read the lines of text into an array in memory, directly from the IFormFile?
The abstraction for the IFormFile has an .OpenReadStream method.
To prevent a ton of undesirable and potentially large allocations, we should read a single line at a time and build up our list from each line that we read. Additionally, we could encapsulate this logic in an extension method. The Index action ends up looking like this:
public List<string> Index(IFormFile file) => file.ReadAsList();
The corresponding extension method looks like this:
public static List<string> ReadAsList(this IFormFile file)
{
var result = new StringBuilder();
using (var reader = new StreamReader(file.OpenReadStream()))
{
while (reader.Peek() >= 0)
result.AppendLine(reader.ReadLine());
}
return result;
}
Likewise you could have an async version as well:
public static async Task<string> ReadAsStringAsync(this IFormFile file)
{
var result = new StringBuilder();
using (var reader = new StreamReader(file.OpenReadStream()))
{
while (reader.Peek() >= 0)
result.AppendLine(await reader.ReadLineAsync());
}
return result.ToString();
}
Alternatively, you could you use an ObjectPool<StringBuilder> and modern C# 8 features.
public static async Task<string> ReadAsStringAsync(
this IFormFile file, Object<StringBuilder> pool)
{
var builder = pool.Get();
try
{
using var reader = new StreamReader(file.OpenReadStream());
while (reader.Peek() >= 0)
{
builder.AppendLine(await reader.ReadLineAsync());
}
return builder.ToString();
}
finally
{
pool.Return(builder);
}
}
Then you could use this version this way:
public Task<List<string>> Index(
IFormFile file, [FromServices] ObjectPool<StringBuilder> pool) =>
file.ReadAsListAsync(pool);
ASP.NET Core 3.0 - Reading a form file's content into string
public static async Task<string> ReadFormFileAsync(IFormFile file)
{
if (file == null || file.Length == 0)
{
return await Task.FromResult((string)null);
}
using (var reader = new StreamReader(file.OpenReadStream()))
{
return await reader.ReadToEndAsync();
}
}

Using memorystream and DotNetZip in MVC gives "Cannot access a closed Stream"

I'm trying to create a zipfile in a MVC method using the DotNetZip components.
Here is my code:
public FileResult DownloadImagefilesAsZip()
{
using (var memoryStream = new MemoryStream())
{
using (var zip = new ZipFile())
{
zip.AddDirectory(Server.MapPath("/Images/"));
zip.Save(memoryStream);
return File(memoryStream, "gzip", "images.zip");
}
}
}
When I run it I get a "Cannot access a closed Stream" error, and I'm not sure why.
Don't dispose the MemoryStream, the FileStreamResult will take care once it has finished writing it to the response:
public ActionResult DownloadImagefilesAsZip()
{
var memoryStream = new MemoryStream();
using (var zip = new ZipFile())
{
zip.AddDirectory(Server.MapPath("~/Images"));
zip.Save(memoryStream);
return File(memoryStream, "application/gzip", "images.zip");
}
}
By the way I would recommend you writing a custom action result to handle this instead of writing plumbing code inside your controller action. Not only that you will get a reusable action result but bear in mind that your code is hugely inefficient => you are performing the ZIP operation inside the memory and thus loading the whole ~/images directory content + the zip file in memory. If you have many users and lots of files inside this directory you will very quickly run out of memory.
A much more efficient solution is to write directly to the response stream:
public class ZipResult : ActionResult
{
public string Path { get; private set; }
public string Filename { get; private set; }
public ZipResult(string path, string filename)
{
Path = path;
Filename = filename;
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
var response = context.HttpContext.Response;
response.ContentType = "application/gzip";
using (var zip = new ZipFile())
{
zip.AddDirectory(Path);
zip.Save(response.OutputStream);
var cd = new ContentDisposition
{
FileName = Filename,
Inline = false
};
response.Headers.Add("Content-Disposition", cd.ToString());
}
}
}
and then:
public ActionResult DownloadImagefilesAsZip()
{
return new ZipResult(Server.MapPath("~/Images"), "images.zip");
}
Couldn't comment.
Darin's answer is great! Still received a memory exception though so had to add response.BufferOutput = false; and because of that had to move content-disposition code higher.
So you have:
...
var response = context.HttpContext.Response;
response.ContentType = "application/zip";
response.BufferOutput = false;
var cd = new ContentDisposition
{
FileName = ZipFilename,
Inline = false
};
response.Headers.Add("Content-Disposition", cd.ToString());
using (var zip = new ZipFile())
{
...
Just in case it wasn't obvious :)

Rendering an RDLC report in HTML in ASP.NET MVC

I would like to render an RDLC report in HTML within an ASP.NET MVC project.
I successfully made a prototype that renders an RDLC report in PDF, Excel, and TIFF image, with the help of this article. But I was surprised that HTML is not one of the default available formats in LocalReport.Render().
I came across this article, which describes a trick to enable the rendering format of HTML4.0, but I think that is only for a ReportViewer control (I could be wrong though).
The question is, in MVC how to render an RDLC report in HTML just like a ReportView does (see the screenshot below)?
This is a simple task. You can follow the following steps.
Create a folder in your solution and give a name Reports.
Add a ASP.Net web form and named it ReportView.aspx
Create a Class ReportData and add it to the Reports folder. Add the following code
to the Class.
public class ReportData
{
public ReportData()
{
this.ReportParameters = new List<Parameter>();
this.DataParameters = new List<Parameter>();
}
public bool IsLocal { get; set; }
public string ReportName { get; set; }
public List<Parameter> ReportParameters { get; set; }
public List<Parameter> DataParameters { get; set; }
}
public class Parameter
{
public string ParameterName { get; set; }
public string Value { get; set; }
}
Add another Class and named it ReportBasePage.cs. Add the following code in this Class.
public class ReportBasePage : System.Web.UI.Page
{
protected ReportData ReportDataObj { get; set; }
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (HttpContext.Current != null)
if (HttpContext.Current.Session["ReportData"] != null)
{
ReportDataObj = HttpContext.Current.Session["ReportData"] as ReportData;
return;
}
ReportDataObj = new ReportData();
CaptureRouteData(Page.Request);
}
private void CaptureRouteData(HttpRequest request)
{
var mode = (request.QueryString["rptmode"] + "").Trim();
ReportDataObj.IsLocal = mode == "local" ? true : false;
ReportDataObj.ReportName = request.QueryString["reportname"] + "";
string dquerystr = request.QueryString["parameters"] + "";
if (!String.IsNullOrEmpty(dquerystr.Trim()))
{
var param1 = dquerystr.Split(',');
foreach (string pm in param1)
{
var rp = new Parameter();
var kd = pm.Split('=');
if (kd[0].Substring(0, 2) == "rp")
{
rp.ParameterName = kd[0].Replace("rp", "");
if (kd.Length > 1) rp.Value = kd[1];
ReportDataObj.ReportParameters.Add(rp);
}
else if (kd[0].Substring(0, 2) == "dp")
{
rp.ParameterName = kd[0].Replace("dp", "");
if (kd.Length > 1) rp.Value = kd[1];
ReportDataObj.DataParameters.Add(rp);
}
}
}
}
}
Add ScriptManager to the ReportView.aspx page. Now Take a Report Viewer to the page. In report viewer set the property AsyncRendering="false". The code is given below.
<rsweb:ReportViewer ID="ReportViewerRSFReports" runat="server" AsyncRendering="false"
Width="1271px" Height="1000px" >
</rsweb:ReportViewer>
Add two NameSpace in ReportView.aspx.cs
using Microsoft.Reporting.WebForms;
using System.IO;
Change the System.Web.UI.Page to ReportBasePage. Just replace your code using the following.
public partial class ReportView : ReportBasePage
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
RenderReportModels(this.ReportDataObj);
}
}
private void RenderReportModels(ReportData reportData)
{
RASolarERPData dal = new RASolarERPData();
List<ClosingInventoryValuation> objClosingInventory = new List<ClosingInventoryValuation>();
// Reset report properties.
ReportViewerRSFReports.Height = Unit.Parse("100%");
ReportViewerRSFReports.Width = Unit.Parse("100%");
ReportViewerRSFReports.CssClass = "table";
// Clear out any previous datasources.
this.ReportViewerRSFReports.LocalReport.DataSources.Clear();
// Set report mode for local processing.
ReportViewerRSFReports.ProcessingMode = ProcessingMode.Local;
// Validate report source.
var rptPath = Server.MapPath(#"./Report/" + reportData.ReportName +".rdlc");
//#"E:\RSFERP_SourceCode\RASolarERP\RASolarERP\Reports\Report\" + reportData.ReportName + ".rdlc";
//Server.MapPath(#"./Report/ClosingInventory.rdlc");
if (!File.Exists(rptPath))
return;
// Set report path.
this.ReportViewerRSFReports.LocalReport.ReportPath = rptPath;
// Set report parameters.
var rpPms = ReportViewerRSFReports.LocalReport.GetParameters();
foreach (var rpm in rpPms)
{
var p = reportData.ReportParameters.SingleOrDefault(o => o.ParameterName.ToLower() == rpm.Name.ToLower());
if (p != null)
{
ReportParameter rp = new ReportParameter(rpm.Name, p.Value);
ReportViewerRSFReports.LocalReport.SetParameters(rp);
}
}
//Set data paramater for report SP execution
objClosingInventory = dal.ClosingInventoryReport(this.ReportDataObj.DataParameters[0].Value);
// Load the dataSource.
var dsmems = ReportViewerRSFReports.LocalReport.GetDataSourceNames();
ReportViewerRSFReports.LocalReport.DataSources.Add(new ReportDataSource(dsmems[0], objClosingInventory));
// Refresh the ReportViewer.
ReportViewerRSFReports.LocalReport.Refresh();
}
}
Add a Folder to the Reports Folder and named it Report. Now add a RDLC report to the Reports/Report folder and named it ClosingInventory.rdlc.
Now add a Controller and Named it ReportController. In to the controller add the following action method.
public ActionResult ReportViewer()
{
ViewData["reportUrl"] = "../Reports/View/local/ClosingInventory/";
return View();
}
Add a view page click on the ReportViewer Controller. Named the view page ReportViewer.cshtml. Add the following code to the view page.
#using (Html.BeginForm("Login"))
{
#Html.DropDownList("ddlYearMonthFormat", new SelectList(ViewBag.YearMonthFormat, "YearMonthValue", "YearMonthName"), new { #class = "DropDown" })
Stock In Transit: #Html.TextBox("txtStockInTransit", "", new { #class = "LogInTextBox" })
<input type="submit" onclick="return ReportValidationCheck();" name="ShowReport"
value="Show Report" />
}
Add an Iframe. Set the property of the Iframe as follows
frameborder="0" width="1000"; height="1000"; style="overflow:hidden;" scrolling="no"
Add Following JavaScript to the viewer.
function ReportValidationCheck() {
var url = $('#hdUrl').val();
var yearmonth = $('#ddlYearMonthFormat').val();
var stockInTransit = $('#txtStockInTransit').val()
if (stockInTransit == "") {
stockInTransit = 0;
}
if (yearmonth == "0") {
alert("Please Select Month Correctly.");
}
else {
//url = url + "dpSpYearMonth=" + yearmonth + ",rpYearMonth=" + yearmonth + ",rpStockInTransit=" + stockInTransit;
url = "../Reports/ReportView.aspx?rptmode=local&reportname=ClosingInventory&parameters=dpSpYearMonth=" + yearmonth + ",rpYearMonth=" + yearmonth + ",rpStockInTransit=" + stockInTransit;
var myframe = document.getElementById("ifrmReportViewer");
if (myframe !== null) {
if (myframe.src) {
myframe.src = url;
}
else if (myframe.contentWindow !== null && myframe.contentWindow.location !== null) {
myframe.contentWindow.location = url;
}
else { myframe.setAttribute('src', url); }
}
}
return false;
}
In Web.config file add the following key to the appSettings section add
key="UnobtrusiveJavaScriptEnabled" value="true"
In system.web handlers Section add the following key
add verb="*" path="Reserved.ReportViewerWebControl.axd" type = "Microsoft.Reporting.WebForms.HttpHandler, Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
Change your data source as your own. This solution is very simple and I think every one enjoy it.
You can use the ReportViewer object to render an RDLC to PDF or HTML. For my case (below) I wanted a PDF document and I returned it as a FileContentResult ActionResult. If you want it to return as a download use the File ActionResult (I've commented that out for your use).
public ActionResult GetPackingSlipPDF(int shipmentId)
{
var shipment = _inboundShipmentService.GetInboundShipmentById(shipmentId);
Warning[] warnings;
string mimeType;
string[] streamids;
string encoding;
string filenameExtension;
var viewer = new ReportViewer();
viewer.LocalReport.ReportPath = #"Labels\PackingSlip.rdlc";
var shipLabel = new ShippingLabel { ShipmentId = shipment.FBAShipmentId, Barcode = GetBarcode(shipment.FBAShipmentId) };
viewer.LocalReport.DataSources.Add(new ReportDataSource("ShippingLabel", new List<ShippingLabel> { shipLabel }));
viewer.LocalReport.Refresh();
var bytes = viewer.LocalReport.Render("PDF", null, out mimeType, out encoding, out filenameExtension, out streamids, out warnings);
return new FileContentResult(bytes, mimeType);
//return File(bytes, mimeType, shipment.FBAShipmentId + "_PackingSlip.pdf");
}

Resources