How to serve html file from another directory as ActionResult - html

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.

Related

How to add "allow-downloads" to the sandbox attributes list

I am trying to get files from my MVC project (asp.net core 3.1)
I created a link
<a asp-action="#nameof(HomeController.Download)" asp-controller="#HomeController.Name" asp-route-fileName="fileName.doc" download>FileName</a>
I created a controller
public async Task<ActionResult> Download(string fileName) {
var path = Path.Combine(_hostingEnvironment.WebRootPath, fileName);
if (!System.IO.File.Exists(path)) {
return NotFound();
}
var fileBytes = await System.IO.File.ReadAllBytesAsync(path);
var response = new FileContentResult(fileBytes, "application/vnd.openxmlformats-officedocument.wordprocessingml.document") {
FileDownloadName = fileName
};
return response;
}
In Chrome i get the warning
Download is disallowed. The frame initiating or instantiating the download is sandboxed, but the flag ‘allow-downloads’ is not set. See https://www.chromestatus.com/feature/5706745674465280 for more details.
Following the link, how can i add:
add "allow-downloads" to the sandbox attributes list to opt in
The file is downloaded if i click the button from Microsoft Edge
This is what I had to do for my project, hopefully it will point you to the right direction.
In your Startup.cs
services.AddMvc(options =>{
options.Filters.Add(new MyActionFilterAttribute());
}
Then in MyActionFilterAttribute.cs
public class MyActionFilterAttribute : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.HttpContext.Response.Headers.Add("Content-Security-Policy", "sandbox allow-downloads; " )
}
}

Problem Saving and Loading Json file in Unity

I'm currently trying to use gestures recognizers in Unity3D. For this I need a library of gestures to be compared with the gesture I'm making.
I'm using a script to save and load from another Unity user since I have no idea how to do it myself.
The problem I'm facing is:
If I save the gestures as json file during gameplay, I can compare them in the same run. But if I restart the run, it stops being able to read the json file and returns NULL or no match as if there were nothing in the json file.
[Serializable]
public class GestureTemplates
{
public List<DrawnGesture> templates;
public GestureTemplates()
{
templates = new List<DrawnGesture>();
}
}
private string gestureFileName = "gestures.json";
void Start () {
LoadTemplates();
}
private void SaveTemplates()
{
string filePath = Application.dataPath + "/streamingAssets/" + gestureFileName;
string saveData = JsonUtility.ToJson(templates);
File.WriteAllText(filePath, saveData);
Debug.Log("Template Saved");
}
private void LoadTemplates()
{
templates = new GestureTemplates();
string filePath = Path.Combine(Application.streamingAssetsPath, gestureFileName);
if (File.Exists(filePath))
{
string data = File.ReadAllText(filePath);
templates = JsonUtility.FromJson<GestureTemplates>(data);
}
}
What I've noticed is it takes a while to save, but it does in fact save since it calls the debug.Log line and the save file can be used in the same run.
Any help would be highly appreciated.
Edit: Nevermind. It's not saving either. It's saving as a Json file with an empty list. The variable is working on the run, but it's not saving nor loading.

How to download a pdf file from IPFS usng ipfs core api in .net?

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

ASP.NET-MVC5 input multiple files

I'm working on ASP.NET MVC-5 and i have a button that lets me select multiple files for input, so it works with this code
<input type="file" name="file" multiple>
How do i fetch the files to use them within my program logic in the [HttpPost] action from the controller?
In this case, you get the uploaded files from HttpPostedFileBase array in controller action.
[HttpPost]
public ActionResult Index(HttpPostedFileBase[] uploadedfiles)
{
try
{
// Loop through array fro getting files
foreach (HttpPostedFileBase file in files)
{
// get current file name
string filename = System.IO.Path.GetFileName(file.FileName);
//Saving the file in relative path (server folder)
file.SaveAs(Server.MapPath("~/Images/" + filename));
string filepathtosave = "Images/" + filename;
/* code for saving the image into database */
}
ViewBag.Message = "File Uploaded successfully.";
}
catch
{
ViewBag.Message = "Error while uploading the files.";
}
return View();
}

How to read appsettings.json in my _layout.chtml

I cannot seem to figure out how to read values from the appsettings.json in my _Layout.chtml file.
Is it not just available, something like this?
#Configuration["ApplicationInsights:InstrumentationKey"]
I created a new MVC project using razor pages.
fyi, i'm an mvc newbee - code samples help a lot.
In .net core mvc you can inject the configuration by adding the following two lines at the top of your view:
#using Microsoft.Extensions.Configuration
#inject IConfiguration Configuration
You can then access the value like this:
#Configuration.GetSection("ApplicationInsights")["InstrumentationKey"]
If you use the options pattern you can inject them into your view like this:
#using Microsoft.Extensions.Options
#inject IOptions<ApplicationInsightsOptions>
ApplicationInsightsOptionsAccessor
#
{
var instrumentationKey =
ApplicationInsightsOptionsAccessor.Value.InstrumentationKey;
}
Options pattern in ASP.NET Core
Using ActionFilters you can interrupt the request and add the configuration variables maybe to the ViewBag so it becomes accessible from the views or from the _Layout.cshtml File.
For example, if the following configuration section is inside your appsettings.json
{
"MyConfig": {
"MyValue": "abc-def"
}
}
In the code MyConfig.cs would be:
public class MyConfig
{
public string MyValue{ get; set; }
}
First create a very simple ActionFilter which derives from IAsyncActionFilter as following :
public class SampleActionFilter : IAsyncActionFilter
{
private MyConfig _options;
public SampleActionFilter(IConfiguration configuration)
{
_options = new MyConfig();
configuration.Bind(_options);
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
((Microsoft.AspNetCore.Mvc.Controller)context.Controller).ViewBag.MyConfig = _options;
await next();
}
}
Later in the Startup.ConfigureServices method change services.AddMvc to the following:
public void ConfigureServices(IServiceCollection services)
{
//..........
services.AddMvc(options=>
{
options.Filters.Add(new SampleActionFilter(
Configuration.GetSection("MyConfig")
));
});
//..........
}
To access the values just simply in the _Layout.cshtml or other view you can type:
#ViewBag.MyConfig.MyValue