ASP.NET MVC Image Uploader for CKEditor? - asp.net

we have a textarea using CKEditor 4.4 on our admin website where users can edit content. They would like to be able to add images from their computer and have them uploaded automatically to the server for hosting.
I've seen a number of image upload scripts for CKEditor, but they all come with a PHP back-end. Does one exist for ASP.NET MVC 4?
I've seen this post and this one which show server-side controls for WebForms, but haven't been able to find an MVC version that we could drop in, or modify to our tastes.
Is my only option to use one of the existing PHP plugins and rewrite the endpoints as ASP.NET MVC?
Thanks.

Based on Alfonso's WebForms code mentioned in the accepted answer, I ended up using a script similar to this in MVC:
using System.Web;
using System.Web.Mvc;
namespace WebApplication1.Controllers
{
public class CKEditorController : Controller
{
const string basePath = #"D:\CKFinder\ckfinder\userfiles\";
const string baseUrl = #"/ckfinder/userfiles/";
const string scriptTag = "<script type='text/javascript'>window.parent.CKEDITOR.tools.callFunction({0}, '{1}', '{2}')</script>";
public ActionResult Index()
{
var funcNum = 0;
int.TryParse(Request["CKEditorFuncNum"], out funcNum);
if (Request.Files == null || Request.Files.Count < 1)
return BuildReturnScript(funcNum, null, "No file has been sent");
if (!System.IO.Directory.Exists(basePath))
return BuildReturnScript(funcNum, null, "basePath folder doesn't exist");
var receivedFile = Request.Files[0];
var fileName = receivedFile.FileName;
if (string.IsNullOrEmpty(fileName))
{
return BuildReturnScript(funcNum, null, "File name is empty");
}
var sFileName = System.IO.Path.GetFileName(fileName);
var nameWithFullPath = System.IO.Path.Combine(basePath, sFileName);
//Note: you may want to consider using your own naming convention for files, as this is vulnerable to overwrites
//e.g. at the moment if two users uploaded a file called image1.jpg, one would clash with the other.
//In the past, I've used Guid.NewGuid() combined with the file extension to ensure uniqueness.
receivedFile.SaveAs(nameWithFullPath);
var url = baseUrl + sFileName;
return BuildReturnScript(funcNum, url, null);
}
private ContentResult BuildReturnScript(int functionNumber, string url, string errorMessage)
{
return Content(
string.Format(scriptTag, functionNumber, HttpUtility.JavaScriptStringEncode(url ?? ""), HttpUtility.JavaScriptStringEncode(errorMessage ?? "")),
"text/html"
);
}
}
}

These aren't exactly MVC samples, but you can find a sample in VB.Net and C# to handle uploads from CKEditor: https://github.com/AlfonsoML/CKEditorUploader
Pick the code that you want and adjust it to your CMS.

The plugin sends the image asynchronously to the server. As long as you have an ASP.NET MVC/Web Api end point to accept the image and save it to the relavant place/update relevant tables, You should be good. Make sure you return data which your plugin is expecting.
for example, from the demo page you provided, the PHP server page is returning the following string on successful upload of the image
<script type="text/javascript">
window.parent.CKEDITOR.tools.callFunction("92", "\/userfiles\/images\/myImgy.jpg", "");
</script>
In your Web api endpoint, You can use HttpContext.Current.Request.Files collection to look for the posted files.

