Need a web API action method to implement removeUrl of kendo angular upload component - file-upload

I need a full working example for implementing the remove functionality in telerik kendo angular with Angular 8 and a backend web API in ASP.net core 2.2
In kendo Angular I'm trying to implement the functionality of upload files and removing it when user clicks the x small buttons
I've already implemented the upload so perfectly but when providing the removeUrl it gives error 404 or 415
The other strange thing is when I provide the same url for the upload and download it binds and code could go well but i need a separate action for the remove functionality
[HttpPost("upload"), DisableRequestSizeLimit]
public async Task<IActionResult> Post(IFormFileCollection files)
{
long size = files.Sum(f => f.Length);
//var reqFiles = Request.Form.Files;
var uploads = Path.Combine(_hostingEnvironment.WebRootPath, "uploads");
if (!Directory.Exists(uploads))
{
Directory.CreateDirectory(uploads);
}
List<string> paths = new List<string>();
foreach (var file in files)
{
if (file.Length > 0)
{
string fileName = Guid.NewGuid() + Path.GetExtension(file.FileName);
var filePath = Path.Combine(uploads, fileName);
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(fileStream);
}
paths.Add(filePath);
}
}
// process uploaded files
// Don't rely on or trust the FileName property without validation.
return Ok(new { count = files.Count, size, paths });
}
and for delete
[HttpPost]
private IActionResult Delete(IList<string> files)
{
// var reqFiles = Request.Form.Files;
var uploads = Path.Combine(_hostingEnvironment.WebRootPath, "uploads");
foreach (var item in files)
{
var filePath = Path.Combine(uploads, item);
System.IO.File.Delete(filePath);
}
return Ok(new { files });
}
Error 404 is raised when trying to name the action in web api and provide this name in the url (although the same thing is working when uploadling) and 415 is being raised when using post request without naming the action in the back end

Related

how to read excel file in memory (without saving it in disk) and return its content dotnet core

Im working on a webApi using dotnet core that takes the excel file from IFormFile and reads its content.Iam following the article
https://levelup.gitconnected.com/reading-an-excel-file-using-an-asp-net-core-mvc-application-2693545577db which is doing the same thing except that the file here is present on the server and mine will be provided by user.
here is the code:
public IActionResult Test(IFormFile file)
{
List<UserModel> users = new List<UserModel>();
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
using (var stream = System.IO.File.Open(file.FileName, FileMode.Open, FileAccess.Read))
{
using (var reader = ExcelReaderFactory.CreateReader(stream))
{
while (reader.Read()) //Each row of the file
{
users.Add(new UserModel
{
Name = reader.GetValue(0).ToString(),
Email = reader.GetValue(1).ToString(),
Phone = reader.GetValue(2).ToString()
});
}
}
}
return Ok(users);
}
}
When system.IO tries to open the file, it could not find the path as the path is not present. How it is possible to either get the file path (that would vary based on user selection of file)? are there any other ways to make it possible.
PS: I dont want to upload the file on the server first, then read it.
You're using the file.FileName property, which refers to the file name the browser send. It's good to know, but not a real file on the server yet. You have to use the CopyTo(Stream) Method to access the data:
public IActionResult Test(IFormFile file)
{
List<UserModel> users = new List<UserModel>();
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
using (var stream = new MemoryStream())
{
file.CopyTo(stream);
stream.Position = 0;
using (var reader = ExcelReaderFactory.CreateReader(stream))
{
while (reader.Read()) //Each row of the file
{
users.Add(new UserModel{Name = reader.GetValue(0).ToString(), Email = reader.GetValue(1).ToString(), Phone = reader.GetValue(2).ToString()});
}
}
}
return Ok(users);
}
Reference

JsReport .NET Core - Generate PDF from url

