How can I specify the download location of the converted pdf in the server?
When I run in the server I want to save the pdf in server files but I don't know how can I manipulate the memory stream or how to do it.
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Syncfusion.HtmlConverter;
using Syncfusion.Pdf;
using System.IO;
using Microsoft.AspNetCore.Hosting;
namespace HospitalQR.Web.Controllers
{
public class FormController : Controller
{
private readonly IHostingEnvironment _hostingEnvironment;
public FormController(IHostingEnvironment hostingEnvironment)
{
_hostingEnvironment = hostingEnvironment;
}
public IActionResult Index()
{
return View("PreForm");
}
public IActionResult PdfConverter()
{
HtmlToPdfConverter converter = new HtmlToPdfConverter();
WebKitConverterSettings settings = new WebKitConverterSettings();
settings.WebKitPath = Path.Combine(_hostingEnvironment.ContentRootPath, "QtBinariesWindows");
converter.ConverterSettings = settings;
PdfDocument document = converter.Convert("https://localhost:44334/form");
MemoryStream ms = new MemoryStream();
document.Save(ms);
document.Close(true);
ms.Position = 0;
FileStreamResult fileStreamResult = new FileStreamResult(ms, "application/pdf");
fileStreamResult.FileDownloadName = "PreForm.pdf";
return fileStreamResult;
}
}
}
By default, it will automatically save the downloaded file in your browser location. We could not able set the defined path in an ASP NET Core Web application and download it from the browser. If you want the save the pdf in a defined path, please change the browser path setting to that predefined path.
However, if you want to save the PDF document in your “wwwroot” location, please refer the below code snippet,
//Initialize HTML to PDF converter with WebKit rendering engine
HtmlToPdfConverter htmlConverter = new HtmlToPdfConverter(HtmlRenderingEngine.WebKit);
WebKitConverterSettings settings = new WebKitConverterSettings();
//Set the QtBinaries folder path
settings.WebKitPath= Path.Combine(_hostingEnvironment.ContentRootPath, "QtBinariesWindows");
//Assign WebKit settings to HTML converter
htmlConverter.ConverterSettings = settings;
//Convert URL to PDF
PdfDocument document = htmlConverter.Convert("https://www.google.com");
string path = _hostingEnvironment.ContentRootPath+ "\\wwwroot\\output.pdf";
FileStream file = new FileStream(path,FileMode.Create, FileAccess.Write);
document.Save(file);
document.Close(true);
Please try the above solution on your end and let us know if it suits your requirement.
Note: I work for Syncfusion.
Related
Recently i am trying to upload a file to IPFS and download/retrieve it using ipfs core api. And for this purpose a use .net library ipfs(c#) library. its works fine for a txt file but when i uploaded a pdf file and tries to download it gives me some kind of string.i thought that that string maybe my pdf file all content but that string proves me wrong. when i tries to compare my original pdf file string with (current string) that is totally diffferent..
my pdf file hash : QmWPCRv8jBfr9sDjKuB5sxpVzXhMycZzwqxifrZZdQ6K9o
and my c# code the get this(api) ==>
static void Main(string[] args)
{
var ipfs = new IpfsClient();
const string filename = "QmWPCRv8jBfr9sDjKuB5sxpVzXhMycZzwqxifrZZdQ6K9o";
var text = ipfs.FileSystem.ReadAllTextAsync(filename).Result;
}
my question is whtat i have done wrong and i have done some wrong then how can i get a pdf file ?? how ??
First of all please check if you can access to the file from live environment:
e.g.
https://ipfs.infura.io/ipfs/QmNtg1uDy1A71udMa2ipTfKghArRQFspfFkncunamW29SA
https://ipfs.io/ipfs/
if the file was uploaded correctly you can IpfsClient package to do this action:
Define property that references on ipfs env (e.g. via infura)
_ipfsClient = new IpfsClient("https://ipfs.infura.io:5001");
Introduce method to download the file by hash
public async Task<byte[]> DownloadAsync(string hash)
{
using (var stream = await _ipfsClient.FileSystem.ReadFileAsync(hash))
{
using (var ms = new MemoryStream())
{
stream.CopyTo(ms);
return ms.ToArray();
}
}
}
If you use web api - introduce controller to return exactly pdf
public async Task<IActionResult> Get(string hash)
{
var data = await _ipfsDownloadService.DownloadAsync(hash);
return File(data, "application/pdf");
}
I have to get html response from another website and load to my application. I written below code,
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
namespace MVC_TEST.Controllers
{
public class DocumentCloudController : Controller
{
public string Index()
{
var result = GetResponse();
return result;
}
private static string GetResponse()
{
var html = string.Empty;
const string url = #"http://localhost/xxxxx/yyyyy/logon.aspx";
var request = (HttpWebRequest)WebRequest.Create(url);
request.AutomaticDecompression = DecompressionMethods.GZip;
using (var response = (HttpWebResponse)request.GetResponse())
{
using (var stream = response.GetResponseStream())
{
if (stream != null)
{
using (var reader = new StreamReader(stream))
{
html = reader.ReadToEnd();
}
}
}
}
return html;
}}
}
}
Controls are loaded properly, But image, css and js path is mapped to relative path
/xxxx/yyyy/dojo.js ,
/xxxx/style/logon.css,
/xxxx/images/logon.png
in html, here i have to change that to actual url like below
http://localhost/xxxx/yyyy/dojo.js ,
http://localhost/xxxx/style/logon.js ,
http://localhost/xxxx/images/logon.png
One option is find these content in html replace that.
Is there any other option to change url dynamically ?
Is IIS URL Rewrite module will suitable for my requirement ?
Please share your thoughts
Using IIS URL Rewrite Module could work but I would recommend using a HTML parser like HTML Agility Pack or AngleSharp to query and manipulate the DOM.
The example below is a snippet that worked for me when creating a reverse proxy:
foreach (var link in document.DocumentNode.SelectNodes("//link[#href]"))
{
var orgHrefValue = link.GetAttributeValue("href", string.Empty);
var updHrefValue = string.Concat("[BASE URL]", GetAbsoluteUrlString(requestedUrl, orgHrefValue).AbsoluteUri);
link.SetAttributeValue("href", updHrefValue);
}
private static Uri GetAbsoluteUrlString(string baseUrl, string url)
{
var uri = new Uri(url, UriKind.RelativeOrAbsolute);
if (!uri.IsAbsoluteUri)
uri = new Uri(new Uri(baseUrl), uri);
return uri;
}
I have created a simple app in WP8 to display web pages using the Microsoft.Phone.Controls.WebBrowser class.
I am able to load the page, navigate links, move back and forward in history.
Apart from this basic functionality I also want to provide means to download files which cannot be displayed within the browser like say .ppt or .mp3.
I have not been able to find anything in the WebBrowser class documentation to initiate a download. There is just a Navigate function which takes a URL to load.
So can a download be done using WebBrowser class?
You'll have to intercept the navigation events and handle it on your own.
The following code sample should point you in the right direction. (You'll want to polish that up, I just put that together to show it can work with a random mp3 site that came up on Google when I searched for test mp3 files)
using Microsoft.Phone.Controls;
using System;
using System.IO;
using System.IO.IsolatedStorage;
using System.Net;
using System.Threading.Tasks;
using System.Windows;
namespace PhoneApp2
{
public partial class MainPage
{
public MainPage()
{
InitializeComponent();
MyWebBrowser.Navigate(new Uri("http://robtowns.com/music/"));
}
private async void MyWebBrowser_OnNavigating(object sender, NavigatingEventArgs e)
{
if (!e.Uri.AbsolutePath.EndsWith(".mp3")) return; //Find a more reliable way to detect mp3 files
e.Cancel = true; // Cancel the browser control navigation, and take over from here
MessageBox.Show("Now downloading an mp3 file");
var fileWebStream = await GetStream(e.Uri);
using(var isolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
var filePath = "downloadedfile.mp3";
var localFile = isolatedStorage.CreateFile(filePath);
await fileWebStream.CopyToAsync(localFile.AsOutputStream().AsStreamForWrite());
fileWebStream.Close();
MessageBox.Show("File saved as 'downloadedfile.mp3'");
}
}
public static Task<Stream> GetStream(Uri url)
{
var tcs = new TaskCompletionSource<Stream>();
var wc = new WebClient();
wc.OpenReadCompleted += (s, e) =>
{
if (e.Error != null) tcs.TrySetException(e.Error);
else if (e.Cancelled) tcs.TrySetCanceled();
else tcs.TrySetResult(e.Result);
};
wc.OpenReadAsync(url);
return tcs.Task;
}
}
}
I have a specialised case where I wish to serve a straight html file from a Controller Action.
I want to serve it from a different folder other than the Views folder. The file is located in
Solution\Html\index.htm
And I want to serve it from a standard controller action. Could i use return File? And
how do I do this?
Check this out :
public ActionResult Index()
{
return new FilePathResult("~/Html/index.htm", "text/html");
}
If you want to render this index.htm file in the browser then you could create controller action like this:
public void GetHtml()
{
var encoding = new System.Text.UTF8Encoding();
var htm = System.IO.File.ReadAllText(Server.MapPath("/Solution/Html/") + "index.htm", encoding);
byte[] data = encoding.GetBytes(htm);
Response.OutputStream.Write(data, 0, data.Length);
Response.OutputStream.Flush();
}
or just by:
public ActionResult GetHtml()
{
return File(Server.MapPath("/Solution/Html/") + "index.htm", "text/html");
}
So lets say this action is in Home controller and some user hits http://yoursite.com/Home/GetHtml then index.htm will be rendered.
EDIT: 2 other methods
If you want to see raw html of index.htm in the browser:
public ActionResult GetHtml()
{
Response.AddHeader("Content-Disposition", new System.Net.Mime.ContentDisposition { Inline = true, FileName = "index.htm"}.ToString());
return File(Server.MapPath("/Solution/Html/") + "index.htm", "text/plain");
}
If you just want to download file:
public FilePathResult GetHtml()
{
return File(Server.MapPath("/Solution/Html/") + "index.htm", "text/html", "index.htm");
}
I extended wahid's answer to create HtmlResult
Create Html Result which extends FilePathResult
public class HtmlResult : FilePathResult
{
public HtmlResult(string path)
: base(path, "text/html")
{
}
}
Created static method on controller
public static HtmlResult Html(this Controller controller, string path)
{
return new HtmlResult(path);
}
used like we return view
public HtmlResult Index()
{
return this.Html("~/Index.html");
}
Hope it helps
I want put my two cents in. I have found this most terse and it is there already :
public ActionResult Index()
{
var encoding = new System.Text.UTF8Encoding();
var html = ""; //get it from file, from blob or whatever
return this.Content(html, "text/html; charset=utf-8");
}
Can you read the html file in a string and return it in action? It is rendered as Html page as shown below:
public string GetHtmlFile(string file)
{
file = Server.MapPath("~/" + file);
StreamReader streamReader = new StreamReader(file);
string text = streamReader.ReadToEnd();
streamReader.Close();
return text;
}
Home/GetHtmlFile?file=Solution\Html\index.htm
If the destination or storage mechanism of HTML files is complicated then you can you Virtual path provider
Virtual path provider MVC sample
Alternative approach if using .net core is to use a FileProvider.
The files could be in a folder or embedded at compile time.
In this example we will use embedded files.
Add a folder in your project let's say assets, in it create a file myfile.html, add some basic html to the file say
<html>
<head>
<title>Test</title>
</head>
<body>
Hello World
</body>
</html>
Right click on the new file (assuming you are in visual studio) select properties, in the properties screen / build action, select embedded resource. It will add the file to the csproj file.
Right click on your project, edit your csproj file.
Check that your property group contains the following:
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
If not please add it. The csproj should also contain the newly created html file as:
<ItemGroup>
<EmbeddedResource Include="assets\myfile.html" />
</ItemGroup>
To read the file in your controller and pass it to the client requires a file provider which is added to the startup.cs
Edit your startup.cs make sure it includes the HostingEnvironment:
private readonly IHostingEnvironment HostingEnvironment;
public Startup(IHostingEnvironment hostingEnvironment)
{
HostingEnvironment = hostingEnvironment;
}
Then create a file provider and make it a service that can be injected at runtime. Create it as follows:
var physicalProvider = HostingEnvironment.ContentRootFileProvider;
var manifestEmbeddedProvider =
new ManifestEmbeddedFileProvider(Assembly.GetEntryAssembly());
var compositeProvider =
new CompositeFileProvider(physicalProvider, manifestEmbeddedProvider);
services.AddSingleton<IFileProvider>(compositeProvider);
To serve the file go to your controller, use dependency injection to get the FileProvider, create a new service and serve the file. To do this, start with dependency injection by adding the provider to your constructor.
IFileProvider _fileProvider;
public MyController(IFileProvider fileProvider)
{
this._fileProvider = fileProvider;
}
Then use the file provider in your service
[HttpGet("/myfile")]
[Produces("text/html")]
public Stream GetMyFile()
{
// Use GetFileInfo to get details on the file passing in the path added to the csproj
// Using the fileInfo returned create a stream and return it.
IFileInfo fileinfo = _fileProvider.GetFileInfo("assets/myfile.html");
return fileinfo.CreateReadStream();
}
For more info see ASP .Net Core file provider sample and the Microsoft documentation here.
I'm using the following to convert HTML to PDF:
InputStream convert(InputStream fileInputStream) {
PipedInputStream inputStream = new PipedInputStream()
PipedOutputStream outputStream = new PipedOutputStream(inputStream)
new Thread({
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(false);
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(fileInputStream)
ITextRenderer renderer = new ITextRenderer()
renderer.setDocument(document, "")
renderer.layout()
renderer.createPDF(outputStream)
}).start()
return inputStream
}
From the documentation, apparently I should be able to set a "User Agent" resolver somewhere, but I'm not sure where, exactly. Anyone know how to ignore external CSS in a document?
Not the same question but my answer for that one will work here too: Resolving protected resources with Flying Saucer (ITextRenderer)
Override this method:
public CSSResource getCSSResource(String uri) {
return new CSSResource(resolveAndOpenStream(uri));
}
with
public CSSResource getCSSResource(String uri) {
return new CSSResource(new ByteArrayInputStream([] as byte[]));
}