How to forward input file path and name in ASP? - c#

I am trying to use ASP to upload a JSON file. However, for some strange reason, the control that I use for that only forwards the file name, but not the path.
Here's what I'm doing in my .cshtml:
<form asp-page-handler="AddDevices" method="post" >
<button
class="btn btn-default"
id="btn_add_devices"
>
Add Devices
</button>
<input type="file" name="fileNameAndPath" accept="application/JSON"/>
</form>
...and here's the function that gets called in the corresponding .cs:
public void OnPostAddDevices(string fileNameAndPath)
{
string jsonString = System.IO.File.ReadAllText(fileNameAndPath);
[Deserialization]
}
The problem is, that instead of the file name and path that I would like to arrive at that function, only the file name is passed on, so for example if I use the file selector to select the file C:/TestFiles/TestJson.json, then in the function OnPostAddDevices, the value of the parameter fileNameAndPath is only TestJson.json instead of what I would need C:/TestFiles/TestJson.json.
Naturally, that subsequently results in a FileNotFoundException.
What can I do to make the input pass on the full file name with path in this case?

Here's what I ended up doing now, and what worked to my satisfaction based on the following tutorial:
https://learn.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-6.0
Summed up in short:
In my index.cshtml, I added this for the upload button:
<form enctype="multipart/form-data" method="post">
<dl>
<dt>
<label asp-for="FormFile"></label>
</dt>
<dd>
<input asp-for="FormFile" type="file">
</dd>
</dl>
<input asp-page-handler="UploadDeviceFile" class="btn" type="submit" value="Upload">
</form>
In my Index.cshtml.cs, I added this for the uploading logic:
[BindProperty]
public IFormFile FormFile { get; set; }
public async Task<IActionResult> OnPostUploadDeviceFileAsync()
{
using (var memoryStream = new MemoryStream())
{
await FormFile.CopyToAsync(memoryStream);
string jsonString = Encoding.ASCII.GetString(memoryStream.ToArray());
DeviceContainer deviceContainer = JsonConvert.DeserializeObject<DeviceContainer>(jsonString);
DatabaseController.AddAll(deviceContainer.Devices);
}
return Page();
}

Related

Passing same parameter to an action on clicking two different buttons

I have a View which displays a list of file names. Also i have two buttons called View and Release. When I select a file name from the list and click on view, it navigates to the appropriate action method along with the file name selected as a parameter and performs the functionality as required.
But when i click on Release after selecting a file name, it does navigates to the appropriate action method, but does not passes the file name as a parameter to the action method. It shows as null.
Please note that View and Release directs to a single controller having different action methods.
How can i get to pass the filename as a parameter when i click on release?
Please see the code below:
public class HoldFilesController : Controller
{
// GET: HoldFiles
string holdpath = ConfigurationManager.AppSettings["HoldPath"].ToString();
public ActionResult Index()
{
DirectoryInfo dirInfo = new DirectoryInfo(holdpath);
List<FileInfo> files = dirInfo.GetFiles().ToList();
return View("Index",files);
}
}
[HttpPost]
public ActionResult ViewFile(string[] Name)
{
byte[] ImageData = null;
for (int i = 0; i < Name.Length; i++)
{
string filepath = holdpath + #"\" + Name[i];
FileStream fs = new FileStream(filepath, FileMode.Open,
FileAccess.ReadWrite);
ImageData = new byte[fs.Length];
fs.Read(ImageData, 0, System.Convert.ToInt32(fs.Length));
fs.Close();
}
return File(ImageData,"application/pdf");
}
[HttpPost]
public ActionResult ReleaseFile(string[] Name)
{
for(int i=0; i<Name.Length;i++)
{
string sourcefilepath= holdpath + #"\" + Name[i];
string Destinationfilepath =
ConfigurationManager.AppSettings["ReleaseFolderPath"].ToString();
string ReleaseFilePath = Destinationfilepath + #"\" + Name[i];
if (Directory.Exists(Destinationfilepath))
{
System.IO.File.Move(sourcefilepath, ReleaseFilePath);
}
}
return RedirectToAction("Index");
}
Here's the code for my view:
#model IEnumerable<FileInfo>
#{
ViewBag.Title = "files";
}
<h2>Held files</h2>
#using (Html.BeginForm())
{
<div style="border:solid;width:100%;overflow-x:auto;">
<table align="center" style="width:100%">
<thead>
<tr>
<th>File Name</th>
<th>Action</th>
</tr>
</thead>
<tbody>
#foreach (FileInfo file in Model)
{
<tr>
<td>
<input type="checkbox" name="Name" value="#file.Name" />
#file.Name
</td>
</tr>
}
</tbody>
</table>
</div>
<input type="submit" id="Held" name="Held file" value="View" />
<input type="submit" id="Release" name="release" value="Release" />
}
Just to avoid confusion, the View button redirects to the ViewFile method
and the Release button redirects to Releasefile method.
You have multiple options to do this.
You can hijack the submit button click and update the form action attribute value based on what button is clicked and do the form submit using javascript.
You can keep the url to the 2 action methods in html5 data attributes on the button.
<input type="submit" data-myaction="#Url.Action("View")" value="View"/>
<input type="submit" data-myaction="#Url.Action("Release")" value="Release"/>
Using the Url.Action method to generate the correct relative path to the action method is a safe practice. Let the method worry about generating the correct path for you.
And the javascript
$(function () {
$("input[data-myaction]").click(function(e) {
e.preventDefault(); // stop the normal form submit
// read the data attribute and update the forms action and do a submit
$(this).closest("form").attr('action', $(this).data('myaction')).submit();
});
});
Another option is using html5 formaction which does not need any javascript hijacking. When you specify a formaction attribute value, it will override the parent form's action attribute. this is very useful when you have more than one submit button with 2 different action methods to submit to (your use case)
<input type="submit" formaction="#Url.Action("View")" value="View"/>
<input type="submit" formaction="#Url.Action("Release")" value="Release"/>
1-HTML5 formaction and formmethod attributes
<input type="submit" name="view" value="view" formaction="ViewFile" formmethod="post" />
<input type="submit" name="Release" value="Release" formaction="ReleaseFile" formmethod="post" />
2-jQuery / JavaScript code
$(document).ready(function () {
$("#Held").click(function () {
$("form").attr("action", "/HoldFiles/ViewFile");
});
$("#Release").click(function () {
$("form").attr("action", "/HoldFiles/ReleaseFile");
});
});

