ASP.NET Core MVC - Image is not getting uploaded in live website directory - file-upload

I have my ASP.NET Core MVC website on production server of godaddy windows hosting. I have a "Create article" page which allows to select an image from PC and upload it in the project folder directory.
This functionality works fine on local server, but it doesn't work on production server. I have tried to change the upload path of the image multiple times, but none of them works for me. I get an error on production. If I don't upload the image and create article without it, it works fine on the production.
Paths which I have tried :
public static string ArticleImgPath = #"\images\Articles\";
public static string ArticleImgPath = "/images/Articles/";
public static string ArticleImgPath = "https://derawala.org/wwwroot/images/Articles/";
public static string ArticleImgPath = "https://derawala.org/httpdocs/wwwroot/images/Articles/";
public static string ArticleImgPath = "https://derawala.org/images/Articles/";
This is the error I got on production :
If I remove the image uploading code, I don't get any errors and the app works just fine.
I have also made sure to upload appsettings.production.json file to make sure that environment variables are set for production environment. Also, all the other functionalities of website including database operations work properly except those which have file uploading in it.
Here is my controller method for article creation:
public IActionResult ArticlePost(ParentForApply ParentVM)
{
var files = HttpContext.Request.Form.Files;
if (files.Count == 0)
{
ParentVM.ArticleModel.Img ="defltimg.png";
_db.Articles.Add(ParentVM.ArticleModel);
_db.SaveChanges();
return View(ParentVM);
}
else
{
string upload = WC.ArticleImgPath;
string fileName = Guid.NewGuid().ToString();
string extension = Path.GetExtension(files[0].FileName);
string fullpath = upload + fileName + extension;
using (var filestream = new FileStream(fullpath, FileMode.Create))
{
files[0].CopyTo(filestream);
}
ParentVM.ArticleModel.Img = fileName + extension;
_db.Articles.Add(ParentVM.ArticleModel);
_db.SaveChanges();
return View(ParentVM);
}
}

The error indicates you swap to development environment to get detailed errors,not means you are not in production enviroment
Alos,you could read this document related with uploading files:https://learn.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-6.0
you could try with the codes in this document to upload file and store the content into database:
public class AppFile
{
public int Id { get; set; }
public byte[] Content { get; set; }
}
in controller:
using (var memoryStream = new MemoryStream())
{
await FileUpload.FormFile.CopyToAsync(memoryStream);
// Upload the file if less than 2 MB
if (memoryStream.Length < 2097152)
{
var file = new AppFile()
{
Content = memoryStream.ToArray()
};
_dbContext.File.Add(file);
await _dbContext.SaveChangesAsync();
}
else
{
ModelState.AddModelError("File", "The file is too large.");
}
Update:
Could you swap to development environment to see the detailed error message?
Have you tried to write the path with WebRootPath?
public IActionResult New([FromServices]IHostingEnvironment env)
{
......
using (var stream = new FileStream(Path.Combine(env.WebRootPath, "...."), FileMode.CreateNew))
.....
}

Related

how to read excel file in memory (without saving it in disk) and return its content dotnet core

Im working on a webApi using dotnet core that takes the excel file from IFormFile and reads its content.Iam following the article
https://levelup.gitconnected.com/reading-an-excel-file-using-an-asp-net-core-mvc-application-2693545577db which is doing the same thing except that the file here is present on the server and mine will be provided by user.
here is the code:
public IActionResult Test(IFormFile file)
{
List<UserModel> users = new List<UserModel>();
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
using (var stream = System.IO.File.Open(file.FileName, FileMode.Open, FileAccess.Read))
{
using (var reader = ExcelReaderFactory.CreateReader(stream))
{
while (reader.Read()) //Each row of the file
{
users.Add(new UserModel
{
Name = reader.GetValue(0).ToString(),
Email = reader.GetValue(1).ToString(),
Phone = reader.GetValue(2).ToString()
});
}
}
}
return Ok(users);
}
}
When system.IO tries to open the file, it could not find the path as the path is not present. How it is possible to either get the file path (that would vary based on user selection of file)? are there any other ways to make it possible.
PS: I dont want to upload the file on the server first, then read it.
You're using the file.FileName property, which refers to the file name the browser send. It's good to know, but not a real file on the server yet. You have to use the CopyTo(Stream) Method to access the data:
public IActionResult Test(IFormFile file)
{
List<UserModel> users = new List<UserModel>();
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
using (var stream = new MemoryStream())
{
file.CopyTo(stream);
stream.Position = 0;
using (var reader = ExcelReaderFactory.CreateReader(stream))
{
while (reader.Read()) //Each row of the file
{
users.Add(new UserModel{Name = reader.GetValue(0).ToString(), Email = reader.GetValue(1).ToString(), Phone = reader.GetValue(2).ToString()});
}
}
}
return Ok(users);
}
Reference

