Im trying to work with an object (VideoInfo) in several Action methods. A form sends a viewmodel with a video file to the Upload method in VideoController. It uploads the video and returns a generated guid. When the callback has returned, a new ajax call is made to the Convert method which returns the guid. As seen in the javascript part of Create.cshtml it makes two other Ajax calls, one to the Progress method and one to the Azure method.
When trying to fetch the VideoInfo object in the Azure method and the Progress method, videoInfo is null. Though it successfully retains the data between the Upload method and Convert method. Im using TempData.Peek() so that it shouldnt mark it for deletion.
I can see that the Upload and Convert method is using the same instance of VideoController, where as the Progress and Azure method uses another instance, I guess this could have to do with the problem.
InstanceId when running Upload method: 23ef96fa-c746-4722-ad07-e9e40fc95f29
InstanceId when running Convert method: 23ef96fa-c746-4722-ad07-e9e40fc95f29
InstanceId when running Progress method: 0aba24b2-ccb8-434d-a27d-cc66cb52c466
InstanceId when running Azure method: 0aba24b2-ccb8-434d-a27d-cc66cb52c466
How can I retain data between my Ajax calls in the VideoController?
Why is the instance id same for the first two calls but then it changes?
VideoController.cs
using System;
namespace MediaPortal.Controllers
{
[Authorize(Roles = "Admin")]
public class VideoController : Controller
{
private static Guid InstanceId { get; }
static VideoController()
{
InstanceId = Guid.NewGuid();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upload(CreateVideoViewModel model)
{
if (ModelState.IsValid)
{
if (model.File != null)
{
Debug.WriteLine("Upload method InstanceId: " + InstanceId.ToString());
// ...
TempData[videoInfo.Id] = videoInfo;
videoInfo.cvvm.File.SaveAs(videoInfo.TempPath);
return Json(new { Successfull = true, Id = videoInfo.Id });
}
return null;
}
return null;
}
[HttpPost]
public ActionResult Convert(string id)
{
Debug.WriteLine("Convert method InstanceId: " + InstanceId.ToString());
// Create new object of FFMpegConvertor
var converter = new FFMpegConverter();
VideoInfo videoInfo = (VideoInfo)TempData.Peek(id);
// ...
return Json(new { Successfull = true, Id = videoInfo.Id });
}
[HttpPost]
public ActionResult Azure(string id)
{
Debug.WriteLine("Azure method InstanceId: " + InstanceId.ToString());
VideoInfo videoInfo = (VideoInfo)TempData[id];
// ...
if (videoUpload != null && thumbnailUpload != null)
{
Video video = new Video
{
Id = videoInfo.Id.ToString(),
Name = videoInfo.cvvm.Name,
ProjectId = videoInfo.cvvm.ProjectId,
Type = "mp4",
VideoUri = videoUpload.Uri.ToString(),
ThumbnailUri = thumbnailUpload.Uri.ToString()
};
db.Videos.Add(video);
db.SaveChanges();
return Json(new { Successful = true, Data = Url.Action("Index", new { projectId = videoInfo.cvvm.ProjectId }) });
}
return null;
}
[HttpPost]
public JsonResult Progress(string id)
{
Debug.WriteLine("Progress method InstanceId: " + InstanceId.ToString());
try
{
VideoInfo videoInfo = (VideoInfo)TempData.Peek(id);
return Json(new { Data = videoInfo.Progress });
}
catch
{
return Json(new { Data = "No Video Information in Dictionary for Id: " + id });
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
}
Create.cshtml (JQuery/Ajax)
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.js"></script>
<script src="http://malsup.github.com/jquery.form.js"></script>
<script>
$.noConflict();
jQuery(document).ready(function ($) {
var bar = $('.progress-bar');
var percent = $('.percent');
$('#Myform').ajaxForm({
type: "POST",
contentType: "application/json; charset=utf-8",
beforeSend: function () {
var percentVal = '0%';
bar.width(percentVal);
percent.html(percentVal);
},
uploadProgress: function (event, position, total, percentComplete) {
var percentVal = percentComplete + '%';
bar.width(percentVal);
percent.html(percentVal);
},
complete: function (uploadStatus) {
console.log("Upload finished for video with Id: " + JSON.parse(uploadStatus.responseText).Id);
setTimeout(function () { progress(uploadStatus) }, 1000);
$.ajax({
type: "POST",
url: '#Url.Action("Convert", "Video")?id=' + JSON.parse(uploadStatus.responseText).Id,
dataType: "json",
contentType: "application/json; charset=utf-8",
complete: function (convertStatus) {
console.log("Conversion finished for video with Id: " + JSON.parse(convertStatus.responseText).Id);
$.ajax({
type: "POST",
url: '#Url.Action("Azure", "Video")?id=' + JSON.parse(convertStatus.responseText).Id,
dataType: "json",
contentType: "application/json; charset=utf-8",
complete: function (azureStatus) {
window.location.href = JSON.parse(azureStatus.responseText).Data;
}
});
}
});
}
});
function progress(uploadStatus) {
$.ajax({
type: "POST",
url: '#Url.Action("Progress", "Video")?id=' + JSON.parse(uploadStatus.responseText).Id,
dataType: "json",
contentType: "application/json; charset=utf-8",
complete: function (progressStatus) {
console.log("Progress: " + JSON.parse(progressStatus.responseText).Data);
if (JSON.parse(progressStatus.responseText).Data < 100) {
setTimeout(function () { progress(uploadStatus) }, 1000);
}
else if (JSON.parse(progressStatus.responseText).Data >= 100) {
console.log("Video Conversion Completed");
}
else {
console.log("Something went wrong");
}
}
})
}
});
</script>
It seems IIS Express was the problem. I cant say why though. I realized this because when I deployed the project to my production server in Azure it all worked fine.
So instead of using IIS Express I installed IIS on my development machine, works perfectly after that.
Related
On click of a button will from a partialview 1 below js function will be called and get the data from the controller and will be redirected to another partialview. Since it the controller is in another project and hosted separately, controller is not returning the partialview hence I am redirecting it if the ajax call is success.
$.ajax({
type: "POST",
url: url,
data: JSON.stringify(paramObj),
contentType: "application/json; charset=utf-8",
traditional: true,
success: function (response) {
var userObject = response.internalObject;
window.location.href = url2;
},
error: function (response, status, error) {
if (response.responseText != undefined) {
const obj = JSON.parse(response.responseText);
fnShowMessage(obj.DisplayMessage);
}
}
});
I have the data in "userObject" from the ajax call which needs to be displayed in partialview, but I cannot access it or not sure how to access it.
The assigned value in OnGet() method in "partialview2.cshtml.cs" is able to retain in "partialview2.cshtml" file. But how to get the values which I got from the ajax call in partialview 1 in code behind of partialview 2.
public class UserModel : PageModel
{
[BindProperty]
public UserObject UserObject { get; set; } = new();
public void OnGet()
{
UserObject.UserName = "man";
}
}
You can try to return JsonResult in OnGet:
ajax:
$.ajax({
type: "POST",
url: "/Home/Test",
data: JSON.stringify(paramObj),
contentType: "application/json; charset=utf-8",
traditional: true,
dataType: "json",
success: function (response) {
var userObject = response;
window.location.href = url2;
},
error: function (response, status, error) {
if (response.responseText != undefined) {
const obj = JSON.parse(response.responseText);
fnShowMessage(obj.DisplayMessage);
}
}
});
OnGet handler:
public class UserModel : PageModel
{
[BindProperty]
public UserObject UserObject { get; set; } = new();
public JsonResult OnGet()
{
UserObject.UserName = "man";
return new JsonResult(UserObject);
}
}
I have this ajax post method in my code that returns undefined. I think its because I have not passed in any data, any help will be appreciated.
I have tried passing the url string using the #Url.Action Helper and passing data in as a parameter in the success parameter in the ajax method.
//jquery ajax post method
function SaveEvent(data) {
$.ajax({
type: "POST",
url: '#Url.Action("Bookings/SaveBooking")',
data: data,
success: function (data) {
if (data.status) {
//Refresh the calender
FetchEventAndRenderCalendar();
$('#myModalSave').modal('hide');
}
},
error: function (error) {
alert('Failed' + error.val );
}
})
}
//controller action
[HttpPost]
public JsonResult SaveBooking(Booking b)
{
var status = false;
using (ApplicationDbContext db = new ApplicationDbContext())
{
if (b.ID > 0)
{
//update the event
var v = db.Bookings.Where(a => a.ID == a.ID);
if (v != null)
{
v.SingleOrDefault().Subject = b.Subject;
v.SingleOrDefault().StartDate = b.StartDate;
v.SingleOrDefault().EndDate = b.EndDate;
v.SingleOrDefault().Description = b.Description;
v.SingleOrDefault().IsFullDay = b.IsFullDay;
v.SingleOrDefault().ThemeColor = b.ThemeColor;
}
else
{
db.Bookings.Add(b);
}
db.SaveChanges();
status = true;
}
}
return new JsonResult { Data = new { status } };
}
Before the ajax call, you should collect the data in object like,
var requestData= {
ModelField1: 'pass the value here',
ModelField2: 'pass the value here')
};
Please note, I have only added two fields but as per your class declaration, you can include all your fields.
it should be like :
function SaveEvent(data) {
$.ajax({
type: "POST",
url: '#Url.Action(Bookings,SaveBooking)',
data: JSON.stringify(requestData),
dataType: 'json',
contentType: 'application/json; charset=utf-8',
success: function (data) {
if (data.status) {
//Refresh the calender
FetchEventAndRenderCalendar();
$('#myModalSave').modal('hide');
}
},
error: function (error) {
alert('Failed' + error.val );
}
})
}
Try adding contentType:'Application/json', to your ajax and simply have:
return Json(status);
In your controller instead of JsonResult. As well as this, You will need to pass the data in the ajax code as a stringified Json such as:
data:JSON.stringify(data),
Also, is there nay reason in particular why it's a JsonResult method?
My Ajax Code is
function UserCheck() {
var q = document.getElementById("username").value;
$.ajax({
url: '#Url.Action("Checks","Ajaxx")',
data: {
'userdata': q
},
type: "POST",
dataType: "html",
success: function (data) {
//------------
alert("insuccess");
document.getElementById("username").innerHTML = data.toString();
}
});
}
Am using this ajax code to check whether the entered username is exists
My controller name is Ajaxx and method is checks
Method is
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using CinemaApplication.Models;
namespace CinemaApplication.Controllers
{
public class AjaxxController : Controller
{
//
// GET: /Ajaxx/
[HttpPost]
public string Checks(string userdata)
{
string tmp = "success";
using (OurDbContext db = new OurDbContext())
{
var SeachData = db.Logins.Where(x => x.username == userdata).FirstOrDefault();
if (SeachData != null)
{
tmp = "Fail";
}
}
return tmp;
}
}
}
This is the whole code of my controller. It is dedicated to this ajax .
the value of username field is correctly arrived in q ,but i don't know that the method (Checks) in controller(Ajaaxx) is working
Try using the following properties in your jquery call:
dataType: 'json',
contentType: "application/json; charset=utf-8"
Ajax code
function Checks()
{
var unm = document.getElementById("username").value;
$.ajax({
type: "POST",
url: "/Ajaxx/Checks",
data: '{user:"' + unm + '"}',
contentType: "application/json; charset=utf-8",
datatype: "json",
success: function(result)
{
var mess = $("#Status");
if (result)
{
mess.html('Username available');
mess.css("color", "green");
}
else{
mess.html('Username not available');
mess.css("color", "red");
}
}
});
}
</script>
var mess is holding the id of the span
Controller
[HttpPost]
public JsonResult Checks(string user)
{
bool tmp = true;
using (OurDbContext db = new OurDbContext())
{
var SeachData = db.Logins.Where(x => x.username == user).FirstOrDefault();
if (SeachData != null)
{
tmp = false;
}
}
return Json(tmp);
}
I'm trying to save data using ajax in MVC 5. When I'm posting form data without #Html.AntiForgeryToken(), it's working nicely. But it's showing me Object reference not set to an instance of an object error for using #Html.AntiForgeryToken(). Here is my ajax code:
$.ajax({
type: "POST",
url: "/Employees/Create",
data: data,
async: false,
success: function (result) {
if (result == 1) {
window.location.href = '/Employees';
}
else {
$('#error-span').html('Error in insert.');
}
},
error: function () {
alert('Failed');
}
});
Here is my controller method:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Address,JoinDate,DoB,Gender,BloodGroup,Email,LastName,FirstName,Mobile,UpdateDate,UpdatedBy,Status,EmployeeType,CreatedBy,CreateDate,DesignationId")] EmpDetail empDetail)
{
try
{
Regex rgx = new Regex("[^a-zA-Z0-9 - .]");
empDetail.FirstName = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(rgx.Replace(empDetail.FirstName, "").ToLower()).Trim();
empDetail.LastName = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(rgx.Replace(empDetail.LastName, "").ToLower()).Trim();
empDetail.Email = empDetail.Email.ToLower().Trim();
empDetail.UpdateDate = DateTime.Now;
empDetail.CreatedBy = 234;
empDetail.CreateDate = DateTime.Now;
empDetail.UpdatedBy = 234;
empDetail.Status = 1;
if (ModelState.IsValid)
{
db.EmpDetails.Add(empDetail);
db.SaveChanges();
return Json(1);
}
else
{
return Json(2);
}
}
catch (Exception e)
{
return Json(e.Message);
}
}
This is happening because the data is being sent via JSON instead of HTML Form data. You should try to pass the token in the headers. For example:
View:
<script>
#functions{
public string TokenHeaderValue()
{
string cookieToken, formToken;
AntiForgery.GetTokens(null, out cookieToken, out formToken);
return cookieToken + ":" + formToken;
}
}
$.ajax("api/values", {
type: "post",
contentType: "application/json",
data: { }, // JSON data goes here
dataType: "json",
headers: {
'RequestVerificationToken': '#TokenHeaderValue()'
}
});
</script>
Controller:
void ValidateRequestHeader(HttpRequestMessage request)
{
string cookieToken = "";
string formToken = "";
IEnumerable<string> tokenHeaders;
if (request.Headers.TryGetValues("RequestVerificationToken", out tokenHeaders))
{
string[] tokens = tokenHeaders.First().Split(':');
if (tokens.Length == 2)
{
cookieToken = tokens[0].Trim();
formToken = tokens[1].Trim();
}
}
AntiForgery.Validate(cookieToken, formToken);
}
Source: https://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-csrf-attacks
I am populating an array with an [int,bool]:
$.each(ownedChecked, function (key, val) {
/*code to set id as int and paintedTrue as bool*/
ownedIDs.push([id,paintedTrue]);
});
I create a var that will be stringified:
var saveData = { OwnedListEntryIDs:ownedIDs };
//send data
$.ajax({
url: '/ListEntry/OwnedModels',
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(saveData),
success: function (data) { alert('Update success: ' + data); },
failure: function (data) { alert('Update failed: ' + data); }
});
Here is the ViewModel:
public class OwnedPaintedSave
{
//collection contains a ListEntryID and a bool indicating whether it is painted or not
public Dictionary<int,bool> OwnedListEntryIDs { get; set; }
}
Once in the controller method, ModelState.Isvalid passes and code gets to the foreach loop, but models is always NULL:
[HttpPost]
public JsonResult OwnedModels(OwnedPaintedSave models)
{
if (ModelState.IsValid)
{
foreach (var id in models.OwnedListEntryIDs)
{ }
}
}
I tried setting traditional:true in the $.ajax method, but same issue. I'm guessing the Dictionary in the ViewModel is not what I need to bind to, but I'm not sure what it should be. Thanks for any help.
I gave the OwnedPaintedSave object two int[] properties, one for OwnedIDs and one for PaintedIDs.
I think the problem lies in your controller. You are passing var saveData = { OwnedListEntryIDs:ownedIDs }; (essentially a Dictionary<int, bool> - yes?) as your data but the parameter in the action result is of type OwnedPaintedSave
I think if you change your controller parameter to Dictionary<int, bool> ownedListEntryIDs and don't stringify the javascript object, the framework is clever enough to serialize and deserialize your object. So you would have this...
var saveData = { OwnedListEntryIDs:ownedIDs };
//send data
$.ajax({
url: '/ListEntry/OwnedModels',
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: saveData,
success: function (data) { alert('Update success: ' + data); },
failure: function (data) { alert('Update failed: ' + data); }
});
And then this in your controller...
[HttpPost]
public JsonResult OwnedModels(Dictionary<int, bool> ownedListEntryIDs)
{
if (ModelState.IsValid)
{
foreach (var id in ownedListEntryIDs)
{ }
}
}