mvc save file to folder in site - c#

I'm trying to save files to a folder in my site, but I keep receiving an UnauthorizedAccessException error.
[HttpPost]
public ActionResult Edit(Product product, HttpPostedFileBase image)
{
var img = Path.GetFileName(image.FileName);
if (ModelState.IsValid)
{
if (image != null && image.ContentLength > 0)
{
var path = Path.Combine(Server.MapPath("~/Content/productImages/"),
System.IO.Path.GetFileName(image.FileName));
image.SaveAs(path);
product.ImageName = img;
}
// save the product
repository.SaveProduct(product);
// add a message to the viewbag
TempData["message"] = string.Format("{0} has been saved", product.Name);
// return the user to the list
return RedirectToAction("Index");
}
else
{
// there is something wrong with the data values
return View(product);
}
}
HERE IS THE VIEW
#using (Html.BeginForm("Edit", "Admin", FormMethod.Post,
new { enctype = "multipart/form-data" })) {
#Html.EditorForModel()
<div class="editor-label">Image</div>
<div class="editor-field">
#if (Model.ImageName == null) {
#:None
} else {
<img width="150" height="150"
src="#Url.Action("GetImage", "Product", new { Model.ProductID })" />
}
<div>Upload new image: <input type="file" name="image" id="image"/></div>
</div>
<input type="submit" value="Save" />
#Html.ActionLink("Cancel and return to List", "Index")
}
I'm receiving the error on the image.SaveAs(path); line
I can't see what exactly I'm doing wrong. Any help?

Looks like a permission problem
Change the Permissions on productImages folder so that ASP.NET can write to that.

Related

Post data from a partial view to another action

Just started with MVC and trying to do the following:
having a Details.cshtml with the following part on one of my tabs:
<!-- DETAILS TAB CONTENT -->
<div class="tab-pane profile active" id="details-tab">
#if (ViewBag.ScreenMode == Constants.ScreenMode.View)
{
#Html.Partial("_ViewDetails", Model)
}
else
{
#*#Html.Partial("_EditDetails", Model)*#
<div id="DetailsEdit">
#{Html.RenderPartial("_EditDetails");}
</div>
}
</div>
My _ViewDetails.cshtml shows detail information and has the following to go to the Edit mode:
#Html.ActionLink("Edit", "Details", new { id = Model.EmployeeId, screenMode = Constants.ScreenMode.Edit })
When clicked, indeed the tab shows the contents of the partial view _EditDetails. My _EditDetails.cshtml looks like this:
#using (Html.BeginForm("Edit", "Employee", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.EmployeeId)
#* fields with editable controls. Left it out here *#
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
and having the following methods in my controller:
public ActionResult Details(Guid? id, Constants.ScreenMode? screenMode)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Employee employee = employeeManager.Get(id.GetValueOrDefault());
if (employee == null || employee.EmployeeId == null || employee.EmployeeId == Guid.Empty)
return HttpNotFound();
if (screenMode == null)
screenMode = Constants.ScreenMode.View;
ViewBag.ScreenMode = screenMode;
return View(employee);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Guid? id, HttpPostedFileBase upload)
{
// code here
return RedirectToAction("Details", "Employee", new { id = employeeToUpdate.EmployeeId, screenMode = Constants.ScreenMode.View });
}
However, when I press the save button from the edit partial view, it never hits my code Edit action in my controller. It only goes back to the Details action, which gets the info again. I thought by using the following at the beginning of my partial view, I could make the post go to my Edit action:
#using (Html.BeginForm("Edit", "Employee", FormMethod.Post, new { enctype = "multipart/form-data" }))
What do I miss or are my thoughts completely wrong?
Thanks in advance.
Aarghhhh, found it.
My Details.cshtml started with:
#using (Html.BeginForm("Details", "Employee", null, FormMethod.Post, new { enctype = "multipart/form-data" }))
Removed this and now it's working.
Overlooked this for days.
Thanks.

Multiple TempData variables passed to same action