Need a web API action method to implement removeUrl of kendo angular upload component

I need a full working example for implementing the remove functionality in telerik kendo angular with Angular 8 and a backend web API in ASP.net core 2.2
In kendo Angular I'm trying to implement the functionality of upload files and removing it when user clicks the x small buttons
I've already implemented the upload so perfectly but when providing the removeUrl it gives error 404 or 415
The other strange thing is when I provide the same url for the upload and download it binds and code could go well but i need a separate action for the remove functionality
[HttpPost("upload"), DisableRequestSizeLimit]
public async Task<IActionResult> Post(IFormFileCollection files)
{
long size = files.Sum(f => f.Length);
//var reqFiles = Request.Form.Files;
var uploads = Path.Combine(_hostingEnvironment.WebRootPath, "uploads");
if (!Directory.Exists(uploads))
{
Directory.CreateDirectory(uploads);
}
List<string> paths = new List<string>();
foreach (var file in files)
{
if (file.Length > 0)
{
string fileName = Guid.NewGuid() + Path.GetExtension(file.FileName);
var filePath = Path.Combine(uploads, fileName);
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(fileStream);
}
paths.Add(filePath);
}
}
// process uploaded files
// Don't rely on or trust the FileName property without validation.
return Ok(new { count = files.Count, size, paths });
}
and for delete
[HttpPost]
private IActionResult Delete(IList<string> files)
{
// var reqFiles = Request.Form.Files;
var uploads = Path.Combine(_hostingEnvironment.WebRootPath, "uploads");
foreach (var item in files)
{
var filePath = Path.Combine(uploads, item);
System.IO.File.Delete(filePath);
}
return Ok(new { files });
}
Error 404 is raised when trying to name the action in web api and provide this name in the url (although the same thing is working when uploadling) and 415 is being raised when using post request without naming the action in the back end

Files uploaded but not appearing on server

