Trouble accessing images uploaded in back-end project - c#

I am trying to access images stored in an /uploads/ folder in my front-end app.
I get a 404 for both http://localhost:4200/uploads/a.jpg and http://localhost:4200/StaticFiles/a.jpg. I need the image's path to display it in a gallery.
I tried using the full path of the image ("D:/blabla/uploads/a.jpg"), but it seems that is restricted. Then I used the code below to provide from the back-end a path to my uploads folder, but I still get 404.
My back-end and front-end projects are in different folders, and my front-end sends requests to back-end's port.
Back-end running latest .net core, front-end is Angular 8.
This is how I serve the static files:
var aux = Path.Combine(Directory.GetCurrentDirectory(), "uploads");
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(aux),
RequestPath = "/StaticFiles"
}
);
This is how I upload the image. The code works and uploads images in the /uploads folder, inside the project.
var uploadFilesPath = Path.Combine(_host.ContentRootPath, "uploads");
if (!Directory.Exists(uploadFilesPath))
Directory.CreateDirectory(uploadFilesPath);
foreach (var file in fileData)
{
var fileName = Guid.NewGuid() + Path.GetExtension(file.FileName);
var filePath = Path.Combine(uploadFilesPath, fileName);
using (var stream = new FileStream(filePath, FileMode.Create))
{
file.CopyTo(stream);
}
var propToAddImageTo = _propManager.GetById(id);
_propManager.AddImage(propToAddImageTo, filePath);
}
When I try to set a simple <img src="localhost:4200/uploads/a.jpg"> or <img src="localhost:4200/StaticFiles/a.jpg">, the request on the network tab from Mozilla's Developer Tools says 404.

The default value for _host.ContentRootPath is equal to Directory.GetCurrentDirectory(), but only if you are using WebHost.CreateDefaultBuilder. From the documentation:
CreateDefaultBuilder performs the following tasks:
...
Sets the content root to the path returned by Directory.GetCurrentDirectory.
Your code assumes ContentRootPath is always the same as Directory.GetCurrentDirectory, but that won't always be true. If you are not using CreateDefaultBuilder, or your code is split across multiple projects (as you mentioned in your comment), they won't point to the same place.

Below codes works for me :
app.UseCors("CorsPolicy");
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), #"uploads")),
RequestPath = new PathString("/StaticFiles")
});
app.UseMvc();
It needs the uploads folder should exist in root directory , otherwise it will throw error . Suppose the structure is ApplicationName/uploads/a.jpg , you can use like :
<img src="http://localhost:xxxx/StaticFiles/a.jpg">
To save images on server side , you could find the path by :
var pathToSave = Path.Combine(Directory.GetCurrentDirectory(), "uploads");

Related

ASP.Net Core - Dynamically generate index.html

The standard way to provide an index.html to the client with ASP.Net core is to use the middleware app.UseStaticFiles(); on IApplicationBuilder instance in the Configure method of the StartUp class. This provides a static index.html file from the wwwroot folder. Is there a way to provide an index.html to the client, that is dynamically generated in code on request?
There is a way to change the SPA files content served from the static folder.
You should do the following:
update your usage of UseStaticFiles, it should have a lambda provided for the OnPrepareResponse property; See this MS DOC
It is called every time the static file is returned to the client;
You can analyze the file name to ensure it is index.html;
Your code can completely change the content that will be returned. Just generate a file dynamically to replace index.html, and write it as a response body by writing to a stream. You might need to clear or save original body content before modifying and returning it if your writing has failed.
See code example to get you started:
var staticFileOptions = new StaticFileOptions
{
OnPrepareResponse = context =>
{
// Only for Index.HTML file
if (context.File.Name == "index.html") {
var response = context.Context.Response;
var str = "This is your new content";
var jsonString = JsonConvert.SerializeObject(str);
// modified stream
var responseData = Encoding.UTF8.GetBytes(jsonString);
var stream = new MemoryStream(responseData);
// set the response body
response.Body = stream;
}
}
};
app.UseStaticFiles(staticFileOptions);

Serve static pdf files in solution folder - in MVC pipeline , with different route