I'm creating ASP.NET web application using MVC and Entity Framework. I have two different success messages I am passing to an index action for when a user clocks in or clocks out. The success message will print correctly when a user clocks in, but will not when a user clocks out for some reason.
The actions are very similar and I used all of the same conventions so I can't figure out why one would print and another would not. I've tried debugging and there are no red flags and everything updates in the database like it should. Is it not possible to pass multiple TempData variables to the same action?
Here is the relevant code:
Controller
// GET: TimeClocks
public ActionResult Index()
{
ViewBag.ClockInSuccess = TempData["ClockInSuccess"];
ViewBag.ClockOutSuccess = TempData["ClockOutSuccess"];
return View();
}
[HttpPost]
public ActionResult ClockIn(TimeClock timeClock)
{
if(db.TimeClocks.ToList().Count == 1)
{
ModelState.AddModelError("ExistsError", "You already clocked in at" + timeClock.ClockIn);
}
string currentUserId = User.Identity.GetUserId();
ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == currentUserId);
timeClock.ApplicationUser = currentUser;
timeClock.ClockIn = DateTime.Now;
if (ModelState.IsValid)
{
db.TimeClocks.RemoveRange(db.TimeClocks.ToList());
db.TimeClocks.Add(timeClock);
db.SaveChanges();
TempData["ClockInSuccess"] = "You clocked in successfully at " + timeClock.ClockIn;
return RedirectToAction("Index");
}
return RedirectToAction("Index", timeClock);
}
[HttpPost]
public ActionResult ClockOut(TimeClock timeClock)
{
timeClock = db.TimeClocks.FirstOrDefault();
if(timeClock.ClockIn == null)
{
ModelState.AddModelError("NullError", "You must clock in before you can clock out.");
return RedirectToAction("Index");
}
timeClock.ClockOut = DateTime.Now;
if (ModelState.IsValid)
{
db.Entry(timeClock).State = EntityState.Modified;
db.SaveChanges();
TempData["ClockOutSuccess"] = "You clocked out successfully at " + timeClock.ClockOut;
return RedirectToAction("Index");
}
return RedirectToAction("Index", timeClock);
}``
View
#model FinalProject.Models.TimeClock
#{
ViewBag.Title = "Create";
}
<h2>Employee Time Clock</h2>
#using (Html.BeginForm("ClockIn", "TimeClocks"))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Clock In" class="btn btn-lg" />
</div>
</div>
</div>
}
#using (Html.BeginForm("ClockOut", "TimeClocks"))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Clock Out" class="btn btn-lg" />
</div>
</div>
</div>
}
#{
if (#ViewBag.ClockInSuccess != "")
{
<p class="alert-success">#ViewBag.ClockInSuccess</p>
}
else if (#ViewBag.ClockOutSuccess != "")
{
<p class="alert-success">#ViewBag.ClockOutSuccess</p>
}
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
TempData is lost once you read it so you need to do a Peek or a Keep:
ViewBag.ClockInSuccess = TempData.Peek("ClockInSuccess");
ViewBag.ClockOutSuccess = TempData.Peek("ClockOutSuccess");
http://www.codeproject.com/Articles/818493/MVC-Tempdata-Peek-and-Keep-confusion

How to upload file in ASP.NET razor

I want to upload a file in folder image.
I use ASP.NET with MVC4 and razor.
I have this in my View :
<div class="editor-label">
#Html.Label("Descriptif")
</div>
<div class="editor-field">
<input type="file" name="fDescriptif" />
#Html.ValidationMessageFor(model => model.fDescriptif)
</div>
[...]
<p>
<input type="submit" value="Create" />
</p>
In my controller :
[HttpPost]
public ActionResult Create(formation formation)
{
if (ModelState.IsValid)
{
db.formations.Add(formation);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(formation);
}
In my model :
public string fDescriptif { get; set; }
I have no idea what I must do to upload my file in my folder "image" and save just the name of my file in my database. When I validate my form it's my complete path who saved.
On your view make sure you have added enctype = "multipart/form-data" to your form tag, and then try like this:
#using (Html.BeginForm("ActionName", "ControllerName", FormMethod.Post, new { enctype = "multipart/form-data", id = "frmID" }))
And you can Get your file in Controller Action AS:
[HttpPost]
public ActionResult Create(formation formation,HttpPostedFileBase file)
{
if (ModelState.IsValid)
{
// Get your File from file
}
return View(formation);
}
you can find many questions like this, even on SO many answers have been given for this topic.
Here are 2 of the links. you should find your answer in this links. and many more other answers are there for this on SO. just google it, and you will find them.
https://stackoverflow.com/a/5193851/1629650
https://stackoverflow.com/a/15680783/1629650
Your form doesn't contain any input tag other than the file so in your controller action you cannot expect to get anything else than the uploaded file (that's all that's being sent to the server). One way to achieve this would be to include a hidden tag containing the id of the model which will allow you to retrieve it from your datastore inside the controller action you are posting to (use this if the user is not supposed to modify the model but simply attach a file):
#using (Html.BeginForm("ACTION", "CONTROLLER", FormMethod.Post, new { enctype = "multipart/form-data" }))
#Html.TextBoxFor(m => m.File, new { #type = "file" })
AND IN CONTROLLER
[HttpPost]
public ActionResult ACTION(ViewModels.Model taskModel)
{
string path = #"D:\Projects\TestApps\uploadedDocs\";
if (taskModel.File != null) {
taskModel.File.SaveAs(path +taskModel.TaskTitle
+ taskModel.File.FileName);
newUserProject.DocumentTitle = taskModel.TaskTitle
+ taskModel.File.FileName;
newUserProject.DocumentPath = path + taskModel.File.FileName;
}
}
<form action="" method="post" enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" />
<input type="submit" />
</form>
And your controller should be as below
[HttpPost]
public ActionResult Index(HttpPostedFileBase file)
{
if (file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
file.SaveAs(path);
}
return RedirectToAction("Index");
}

post values through mvc repeater

Form-
#using IEnumerable<Myapplication.Models.CardModel>
#foreach(var item in Model)
{
<form method="post" action="/Upload/EditCard/?cardID=#item.cardID" enctype="multipart/form-data">
<h3>
Change Title-
</h3>
<div class="display-field">
#Html.HiddenFor(m => item.cardTitle)
#Html.TextBoxFor(cardTitle => item.cardTitle)
</div>
<img src="#item.cardFilePath" />
<input type="submit">
</form>
}
Method-
[HttpPost]
public void EditCard(CardModel card, HttpPostedFileBase file) {}
Where in form I am sending values through this form, and cardID is sent in form's url parameter.
For other value like cardTitle is coming null in EditCard Method.
How do I get this value using repeater?
However when data is not IEnumerable type , then I was able to send value through form directly as-
#using Myapplication.Models.CardModel
<form method="post" action="/Upload/EditCard/?cardID=#Model.cardID" enctype="multipart/form-data">
<h3>
Change Title-
</h3>
<div class="display-field">
#Html.HiddenFor(m => m.cardTitle)
#Html.TextBoxFor(m=> m.cardTitle)
</div>
<img src="#Model.cardFilePath" />
<input type="submit">
</form>
}
but In case of repeater values don't come at method. As soon as i change values of title, or anything else, The values comes old one.
From the pictures-
And server code-
As you can see from 1st picture that, Form is editable for one record from the list. As soon as I change something in i.e. Title to --> 2nd Upload to 2nd Uploadsssss
Then this values is null at server side. I mean this form don't send values of it.
Note-
However I can send values in URL through parameters. But if I do change in something like Title or aboutCard model value. The form keeps sending only those values which has come by default while the form was rendered.
Rather than using foreach use for loop. To apply indexing you would need to convert Model to List
#{ var list=Model.ToList();)
#for(var i = 1;i <= list.Count();i++)
{
<form method="post" action="/Upload/EditCard/?cardID=#list[i].cardID" enctype="multipart/form-data">
<h3>
Change Title-
</h3>
<div class="display-field">
#Html.HiddenFor(m => list[i].cardTitle)
#Html.TextBoxFor(m=> list[i].cardTitle)
</div>
<img src="#list[i].cardFilePath" />
<input type="submit">
</form>
}
Update..
I have tested same but doesnt work. I have created workaround check if that helps.
In controller get title using cardId
var title=Request["[" + (model.cardTitle)+ "].cardTitle"];
Same thing can be done for other properties for model.
Note that i have changed for loop, index now starts with 1
You need to change IEnumerable to IList, and then you'll be able to bind Model correctly by index.
See this working exaple.
View Page
#model IList<MvcApplication3.Models.CardModel>
#using (Html.BeginForm("EditCard", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
for (int i = 0; i < Model.Count; i++)
{
#Html.HiddenFor(m => Model[i].CardID)
#Html.TextBoxFor(cardTitle => Model[i].CardTitle)
<img src="#Model[i].CardFilePath" />
<input type="file" name="files">
}
<br>
<input type="submit" value="Upload File to Server">
}
Controller
[HttpPost]
public void EditCard(IList<CardModel> cm, IEnumerable<HttpPostedFileBase> files)
{
string strfile = string.Empty;
string cardTitle = string.Empty;
if (files != null)
{
foreach (var file in files) //loop through to get posted file
{
strfile = file.FileName;
}
}
if (cm != null)
{
foreach (var item in cm) //loop through to get CardModel fields
{
cardTitle = item.CardTitle;
}
}
}
I dont know if this helps in solving your problem. I tried this and it works really well.
The Model
public class CardFileModel
{
public int CardId { get; set; }
public string Name { get; set; }
public HttpPostedFileBase File { get; set; }
}
Index Action
public ActionResult Index()
{
List<CardFileModel> cards = new List<CardFileModel>
{
new CardFileModel{ CardId =1 , Name="Card1" },
new CardFileModel{ CardId =2 , Name="Card2" }
};
return View(cards);
}
Home View
#model List<MVC3Stack.Models.CardFileModel>
#{
ViewBag.Title = "Home Page";
}
<h2>#ViewBag.Message</h2>
#for (int i = 0; i < Model.Count; i++)
{
using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div>
<div>
#Html.TextBoxFor(x => x[i].CardId)
</div>
<div>
#Html.TextBoxFor(x => x[i].Name)
</div>
#Html.TextBoxFor(x => x[i].File, new { type = "file" })
<input type="submit" value="submit" id="submit" />
</div>
}
}
index post action
[HttpPost]
public ActionResult Index(List<CardFileModel> card)
{
//Access your card file from the list.
var name = card.FirstOrDefault().Name;
return View();
}
And here are the results in the quick watch
Hope this helps.

