How to pass a file to a controller - c#

I have this controller :
public ActionResult Index(HttpPostedFileBase file)
{
if (file != null && file.ContentLength > 0)
try
{
string path = Path.Combine(Server.MapPath("~/Files"),
Path.GetFileName(file.FileName));
file.SaveAs(path);
ViewBag.Message = "Success";
}
catch (Exception ex)
{
ViewBag.Message = "Error:" + ex.Message.ToString();
}
return RedirectToAction("NewController", new { myFile : file });
}
My new controller :
public ActionResult NewController(HttpPostedFile myFile)
{
}
I want to pass "file" to the NewController but it gives me an error at RedirectToAction. How can I pass correct values to RedirectToAction so that it will work? Thanks.

The File is potentially very complex object and you can't pass potentially complex object in simple RedirectToAction. So you have to store File in Session to get it in your next redirection but storing data in Session is not good due to performance perspective and you have to set Session null after retrieving of data from it.
But you can use TempData instead which remains alive during subsequent requests and it immediately destroyed after you retrieved data from it.
So just add your file in TempData and retrieve it in New Controller Action.
Another thing that i noticed that you are storing Message in ViewBag. But ViewBag becomes null during redirection, so you won't be able to get ViewBag.Message in your NewControllerAction action. To make it accessible in your NewControllerAction, you have to store it in TempData but Message is going to have simple string so you can pass it as parameter to NewControllerAction action.
public ActionResult Index(HttpPostedFileBase file)
{
string Message = string.Empty;
if (file != null && file.ContentLength > 0)
try
{
string path = Path.Combine(Server.MapPath("~/Files"), Path.GetFileName(file.FileName));
file.SaveAs(path);
Message = "Success";
}
catch (Exception ex)
{
Message = "Error:" + ex.Message.ToString();
}
//Adding File in TempData.
TempData["FileData"] = file;
return RedirectToAction("NewControllerAction", "NewController", new { strMessage = Message });
}
In your new controller:
public ActionResult NewControllerAction(string strMessage)
{
if(!string.IsNullOrWhiteSpace(strMessage) && strMessage.Equals("Success"))
{
HttpPostedFileBase myFile = TempData["FileData"] as HttpPostedFileBase;
}
else
{
//Something went wrong.
}
}

Related

C# ASP.NET MVC - Download XML to Browser

I'm using ASP.NET 4.6 MVC. I'm saving an xml file as a byte array in my SQL db. I want to allow my user to download the file from the browser. I'm not getting any errors and no file is getting downloaded. I know there are plenty of these issues out there but I haven't seen one where a file isn't being downloaded (not even a corrupted one).
public ActionResult DownloadScript(int id) {
try {
var script = _db.PortalScripts.FirstOrDefault(i = >i.Id == id);
if (script != null) {
return File(script.ScriptBytes, "text/xml", script.Name);
}
}
catch(Exception e) {
FlashMessage.Danger("Error downloading script");
}
return RedirectToAction("Scripts");
}
[HttpPost]
public ActionResult UploadScript(HttpPostedFileBase file) {
try {
if (file.ContentLength > 0) {
var newScript = new PortalScript {
Name = Path.GetFileName(file.FileName),
Version = "190.161",
Description = "This is a placeholder",
Displayed = true
};
using(MemoryStream ms = new MemoryStream()) {
file.InputStream.CopyTo(ms);
newScript.ScriptBytes = ms.ToArray();
}
var existingScripts = _db.PortalScripts.FirstOrDefault(s = >s.ScriptBytes == newScript.ScriptBytes);
if (existingScripts == null) {
_db.PortalScripts.AddOrUpdate(newScript);
_db.SaveChanges();
FlashMessage.Confirmation(newScript.Name + " successfully uploaded");
}
else FlashMessage.Warning(newScript.Name + " already exists. Duplicate upload ignored.");
}
}
catch(Exception ex) {
FlashMessage.Danger("Upload failed: " + ex.Message);
}
return RedirectToAction("Scripts");
}
In my download method, my script variable is returning a properly filled out model. Not going into the catch either. Just getting redirected back to my original view with no file. Any suggestions??