One of my old project we do have a static content file folder named XYZ which we are keeping in the same location fo the root.
Currently we are directly passing the url like 'siteaddress/XYZ/test.pdf' or siteaddress/XYZ/2020/Test1.pdf to get the pdf files.
Now we have a requirement to store some of the confidential files also in the path. So we are planning to restrict the direct access to the path and serve via MVC pipeline
we have added a handlers to enable the requests from the folder, to go through mvc pipeline
<add
name="ManagedPdfExtension"
path="XYZ/*/*.pdf"
verb="GET"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0"
/>
<add
name="ManagedPdfInnerFolderExtension"
path="CommonFiles/*/*.pdf"
verb="GET"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0"
/>
Also created a method to return the file in controller
[HttpGet]
[Route("XYZ/{attachmentName}")]
public ActionResult CommonFiles(string attachmentName)
{
var path = System.Web.Hosting.HostingEnvironment.MapPath("~/XYZ/"+ attachmentName);
byte[] fileBytes = System.IO.File.ReadAllBytes(path);
string fileName = "Test.pdf";
var cd = new ContentDisposition
{
Inline = true,
FileName = fileName
};
Response.Clear();
Response.AddHeader(CoreConstants.ContentDisposition, cd.ToString());
Response.AddHeader(CoreConstants.WindowTarget, CoreConstants.WindowTargetBlank);
Response.BufferOutput = false;
return File(fileBytes, "application/pdf");
}
This code works ok with files which are directly under folder XYZ
That means if I try a url like
siteaddress/XYZ/test.pdf which is working.
But for the pdf that are inside another folder, I am not able to get with the existing approach.
Since we have only single param attachmentName defined in the method i couldn't get the files under subfolders.
Is there any way to do the same in MVC ??
Because of some reasons, I cannot move all these items to database , change the folder structure . Also i cannot create a mapping table like
url : key and use the key instead.
Th urls are coming from a common table which is used in many applications. So changing that is bit difficult.
If the folder and subfolders are limited then may be with multiple route i could handle this. But here the subfolder number can be a variable too.
In fact from the following urls
siteadress/XYZ/abc/bn/test.pdf
siteadress/XYZ/abc/cf/bn/test.pdf
siteadress/XYZ/abc/bn/test.pdf
is there any way to make it hit a single controller method with a string params like
abc/bn/test.pdf
abc/cf/bn/test.pdf
abc/bn/test.pdf
??
Added a route with * in the property part.
[HttpGet]
[Route("CommonFiles/{*any}")]
public ActionResult CommonFiles(string attachmentName)
{
var filePathWithName = this.RouteData.Values["any"];
var path = System.Web.Hosting.HostingEnvironment.MapPath("~/CommonFiles/"+ filePathWithName);
path = path.Replace("//", "/").Replace("/","//");
byte[] fileBytes = System.IO.File.ReadAllBytes(path);
string fileName = "Test.pdf";
var cd = new ContentDisposition
{
Inline = true,
FileName = fileName
};
Response.Clear();
Response.AddHeader(CoreConstants.ContentDisposition, cd.ToString());
Response.AddHeader(CoreConstants.WindowTarget, CoreConstants.WindowTargetBlank);
Response.BufferOutput = false;
return File(fileBytes, "application/pdf");
}

How to access a photo that is upload into another project in the same solution

I have Solution named Company where I have three projects
Company
| ----Company.Data
| ----Company.Intranet
| ----Company.Website
In Company.Intranet project I upload photo into server (and save his name to database). It is possible get access to upload file from other project (eg. Company.Website)?
Create a directory where you will store files (I create wwwroot dictionary, in this images dictionary and in this item dictionary)
**Company
| ----Company.Data
| ----Company.Intranet
| ----Company.Website
| ----wwwroot
|-------|--------images
|-------|--------|--------items
In Company.Intranet edit Startup.cs
app.UseFileServer(new FileServerOptions()
{
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(),
"..\\wwwroot\\images\\items")),
RequestPath = new PathString("/files"),
EnableDirectoryBrowsing = false // you make this true or false.
}
);
Where "..\\wwwroot\\images\\items" is path where your photo will be upload and /files is name
is the name you will use when referring to photo.
In your controller change directory where you will be upload file
var fileName = Path.GetFileName(Photo.FileName);
var filePath = Path.Combine(Directory.GetCurrentDirectory(), "..\\wwwroot\\images\\items", fileName);
using (var fileSteam = new FileStream(filePath, FileMode.Create))
{
await Photo.CopyToAsync(fileSteam);
}
Where "..\\wwwroot\\images\\items" is path where your photo will be upload -> the same one you provided in the Startup.cs file
In Company.Website edit Startup.cs
app.UseFileServer(new FileServerOptions()
{
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(),
"..\\wwwroot\\images\\items")),
RequestPath = new PathString("/files"),
EnableDirectoryBrowsing = false // you make this true or false.
}
);
Where "..\\wwwroot\\images\\items" is path where your photo will be upload -> the same one you provided in the Startup.cs file in Company.Intranet project
To view pictures in View use code
<img src="#("/files/" + #item.Photo2)"/>
Where /files/ is your custom name you will use when referring to photo and #item.Photo2 is name your photo file (i storage it in database)

