I am setting an error Message in the viewbag to show to the user after each postback how ever I do not want to show this error message on page reload or refresh. I have tried to set it to null but it still is shown because the json parameter still contains the values of the first submit.
[HttpPost]
[CustomAuthorize(Definitions.RoleAnalystManager, Definitions.RoleProjectManager)]
public ActionResult ExportReportAllMediaDetailsCsv(string json)
{
ViewBag.Error = null;
var serializer = new JavaScriptSerializer();
var reportParams = serializer.Deserialize<ReportAllMediaDetailsParams>(json);
var rows = uow.Items.Report_AllMediaDetails(reportParams.profileID, reportParams.organisationID, reportParams.startDate, reportParams.endDate).ToList();
if (rows.Count <= 1)
{
ViewBag.Error = "There were no results for the provided parameters, please adjust the parameters and try again.";
return View("AllMediaDetails");
}
This is because refreshing the page actually resubmits the previous request, so your POST request is resubmitted by the browser. Can't test this at the minute; however, perhaps try setting a bool - TempData["FirstLoad"] - to true on the GET request and then do something like this in the POST method:
if (TempData["FirstLoad"] != null && TempData["FirstLoad"] == true)
{
if (rows.Count <= 1)
{
ViewBag.Error = "...";
}
}
else
{
ViewBag.Error = null;
return View();
}
TempData["FirstLoad"] = false;
return View("AllMediaDetails");
I'm basing this on the fact that TempData is stored in the session, so its values should be retained on a refresh (rather than resubmitted as they were originally as if the value was passed as, for example, a hidden field).
Related
I have this form with a lot of input fields in page including dropdownlist, textboxes and textarea. And at the end of page, I have file uploading field.
The problem is when I entered all the data in the fields and I attached a file at the end, all the data I entered disappears and I need to retype again.
I have this code below. Here I use a Session to hold the data to retain the values entered in fields when uploading a file, but still the data disappears after a file has uploaded.
Can someone help me resolve this? Thank you so much.
CONTROLLER
[HttpGet]
[Authorize]
public ActionResult Create()
{
All_Issues all_Issues = new All_Issues();
ViewBag.StatusID = new SelectList(db.issue_status_ref, "StatusID", "StatusName");
ViewBag.IncLevelID = new SelectList(db.incident_level_ref, "IncLevelID", "Description");
ViewBag.DeptID = new SelectList(db.all_department_ref, "department_id", "department_name");
ViewBag.CatID = new SelectList(db.category_ref, "CatID", "Category");
ViewBag.NocID = new SelectList(db.nature_of_occurrence_ref, "NocID", "Title");
ViewBag.UsersID = new SelectList(db.ad_users, "user_id", "display_name");
if (Session["ir_session"] != null)
{
return View("Create", (All_Issues)Session["ir_session"]);
}
return View(new All_Issues());
}
FILE UPLOAD
[HttpPost]
public ActionResult FileUpload(Guid? IRID, All_Issues all_Issues)
{
Session["ir_session"] = all_Issues;
HttpFileCollectionBase ir_files;
List<files_ref> ir_uploadFileModel = new List<files_ref>();
ir_files = Request.Files;
string mapPath = "~/App_Data/UploadedFiles/";
FileUploads ir_fileupload = new FileUploads();
ir_fileupload.UploadFiles(null, null, IRID, ir_files, mapPath, "IR");
if (IRID == null)
{
return RedirectToAction("Create");
}
else
{
return RedirectToAction("Edit", new { id = IRID });
}
}
Already found a solution to this. Just took a long time to post an update.
What I did is still the same. I use session to store the data in my fields and I call this session in every action so that whenever I made a lot of action in the form, the data will retain until the page is submitted.
if (Session["ir_session"] != null)
{
IMRDTO model = (IMRDTO)Session["ir_session"];
return View("Create", (IMRDTO)Session["ir_session"]);
}
And with this line of code, which I call in every action, I retain all the data in fields even when the page reloaded.
Session["ir_session"] = imr;
Hoping it would also help someone.
I'm trying to build a very simple website to display some test data being added & updated using asp.net mvc (with razor) but whenever data is posted to my Post method, my data is not being updated. I'm trying to get a unordered list (for now) to be updated the second a post is triggered.
I'm posting my data as JSON using the following code:
string jsonDeviceData = SerializeHelper.Serialize<IDeviceData>(deviceData,
ContentTypeEnum.Json, false);
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(localServerUrl);
webRequest.Method = "POST";
webRequest.ContentType = "application/json"; //"application/x-www-form-urlencoded";
byte[] deviceDataBuffer = Encoding.UTF8.GetBytes(jsonDeviceData);
Task<Stream> requestTask = webRequest.GetRequestStreamAsync();
using (Stream requestStream = requestTask.Result)
{
requestStream.Write(deviceDataBuffer, 0, deviceDataBuffer.Length);
}
Task<WebResponse> responseTask = webRequest.GetResponseAsync();
using (StreamReader requestReader = new StreamReader(responseTask.Result
.GetResponseStream()))
{
string webResponse = requestReader.ReadToEnd();
Debug.WriteLine("Web Response: " + webResponse);
}
Below is the code I'm using in the POST method. Don't worry about the logic being so simplistic and probably horrible, but I'm just dabbling with this idea. Data will be stored in SQL Server database and I'll use EF if I decide to go further with this:
[HttpPost()]
public ActionResult Index(DeviceModel model)
{
if (ModelState.IsValid && model != null)
{
var deviceViewModelList = HttpContext.Application["DeviceList"]
as List<DeviceViewModel> ?? new List<DeviceViewModel>();
if (deviceViewModelList.All(m => !string.Equals(m.Name,
model.Name,
StringComparison.InvariantCultureIgnoreCase)))
{
deviceViewModelList.Add(new DeviceViewModel(model));
}
HttpContext.Application["DeviceList"] = deviceViewModelList;
var homePageViewModel = new HomePageViewModel
{
DeviceList = deviceViewModelList
};
return RedirectToAction("Index");
}
else
{
return View();
}
}
My model is passed correctly and everything works ok when the data is posted my page is not updated, even after calling RedirectToAction("Index");
The code below gets called the first time the page is loaded and after calling the RedirectToActio("Index"):
public ActionResult Index()
{
ViewBag.Title = "Test Server";
var deviceViewModelList = HttpContext.Application["DeviceList"]
as List<DeviceViewModel> ?? new List<DeviceViewModel>();
var homePageViewModel = new HomePageViewModel
{
DeviceList = deviceViewModelList
};
return View(homePageViewModel);
}
This is the code I have in my .cshtml page:
<ul>
#if (Model?.DeviceList != null)
{
foreach (var device in Model.DeviceList)
{
<li>#device.Name</li>
}
}
</ul>
If I check Fiddler, the data, in this case, the list is build correctly.
If I press F5 my data is displayed correctly.
I've read so many articles at this stage and I still haven't got a solution, one of them being View not updated after post and while I've tried ModelState.Clear(); and as you can see from my code I'm using #device.Name which is one of the suggestion. I'm not sure about the last one.
Another article I read was ASP NET MVC Post Redirect Get Pattern but again to no avail.
I'm obviously missing something.
Most articles/samples I've been looking at refer to posting via a Form and I know I'm posting, but is that the same as posting via a Form?
Also my page's viewModel is for my page and it contains a list of devices. Is that OK rather than passing the list of device as the viewmodel to the page? The reason I'm doing this is that I will want to access other lists at a later stage.
Has anyone got any suggestions?
Much appreciated.
I have already looked at these links for references.
Link 1: ASP.Net MVC and state - how to keep state between requests
Link 2: ASP.NET MVC: Keeping last page state
I have a few pages that a user will be filling out. We will call these pages Page 1. If they get to a field that they need to select from, drop down, but need to create a new item to be included in the drop down, because it will be used again later, they go to a new page, Page 2, to create the item. After create they create the item they are returned to Page 1 to finishing filling out the form. The problem is that the Page 1 is now erased because is a new page load. I would like for this to persist for when they come back so they don't have to refill out fields.
The route I am currently Link2 using a cookie. I don't know how to set the cookie's info before it gets to the next page, or how to pass it to that page before since it is going to a GET method and not a POST.
GET method for Page 1:
public ActionResult Create()
{
var courseTitles = (from title in db.CourseTitles
join type in db.CourseTypes on title.Type equals type.CourseTypeID
select new
{
CourseTitleID = title.CourseTitleID,
Title = title.Title + " - " + type.Type
});
Course course = new Course();
if (Request.Cookies["CourseInfo"] != null) //If it's not null, set the model.
{
HttpCookie cookie = Request.Cookies["CourseInfo"];
course.ClassNumber = Convert.ToInt32(cookie.Values["ClassNumber"]);
course.CourseStartDate = Convert.ToDateTime(cookie.Values["StartDate"]);
course.CourseEndDate = Convert.ToDateTime(cookie.Values["EndDate"]);
ViewBag.CourseList = new SelectList(courseTitles, "CourseTitleID", "Title", cookie.Values["CourseTitle"]);
return View(course);
}
ViewBag.CourseList = new SelectList(courseTitles, "CourseTitleID", "Title");
return View();
}
GET and POST method for Page 2:
public ActionResult NewCourseTitle()
{
ViewBag.Type = new SelectList(db.CourseTypes, "CourseTypeID", "Type");
return View();
}
//
//Post:
[HttpPost]
public ActionResult NewCourseTitle(CourseTitle courseTitle)
{
if (ModelState.IsValid)
{
db.CourseTitles.AddObject(courseTitle);
db.SaveChanges();
return RedirectToAction("Create", "Course");
}
return View();
}
Let me know if you need more code.
You can use TempData to store objects between requests:
public ActionResult Create()
{
var courseTitles = (from title in db.CourseTitles
join type in db.CourseTypes on title.Type equals type.CourseTypeID
select new
{
CourseTitleID = title.CourseTitleID,
Title = title.Title + " - " + type.Type
});
Course course = new Course();
if (TempData["CourseInfo"] != null) //If it's not null, set the model.
{
course = TempData["CourseInfo"] as Course;
ViewBag.CourseList = new SelectList(courseTitles, "CourseTitleID", "Title", course.Title);
return View(course);
}
ViewBag.CourseList = new SelectList(courseTitles, "CourseTitleID", "Title");
return View();
}
In order to store the Course simply use TempData["CourseInfo"] = course
TempData exposes couple of options that define for how long its content is going to be persisted. You can read about it here
You could use some JavaScript to modify the GET request to NewCourseTitle so that it will contain the course data that the user entered.
With jQuery it could look roughly like this:
$(function () {
var newCourseTitleLink = $('#new-course-title-link');
newCourseTitleLink.on("click", function ()
{
document.location.href = newCourseTitleLink.attr('href') + '?' + $('#course-data-form').serialize();
});
});
Then you can create a cookie in your action method NewCourseTitle:
public ActionResult NewCourseTitle(int classNumber, ... /*other form values*/)
{
var cookie = new HttpCookie("CourseInfo");
cookie.Values.Add("ClassNumber", classNumber.ToString());
...
Response.SetCookie(cookie);
ViewBag.Type = new SelectList(db.CourseTypes, "CourseTypeID", "Type");
return View();
}
Here's my cshtml code:
#model pedidosOnlineMVC.Models.Administrador
#{
Layout = "~/Views/SuperUser/_LayoutSU.cshtml";
}
#using (var f = Html.Bootstrap().Begin(new Form()))
{
#f.FormGroup().CustomControls(Html.AntiForgeryToken())
#f.FormGroup().TextBoxFor(model=>model.nome)
#f.FormGroup().TextBoxFor(model=>model.cpf).Data(new {mask="999.999.999-99"})
#f.FormGroup().TextBoxFor(model=>model.telefone).Data(new {mask="(99)99999-9999"})
#f.FormGroup().TextBoxFor(model=>model.login)
#f.FormGroup().PasswordFor(model=>model.senha)
#f.FormGroup().TextBoxFor(model => model.fim_gerencia).Data(new { provide = "datepicker", date_format = "mm/dd/yyyy" })
#f.FormGroup().CustomControls(#Html.Bootstrap().SubmitButton().Text("Cadastrar"))
}
And here's view's controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult cadAdmin([Bind(Include = "Administrador_Id, nome, cpf, telefone, login, senha, fim_gerencia")] Administrador adm)
{
if (ModelState.IsValid)
{
if (Helpers.Helpers.validaCPF(adm.cpf))
if (db.Administrador.ToList().Where(x => x.cpf == adm.cpf).ToArray().Length == 0)
{
adm.senha = System.Text.Encoding.Default.GetString(SHA1.Create().ComputeHash(System.Text.Encoding.UTF8.GetBytes(adm.senha)));
db.Administrador.Add(adm);
db.SaveChanges();
return RedirectToAction("Index");
}
else
{
ModelState.AddModelError("cpf", "CPF já cadastrado");
return View("Index", "Index");
}
else
{
ModelState.AddModelError("cpf", "CPF inválido");
return View(adm);
}
}
Type type = adm.GetType();
PropertyInfo[] props = type.GetProperties();
for (int i = 2; i < props.Length; i++)
if (ModelState.Values.ToList()[i-2].Errors.Count>0)
ModelState.AddModelError(props[i].Name, props[i].Name + " inválido");
return PartialView(adm);
}
The problem that I have is that the date value from the field fim_gerencia is not passing through. Everything else works fine, excepet the Date.
I'm using the datepicker found here: http://bootstrap-datepicker.readthedocs.org/en/release/
It shouldn't be a problem though, beacause I'm using date on another class and it works fine with he exact same code.
Anyone know what's wrong?
In your situation, first thing I would check is the id of the textbox of the date field. Does it contain the expected id value? e.g.
<input ..... id="fim_gerencia"......
If that's correct, then open the Network window in the browser dev tools. When you submit the page, have a look at the request by clicking on it in the Network page. Take a look at the request details, a section of which will be the form values passed to the server. In that section look for fim_gerencia.
Do those first.
If it's still not being passed, try removing the [Bind(Include=.... bit, as you don't need that in your example. It's worth removing that attribute and checking the result.
This ought to be simple enough, although I find I can only set cookies but not read them back, despite my browser showing me the cookie.
In my HomeController I set the cookie once a user enters a valid string:
[HttpPost]
public ActionResult Index(string fMemberCode)
{
try
{
// TODO: controller-->member table module-->member data gateway-->DB
// Check member num against member table
// Return cookie if exists
// Return error if not
MembersModule membersModule = new MembersModule();
int memberId = membersModule.AuthMember(fMemberCode);
if (memberId > 0)
{
HttpCookie mCookie = new HttpCookie("MMedia");
mCookie.Value = memberId.ToString();
Response.Cookies.Add(mCookie);
}
else { }
return RedirectToAction("Index");
}
catch
{
return View();
}
}
Then later on, in a different context, the LibraryController needs to check the cookie is present:
public LibraryController()
{
// TODO
// Check member cookie present
int id = int.Parse(Request.Cookies["Media"].Value);
if (id > 0)
this.module = new LibraryModule(id);
else throw new Exception("Invalid cookie");
}
However, when stepping through the code in VS2012 when the line of execution in LibraryController reaches:
int id = int.Parse(Request.Cookies["Media"].Value);
The exception is thrown: Object reference not set to an instance of an object
You can't access the Request property in the constructor of your controller. It doesn't exist at that point in the controller life cycle.
Perhaps an action or controller filter might help you.