View not updating after post with ASP.Net MVC - asp.net-mvc

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.

Related

MVC - Posting From a Partial View

I have an MVC web application and I'm using a partial view. This consists of a series of criteria and associated checkboxes.
Shown here
Currently a checkbox is checked and the save button clicked, posting via this custom action
[HttpPost]
public PartialViewResult SaveParticipationMeasurementTimeCriteria(int participationMeasurementTimeCriteriaId, bool response)
{
var participationMeasurementTime =
repository.GetParticipationMeasurementTime(participationMeasurementTimeCriteriaId);
repository.SaveParticipationMeasurementTimeCriteria(participationMeasurementTimeCriteriaId, response);
unitOfWork.Save();
var vm = GetParticipationMeasurementTimeCriteriaVM(participationMeasurementTime.ParticipationMeasurementTimeId);
return PartialView("ParticipationMeasurementTimesCriteria", vm);
}
Which routes to this method in the repository:
public void SaveParticipationMeasurementTimeCriteria(int participationMeasurementTimeCriteriaId, bool response)
{
var participationMeasurementTimeCriteria = Context.ParticipationMeasurementTimeCriteria
.First(x => x.ParticipationMeasurementTimeCriteriaId == participationMeasurementTimeCriteriaId);
participationMeasurementTimeCriteria.Response = response;
participationMeasurementTimeCriteria.ModifiedDate = DateTime.Now;
participationMeasurementTimeCriteria.ModifiedBy = System.Threading.Thread.CurrentPrincipal.Identity.Name;
}
My objective is to streamline the process by only having one save button that updates all of them. There could be any number of criteria.
I've tried using JQuery to fire the action when the checkbox is updated.
I've tried creating a new custom action in the controller to take a list of criteria and update them, as shown below.
[HttpPost]
public PartialViewResult SaveParticipationMeasurementTimeCriteria(List<ParticipationMeasurementTimeCriteria> participationMeasurementTimeCriterias, int participationMeasurementTimeCriteriaId)
{
var participationMeasurementTime =
repository.GetParticipationMeasurementTime(participationMeasurementTimeCriteriaId);
foreach (var criteria in participationMeasurementTimeCriterias)
{
var participationMeasurementTimeCriteria =
participationMeasurementTimeCriteriaRepository.GetById(criteria.ParticipationMeasurementTimeCriteriaId);
participationMeasurementTimeCriteriaRepository.Update(criteria);
}
unitOfWork.Save();
var vm = GetParticipationMeasurementTimeCriteriaVM(participationMeasurementTime.ParticipationMeasurementTimeId);
return PartialView("ParticipationMeasurementTimesCriteria", vm);
}
But now I'm at a loss. Clearly there are gaps in my knowledge pertaining both to partial views and mvc in general, in regards to posting a list of entities from a view.
Any help would be appreciated.

Keeping a page's state

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();
}

Calling RazorEngine.Parse() in Controller Action fails with bad HttpContextBase