How to pass uploaded file content to HttpPostedFileBase type in controller using angular js

i am developing an asp.net mvc4 application with angularjs. I want to provide an choose file option along with some form data. By referring some links i provided an choose file option but the problem now is i am not able to pass the uploaded file content to controller where i am trying to store the path of a file into database.
Below is my .cshtml page...
<div ng-app="formapp">
<div ng-controller="FormController">
<form name="myform" ng-submit="submit(myform.$valid)" novalidate>
<div class="form-group">
<p class="bg-text">User Name</p>
<div class="input-group">
<input id="username" class="form-control" type="text" name="username" ng- model="username" placeholder="Username" required />
<span class="help-inline" ng-show="(myform.username.$dirty || submitted) && myform.username.$error.required">UserName is required</span>
</div>
</div>
<div class="form-group">
<p class="bg-text">Choose file</p>
<div class="input-group">
<input type="file" ng-file-select="onFileSelect($files)" name="file" />
</div>
</div>
<button type="submit" ng-click="submitted=true" class="btn btn-primary">Sign Up</button>
<button type="reset" class="btn btn-warning">Reset</button>
</form>
</div>
</div>
Script part is as follows...
<script>
var formapp = angular.module('formapp', ['ui.bootstrap', 'angularFileUpload']);
formapp.controller('FormController', function ($scope, $http, $upload) {
$scope.selectedFile = [];
$scope.uploadProgress = 0;
$scope.onFileSelect = function ($files) {
$scope.uploadProgress = 0;
$scope.selectedFile = $files;
};
$scope.submit = function (isValid) {
$scope.object = {
UserName: $scope.username,
};
var file = $scope.selectedFile[0];
var request = $http({
method: "post",
url: "/Admin/SaveUser",
data: $scope.object,
file:file
}).success(function (data) {
if (data.success)
window.location.href = data.Url;
else {
alert(data.message);
$scope.username = "";
$scope.EmployeeDetailId = "";
}
}).error(function (data) {
window.location.href = data.Url;
});
}
}
});
</script>
Below is my controller...
public ActionResult SaveUser(RegisteredUser data, HttpPostedFileBase file)
{
string ImageName = Path.GetFileName(file.FileName);
string physicalPath = Server.MapPath("~/Pictures/" + ImageName);
data.picture = System.Text.Encoding.UTF8.GetBytes(physicalPath);
db.RegisteredUsers.Add(data);
db.SaveChanges();
}
Problem:
HttpPostedFileBase always returning null at controller but when i debug the cshtml page i able to see that the 'file' parameter holds all the content of uploaded data.
where i am making mistake, Please help me to resolve this issue...
Previous to HTML5, there was no way to send a file over AJAX. With HTML5, if you want to do this, you must first use the File API to read the file data, and then put the content of the file into your POST object manually. You still can't just serialize the form and call it day. Also, since this is HTML5 only, the usual caveats apply. It won't work in anything but modern browsers, which is IE10+, for example. If you need to still support IE7 or IE8, then you can't do it this way. You'll instead need to make use of some Flash or Java component for file uploads. There's tons of different libraries; just do a search.

extracting files from request

