The binary image can't display on view asp.net core 2.x - asp.net-core-mvc-2.0

I upload an image into a table with byte[] format. My problem is, that when I retrieve that on a view, the image won't show up.
Model
{
public byte[] image {get; set;}
}
Controller
public async Task<IActionResult> Create(Profile profile, IFormFile image)
{
if (ModelState.IsValid)
{
using (var memoryStream = new MemoryStream())
{
image.CopyTo(memoryStream);
profile.image = memoryStream.ToArray();
}
_context.Add(image);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(image);
}
View
<img src="#item.image" />

You cannot simply dump a byte array as the source of an HTML image tag. It has to be a URI. That typically means that you need an action that retrieves the image data from the database and returns it as file:
[HttpGet("profileimage")]
public async Task<IActionResult> GetProfileImage(int profileId)
{
var profile = _context.Profiles.FindAsync(profileId);
if (profile?.image == null) return NotFound();
return File(profile.image, "image/jpeg");
}
Then, you can do something like:
<img src="#Url.Action("GetProfileImage", new { profileId = item.Id })" />
Alternatively, you can use a Data URI. However, this will result in the entire image data being included in your HTML document, increasing the overall download time of the document and delaying rendering. Additionally, Data URIs must be Base64 encoded, which effectively increases the image size roughly 1.5 times. For small, simple images, it's not too big of a deal, but you definitely should avoid this approach with larger images. Anyways, doing this would look something like:
<img src="data:image/jpeg;base64,#Convert.ToBase64String(item.image)" />

Related

How to upload image in blob storage using ASP.NET MVC web app

I need to upload an image as I also create a new row in mysql database. The instruction given to me is that images should be stored in Azure blob storage while info are stored in mysql database.
This is my code for creating a new row
// POST: Books/Create
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult>Create([Bind("Id,Isbn,Price,Rank,Title,Genre,Author,Overview,Summary,Publisher,PubDate,Pages,Length,Width,Height,Weight")] Books books)
{
try
{
if (ModelState.IsValid)
{
var responseTask = Client.PostAsJsonAsync("api/Books", books);
responseTask.Wait();
var result = responseTask.Result;
if (result.IsSuccessStatusCode)
{
return RedirectToAction(nameof(Index));
}
}
}
catch
{
return BadRequest();
}
return View(books);
}
Now I don't have any idea what codes to put in so I can upload an image alongside it
Please help me I need to pass this project in 24hrs and I am still far from the projected outcome 🥺
So, at first, you need to add a new property which type is IFormFile into your Books model, so that when you creating a new row you can also get the Iformfile for the image.
Then pls follow this answer to upload your image to azure storage blob. Here's the code snippet when I test in my side:
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
[HttpPost]
public async Task<string> uploadFile(TestModel mod)
{
var connectionstring = "connection_string";
BlobServiceClient blobServiceClient = new BlobServiceClient(connectionstring);
BlobContainerClient blobContainerClient = blobServiceClient.GetBlobContainerClient("container_name");
await blobContainerClient.CreateIfNotExistsAsync();
BlobClient blobClent = blobContainerClient.GetBlobClient(mod.fileName);
BlobHttpHeaders httpheaders = new BlobHttpHeaders()
{
ContentType = mod.img.ContentType
};
await blobClent.UploadAsync(mod.img.OpenReadStream(), httpheaders);
return "success";
}

Get link to the file returned by a FileContentResult

In my controller I have created an action that returns images from a database. The images are stored as bytearrays, so I'm returning the contents as a FileContentResult.
In the view, I'm linking to this action with:
<img src="#Url.Action("GetImage", new { id=a.Id })"/>
The controller action looks like
public ActionResult GetImage(long id)
{
var article = SolrOperations.GetArticleById(id);
if (article != null && !string.IsNullOrEmpty(article.Image) && !string.IsNullOrEmpty(article.ImageType))
{
var imageBytes = Convert.FromBase64String(article.Image);
return new FileContentResult(imageBytes, article.ImageType);
}
return null;
}
This does not yield the desired behavior (even though the images are displayed), as I need the full link to the image, ie: /getimage/id.jpg instead of just /getimage/id. The reason for this is that I want to use ImageProcessor.Web to further process (and cache) the images by supplying a query string in the image src attribute (fx src="myimage.jpg?filter=greyscale").
If you want to axtend the link you can just extend your controller method signature, like this:
public ActionResult GetImage(long id , string src, string filter)
ASP.NET MVC will bind this values and on your View you can write like this:
<img src="#Url.Action("GetImage", new { id=a.Id, src = "myimage.jpg", filter = "greyscale" })"/>

Display a view as image in another view ASP.NET MVC4

I have created a view jpegImage.cshtml (not the partial view) and it has jpegImageController. Controller has Index method, which is writing an image to Output Stream.
In my main view testimage.cshtml, I am calling the jpegImage view as <img src="jpegImage.cshtml" />, which is not showing any image, while if I call the view by URL like http://<server>/jpegImage/Index, it returns the image.
Is there anything I am missing?
Below is my code
-----------JpegImageController.cs----------------
public ActionResult JpegImage()
{
Random random = new Random();
string s = "";
for (int i = 0; i < 6; i++)
s = String.Concat(s, random.Next(10).ToString());
this.Session["CaptchaImageText"] = s;
CaptchaImage ci = new CaptchaImage(this.Session["CaptchaImageText"].ToString(),200, 40, "Century Schoolbook");
this.Response.Clear();
this.Response.ContentType = "image/jpeg";
// Write the image to the response stream in JPEG format.
ci.Image.Save(this.Response.OutputStream, ImageFormat.Jpeg);
// Dispose of the CAPTCHA image object.
ci.Dispose();
return View();
}
CaptchaImage is class which is generating the image
--------------jpegImage.cshtml------------
#Html.BeginForm()
--------testImage.cshtml--------------
< img src="#Url.Content("~/views/JpegImage/JpegImage.cshtml")" alt="Captcha" />
Delete your jpegImage.cshtml. It is not necessary and kind of a waste to generate.
Change your JpegImageController.cs Action to:
public FileResult JpegImage()
{
Random random = new Random();
string s = "";
for (int i = 0; i < 6; i++)
s = String.Concat(s, random.Next(10).ToString());
Session["CaptchaImageText"] = s;
using (CaptchaImage ci = new CaptchaImage(Session["CaptchaImageText"].ToString(), 200, 40, "Century Schoolbook"))
{
// Write the image to a stream in JPEG format.
var output = new MemoryStream();
ci.Image.Save(output, ImageFormat.Jpeg);
return File(output, "image/jpeg");
}
}
In testImage.cshtml simply use:
<img src="#Url.Action("JpegImage")" alt="Captcha" />
Views like jpegImage.cshtml are not served directly by the web server. That is why your view is not being served when you request it in your image tag:
<img src="jpegImage.cshtml" />
Instead, views are rendered as the result of an action method returning a ViewResult. An action method, in turn, is invoked when you make a request for a URL that is routed to the action method. That is why your request for
http://<server>/jpegImage/Index
does return the image. In other words, your image tag should be
<img src="jpegImage/Index" />
(you can probably leave out the "Index" part, as that is probably configured as a default in your route).
By the way, if all you need is for your action to return an image, you don't need to return a ViewResult or to have a view (.cshtml file) at all. Consider just returning a FileResult:
public ActionResult Image(string id)
{
/* Generate your CaptchaImage and somehow get hold of a stream */
return base.File(steam, "image/jpeg");
}
As I don't know the library you are using for generating the image, I cannot tell you how to get a hold of a Stream, but you can probably figure that out yourself.

ASP.NET MVC 3 Preview Image

I'm using MVC 3 and using the AjaxUpload plugin to upload an image using AJAX. I don't want to save the image in the file system, instead save it to the session object and then output the stream to populate an image control on the form? Would anyone know how to do this?
No idea why would ever want to do that (store the file in session) because if you have lots of users uploading their files at the same time, storing those files in the memory of your web server, especially if those files are big, won't make this server last very long. Storing the file on the filesystem is the recommended approach.
But anyway, here's how you could do it (assuming you didn't read or cared about my previous remark):
[HttpPost]
public ActionResult Upload(MyViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var buffer = new byte[model.File.InputStream];
model.File.InputStream.Read(buffer, 0, buffer.Length);
Session["uploadedFile"] = buffer;
return View(model);
}
where the File property on the view models is a HttpPostedFileBase. Next you could have a controller action which will serve this file:
public ActionResult Image()
{
byte[] buffer = (byte[])Session["uploadedFile"];
return File(buffer, "image/png");
}
and in the view you will have an <img> tag pointing to this action:
<img src="#Url.Action("image")" alt="" />
Now of course the AjaxUpload plugin allows you to upload the file using AJAX, so you don't need to reload the entire page. So in this case your controller action could simply return a JSON object to indicate whether the upload process succeeded and then in the success callback set the src property of the <img> tag to the controller action that will serve the file.
SomeView.cshtml:
<img src="#Url.Action("/Image/Render")" />
ImageController.cs:
public ActionResult Render() {
return File((byte[])Session["Avatar"], "image/jpeg")
}
Some example code. Modify it to whatever you want to do. Not really a good idea to sling an image into a session if lots of users. Better to stick it into a db if short lived, or if long lived, a more permanent storage (filesystem maybe).
public ActionResult UploadImage()
{
foreach (string imageName in Request.Files)
{
HttpPostedFileBase file = Request.Files[imageName];
if (file.ContentLength > 0)
{
BinaryReader br = new BinaryReader(file.InputStream);
byte[] content = br.ReadBytes(file.ContentLength);
Session[imageName] = content; // better to store in a db here
}
}
return View();
}
// return the image (controller action) /mycontroller/ViewImage?imageName=whatever
public FileStreamResult ViewImage(string imageName)
{
byte[] content = (byte[])Session[imageName] ; // where ever your content is stored (ideally something other than session)
MemoryStream ms = new MemoryStream(content);
return new FileStreamResult(ms, "application/octet-stream"); // set content type based on input image, it might be png, jpg, gif etc.,
}
Hope this helps.