Trying to use JsReport to generate a pdf from a url but can't find any documentation or examples in their github repo.
Basically I need to generate the pdf and attach it to an email and I've managed to get data back as a byte[], but I can't seem to figure out how to use an existing View/Action.
This is the action that generates the PDF for viewing...
[MiddlewareFilter(typeof(JsReportPipeline))]
public async Task<IActionResult> Pdf(Guid id)
{
var serviceOrder = await _serviceOrderService.Get(id);
if (serviceOrder == null) return new NotFoundResult();
var model = _mapper.Map<ServiceOrderModel>(serviceOrder);
HttpContext.JsReportFeature().Recipe(Recipe.PhantomPdf);
return View(model);
}
This action should take the pdf view from "Details" and generate a PDF that I can attach. Below I can generate it with static content like "Hello from pdf" but I can't figure out how to use my "Details" view in ASPNET Core.
public async Task<IActionResult> Email(Guid id)
{
var rs = new LocalReporting().UseBinary(JsReportBinary.GetBinary()).AsUtility().Create();
var report = await rs.RenderAsync(new RenderRequest()
{
Template = new Template()
{
Recipe = Recipe.PhantomPdf,
Engine = Engine.None,
Content = "Hello from pdf",
}
});
var memoryStream = new MemoryStream();
await report.Content.CopyToAsync(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
return new FileStreamResult(memoryStream, "application/pdf") { FileDownloadName = "out.pdf" };
}
Taken From the JsReport Github Dotnet Example,
[MiddlewareFilter(typeof(JsReportPipeline))]
public IActionResult InvoiceDownload()
{
HttpContext.JsReportFeature().Recipe(Recipe.ChromePdf)
.OnAfterRender((r) => HttpContext.Response.Headers["Content-Disposition"] = "attachment; filename=\"myReport.pdf\"");
return View("Invoice", InvoiceModel.Example());
}
If you want to return a file from Asp.net Core Controller Action method then try the following
[MiddlewareFilter(typeof(JsReportPipeline))]
public async Task<IActionResult> Pdf(Guid id)
{
var serviceOrder = await _serviceOrderService.Get(id);
if (serviceOrder == null) return new NotFoundResult();
var model = _mapper.Map<ServiceOrderModel>(serviceOrder);
HttpContext.JsReportFeature().Recipe(Recipe.PhantomPdf).OnAfterRender((r) =>
HttpContext.Response.Headers["Content-Disposition"] = "attachment; filename=\"out.pdf\"");
return View(model);
}

Sensenet: upload files through sensenet client API for version 6.5 is not working properly

I have installed SenseNet version 6.5 (Code from codeplex). Wanted to upload the files in content repositry using Sensenet Client API, unfortunately it is not working with bulk upload.
string [] fileEntries = Directory.GetFiles(#"C:\Users\conyna\Downloads\Chirag");
foreach (string fileName in fileEntries)
{
using (Stream fs = File.OpenRead(fileName))
{
string fn = Path.GetFileName(fileName);
Task<SenseNet.Client.Content> x = SenseNet.Client.Content.UploadAsync("/Root/Sites/Default_Site/workspaces/(apps)/DocumentLibrary", fn, fs);
}
}
There are two problems with the code above:
you have to 'await' for async methods. Currently you start the task with the UploadAsync method, but you do not wait for it to finish, which casuses problems, because the file stream closes immediately after starting the upload task. Please upload files in an async way (of course you'll have to make your caller method async too, but that is the point of using an async api):
await Content.UploadAsync(...)
You may also consider using the Importer class in the client, it is able to import full directory structures.
You are trying to upload into an (apps) folder, which is not a correct target, that was designed to contain applications (mostly pages). It would be better if you uploaded into a document library in a workspace, for example:
/Root/Sites/Default_Site/workspaces/Document/SampleWorkspace/DocumentLibrary
We created a small application with SN ClientLibrary. I think, you can use this application/information/code.
This application can upload entire folders via Client Libray. Please check it out my Github repository: https://github.com/marosvolgyiz/SNClientLibraryUploader
There is relevant upload method:
public async Task Upload()
{
try
{
Console.WriteLine("Initilization...");
ClientContext.Initialize(new[] { sctx });
Console.WriteLine("Upload Started");
//Is Parent exists
var content = await Content.LoadAsync(Target);
if (content != null)
{
//Uploading files
var tasks = new List<Task>();
foreach (var file in Files)
{
string fileTargetFolder = Target + file.DirectoryName.Replace(Source, "").Replace(BaseDirectory, "").Replace("\\", "/");
var fileTargetContentFolder = await Content.LoadAsync(fileTargetFolder);
if (fileTargetContentFolder == null)
{
if (CreateFolderPath(Target, file.DirectoryName.Replace(Source, "")))
{
fileTargetContentFolder = await Content.LoadAsync(fileTargetFolder);
Console.WriteLine("#Upload file: " + file.FullName);
tasks.Add(Content.UploadAsync(fileTargetContentFolder.Id, file.Name, file.OpenRead()));
LoggerClass.LogToCSV("File uploaded", file.Name);
}
else
{
LoggerClass.LogToCSV("File target folder does not exist or you do not have enough permission to see! File can not be uploaded. ", file.Name);
}
}
else
{
Console.WriteLine("#Upload file: " + file.FullName);
tasks.Add(Content.UploadAsync(fileTargetContentFolder.Id, file.Name, file.OpenRead()));
LoggerClass.LogToCSV("File uploaded", file.Name);
}
}
await Task.WhenAll(tasks);
}
else
{
Console.WriteLine("Target does not exist or you do not have enough permission to see!");
LoggerClass.LogToCSV("Target does not exist or you do not have enough permission to see!");
}
Console.WriteLine("Upload finished.");
}
catch (Exception ex)
{
LoggerClass.LogToCSV(ex.Message);
}
}
I hope my answer is helpful to you.
Br,
maros

Export html to pdf in ASP.NET Core

I want to export a piece of html to a pdf file but i do not any compatible nuget package.
When I try to install anyone: "X not compatible with netcoreapp1.0 (.NETCoreApp,Version=v1.0)."
Does anyone know any way to export to a pdf using asp.net core??
You can use jsreport .net sdk if you are in .net core 2.0 also without more complex node services. This includes among other features filters to convert your existing razor views into pdf. From the docs:
1.
Install nugets jsreport.Binary, jsreport.Local and jsreport.AspNetCore
2.
In you Startup.cs configure it as the following
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddJsReport(new LocalReporting()
.UseBinary(JsReportBinary.GetBinary())
.AsUtility()
.Create());
}
3.
Then you need to add MiddlewareFilter attribute to the particular action and specify which conversion you want to use. In this case html to pdf conversion.
[MiddlewareFilter(typeof(JsReportPipeline))]
public IActionResult Invoice()
{
HttpContext.JsReportFeature().Recipe(Recipe.ChromePdf);
return View();
}
You can reach bunch of other options for headers, footers or page layout on JsReportFeature(). Note that the same way you can also produce excel files from html. See more information in the documentation.
PS: I'm the author of jsreport.
Copied from my original answer here Export to pdf using ASP.NET 5:
One way to generate pdf from html in .NET Core (without any .NET framework dependencies) is using Node.js from within the .NET Core application.
The following example shows how to implement an HTML to PDF converter in a clean ASP.NET Core Web Application project (Web API template).
Install the NuGet package Microsoft.AspNetCore.NodeServices
In Startup.cs add the line services.AddNodeServices() like this
public void ConfigureServices(IServiceCollection services)
{
// ... all your existing configuration is here ...
// Enable Node Services
services.AddNodeServices();
}
Now install the required Node.js packages:
From the command line change working directory to the root of the .NET Core project and run these commands.
npm init
and follow the instructions to create the package.json file
npm install jsreport-core --save
npm install jsreport-jsrender --save
npm install jsreport-phantom-pdf --save
Create a file pdf.js in the root of the project containing
module.exports = function (callback) {
var jsreport = require('jsreport-core')();
jsreport.init().then(function () {
return jsreport.render({
template: {
content: '<h1>Hello {{:foo}}</h1>',
engine: 'jsrender',
recipe: 'phantom-pdf'
},
data: {
foo: "world"
}
}).then(function (resp) {
callback(/* error */ null, resp.content.toJSON().data);
});
}).catch(function (e) {
callback(/* error */ e, null);
})
};
Have a look here for more explanation on jsreport-core.
Now create an action in an Mvc controller that calls this Node.js script
[HttpGet]
public async Task<IActionResult> MyAction([FromServices] INodeServices nodeServices)
{
var result = await nodeServices.InvokeAsync<byte[]>("./pdf");
HttpContext.Response.ContentType = "application/pdf";
string filename = #"report.pdf";
HttpContext.Response.Headers.Add("x-filename", filename);
HttpContext.Response.Headers.Add("Access-Control-Expose-Headers", "x-filename");
HttpContext.Response.Body.Write(result, 0, result.Length);
return new ContentResult();
}
Off course you can do whatever you want with the byte[] returned from nodeServices, in this example I'm just outputting it from a controller action so it can be viewed in the browser.
You could also exchange the data between Node.js and .NET Core by a base64 encoded string using resp.content.toString('base64') in pdf.js and use
var result = await nodeServices.InvokeAsync<byte[]>("./pdf"); in the action and then decode the base64 encoded string.
Alternatives
Most pdf generator solutions still depend on .NET 4.5/4.6 framework. But there seems to be some paid alternatives available if you don't like to use Node.js:
NReco.PdfGenerator.LT
EVO HTML to PDF Converter Client for .NET Core
Winnovative HTML to PDF Converter Client for .NET Core
I haven't tried any of these though.
I hope we will soon see some open source progress in this area.
You can check DinkToPdf library. It is a wrapper around wkhtmltopdf library for .NET Core.
Synchronized converter
Use this converter in multi threaded applications and web servers. Conversion tasks are saved to blocking collection and executed on a single thread.
var converter = new SynchronizedConverter(new PdfTools());
Define document to convert
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Landscape,
PaperSize = PaperKind.A4Plus,
},
Objects = {
new ObjectSettings() {
PagesCount = true,
HtmlContent = #"Lorem ipsum dolor sit amet, consectetur adipiscing elit. In consectetur mauris eget ultrices iaculis. Ut odio viverra, molestie lectus nec, venenatis turpis.",
WebSettings = { DefaultEncoding = "utf-8" },
HeaderSettings = { FontSize = 9, Right = "Page [page] of [toPage]", Line = true, Spacing = 2.812 }
}
}
};
I was having the same issue! I wanted to generate PDF files from HTML strings. I then came across PhantomJs which is a command line utility for converting html files to pdf. I wrote a cross-platform wrapper over it in C# for .NET CORE and its working great on Linux! Though as of now its only for 64-bit Linux, because that is the only platform .NET Core Supports currently.
The project can be found here
PhantomJs.NetCore.PdfGenerator gen = new PhantomJs.NetCore.PdfGenerator("/path/to/pantomjsfolder");
string outputFilePath = gen.GeneratePdf("<h1>Hello</h1>","/folder/to/write/file/in");
This is a solution working for ASP.NET Core 2.0, which allows either to generate dynamic PDF files from cshtml, directly send them to users and/or save them before sending.
To complement Jan Blaha answer there, for more flexibility, you may want to use the following code:
/// Generate a PDF from a html string
async Task<(string ContentType, MemoryStream GeneratedFileStream)> GeneratePDFAsync(string htmlContent)
{
IJsReportFeature feature = new JsReportFeature(HttpContext);
feature.Recipe(Recipe.PhantomPdf);
if (!feature.Enabled) return (null, null);
feature.RenderRequest.Template.Content = htmlContent;
var report = await _RenderService.RenderAsync(feature.RenderRequest);
var contentType = report.Meta.ContentType;
MemoryStream ms = new MemoryStream();
report.Content.CopyTo(ms);
return (contentType, ms);
}
Using a class to render cshtml files as string, you may use the following service (which can be injected as a scoped service):
public class ViewToStringRendererService: ViewExecutor
{
private ITempDataProvider _tempDataProvider;
private IServiceProvider _serviceProvider;
public ViewToStringRendererService(
IOptions<MvcViewOptions> viewOptions,
IHttpResponseStreamWriterFactory writerFactory,
ICompositeViewEngine viewEngine,
ITempDataDictionaryFactory tempDataFactory,
DiagnosticSource diagnosticSource,
IModelMetadataProvider modelMetadataProvider,
ITempDataProvider tempDataProvider,
IServiceProvider serviceProvider)
: base(viewOptions, writerFactory, viewEngine, tempDataFactory, diagnosticSource, modelMetadataProvider)
{
_tempDataProvider = tempDataProvider;
_serviceProvider = serviceProvider;
}
public async Task<string> RenderViewToStringAsync<TModel>(string viewName, TModel model)
{
var context = GetActionContext();
if (context == null) throw new ArgumentNullException(nameof(context));
var result = new ViewResult()
{
ViewData = new ViewDataDictionary<TModel>(
metadataProvider: new EmptyModelMetadataProvider(),
modelState: new ModelStateDictionary())
{
Model = model
},
TempData = new TempDataDictionary(
context.HttpContext,
_tempDataProvider),
ViewName = viewName,
};
var viewEngineResult = FindView(context, result);
viewEngineResult.EnsureSuccessful(originalLocations: null);
var view = viewEngineResult.View;
using (var output = new StringWriter())
{
var viewContext = new ViewContext(
context,
view,
new ViewDataDictionary<TModel>(
metadataProvider: new EmptyModelMetadataProvider(),
modelState: new ModelStateDictionary())
{
Model = model
},
new TempDataDictionary(
context.HttpContext,
_tempDataProvider),
output,
new HtmlHelperOptions());
await view.RenderAsync(viewContext);
return output.ToString();
}
}
private ActionContext GetActionContext()
{
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = _serviceProvider;
return new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
}
/// <summary>
/// Attempts to find the <see cref="IView"/> associated with <paramref name="viewResult"/>.
/// </summary>
/// <param name="actionContext">The <see cref="ActionContext"/> associated with the current request.</param>
/// <param name="viewResult">The <see cref="ViewResult"/>.</param>
/// <returns>A <see cref="ViewEngineResult"/>.</returns>
ViewEngineResult FindView(ActionContext actionContext, ViewResult viewResult)
{
if (actionContext == null)
{
throw new ArgumentNullException(nameof(actionContext));
}
if (viewResult == null)
{
throw new ArgumentNullException(nameof(viewResult));
}
var viewEngine = viewResult.ViewEngine ?? ViewEngine;
var viewName = viewResult.ViewName ?? GetActionName(actionContext);
var result = viewEngine.GetView(executingFilePath: null, viewPath: viewName, isMainPage: true);
var originalResult = result;
if (!result.Success)
{
result = viewEngine.FindView(actionContext, viewName, isMainPage: true);
}
if (!result.Success)
{
if (originalResult.SearchedLocations.Any())
{
if (result.SearchedLocations.Any())
{
// Return a new ViewEngineResult listing all searched locations.
var locations = new List<string>(originalResult.SearchedLocations);
locations.AddRange(result.SearchedLocations);
result = ViewEngineResult.NotFound(viewName, locations);
}
else
{
// GetView() searched locations but FindView() did not. Use first ViewEngineResult.
result = originalResult;
}
}
}
if(!result.Success)
throw new InvalidOperationException(string.Format("Couldn't find view '{0}'", viewName));
return result;
}
private const string ActionNameKey = "action";
private static string GetActionName(ActionContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (!context.RouteData.Values.TryGetValue(ActionNameKey, out var routeValue))
{
return null;
}
var actionDescriptor = context.ActionDescriptor;
string normalizedValue = null;
if (actionDescriptor.RouteValues.TryGetValue(ActionNameKey, out var value) &&
!string.IsNullOrEmpty(value))
{
normalizedValue = value;
}
var stringRouteValue = routeValue?.ToString();
if (string.Equals(normalizedValue, stringRouteValue, StringComparison.OrdinalIgnoreCase))
{
return normalizedValue;
}
return stringRouteValue;
}
}
Then to conclude, in your controller, supposing the razor cshtml view template to be /Views/Home/PDFTemplate.cshtml you may use the following.
Note: The cshtml file may need to be copied when published (even if views are compiled).
var htmlContent = await _ViewToStringRendererService.RenderViewToStringAsync("Home/PDFTemplate", viewModel);
(var contentType, var generatedFile) = await GeneratePDFAsync(htmlContent);
Response.Headers["Content-Disposition"] = $"attachment; filename=\"{System.Net.WebUtility.UrlEncode(fileName)}\"";
// You may save your file here
using (var fileStream = new FileStream(Path.Combine(folder, fileName), FileMode.Create))
{
await generatedFile.CopyToAsync(fileStream);
}
// You may need this for re-use of the stream
generatedFile.Seek(0, SeekOrigin.Begin);
return File(generatedFile.ToArray(), "application/pdf", fileName);
On the server-side, you can output pdf of a html and use library that generate PDF from HTML string .NET Core after you got pdf, you need to pass it to the library see this link to convert HTML to PDF in .NET.
install nuget package : Select.HtmlToPdf.NetCore
HtmlToPdf htmlToPdf = new HtmlToPdf();
htmlToPdf.Options.PdfPageOrientation = PdfPageOrientation.Portrait;
// put css in pdf
htmlToPdf.Options.MarginLeft = 15;
htmlToPdf.Options.MarginRight = 15;
---------------------------
string url = "<html><head></head><body>Hello World</body></html>"
PdfDocument pdfDocument = htmlToPdf.ConvertHtmlString(url);
byte[] pdf = pdfDocument.Save();
//convert to memory stream
Stream stream = new MemoryStream(pdf);
pdfDocument.Close();
//if want to transfer stream to file
File(stream, "application/pdf", Guid.NewGuid().ToString() + ".pdf");
For exporting html to pdf you can use itextsharp library and even you can place html inside a partial view and export that view as pdf. Recently , i have tried that in a project where i needed to export pdf and i got refer How to export view as pdf in Asp.Net core . So you can give this a try.

FileUpload and Retrieval

I am trying to make a file upload page where users can upload an image or document to it and it to show up in a list fashion, I have managed to upload the image into a folder I created in my Project, but I have no idea how I'm meant to retrieve it, every time I try and search for it I get useless posts which don't really fit my question.
Here is my code:
//
// GET: /Upload/
[HttpPost]
public ActionResult Index(HttpPostedFileBase file)
{
if (file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/Images/Uploads"), fileName);
file.SaveAs(path);
System.Diagnostics.Debug.WriteLine(path);
}
Server.MapPath("~/App_Data/Uploads/");
return RedirectToAction("Index", file);
}