asp.net MVC5 handling errors inside child action method in parent view -- would like to redirect to error page

I'm still somewhat new to ASP.NET MVC so I hope my question is clear. In my project I have a parent view, that renders partial views inside the parent view by calling #Html.Action(controller action name) inside the parent view.
My goal is that if the controller action that returns the partial view fails, I would like the application to redirect to my error page. This works perfectly fine for my controller actions that are returning full views by doing the following: return RedirectToAction("Index", "ErrorHandler", null). However in the controller methods returning partial views (that are invoked with #Html.Action inside parent View), this returns error that child action cannot do redirect.
I also tried doing, return View("~/Views/ErrorHandler/Index.cshtml"), inside controller action that returns partial view. This doesn't throw an error but results in displaying the error page inside the parent page. That is not ideal as I stated earlier, my goal is to have application fully redirect to error page.
Here is some code. Let me know if you want to see more of my code:
Inside Parent View
#Html.Action("LoadEmployeeNames")
Controller method below:
public ActionResult LoadEmployeeNames()
{
string ManageRSVPApplicationName =
ConfigurationManager.AppSettings["ManageRSVPApplicationName"];
Log log = new Log(ManageRSVPApplicationName);
try
{
int applicationId =
Convert.ToInt32(ControllerContext.HttpContext.Session["ApplicationId"]);
Application application = new Application();
application.ApplicationId = applicationId;
if (DataBase.PopulateInviteeList(ref application, ref log))
{
List<EmployeeDropDownOption> employees = new List<EmployeeDropDownOption>();
if(false)
//if (EmployeeData.LoadEmployees(ref employees, application.InviteeList, ref log))
{
string currUserAccountName = User.Identity.Name.Split('\\')[1];
EmployeeDropDownOption currEmployee = employees.FirstOrDefault(t => t.AccountName.Trim().ToLower() == currUserAccountName.Trim().ToLower());
ViewBag.CurrentUserIdentity = (currEmployee == null) ? "" : currEmployee.EmployeeID.ToString() + ":" + currEmployee.DisplayName;
int currOfficeId = 0;
if (currEmployee != null)
{
DataBase.GetOfficeId(currEmployee.Office, ref currOfficeId, ref log);
if (string.IsNullOrWhiteSpace(ConfigurationManager.AppSettings["TestOffice"]))
{
ControllerContext.HttpContext.Session["CurrentOffice"] = currEmployee.Office;
}
else
{
ControllerContext.HttpContext.Session["CurrentOffice"] = ConfigurationManager.AppSettings["TestOffice"];
}
}
ControllerContext.HttpContext.Session["CurrentOfficeId"] = currOfficeId;
EmployeeDropDown employeeNameDD = new EmployeeDropDown(employees);
return PartialView("~/Views/RSVP/RSVP/SelectEmployeeName.cshtml", employeeNameDD);
}
}
log.Capture(Log.LogLevel.Error, "Unable to load employees when " + User.Identity.Name + " attempted to view RSVP application " + applicationId);
return View("~/Views/ErrorHandler/Index.cshtml");
}
catch (Exception e)
{
log.Capture(Log.LogLevel.Error, "Unable to load employees when " + User.Identity.Name + " attempted to view RSVP application ");
log.Capture(Log.LogLevel.Error, e);
return View("~/Views/ErrorHandler/Index.cshtml");
}
}
In general avoid using try catch block in controller actions, it make error handling process hard to maintain. instead use action filters to separate error handling code from code that define application normal flow
here is a simple custom error handler filter
public class CustomHandleErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
var controllerName = (string)filterContext.RouteData.Values["controller"];
var actionName = (string)filterContext.RouteData.Values["action"];
var model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
filterContext.Result = new ViewResult
{
ViewName = "CustomError",
MasterName = Master,
ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
TempData = filterContext.Controller.TempData
};
filterContext.ExceptionHandled = true;
}
}
And use the filter on controller level or individual action as follow
[CustomHandleErrorAttribute]
public ActionResult LoadEmployeeNames()
{
string ManageRSVPApplicationName =
ConfigurationManager.AppSettings["ManageRSVPApplicationName"];
Log log = new Log(ManageRSVPApplicationName);
int applicationId = Convert.ToInt32(ControllerContext.HttpContext.Session["ApplicationId"]);
Application application = new Application();
application.ApplicationId = applicationId;
if (DataBase.PopulateInviteeList(ref application, ref log))
{
List<EmployeeDropDownOption> employees = new List<EmployeeDropDownOption>();
if (false)
//if (EmployeeData.LoadEmployees(ref employees, application.InviteeList, ref log))
{
string currUserAccountName = User.Identity.Name.Split('\\')[1];
EmployeeDropDownOption currEmployee = employees.FirstOrDefault(t => t.AccountName.Trim().ToLower() == currUserAccountName.Trim().ToLower());
ViewBag.CurrentUserIdentity = (currEmployee == null) ? "" : currEmployee.EmployeeID.ToString() + ":" + currEmployee.DisplayName;
int currOfficeId = 0;
if (currEmployee != null)
{
DataBase.GetOfficeId(currEmployee.Office, ref currOfficeId, ref log);
if (string.IsNullOrWhiteSpace(ConfigurationManager.AppSettings["TestOffice"]))
{
ControllerContext.HttpContext.Session["CurrentOffice"] = currEmployee.Office;
}
else
{
ControllerContext.HttpContext.Session["CurrentOffice"] = ConfigurationManager.AppSettings["TestOffice"];
}
}
ControllerContext.HttpContext.Session["CurrentOfficeId"] = currOfficeId;
EmployeeDropDown employeeNameDD = new EmployeeDropDown(employees);
return PartialView("~/Views/RSVP/RSVP/SelectEmployeeName.cshtml", employeeNameDD);
}
}
log.Capture(Log.LogLevel.Error, "Unable to load employees when " + User.Identity.Name + " attempted to view RSVP application " + applicationId);
return View("~/Views/ErrorHandler/Index.cshtml");
}
Finally add CustomError.cshtml to Views/Shared folder