ASP.NET MVC Dynamically generated image URLs

I have an ASP.NET MVC application where I am displaying images.
These images could be located on the file system or inside a database. This is fine as I can use Url.Action in my image, call the action on my controller and return the image from the relevant location.
However, I want to be able to support images stored in Amazon S3. In this case, I don't want my controller action to return the image, it should instead generate an image URL for Amazon S3.
Although I could just perform this logic inside my view e.g.
<%if (Model.Images[0].ImageLocation == ImageLocation.AmazonS3) {%>
// render amazon image
I need to ensure that the image exists first.
Essentially I need to pass a size value to my controller so that I can check that the image exists in that size (whether it be in the database, file system or amazon s3). Once I am sure that the image exists, then I return the URL to it.
Hope that makes sense,
Ben
Try the following approach.
A model class for an image tag.
public class ImageModel
{
public String Source { get; set; }
public String Title { get; set; }
}
Helper
public static String Image(this HtmlHelper helper, String source, String title)
{
var builder = new TagBuilder("img");
builder.MergeAttribute("src", source);
builder.MergeAttribute("title", title);
return builder.ToString();
}
View with Model.Images of type IEnumerable<ImageModel>
...
<%= Html.Image(Model.Images[0].Source, Model.Images[0].Title) %>
Action
public ActionResult ActionName(/*whatever*/)
{
// ...
var model = ...;
//...
var model0 = ImageModel();
if (Image0.ImageLocation == ImageLocation.AmazonS3)
model0.Source = "an amazon url";
else
model0.Source = Url.Action("GetImageFromDatabaseOrFileSystem", "MyController", new { Id = Image0.Id });
model0.Title = "some title";
model.Images.Add(model0);
// ...
return View(model);
}
An action is a kind of a pseudo code, however the idea should be clear.
After several iterations I have come up with a workable solution, although I'm still not convinced its the best solution.
Originally I followed Anton's suggestion and just set the image url accordingly within my controller action. This was simple enough with the following code:
products.ForEach(p =>
{
p.Images[0].Url = _mediaService.GetImageUrl(p.Images[0], 200);
});
However, I soon found that this approach did not give me the flexibility I needed. Often I will need to display images of different sizes and I don't want to use properties of my model for this such as Product.FullSizeImageUrl, Product.ThumbnailImageUrl.
As far as "Product" is concerned it only knows about the images that were originally uploaded. It doesn't need to know about how we manipulate and display them, or whether we are caching them in Amazon S3.
In web forms I might use a user control to display product details and then use a repeater control to display images, setting the image urls programatically in code behind.
I found that the use of RenderAction in ASP.NET MVC gave me similar flexibility:
Controller Action:
[ChildActionOnly]
public ActionResult CatalogImage(CatalogImage image, int targetSize)
{
image.Url = _mediaService.GetImageUrl(image, targetSize);
return PartialView(image);
}
Media Service:
public MediaCacheLocation CacheLocation { get; set; }
public string GetImageUrl(CatalogImage image, int targetSize)
{
string imageUrl;
// check image exists
// if not exist, load original image from store (fs or db)
// resize and cache to relevant cache location
switch (this.CacheLocation) {
case MediaCacheLocation.FileSystem:
imageUrl = GetFileSystemImageUrl(image, targetSize);
break;
case MediaCacheLocation.AmazonS3:
imageUrl = GetAmazonS3ImageUrl(image, targetSize);
break;
default:
imageUrl = GetDefaultImageUrl();
break;
}
return imageUrl;
}
Html helper:
public static void RenderCatalogImage(this HtmlHelper helper, CatalogImage src, int size) {
helper.RenderAction("CatalogImage", "Catalog", new { image = src, targetSize = size });
}
Usage:
<%Html.RenderCatalogImage(Model.Images[0], 200); %>
This now gives me the flexibility I require and will support both caching the resized images to disk or saving to Amazon S3.
Could do with some url utility methods to ensure that the generated image URL supports SSL / virtual folders - I am currently using VirtualPathUtility.
Thanks
Ben
You can create a HttpWebRequest to load the image. Check the header in the response, if it's 200 that means it was successful, otherwise something went wrong.

Resources