Perhaps I'm not calling RazorEngine in the correct place.
In my controller action I use the following code to call RazorEngine. But I think this may not be correct as when it calls through to .Execute() and then into MVC's GetActionCache() the HttpContextBase.Items fails with a "method not implemented" exception.
Am I calling RazorEngine in the wrong way? #Html.LabelFor() works fine.
string template = "#Html.EditorFor(model => model.OldPassword)";
string result = string.Empty;
var config = new RazorEngine.Configuration.TemplateServiceConfiguration
{
BaseTemplateType = typeof(System.Web.Mvc.Helpers.HtmlTemplateBase<>)
};
using (var service = new RazorEngine.Templating.TemplateService(config))
{
// Use template service.
RazorEngine.Razor.SetTemplateService(service);
result = RazorEngine.Razor.Parse(template, model);
}
powercat97 over on the github issues page has a workaround for an issue that addresses this.
https://github.com/Antaris/RazorEngine/issues/46
The reason I've had much trouble is that there is no context set. Creating a new ViewContext is not sufficient.
Therefore by calling a view that in turn calls our RazorEngine code via RenderAction() we get the context and the MVC framework has everything it needs when it is called by RazorEngine.
Using the AccountController as an example (HtmlTemplateBase comes from RazorEngine issues with #Html and http://www.haiders.net/post/HtmlTemplateBase.aspx):
public ActionResult Test()
{
var model = new MySite.Models.LocalPasswordModel();
model.OldPassword = "MyOldPwd";
model.NewPassword = "SomeNewPwd";
return PartialView(model);
}
[ChildActionOnly()]
public string TestTemplate(MySite.Models.LocalPasswordModel vm)
{
string result = string.Empty;
string template = "#Html.EditorFor(model => model.OldPassword)";
var config = new RazorEngine.Configuration.TemplateServiceConfiguration
{
BaseTemplateType = typeof(HtmlTemplateBase<>)
};
using (var service = new RazorEngine.Templating.TemplateService(config))
{
// Use template service.
RazorEngine.Razor.SetTemplateService(service);
result = RazorEngine.Razor.Parse(template, vm, "MyTemplateName");
}
return result;
}
and in Test.cshtml:
#model TestRazorEngine.Models.LocalPasswordModel
#{ Html.RenderAction("TestTemplate", new { vm = Model }); }

Jquery postback not working on mvc 4 client side

I'm trying to simply create a json postback so I can update some controls on the client side. I cant find a good example to show this.
Here's what I got so far which appears to be firing off an alert from the controller but keeps saying 'undefined' object on client side.
What is best practice method of achieving this as I dont know how to debug javascript in the same manner as regular code? :( I'm using vs2012 express, mvc 4, jquery 1.7.1 and jquery mobile 1.1.
My controller Time/Index:
[HttpPost]
public JsonResult Index()
{
var msg = "hello there"; //test message
return Json(msg);
}
My client side:
function populateUserDetails() {
var user = {};
user.UserId = $("#UserId").val(); // potential fields i may use once i get it working
$.post('Time/Index', user, updateFields, 'json');
};
updateFields = function (data) {
alert("hi " + data.msg);
$("#textEntered").val(data.msg);
};
*** UPDATE *********
fixed it by wrapping returned object in controller into a temporary class:
[HttpPost]
public JsonResult Index()
{
var response = new {msg = "hello there"}; //here's what i changed
return Json(response);
}
Replace your last line of code as below.
return Json(response,JsonRequestBehavior.AllowGet);
so it should be like that
[HttpPost]
public JsonResult Index()
{
var response = new {msg = "hello there"};
//here's what i changed
return Json(response,JsonRequestBehavior.AllowGet);
}

Posting with multiple parameters to webapi using RestSharp

I just started playing around with RestSharp and WebApi and I've run into a little bit of an issue.
I'm not sure if this is best practice or even possible, but I'll demonstrate through code (this isn't my exact code but it's the exact same concept)
[HttpPost]
public HttpResponseMessage CreateEmployee(Employee emp, int employeeType)
{
// CREATE EMPLOYEE
return Request.CreateResponse(HttpStatusCode.Created, emp.id);
}
I've created a console app to test this using RestSharp. Here's what I have:
var client = new RestClient();
client.BaseUrl = #"http://localhost:15507";
var employee = new Employee();
//populate employee model
postrequest.Method = Method.POST;
postrequest.Resource = "api/Employee/CreateEmployee";
postrequest.AddHeader("Accept", "application/json");
postrequest.AddHeader("Content-Type", "application/json");
postrequest.RequestFormat = DataFormat.Json;
postrequest.AddBody(new { emp = employee, listId = 2 });
var res = client.Execute(postrequest);
The error that I get is that employeeType parameter comes in as null. Am I formatting this properly? Is this something that's even possible to do?
When i remove the employeeType parameter from the WebApi action method and modify the request to:
postrequest.AddBody(employee);
everything works fine.
any ideas? Thanks
if you are expecting employeetype from uri and if its not part of defined route, you can send it as query string parameter...Ex:
api/Employee/CreateEmployee?employeeType=

Resources