An error occurred while processing your request. MVC 4

I'm creating a MVC 4 application, I had error like following.
I tried lot of things but I can't find what is the problem.here is my Controller source
public ActionResult Index(string EventId)
{
HttpCookie cookie = this.ControllerContext.HttpContext.Request.Cookies["User"];
if (cookie != null)
{
string Type = (cookie["Type"] == null || cookie["Type"] == "") ? null : cookie["Type"].ToString();
string Username = (cookie["Username"] == null || cookie["Username"] == "") ? null : cookie["Username"].ToString();
ViewBag.Message = Type;
ViewBag.Username = Username;
try
{
string ReplaceEventID = EventId.Replace('-', '/');
ViewBag.Message = ReplaceEventID;
IEnumerable<Job> JobListRelatedToEvent = DBContext.Jobs.Where(x => x.EventId == ReplaceEventID);
return View(JobListRelatedToEvent);
}
catch
{
return View();
}
}
else
{
return RedirectToAction("Index", "Home");
}
}
UPDATE:
When it run on my local machine it works fine, but after i published to the server I got this error.
Can anyone tell about what's the wrong?
I am facing the same issue and this issue we are getting if the custom error is on.
What you need to do the changes in web.config and add the below code.
So, you will get the actual error of the application or in code level.
<system.web>
<customErrors mode="Off" />
Now insted of generic page of IIS it will shows the error.
I don't know if it will help you, but I ran into an issue where the POST action had [RequireHttps], but the GET didn't. That caused the issue for me. So, check you don't have restrictions on one verb and not the other, especially with a form post.
The issue didn't show until I published to Production because DEBUG directives removed the [RequireHttps] attribute :)
TRY THIS :
public ActionResult Job(string EventId)
{
HttpCookie cookie = this.ControllerContext.HttpContext.Request.Cookies["User"];
if (cookie != null)
{
string Type = (cookie["Type"] == null || cookie["Type"] == "") ? null : cookie["Type"].ToString();
string Username = (cookie["Username"] == null || cookie["Username"] == "") ? null : cookie["Username"].ToString();
ViewBag.Message = Type;
ViewBag.Username = Username;
try
{
string ReplaceEventID = EventId.Replace('-', '/');
ViewBag.Message = ReplaceEventID;
IEnumerable<Job> JobListRelatedToEvent = DBContext.Jobs.Where(x => x.EventId == ReplaceEventID);
return View(JobListRelatedToEvent);
}
catch
{
return View();
}
}
else
{
return RedirectToAction("Index", "Home");
}
}