How can I solve FileSystemException: Cannot retrieve length of file, path ='...' (OS Error: No such file or directory, errno = 2)

I am trying to send a user model from dart to the api where my file is set as "IFormFile" data type in my c# backend.
I tried using the multipart request but all i get is the error stated , i can't understand why it cannot retrieve the length of file.
This is my code:
updateUser() async {
var uri = Uri.parse('http://myIP:8070/api/Users');
var request = http.MultipartRequest('Put', uri);
request.fields['id']="07bb2a17-7cd5-471b-973a-4b77d239b6c3";
request.fields['username']="beeso";
request.fields['email']="jake-username2#gmail.com";
request.fields['password']="Jake123-";
request.fields["oldPassword"]="Jake124-";
request.fields["gender"]="Male";
request.fields["dateOfBirth"]=DateTime.now().toString();
request.fields["name"]="dsjnss";
request.fields["languages"]=["Language1","Language2"].toString();
request.fields["nationalities"]=["Nationality1","Nationality2"].toString();
request.fields["phoneNumber"]="70502030";
request.fields["biography"]="jdnknkdas";
request.fields["info"]="asndasnkdas";
request.fields["religion"]="Christian";
request.fields["location"]="LA";
File imageFile = new File('Anatomy_of_a_Sunset-2.jpg');
var stream = new http.ByteStream(DelegatingStream.typed(imageFile.openRead()));
var length = await imageFile.length();
var multipartFile = new http.MultipartFile('file', stream, length,
filename: basename(imageFile.path));
request.files.add(multipartFile);
Map<String, String> headers = {
"content-type": "application/json"
};
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
print(response.statusCode);
}
Any help would be appreciated.
This picture shows where my file is located
In Flutter, you can't access files directly from the project. You need to add them to an assets folder (typically assets) and also to pubspec.yaml. Then, instead of using File to read them, you use rootBundle (or one of the Asset classes).
var multipartFile = http.MultipartFile.fromBytes(
'file',
(await rootBundle.load('assets/anatomy.jpg')).buffer.asUint8List(),
filename: 'anatomy.jpg', // use the real name if available, or omit
contentType: MediaType('image', 'jpg'),
);
request.files.add(multipartFile);
While testing your API, you may find it easier to just create a Dart command line project, where you do have access to Files in the project folders.
my case was image uploading problem and I solved it by using
xfile.path that image picker returned
XFile? image = await _picker.pickImage(
source: ImageSource.gallery,
imageQuality: 50,
maxHeight: 500,
maxWidth: 500);
#flutter
#dio

How to use uploaded files from .net core API in my angular application?

I have trouble with display a image in my Angular app.
This is in my profile.ts and profile.html page
public createImgPath = (serverPath: string) => {
return `http://localhost:63040/${serverPath}`;
}
<img class="img-responsive" src="{{createImgPath(userApi.user.imageUrl.folderName)}}" />
From the server I get filepath:
var folderName = Path.Combine( "userImages", fileName);
return Ok(new { folderName });
When I try to display image in src I get the path but image is not display.
And I got error message:
It was very silly typo mistake. Instead "usersImages", in var folderName I used to use "userImages". I'm sorry for trouble to everyone.
I think you're supposed to return the file as a blob. Because you cannot send your images as a JSON to angular. Well, at first, change your backend code to something like this:
var folderName = Path.Combine( "userImages", fileName);
return new FileStream(folderName , FileMode.Open, FileAccess.Read);
and then change [HttpGet] to [HttpPost]
I don't know how to send your image file to the backend but I think you can fix your problem with these changes.

Categories

Resources