I have created a visualforce page which has attachment upload feature.
The attachment gets uploaded under a custom object invoice.
Now this page is accessible to internal users using tab and also available publicly on salesforce sites.
Upload feature work perfect in salesforce instance, but when uploading the attachment on sites, the attachment variable does not set.
here is the snippet: (Not complete code)
<apex:outputPanel id="AddAttachmentinner">
<div class="slds-form-element">
<label class="slds-form-element__label">Select Relevant Attachment:</label>
<br/>
<apex:inputFile title="Choose File" value="{!filebody}" filename="{!filename}" />
<br/> Please select only pdf, xls, doc, jpg, tiff, png type of files
</div>
</apex:outputPanel>
public pagereference SubmitInvoice(){
public String filename {
get;
set;
}
public Blob filebody {
get;
set;
}
public Attachment attachment {
get;
set;
}
if (filebody != null && filename != null && filename != '') {
attachment.Name = filename;
attachment.Body = filebody;
attachment.OwnerId = UserInfo.getUserId();
attachment.ParentId = newInvoice.Id; // the record the file is attached to
attachment.IsPrivate = false;
upsert attachment;
}
}
Am i missing something here?
Related
I have an image saved in my database.
public class FileData
{
[Key]
public Guid Oid { get; set; }
public int size { get; set; }
public string FileName { get; set; }
public byte[] Content { get; set; }
}
I want to return the file from my web api (.Net Core 3.1). I have tried this code. The image is returned, but appears damaged, cannot be seen.
public async Task<ActionResult> GetFileData(Guid id)
{
var fileData = await _context.FileData.FindAsync(id);
if (fileData == null)
{
return NotFound();
}
MemoryStream ms = new MemoryStream(fileData.Content);
ms.Seek(0, SeekOrigin.Begin);
string contentType = System.Net.Mime.MediaTypeNames.Application.Octet;
return File(ms.ToArray(), contentType, fileData.FileName);
}
How can I do it?
Your return type seems off. You could specify a Mime type for images, e.g. "ìmage/jpeg" for JPEG files.
I do have a similar code to read images previously uploaded to an Azure blobstorage. Apart from the way you load the byte array into the MemoryStream, the overall parameters of the function look the same.
Try
return File(ms, "image/jpeg");
instead.
I am working on a small blog using ASP.NET Core(MVC 6) EF Visual Studio. I have trouble finding how to save images to a database. I have read about IFormfile but I do not really understand how to go about it, I am stuck. I am new to this and would love to have a little help.
I want to save the image to the post I am creating(In the same form). I, therefore, want to save it to postID. Then I need to be able to display the image, how do I do that?
You may find this useful if u need to save to database. This was a modification of https://www.mikesdotnetting.com/article/259/asp-net-mvc-5-with-ef-6-working-with-files and lots of input from k7Boys answer here MVC 6 HttpPostedFileBase?
<input type="file" name="Image" id="Imageinput">
Blog Modal Class should have Img field like;
public int BlogId{ get; set; }
...
public byte[] Img{ get; set; }
Controller;
public async Task<IActionResult> Create([Bind("BlogId,...Img")] Blog blog t, IFormFile Image)
if (ModelState.IsValid)
{
if (Image!= null)
{
if (Image.Length > 0)
//Convert Image to byte and save to database
{
byte[] p1 = null;
using (var fs1 = Image.OpenReadStream())
using (var ms1 = new MemoryStream())
{
fs1.CopyTo(ms1);
p1 = ms1.ToArray();
}
Blog.Img= p1;
}
}
_context.Add(client);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
Took me a couple of hours to get here. Now working on viewing the images in a view, am sure this will not be complex. Enjoy
Try this its working fine
controller
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,PostMode,Message,Image,AccountId,Created,Status")] Post post, IFormFile Image)
{
if (ModelState.IsValid)
{
using (var ms = new MemoryStream())
{
Image.CopyTo(ms);
post.Image = ms.ToArray();
}
_context.Add(post);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(post);
}
Display Image
#foreach (var item in Model)
{
<img class="img-responsive full-width" src="data:image/jpeg;base64,#Convert.ToBase64String(item.Image)" />
}
You can use IFormFile to save image posted from view. Below is the sample code.
public class UserProfileViewModel
{
public string UserName { get; set; }
public IFormFile UploadedImage { get; set; }
public string ImageUrl { get; set; }
}
In view simply bind it with IFormFile property like:
<img src="#Model.ImageUrl" alt="User Logo" asp-append-version="true" />
<input type="file" asp-for="UploadedImage" />
In your controller you just need to save file on server like:
var filename = ContentDispositionHeaderValue
.Parse(user.UploadedImage.ContentDisposition)
.FileName
.Trim('"');
filename = Path.Combine(webRoot, "/Content/UserProfile/", $#"\{filename}");
if (Directory.Exists(webRoot + "/Content/UserProfile/"))
{
using (FileStream fs = System.IO.File.Create(filename))
{
user.UploadedImage.CopyTo(fs);
fs.Flush();
}
}
model.ImageURL = "~/Content/Brands/" + user.UploadedImage.FileName;
public class Opportunity
{
[Key]
public int OpportunityId { get; set; }
[Required(ErrorMessage = "Graphics Image is required")]
public byte[] Graphics { get; set; }
[DisplayName("Faculty Picture")]
[Required(ErrorMessage = "Faculty Image is required")]
public byte[] FacultyPicture { get; set; }
}
Controller:
namespace Kaust.Views.Opportunities
{
public class OpportunitiesController : Controller
{
private KaustContext db = new KaustContext();
public ActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "OpportunityId,Graphics,FacultyPicturen")] Opportunity opportunity)
{
if (ModelState.IsValid)
{
db.Opportunities.Add(opportunity);
db.SaveChanges();
return RedirectToAction("Index");
}
}
View:
Create index:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Opportunity</h4>
<hr />
#Html.Images(m => m.Graphics, "Graphics", "id")
#Html.ValidationMessageFor(model => model.Graphics, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-horizontal">
<h4>Opportunity</h4>
<hr />
#Html.Images(m => m.FacultyPicture, "Graphics", "id")
#Html.ValidationMessageFor(model => model.FacultyPicture, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
And #Html.Images is a customhelper:
public static IHtmlString Images<TModel,TValue>(this HtmlHelper<TModel> helper,System.Linq.Expressions.Expression<Func<TModel, TValue>> expression, string name, string id){
TagBuilder tb = new TagBuilder("input");
tb.Attributes.Add("ex", expression.ToString());
tb.Attributes.Add("name", name);
tb.Attributes.Add("id", id);
tb.Attributes.Add("type", "file");
tb.Attributes.Add("accept", "Image/*");
return new MvcHtmlString(tb.ToString(TagRenderMode.SelfClosing));
}
}
It creates this output:
<input accept="Image/*" ex="m => m.Graphics" id="id" name="Graphics" type="file">
When I click the submit button:
The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters.
I have seend several methods to change the image file to Byte[] but I just don't know how to do it before the submit button or because it doesn't get into the "httppost method".
I have tried this solutions. but... I still get the error.
How to upload/display images using ASP.net MVC4 with Entity Framework
http://www.prideparrot.com/blog/archive/2012/8/uploading_and_returning_files
The question is how can I save this files into the databases in after clicking the submit button?
The properties in your model need to be HttpPostedFileBase (not byte[]) for binding to a file input in the view. Since your also wanting to store the filein the data base, you will need a separate view model and data model
// View model (Note ID property not required)
public class OpportunityVM
{
[Required(ErrorMessage = "Image is required")]
public HttpPostedFileBase Graphics { get; set; }
[DisplayName("Faculty Picture")]
public HttpPostedFileBase FacultyPicture { get; set; }
}
And in the POST method
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([OpportunityVM model)
{
if(!ModelState.IsValid)
{
return View(model);
}
// Initialize data model
Opportunity opportunity = new Opportunity();
using (var reader = new System.IO.BinaryReader(model.Graphics.InputStream))
{
opportunity.Graphics = reader.ReadBytes(model.Graphics.ContentLength);
}
if (model.FacultyPicture != null && modelFacultyPicture.ContentLength > 0)
{
// ditto for FacultyPicture
}
db.Opportunities.Add(opportunity);
db.SaveChanges();
return RedirectToAction("Index");
}
Note that you also need to include the enctype = "multipart/form-data" attribute in the form tag
#using (Html.BeginForm("Create", "Opportunities", FormMethod.Post, new { enctype = "multipart/form-data" }))
Side note: Your generating invalid html. Both file inputs in your model have id="id" (duplicate id attributes)
There is no need to pass the name and id to the helper (and in fact a minor typo passing the name means binding will fail). Instead use the ModelMetadata to generate the correct attributes. In addition, ex is not a valid attribute and its not clear what you are trying to achieve with tb.Attributes.Add("ex", expression.ToString()); but it should be removed.
public static IHtmlString Images<TModel,TValue>(this HtmlHelper<TModel> helper,System.Linq.Expressions.Expression<Func<TModel, TValue>> expression)
{
string name = ExpressionHelper.GetExpressionText(expression);
string id = HtmlHelper.GenerateIdFromName(name);
TagBuilder tb = new TagBuilder("input");
// tb.Attributes.Add("ex", expression.ToString());
tb.MergeAttribute("name", name);
tb.MergeAttribute("id", id);
tb.MergeAttribute("type", "file");
tb.MergeAttribute("accept", "Image/*");
return new MvcHtmlString(tb.ToString(TagRenderMode.SelfClosing));
}
I am trying to send a KML file (which is XML) by HTTP Post to an ASPX page. This works as long as there is no escaped HTML contained in the KML.
To create the KML I use the following class for the XmlSerializer
public class kml
{
[DataMember]
public DocumentItem Document
{ get; set; }
public kml()
{
}
public class BalloonStyleItem
{
[DataMember]
public string text
{ get; set; }
[DataMember]
public string displayMode
{ get; set; }
public BalloonStyleItem()
{
displayMode = "default";
}
}
}
//(...)
In my code, that creates the KML I have this line:
balloonStyleItem.text = "<h2>name: " + substation.name + "</h2>region: " + substation.Region.Region.name + "<br>subregion: " + substation.Region.name;
As you see it contains HTML
Now I want to send this KML by HTTP Post:
HttpWebRequest request = asyncResult.AsyncState as HttpWebRequest;
Stream stream = request.EndGetRequestStream(asyncResult);
StreamWriter writer = new StreamWriter(stream);
System.Xml.Serialization.XmlSerializer xmlSerializer = new System.Xml.Serialization.XmlSerializer(typeof(kml));
xmlSerializer.Serialize(writer, kmlContainer);
writer.Write(xmlstring); //here it crashes!
At this point the execution of the program stops with the error message "WebException was unhadled by user code, The remote server returned an error: NotFound"
If I give something like
balloonStyleItem.text = "xxxxx";
(without HTML) everything works fine. Do you have any ideas?
Can you give it a try using DataContractSerializer instead of XmlSerializer? I noticed that you are using attributes designed for DataContractSerializer...
DataContractSerializer ser = new DataContractSerializer(typeof(kml));
ser.WriteObject(stream, kmlContainer);
I'm trying to save and display a image for each contact individually. I was able to save the image successfully at respective contact. But, when i refreshed the page the photo i have attached is not displaying.
Here is the code:
<apex:page standardController="Contact" extensions="photo_attachmentcls">
<apex:pageBlock >
<apex:form >
<apex:inputFile value="{!attach}" fileName="{!fileName}"></apex:inputFile>
<apex:commandButton value="Load" action="{!loader}" />
<apex:actionSupport event="onchange" />
</apex:form>
<apex:outputPanel id="iidd1">
<img id="theImage" src="/servlet/servlet.FileDownload?file={!dsa}" width="100" height="100" />
</apex:outputPanel>
</apex:pageBlock>
</apex:page>
public class photo_attachmentcls {
public Attachment asd{get;set;}
public string purl{get;set;}
public blob attach{get;set;}
public String fileName{get;set;}
public Id recId{get;set;}
public String dsa {get;set;}
public photo_attachmentcls(ApexPages.StandardController ctrl) {
recId = ApexPages.currentPage().getParameters().get('id');
asd = new Attachment();
}
public void loader()
{
asd.body = attach;
asd.Name = fileName;
asd.ParentId = recId;
insert asd;
system.debug('nnnn'+asd);
dsa = asd.id;
system.debug('ddddd'+dsa);
}
}
Thanks in Advance.
You need to check for the existence of the attachment for that record when the page loads:
public class photo_attachmentcls {
public Attachment asd{get;set;}
public string purl{get;set;}
public blob attach{get;set;}
public String fileName{get;set;}
public Id recId{get;set;}
public String dsa {get;set;}
public photo_attachmentcls(ApexPages.StandardController ctrl) {
recId = ApexPages.currentPage().getParameters().get('id');
// check if the contact already has an attachment:
Contact thisRecord = [select id, (Select Id From NotesAndAttachments) from Contact where Id =: recId];
if(!thisRecord.NotesAndAttachments.isEmpty()){
dsa = thisRecord.NotesAndAttachments[0].Id;
} else{
asd = new Attachment();
}
}
public void loader()
{
asd.body = attach;
asd.Name = fileName;
asd.ParentId = recId;
insert asd;
system.debug('nnnn'+asd);
dsa = asd.id;
system.debug('ddddd'+dsa);
}
}
I'll recommend to choose better variable names as well, but I recognize is a prototype of some sort.