mvc 4 - html.dropdownlist retrieve no data from database, it should return blank instead of throw error

I am a beginner of MVC 4. I wrote code to retrieve data and populate data into dropdownlist which is working fine. But if database is broken, data cannot be retrieved so I want the dropdownlist to display blank or like "no data" in a nice way instead of throw error. I tried to use ViewBag.NoData but it doesnt work. How to solve this problem with my below code:
HomeController C#:
public ActionResult Index()
{
try
{
ViewBag.PersonList = Helper.LoadPersonData();
if (ViewBag.PersonList == null)
{
ViewBag.NoPersonData = "NO DATA";
}
}
catch (Exception ex)
{
TempData["Message"] = string.Format("An error occurred. Details: {0}", ex.Message);
}
return View(persons);
}
Index.cshtml:
<td>#Html.DropDownList("txtPersonName",((IEnumerable<SelectListItem>)ViewBag.PersonList).Any() ? new SelectList(ViewBag.PersonList as IEnumerable<SelectListItem>,"Value", "Text",selectedValue: Session["search"] != null ? (((SearchKey)Session["search"]).PersonName) : (string)ViewBag.NoPersonData ): null, "---------SELECT---------")</td>
You could just return a list containing an "No Data" entry:
public ActionResult Index()
{
try
{
ViewBag.PersonList = Helper.LoadPersonData();
if (ViewBag.PersonList == null)
{
ViewBag.PersonList = new List<SelectListItem>()
{
new SelecListItem()
{
Value = "nodata",
Text = "No Data"
}
};
}
}
catch (Exception ex)
{
TempData["Message"] = string.Format("An error occurred. Details: {0}", ex.Message);
}
return View(persons);
}
Your PersonList may be empty. Try this:
if (ViewBag.PersonList == null)
{
ViewBag.PersonList = new List<SelectListItem>();
ViewBag.NoPersonData = "NO DATA";
}

MVC 3 Image field validation

I have a form that I upload two images. I want to do validation on these images, such as image size and I want to be able to check if the image field are not left blank.
public ActionResult Create(NewsViewModel newsViewModel, IEnumerable<HttpPostedFileBase> files)
{
try
{
//more code here
var originalFile = string.Empty;
IList<string> images = new List<string>(2);
foreach (var file in files)
{
if (file != null && file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
if (fileName != null) originalFile = Path.Combine(Server.MapPath(upload_path), DateTime.Now.Ticks+"_ "+ fileName);
file.SaveAs(originalFile);
images.Add(originalFile);
}
}
if (images.Count == 2)
{
newsViewModel.News.Thumbnail = images[0] ?? "";
newsViewModel.News.Image = images[1] ?? "";
}
//more code here
return RedirectToAction("Index");
}
catch
{
return View();
}
}
How can i send response back to the form after checking the image sizes and find out that they are not valid?
or if images.count is not 2, how do i validate that?
any ideas ?
You could add an error to the ModelState and then re-show the same view, something like this:
ModelState.AddModelError(string.Empty, "The image is not valid becuase...");
return View(newsViewModel)
Then in the view if you have a ValidationSummary your validation error message would be shown on it (the first argument is the "key" which matches to the control ID to show the message next to usually, which is why it is String.empty here but maybe you have a control you want it to be associated with).

Categories