Cannot Upload image to server using asp.net mvc

I want to upload image to the server, The below code is working properly when i run the the code locally on my system, but when i upload it to the server it gives error message - The model item passed into the dictionary is of type 'Login.Models.User', but this dictionary requires a model item of type 'System.Collection.Generic.IEnumerable'[Login.Models.User]'.Please help to solve this issue.
public ActionResult FileUpload(HttpPostedFileBase file, Login.Models.User model)
{
if(ModelState.IsValid)
{
try
{
var user=db.User.FirstOrDefault(c=>c.Userid==model.Userid);
if (file != null)
{
string pic = System.IO.Path.GetFileName(file.FileName);
string path = System.IO.Path.Combine(Server.MapPath("~/images/profile/"), pic);
file.SaveAs(path);
user.imagepath = "http://sampleApp.com/images/profile/" + pic;
}
Catch(Exception ex)
{
ModelState.AddModelError("",ex.Message);
}
return View("ViewAdmin",model);
}
db.ObjectStateManager.ChangeObjectState(user,System.Data.EntityState.Modified);
db.SaveChanges();
return RedirectToAction("User");
}
View
#model Login.Models.User
#using (Html.BeginForm("FileUpload", "Home", FormMethod.Post, new { enctype = "multipart/form-data"}))
{
<label for="file">Upload Image:</label>
<input type="file" name="file" id="file" style="width: 100%;" />
<input type="submit" value="Upload" class="submit" />
}

Categories