Try this
Html and JavaScript
<script src="~/Vendors/ckeditor/ckeditor.js"></script>
<script src="~/Vendors/ckeditor/adapters/jquery.js"></script>
<div class="jumbotron">
<textarea name="editor1"></textarea>
<script>
CKEDITOR.replace('editor1', {
uiColor: '#9AB8F3',
filebrowserUploadUrl: '/CkEditorUpload/'
});
</script>
</div>
Controller
using System;
using System.IO;
using System.Web;
using System.Web.Mvc;
namespace ImageUploadCkEditor.Controllers
{
public class CkEditorUploadController : Controller
{
const string filesavepath = "~/Content/Uploads/Ckeditor";
const string baseUrl = #"/Content/Uploads/Ckeditor/";
const string scriptTag = "<script type='text/javascript'>window.parent.CKEDITOR.tools.callFunction({0}, '{1}', '{2}')</script>";
public ActionResult Index()
{
var funcNum = 0;
int.TryParse(Request["CKEditorFuncNum"], out funcNum);
if (Request.Files == null || Request.Files.Count < 1)
return BuildReturnScript(funcNum, null, "No file has been sent");
string fileName = string.Empty;
SaveAttatchedFile(filesavepath, Request, ref fileName);
var url = baseUrl + fileName;
return BuildReturnScript(funcNum, url, null);
}
private ContentResult BuildReturnScript(int functionNumber, string url, string errorMessage)
{
return Content(
string.Format(scriptTag, functionNumber, HttpUtility.JavaScriptStringEncode(url ?? ""), HttpUtility.JavaScriptStringEncode(errorMessage ?? "")),
"text/html"
);
}
private void SaveAttatchedFile(string filepath, HttpRequestBase Request, ref string fileName)
{
for (int i = 0; i < Request.Files.Count; i++)
{
var file = Request.Files[i];
if (file != null && file.ContentLength > 0)
{
fileName = Path.GetFileName(file.FileName);
string targetPath = Server.MapPath(filepath);
if (!Directory.Exists(targetPath))
{
Directory.CreateDirectory(targetPath);
}
fileName = Guid.NewGuid() + fileName;
string fileSavePath = Path.Combine(targetPath, fileName);
file.SaveAs(fileSavePath);
}
}
}
}
}

Related

How to write HTTP post sending an image file (.jpg/.png) in Unity by using UnityWebRequest?