I'm using ASP.net MVC 5.
The code below works to store files, but I need to store the request or extract the files uploaded from the request so I can pass the file to a method in another class for validation BEFORE I upload to the file server.
I noticed below that Request.Files[upload].SaveAs contains the files, but how do I pass the file to another class? I tried passing the HttpPostedFileBase File to another class, but it doesn't recognize Files.
In my view:
#using (Html.BeginForm("FileUpload",
"Upload",
FormMethod.Post,
new { enctype = "multipart/form-data" }))
{ <label for="file">Upload Image:</label>
<input type="file" name="FileUpload" /><br />
<input type="submit" name="Submit" id="Submit" value="Upload" />
}
My Controller:
public ActionResult FileUpload(HttpPostedFileBase file)
{
//HttpPostedFileBase request = file;
foreach (string upload in Request.Files)
{
System.Diagnostics.Debug.WriteLine("*********************savepath:" + Request.Files[upload].FileName+"********************");
string savePath = "C:\desktop";
string newPathForFile = Path.Combine(savePath, Path.GetFileName(Request.Files[upload].FileName));
Request.Files[upload].SaveAs(Path.Combine(savePath, newPathForFile));
}
return View("Home");
}
You can't really pass the "file," since at this point there really isn't a file. We're really looking at a bunch of bytes. Your Request.Files should also have an InputStream. Use that to copy the file to a Byte[] buffer, and go from there.

Multiple file upload using single input controller

I'm attempting upload multiple files in ASP.NET MVC and my controller is
public ActionResult GalleryAdd()
{
foreach (string fil in Request.Files)
{
HttpPostedFileBase file = Request.Files[fil];
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/Images/Gallery"), fileName);
file.SaveAs(path);
}
return RedirectToAction("Index");
}
And my input field is
<input type="file" id="files" name="files" multiple>
Problem is that always upload only one file(first file) . Foreach loop only take the first file , but Request.Files Count shows number of file uploaded. What is the problem here
Change the signature of your GalleryAdd action to take an IEnumerable of HttpPostedFileBase, then you can iterate over the files passed in from the view:
public ActionResult GalleryAdd(IEnumberable<HttpPostedFileBase> files)
{
foreach (string file in files)
{
//iterate over files
}
}
Then add a file input for each file to add:
<form action="#Url.Action(GalleryAdd)" method="post" enctype="multipart/form-data">
<label for="file1">Filename:</label>
<input type="file" name="files" id="file1" />
<label for="file2">Filename:</label>
<input type="file" name="files" id="file2" />
<input type="submit" />
you can write webservice that will be called in controller.
use this link for getting help regarding upload file
also look in this link.

An object specified for refresh is not recognized

I have a update function like this:
public void Update(HomeBanner homebanner)
{
homebanner.EnsureValid();
DataSource.DataContext.Refresh(System.Data.Linq.RefreshMode.KeepCurrentValues, homebanner);
DataSource.DataContext.SubmitChanges();
}
And i write a update controller
[AcceptVerbs(HttpVerbs.Post)]
//[ValidateAntiForgeryToken]
[ValidateInput(false)]
public ActionResult ManageImages(int ? id,FormCollection form)
{
HomeBanner homebanner= BannerRepository.RetrieveById(id);
this.TryUpdateModel(homebanner);
string photoName = saveImage("photo");
if (photoName != string.Empty)
homebanner.ImageID = photoName;
BannerRepository.Update(homebanner);
return RedirectToAction("list", "Admin");
}
and then the view:
<% using (Html.BeginForm("ManageImages", "Admin", FormMethod.Post, new { enctype = "multipart/form-data" }))
{%>
<h3>Manage Images</h3>
<div class="label-field">
<label for="ID">Chọn vị trí:</label>
<%= Html.DropDownList("ID", DataHelper.Banner().ToList().ToSelectList("value", "name",Model.HomeBanner.ID.ToString()))%>
</div>
<div class="label-field">
<label for="photo">
Chọn hình</label>
<input type="file" name="photo" value=""/>
</div>
<div class="label-field">
<label for="Link">
Liên kết</label>
<input type="text" name="Link"/>
</div>
<p>
<input type="submit" value="Lưu" />
</p>
<% } %>
It get data as well but update step is not success: It mark right here
DataSource.DataContext.Refresh(System.Data.Linq.RefreshMode.KeepCurrentValues, homebanner);
and throw exception: An object specified for refresh is not recognized.
I dont know why, i see data filled to object when i debug. Plz someone help me!
Check the instance of DataContext there, maybe you are using different instance in which original object doesn't exists.
If it doesn't exist, you must first attach object to data context, then call refresh.
P.S. a tip: Make model or service for interacting with data, in controller it looks messy ;)'
I bump into this error because i was trying to update a just created object that did not exist yet on the database.

Categories