I use the code stated here to upload files through a webapi http://bartwullems.blogspot.pe/2013/03/web-api-file-upload-set-filename.html. I also made the following api to list all the files I have :
[HttpPost]
[Route("sharepoint/imageBrowser/listFiles")]
[SharePointContextFilter]
public async Task<HttpResponseMessage> Read()
{
string pathImages = HttpContext.Current.Server.MapPath("~/Content/images");
DirectoryInfo d = new DirectoryInfo(pathImages);//Assuming Test is your Folder
FileInfo[] Files = d.GetFiles(); //Getting Text files
List<object> lst = new List<object>();
foreach (FileInfo f in Files)
{
lst.Add(new
{
name = f.Name,
type = "f",
size = f.Length
});
}
return Request.CreateResponse(HttpStatusCode.OK, lst);
}
When calling this api, all the files uploaded are listed. But when I go to azure I dont see any of them (Content.png is a file I manually uploaded to azure)
Why are the files listed if they dont appear on azure.
According to your description, I suggest you could firstly use azure kudu console to locate the right folder in the azure web portal to see the image file.
Open kudu console:
In the kudu click the debug console and locate the site\wwwroot\yourfilefolder
If you find your file is still doesn't upload successfully, I guess there maybe something wrong with your upload codes. I suggest you could try below codes.
Notice: You need add image folder in the wwwort folder.
{
public class UploadingController : ApiController
{
public async Task<HttpResponseMessage> PostFile()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = Environment.GetEnvironmentVariable("HOME").ToString() + "\\site\\wwwroot\\images";
//string root = HttpContext.Current.Server.MapPath("~/images");
var provider = new FilenameMultipartFormDataStreamProvider(root);
try
{
StringBuilder sb = new StringBuilder(); // Holds the response body
// Read the form data and return an async task.
await Request.Content.ReadAsMultipartAsync(provider);
// This illustrates how to get the form data.
foreach (var key in provider.FormData.AllKeys)
{
foreach (var val in provider.FormData.GetValues(key))
{
sb.Append(string.Format("{0}: {1}\n", key, val));
}
}
// This illustrates how to get the file names for uploaded files.
foreach (var file in provider.FileData)
{
FileInfo fileInfo = new FileInfo(file.LocalFileName);
sb.Append(string.Format("Uploaded file: {0} ({1} bytes)\n", fileInfo.Name, fileInfo.Length));
}
return new HttpResponseMessage()
{
Content = new StringContent(sb.ToString())
};
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
}
public class FilenameMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
{
public FilenameMultipartFormDataStreamProvider(string path) : base(path)
{
}
public override string GetLocalFileName(System.Net.Http.Headers.HttpContentHeaders headers)
{
var name = !string.IsNullOrWhiteSpace(headers.ContentDisposition.FileName) ? headers.ContentDisposition.FileName : Guid.NewGuid().ToString();
return name.Replace("\"", string.Empty);
}
}
}
Result:

How to save a file from a windows store app in Unity

I'm making an app in Unity3D for release on the windows store.
It seems you cant write files using the .net streamwriter.
I'd like to save a csv file to a certain location and then later send it to a server using the WWW class.
I found a project which reads a file from the assets folder.
Heres the code for that...
using UnityEngine;
using System;
using System.Collections;
using System.IO;
#if NETFX_CORE
using System.Text;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Streams;
#endif
namespace IOS
{
public class File
{
public static object result;
#if NETFX_CORE
public static async Task<byte[]> _ReadAllBytes(string path)
{
StorageFile file = await StorageFile.GetFileFromPathAsync(path.Replace("/", "\\"));
byte[] fileBytes = null;
using (IRandomAccessStreamWithContentType stream = await file.OpenReadAsync())
{
fileBytes = new byte[stream.Size];
using (DataReader reader = new DataReader(stream))
{
await reader.LoadAsync((uint)stream.Size);
reader.ReadBytes(fileBytes);
}
}
return fileBytes;
}
#endif
public static IEnumerator ReadAllText(string path)
{
#if NETFX_CORE
Task<byte[]> task = _ReadAllBytes(path);
while (!task.IsCompleted)
{
yield return null;
}
UTF8Encoding enc = new UTF8Encoding();
result = enc.GetString(task.Result, 0, task.Result.Length);
#else
yield return null;
result = System.IO.File.ReadAllText(path);
#endif
}
}
}
public class Example : MonoBehaviour
{
private string data;
IEnumerator ReadFile(string path)
{
yield return StartCoroutine(IOS.File.ReadAllText(path));
data = IOS.File.result as string;
}
public void OnGUI()
{
string path = Path.Combine(Application.dataPath, "StreamingAssets/Data.txt");
if (GUILayout.Button("Read file '" + path + "'"))
{
StartCoroutine(ReadFile(path));
}
GUILayout.Label(data == null ? "<NoData>" : data);
}
}
Heres the MSDN docs for serializing with Windows Store apps
https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh758325.aspx
I'm wondering how to adapt this to suit my purposes. ie. Write a file to a specific location that I can reference later when I am sending the file via WWW.
The main issue is the location. The Application.dataPath is read only data within the app's package. To write data use Application.persistentDataPath to get a writable location in the application data folder.
Unity provides alternatives to System.IO.File with its UnityEngine.Windows.File object. You can just switch the using between System.IO and UnityEngine.Windows then call File.ReadAllBytes or File.WriteAllBytes regardless of platform.
This is essentially what your code snippit is doing, except that Unity already provides it.

FileUpload and Retrieval

I am trying to make a file upload page where users can upload an image or document to it and it to show up in a list fashion, I have managed to upload the image into a folder I created in my Project, but I have no idea how I'm meant to retrieve it, every time I try and search for it I get useless posts which don't really fit my question.
Here is my code:
//
// GET: /Upload/
[HttpPost]
public ActionResult Index(HttpPostedFileBase file)
{
if (file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/Images/Uploads"), fileName);
file.SaveAs(path);
System.Diagnostics.Debug.WriteLine(path);
}
Server.MapPath("~/App_Data/Uploads/");
return RedirectToAction("Index", file);
}