I want to do a post request in Unity using UnityWebRequest. I have to send a jpg image or png image and the api has to response with a string message or int code.
How to write the C# Script to send the data through post?
Check this out I'm using this method for a long time and it's working for me.
public static IEnumerator CallAPIwithPostAndFileData1(string api_url, List<FileDetails> files, Action<string> callback)
{
WWWForm form = new WWWForm();
int i = 0;
foreach (FileDetails file in files)
{
i++;
UnityWebRequest localFile = UnityWebRequest.Get(#"file://" + file.filePath);
yield return localFile;
form.AddBinaryData("image[]", localFile.downloadHandler.data, file.fileName, "image/" + file.fileType);
}
UnityWebRequest request = UnityWebRequest.Post(api_url, form);
request.SetRequestHeader("Content-Type", "application/json");
request = APIHelper.setAuthToRequest(request, AuthType.BASIC);
request.SendWebRequest();
while (!request.isDone)
{
downloadProgress = request.downloadProgress * 100;
yield return null;
}
if (request.isDone && (!request.isHttpError || !request.isNetworkError))
{
callback(request.downloadHandler.text);
}
else if (request.isHttpError || request.isNetworkError)
{
Debug.LogError(request.error);
}
}
FileDetails This class is only holding some necessary values for me like filepath, fileName, and filetype. It's a bit too long let me know if you don't understand anything.

ASP.NET URL OF IMAGE does not exist

I have created a blog with ASP.NET MVC 4.
The problem is when my url is not localhost I cannot see any pictures inside my Posts, because they get wrong url. The url of the post can be:
1.localhost/post/2015/4/name_of_post or
2.localhost/archive/name_of_post or
3.localhost/name_of_category/name_of_post ,
and inside the post is the picture.
The picture must have this
url:localhost/App_Files/Upload/name_of_image.jpg
but gets instead this
url:localhost/post/2015/4/App_Files/Upload/name_of_image.jpg or
localhost/archive/name_of_post or
localhost/name_of_category/App_Files/Upload/name_of_image.jpg.
If you use the right url you will see the picture in browser.
I use tinymce to add pictures inside the the post when i create it. The picture is saved as file in the App_Files/Upload folder. The post is inserted in a row as html in sql database. I use this routeConfig
routes.MapRoute(
"Post",
"Archive/{year}/{month}/{title}",
new { controller = "Blog", action = "Post" }
);
and the uploadController is this:
using HotNews.ViewModels;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace HotNews.Controllers
{
public class UploadController : Controller
{
//
// GET: /Upload/
public ActionResult Index(string id)
{
//var url = HttpRuntime.AppDomainAppVirtualPath;
var url = ConfigurationManager.AppSettings["BlogUrl"];
return View(new UploadViewModel
{
baseUrl = url,
track = id
});
}
[HttpPost]
public ActionResult UploadFile()
{
var file = Request.Files[0];
if (file != null && file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/App_Files/Upload"), fileName);
file.SaveAs(path);
}
return RedirectToAction("Index");
}
public ActionResult ListFiles()
{
var fileData = new List<ViewDataUploadFileResults>();
DirectoryInfo dir = new DirectoryInfo(Server.MapPath("~/App_Files/Upload"));
if (dir.Exists)
{
string[] extensions = MimeTypes.ImageMimeTypes.Keys.ToArray();
FileInfo[] files = dir.EnumerateFiles()
.Where(f => extensions.Contains(f.Extension.ToLower()))
.ToArray();
if (files.Length > 0)
{
foreach (FileInfo file in files)
{
// var baseurl = ConfigurationManager.AppSettings["BlogUrl"];
var relativePath = VirtualPathUtility.ToAbsolute("~/App_Files/Upload") + "/" + file.Name;
fileData.Add(new ViewDataUploadFileResults()
{
// url = baseurl+relativePath,
url = relativePath,
name = file.Name,
type = MimeTypes.ImageMimeTypes[file.Extension],
size = Convert.ToInt32(file.Length)
});
}
}
}
return Json(fileData, JsonRequestBehavior.AllowGet);
}
}
}
Must I create an image hanndler?? Must I create a new routeconfig?? And what kind??

Generating PDFs using Phantom JS on .NET applications

I have been looking into phantomJS and looks like it could be a great tool to use generating PDFs. I wonder if anyone have successfully used it for their .NET applications.
My specific question is: how would you use modules like rasterize.js on the server, receive requests and send back generated pdfs as a response.
My general question is: is there any best practice for using phantomJS with .NET Applications. What would be the best way to achieve it?
I am fairly new in .NET World and I would appreciate the more detailed answers. Thanks everyone. :)
I don't know about best practices, but, I'm using phantomJS with no problems with the following code.
public ActionResult DownloadStatement(int id)
{
string serverPath = HttpContext.Server.MapPath("~/Phantomjs/");
string filename = DateTime.Now.ToString("ddMMyyyy_hhmmss") + ".pdf";
new Thread(new ParameterizedThreadStart(x =>
{
ExecuteCommand("cd " + serverPath + #" & phantomjs rasterize.js http://localhost:8080/filetopdf/" + id.ToString() + " " + filename + #" ""A4""");
})).Start();
var filePath = Path.Combine(HttpContext.Server.MapPath("~/Phantomjs/"), filename);
var stream = new MemoryStream();
byte[] bytes = DoWhile(filePath);
return File(bytes, "application/pdf", filename);
}
private void ExecuteCommand(string Command)
{
try
{
ProcessStartInfo ProcessInfo;
Process Process;
ProcessInfo = new ProcessStartInfo("cmd.exe", "/K " + Command);
ProcessInfo.CreateNoWindow = true;
ProcessInfo.UseShellExecute = false;
Process = Process.Start(ProcessInfo);
}
catch { }
}
public ViewResult FileToPDF(int id)
{
var viewModel = file.Get(id);
return View(viewModel);
}
private byte[] DoWhile(string filePath)
{
byte[] bytes = new byte[0];
bool fail = true;
while (fail)
{
try
{
using (FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
bytes = new byte[file.Length];
file.Read(bytes, 0, (int)file.Length);
}
fail = false;
}
catch
{
Thread.Sleep(1000);
}
}
System.IO.File.Delete(filePath);
return bytes;
}
Here is the action flow:
The user clicks on a link to DownloadStatement Action. Inside there, a new Thread is created to call the ExecuteCommand method.
The ExecuteCommand method is responsible to call phantomJS. The string passed as an argument do the following.
Go to the location where the phantomJS app is and, after that, call rasterize.js with an URL, the filename to be created and a print format. (More about rasterize here).
In my case, what I really want to print is the content delivered by the action filetoupload. It's a simple action that returns a simple view. PhantomJS will call the URL passed as parameter and do all the magic.
While phantomJS is still creating the file, (I guess) I can not return the request made by the client. And that is why I used the DoWhile method. It will hold the request until the file is created by phantomJS and loaded by the app to the request.
If you're open to using NReco.PhantomJS, which provides a .NET wrapper for PhantomJS, you can do this very succinctly.
public async Task<ActionResult> DownloadPdf() {
var phantomJS = new PhantomJS();
try {
var temp = Path.Combine(Path.GetTempPath(),
Path.ChangeExtension(Path.GetRandomFileName(), "pdf")); //must end in .pdf
try {
await phantomJS.RunAsync(HttpContext.Server.MapPath("~/Scripts/rasterize.js"),
new[] { "https://www.google.com", temp });
return File(System.IO.File.ReadAllBytes(temp), "application/pdf");
}
finally {
System.IO.File.Delete(temp);
}
}
finally {
phantomJS.Abort();
}
}
Here's some very basic code to generate a PDF using Phantom.JS but you can find more information here: https://buttercms.com/blog/generating-pdfs-with-node
var webPage = require('webpage');
var page = webPage.create();
page.viewportSize = { width: 1920, height: 1080 };
page.open("http://www.google.com", function start(status) {
page.render('google_home.pdf, {format: 'pdf', quality: '100'});
phantom.exit();
});

Using Url.Content() when sending an html email with images

I need my app to send a confirmation email to a user. I have used the following method to render the view as a string:
public string RenderViewToString<T>(string viewPath, T model)
{
using (var writer = new StringWriter())
{
var view = new WebFormView(viewPath);
var vdd = new ViewDataDictionary<T>(model);
var viewCxt = new ViewContext(ControllerContext, view, vdd, new TempDataDictionary(), writer);
viewCxt.View.Render(viewCxt, writer);
return writer.ToString();
}
}
which I got from here. It works great, however my images aren't being included. I'm using:
<img src="<%:Url.Content("~/Resource/confirmation-email/imageName.png") %>"
which is giving me
http://resource/confirmation-email/imageName.png
This works fine when viewing the page on the site, however the image links don't work in the email.
I need it to give me me:
http://domain.com/application/resource/confirmation-email/imageName.png
I've also tried using:
VirtualPathUtility.ToAbsolute()
This is what I used on a site recently:
public static string ResolveServerUrl(string serverUrl, bool forceHttps = false, bool getVirtualPath = true)
{
if (getVirtualPath)
serverUrl = VirtualPathUtility.ToAbsolute(serverUrl);
if (serverUrl.IndexOf("://") > -1)
return serverUrl;
string newUrl = serverUrl;
Uri originalUri = System.Web.HttpContext.Current.Request.Url;
newUrl = (forceHttps ? "https" : originalUri.Scheme) + "://" + originalUri.Authority + newUrl;
return newUrl;
}
I could then use it to generate Absolute urls by doing Core.ResolveServerUrl("~/Resource/confirmation-email/imageName.png"); (assuming you wrap the static function in a class named Core)
HTH
There isn't a way to do this. You can add the following extension method.
using System.Web.Mvc;
public static class UrlHelperExtensions
{
public static string ToAbsoluteUrl(this UrlHelper helper, string relativeUrl) {
if (Request.IsSecureConnection)
return string.Format("https://{0}{1}", Request.Url.Host, Page.ResolveUrl(relativeUrl));
else
return string.Format("http://{0}{1}", Request.Url.Host, Page.ResolveUrl(relativeUrl));
}
}
Which you can then call like so
<img src="<%:Url.ToAbsoluteUrl("~/Resource/confirmation-email/imageName.png") %>" ...

Can an ASP.NET MVC controller return an Image?

Can I create a Controller that simply returns an image asset?
I would like to route this logic through a controller, whenever a URL such as the following is requested:
www.mywebsite.com/resource/image/topbanner
The controller will look up topbanner.png and send that image directly back to the client.
I've seen examples of this where you have to create a View - I don't want to use a View. I want to do it all with just the Controller.
Is this possible?
Use the base controllers File method.
public ActionResult Image(string id)
{
var dir = Server.MapPath("/Images");
var path = Path.Combine(dir, id + ".jpg"); //validate the path for security or use other means to generate the path.
return base.File(path, "image/jpeg");
}
As a note, this seems to be fairly efficient. I did a test where I requested the image through the controller (http://localhost/MyController/Image/MyImage) and through the direct URL (http://localhost/Images/MyImage.jpg) and the results were:
MVC: 7.6 milliseconds per photo
Direct: 6.7 milliseconds per photo
Note: this is the average time of a request. The average was calculated by making thousands of requests on the local machine, so the totals should not include network latency or bandwidth issues.
Using the release version of MVC, here is what I do:
[AcceptVerbs(HttpVerbs.Get)]
[OutputCache(CacheProfile = "CustomerImages")]
public FileResult Show(int customerId, string imageName)
{
var path = string.Concat(ConfigData.ImagesDirectory, customerId, "\\", imageName);
return new FileStreamResult(new FileStream(path, FileMode.Open), "image/jpeg");
}
I obviously have some application specific stuff in here regarding the path construction, but the returning of the FileStreamResult is nice and simple.
I did some performance testing in regards to this action against your everyday call to the image (bypassing the controller) and the difference between the averages was only about 3 milliseconds (controller avg was 68ms, non-controller was 65ms).
I had tried some of the other methods mentioned in answers here and the performance hit was much more dramatic... several of the solutions responses were as much as 6x the non-controller (other controllers avg 340ms, non-controller 65ms).
To expland on Dyland's response slightly:
Three classes implement the FileResult class:
System.Web.Mvc.FileResult
System.Web.Mvc.FileContentResult
System.Web.Mvc.FilePathResult
System.Web.Mvc.FileStreamResult
They're all fairly self explanatory:
For file path downloads where the file exists on disk, use FilePathResult - this is the easiest way and avoids you having to use Streams.
For byte[] arrays (akin to Response.BinaryWrite), use FileContentResult.
For byte[] arrays where you want the file to download (content-disposition: attachment), use FileStreamResult in a similar way to below, but with a MemoryStream and using GetBuffer().
For Streams use FileStreamResult. It's called a FileStreamResult but it takes a Stream so I'd guess it works with a MemoryStream.
Below is an example of using the content-disposition technique (not tested):
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult GetFile()
{
// No need to dispose the stream, MVC does it for you
string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "App_Data", "myimage.png");
FileStream stream = new FileStream(path, FileMode.Open);
FileStreamResult result = new FileStreamResult(stream, "image/png");
result.FileDownloadName = "image.png";
return result;
}
This might be helpful if you'd like to modify the image before returning it:
public ActionResult GetModifiedImage()
{
Image image = Image.FromFile(Path.Combine(Server.MapPath("/Content/images"), "image.png"));
using (Graphics g = Graphics.FromImage(image))
{
// do something with the Graphics (eg. write "Hello World!")
string text = "Hello World!";
// Create font and brush.
Font drawFont = new Font("Arial", 10);
SolidBrush drawBrush = new SolidBrush(Color.Black);
// Create point for upper-left corner of drawing.
PointF stringPoint = new PointF(0, 0);
g.DrawString(text, drawFont, drawBrush, stringPoint);
}
MemoryStream ms = new MemoryStream();
image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
return File(ms.ToArray(), "image/png");
}
You can create your own extension and do this way.
public static class ImageResultHelper
{
public static string Image<T>(this HtmlHelper helper, Expression<Action<T>> action, int width, int height)
where T : Controller
{
return ImageResultHelper.Image<T>(helper, action, width, height, "");
}
public static string Image<T>(this HtmlHelper helper, Expression<Action<T>> action, int width, int height, string alt)
where T : Controller
{
var expression = action.Body as MethodCallExpression;
string actionMethodName = string.Empty;
if (expression != null)
{
actionMethodName = expression.Method.Name;
}
string url = new UrlHelper(helper.ViewContext.RequestContext, helper.RouteCollection).Action(actionMethodName, typeof(T).Name.Remove(typeof(T).Name.IndexOf("Controller"))).ToString();
//string url = LinkBuilder.BuildUrlFromExpression<T>(helper.ViewContext.RequestContext, helper.RouteCollection, action);
return string.Format("<img src=\"{0}\" width=\"{1}\" height=\"{2}\" alt=\"{3}\" />", url, width, height, alt);
}
}
public class ImageResult : ActionResult
{
public ImageResult() { }
public Image Image { get; set; }
public ImageFormat ImageFormat { get; set; }
public override void ExecuteResult(ControllerContext context)
{
// verify properties
if (Image == null)
{
throw new ArgumentNullException("Image");
}
if (ImageFormat == null)
{
throw new ArgumentNullException("ImageFormat");
}
// output
context.HttpContext.Response.Clear();
context.HttpContext.Response.ContentType = GetMimeType(ImageFormat);
Image.Save(context.HttpContext.Response.OutputStream, ImageFormat);
}
private static string GetMimeType(ImageFormat imageFormat)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
return codecs.First(codec => codec.FormatID == imageFormat.Guid).MimeType;
}
}
public ActionResult Index()
{
return new ImageResult { Image = image, ImageFormat = ImageFormat.Jpeg };
}
<%=Html.Image<CapchaController>(c => c.Index(), 120, 30, "Current time")%>
Why not go simple and use the tilde ~ operator?
public FileResult TopBanner() {
return File("~/Content/images/topbanner.png", "image/png");
}
You can write directly to the response but then it isn't testable. It is preferred to return an ActionResult that has deferred execution. Here is my resusable StreamResult:
public class StreamResult : ViewResult
{
public Stream Stream { get; set; }
public string ContentType { get; set; }
public string ETag { get; set; }
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.ContentType = ContentType;
if (ETag != null) context.HttpContext.Response.AddHeader("ETag", ETag);
const int size = 4096;
byte[] bytes = new byte[size];
int numBytes;
while ((numBytes = Stream.Read(bytes, 0, size)) > 0)
context.HttpContext.Response.OutputStream.Write(bytes, 0, numBytes);
}
}
Below code utilizes System.Drawing.Bitmap to load the image.
using System.Drawing;
using System.Drawing.Imaging;
public IActionResult Get()
{
string filename = "Image/test.jpg";
var bitmap = new Bitmap(filename);
var ms = new System.IO.MemoryStream();
bitmap.Save(ms, ImageFormat.Jpeg);
ms.Position = 0;
return new FileStreamResult(ms, "image/jpeg");
}
UPDATE: There are better options than my original answer. This works outside of MVC quite well but it's better to stick with the built-in methods of returning image content. See up-voted answers.
You certainly can. Try out these steps:
Load the image from disk in to a byte array
cache the image in the case you expect more requests for the image and don't want the disk I/O (my sample doesn't cache it below)
Change the mime type via the Response.ContentType
Response.BinaryWrite out the image byte array
Here's some sample code:
string pathToFile = #"C:\Documents and Settings\some_path.jpg";
byte[] imageData = File.ReadAllBytes(pathToFile);
Response.ContentType = "image/jpg";
Response.BinaryWrite(imageData);
Hope that helps!
Solution 1: To render an image in a view from an image URL
You can create your own extension method:
public static MvcHtmlString Image(this HtmlHelper helper,string imageUrl)
{
string tag = "<img src='{0}'/>";
tag = string.Format(tag,imageUrl);
return MvcHtmlString.Create(tag);
}
Then use it like:
#Html.Image(#Model.ImagePath);
Solution 2: To render image from database
Create a controller method that returns image data like below
public sealed class ImageController : Controller
{
public ActionResult View(string id)
{
var image = _images.LoadImage(id); //Pull image from the database.
if (image == null)
return HttpNotFound();
return File(image.Data, image.Mime);
}
}
And use it in a view like:
# { Html.RenderAction("View","Image",new {id=#Model.ImageId})}
To use an image rendered from this actionresult in any HTML, use
<img src="http://something.com/image/view?id={imageid}>
This worked for me.
Since I'm storing images on a SQL Server database.
[HttpGet("/image/{uuid}")]
public IActionResult GetImageFile(string uuid) {
ActionResult actionResult = new NotFoundResult();
var fileImage = _db.ImageFiles.Find(uuid);
if (fileImage != null) {
actionResult = new FileContentResult(fileImage.Data,
fileImage.ContentType);
}
return actionResult;
}
In the snippet above _db.ImageFiles.Find(uuid) is searching for the image file record in the db (EF context). It returns a FileImage object which is just a custom class I made for the model and then uses it as FileContentResult.
public class FileImage {
public string Uuid { get; set; }
public byte[] Data { get; set; }
public string ContentType { get; set; }
}
you can use File to return a file like View, Content etc
public ActionResult PrintDocInfo(string Attachment)
{
string test = Attachment;
if (test != string.Empty || test != "" || test != null)
{
string filename = Attachment.Split('\\').Last();
string filepath = Attachment;
byte[] filedata = System.IO.File.ReadAllBytes(Attachment);
string contentType = MimeMapping.GetMimeMapping(Attachment);
System.Net.Mime.ContentDisposition cd = new System.Net.Mime.ContentDisposition
{
FileName = filename,
Inline = true,
};
Response.AppendHeader("Content-Disposition", cd.ToString());
return File(filedata, contentType);
}
else { return Content("<h3> Patient Clinical Document Not Uploaded</h3>"); }
}
Look at ContentResult. This returns a string, but can be used to make your own BinaryResult-like class.
if (!System.IO.File.Exists(filePath))
return SomeHelper.EmptyImageResult(); // preventing JSON GET/POST exception
else
return new FilePathResult(filePath, contentType);
SomeHelper.EmptyImageResult() should return FileResult with existing image (1x1 transparent, for example).
This is easiest way if you have files stored on local drive.
If files are byte[] or stream - then use FileContentResult or FileStreamResult as Dylan suggested.
I see two options:
1) Implement your own IViewEngine and set the ViewEngine property of the Controller you are using to your ImageViewEngine in your desired "image" method.
2) Use a view :-). Just change the content type etc.
You could use the HttpContext.Response and directly write the content to it (WriteFile() might work for you) and then return ContentResult from your action instead of ActionResult.
Disclaimer: I have not tried this, it's based on looking at the available APIs. :-)
I also encountered similar requirement,
So in my case I make a request to Controller with the image folder path, which in return sends back a ImageResult object.
Following code snippet illustrate the work:
var src = string.Format("/GenericGrid.mvc/DocumentPreviewImageLink?fullpath={0}&routingId={1}&siteCode={2}", fullFilePath, metaInfo.RoutingId, da.SiteCode);
if (enlarged)
result = "<a class='thumbnail' href='#thumb'>" +
"<img src='" + src + "' height='66px' border='0' />" +
"<span><img src='" + src + "' /></span>" +
"</a>";
else
result = "<span><img src='" + src + "' height='150px' border='0' /></span>";
And in the Controller from the the image path I produce the image and return it back to the caller
try
{
var file = new FileInfo(fullpath);
if (!file.Exists)
return string.Empty;
var image = new WebImage(fullpath);
return new ImageResult(new MemoryStream(image.GetBytes()), "image/jpg");
}
catch(Exception ex)
{
return "File Error : "+ex.ToString();
}
Read the image, convert it to byte[], then return a File() with a content type.
public ActionResult ImageResult(Image image, ImageFormat format, string contentType) {
using (var stream = new MemoryStream())
{
image.Save(stream, format);
return File(stream.ToArray(), contentType);
}
}
}
Here are the usings:
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using Microsoft.AspNetCore.Mvc;
Yes you can return Image
public ActionResult GetImage(string imageFileName)
{
var path = Path.Combine(Server.MapPath("/Images"), imageFileName + ".jpg");
return base.File(path, "image/jpeg");
}
(Please don't forget to mark this as answer)
From a byte[] under Core 3.2, you can use:
public ActionResult Img(int? id) {
MemoryStream ms = new MemoryStream(GetBytes(id));
return new FileStreamResult(ms, "image/png");
}

Resources