Share data among Controller actions while one action is executing - ajax

Following action in same controller:
string vTotalRows = "0";
string vCurrentRow = "0";
[HttpPost]
public ActionResult Save(IEnumerable<HttpPostedFileBase> files)
{
vTotalRows = "100"; //it is getting set in loop
vCurrentRow = "1"; //it is getting set in loop
//Process takes some time here.. depend on how many records in the excel file
}
second action function as below:
public JsonResult GetUploadStatus()
{
string totalItems="?";
try
{
totalItems = vTotalRows;// Convert.ToString(TempData["TotalRows"]);
if (totalItems.Trim() == "") totalItems = "?";
}
catch { }
string currentItem = "?";
try
{
currentItem = vCurrentRow;// Convert.ToString(TempData["CurrentRow"]);
if (currentItem.Trim() == "") currentItem = "?";
}
catch { }
string result = string.Format("Uploading Item <b>{0}</b> of <b>{1}</b> - {2} of {3}", currentItem, totalItems, vCurrentRow, vTotalRows);
var jsonResult = Json(result, JsonRequestBehavior.AllowGet);
jsonResult.MaxJsonLength = int.MaxValue;
return jsonResult;
}
If I am calling second function through ajax I am always getting 0 for both variables. Have tried TempData, ViewBag etc.
Cheers

Related

web api validation messages for one section display before application form is submitted

I am try to deal with a bug on one of the sections for the application form I am currently developing in order to explain my issue the screenshots below show the workflow for this section:
When you first navigate to the section you are presented with this screen you then chose an option from the dropdownlist and click next.
When you click next the form values for the option selected are generated as below:
the problem comes when you change the option, when the new option form values are generated errors for the previous option are being generated as shown below:
to explain some of the logic when the next or change button is clicked it posts back to an actionresult in the corresponding applycontroller in the actionresult it posts the option value to a web api which saves the data to the database the code below is performing this task:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> AdmissionsTest(AdmissionsTestViewModel model, ApplyService service, string programmeDesc, int? programmeId, FormCollection formCollection)
{
Guid applicationId = (Guid)TempData["ApplicationId"];
TempData["ApplicationId"] = applicationId;
model.ApplicationValidations = (ICollection<ApplicationValidation>)TempData["ApplicationValidations"];
TempData["ApplicationValidations"] = model.ApplicationValidations;
model.ApplicationProgrammeDetails = DependencyResolver.Current.GetService<ApplicationProgrammeDetailsViewModel>();
if (programmeId != null)
{
Programme programme = service.GetProgramme(model.ProgrammeId);
model.ApplicationProgrammeDetails.ProgrammeDesc = programme.ProgrammeDesc;
}
else
{
model.ApplicationProgrammeDetails.ProgrammeDesc = programmeDesc;
}
foreach (var item in formCollection.AllKeys)
{
if ((model.AdmissionsTestOptionId == null) && (item.ToLowerInvariant().StartsWith("submitbuttonnext") || (item.ToLowerInvariant().StartsWith("submitbuttonchange"))))
{
model.ApplicationId = applicationId;
model.NavButton = "10";
await _client.PostAsJsonAsync("api/ApplicationAdmissionsTestDetail/UpdateApplicationAdmissionsTestDetail", model)
.ContinueWith((postTask) => postTask.Result.EnsureSuccessStatusCode());
return View("AdmissionsTest", model);
}
if ((model.AdmissionsTestOptionId == 1) && (item.ToLowerInvariant().StartsWith("submitbuttonnext") || (item.ToLowerInvariant().StartsWith("submitbuttonchange"))))
{
model.ApplicationId = applicationId;
model.NavButton = "10";
await _client.PostAsJsonAsync("api/ApplicationAdmissionsTestDetail/UpdateApplicationAdmissionsTestDetail", model)
.ContinueWith((postTask) => postTask.Result.EnsureSuccessStatusCode());
return View("AdmissionsTest", model);
}
if ((model.AdmissionsTestOptionId == 2) && (item.ToLowerInvariant().StartsWith("submitbuttonnext") || (item.ToLowerInvariant().StartsWith("submitbuttonchange"))))
{
model.ApplicationId = applicationId;
model.NavButton = "10";
await _client.PostAsJsonAsync("api/ApplicationAdmissionsTestDetail/UpdateApplicationAdmissionsTestDetail", model)
.ContinueWith((postTask) => postTask.Result.EnsureSuccessStatusCode());
return View("AdmissionsTest", model);
}
if ((model.AdmissionsTestOptionId == 3) && (item.ToLowerInvariant().StartsWith("submitbuttonnext")))
{
model.ApplicationId = applicationId;
await _client.PostAsJsonAsync("api/ApplicationAdmissionsTestDetail/UpdateApplicationAdmissionsTestDetail", model)
.ContinueWith((postTask) => postTask.Result.EnsureSuccessStatusCode());
if (model.NavButton == null) { model.NavButton = "11"; }
return NavigateToStage(model.NavButton);
}
if ((model.AdmissionsTestOptionId == 3) && (item.ToLowerInvariant().StartsWith("submitbuttonchange")))
{
model.ApplicationId = applicationId;
model.NavButton = "10";
await _client.PostAsJsonAsync("api/ApplicationAdmissionsTestDetail/UpdateApplicationAdmissionsTestDetail", model)
.ContinueWith((postTask) => postTask.Result.EnsureSuccessStatusCode());
return View("AdmissionsTest", model);
}
}
//save
string dateGMATTaken = model.DateGMATTakenDay + "/" + model.DateGMATTakenMonth + "/" + model.DateGMATTakenYear;
string dateGRETaken = model.DateGRETakenDay + "/" + model.DateGRETakenMonth + "/" + model.DateGRETakenYear;
DateTime dateOfGMATTestTaken;
DateTime dateOfGRETestTaken;
if (DateTime.TryParse(dateGMATTaken, out dateOfGMATTestTaken))
{
model.GMATDateTaken = dateOfGMATTestTaken;
}
else
{
model.GMATDateTaken = null;
}
if (DateTime.TryParse(dateGRETaken, out dateOfGRETestTaken))
{
model.GREDateTaken = dateOfGRETestTaken;
}
else
{
model.GREDateTaken = null;
}
model.ApplicationId = applicationId;
await _client.PostAsJsonAsync("api/ApplicationAdmissionsTestDetail/UpdateApplicationAdmissionsTestDetail", model)
.ContinueWith((postTask) => postTask.Result.EnsureSuccessStatusCode());
//redirect based on submit
if (model.NavButton == null) { model.NavButton = "11"; }
return NavigateToStage(model.NavButton);
}
I have tested the actionresult using break points to see if it might be going to the final submit action but so far it appears to be staying within the actionresult I have also used fiddler to see if the submit method on the web api is being called this has also return blank.
Does anyone have any ideas as to why this might be happening?
Thanks in advance for the advice.
have modified the return value so instead of returning return View() they now use return RedirectToRoute() which has resolved the bug

conversion Error from String to System.Web.Mvc.ViewResult in MVC3

Hi I am quite new on MVC and I am trying to create a simple conversion from Fahrenheit to Celsius along with its unit testing. Sorry in advance for putting all the code here.
This is my controller code:
public string Convert(double value,string option)
{
string d;
if(option=="1") {
d = " To Celcius"+FahrenheitToCelsius(value).ToString();
}
else {
d = " To Fahrenheit" + CelsiusToFahrenheit(value).ToString();
}
return "ConvertTo" + d;
}
public static double CelsiusToFahrenheit(double temperatureCelsius)
{
double celsius = temperatureCelsius;
return (celsius * 9 / 5) + 32;
}
public static double FahrenheitToCelsius (double temperatureFahrenheit)
{
double fahrenheit = temperatureFahrenheit;
return (fahrenheit - 32) * 5 / 9;
}
This is my View Page
protected void btnConvert(object sender, EventArgs e)
{
if (DropDownList1.SelectedValue=="1"){
double temp = TemperatureConverterController.FahrenheitToCelsius(double.Parse(TextBox1.Text));
Literal1.Text = temp.ToString();
}
else{
double temp = TemperatureConverterController.CelsiusToFahrenheit(double.Parse(TextBox1.Text));
Literal1.Text = temp.ToString();
Literal1.Text = temp.ToString();
}
}
When i do this unit testing i got an error:
[TestMethod]
public void ConvertReturnsAViewResultWhenInputDataIsValid()
{
//Arrange
var controller = new TemperatureConverterController();
//Act
double x = 80;
double y = 25;
var result = controller.Convert(x, "1") as ViewResult;
// here i get this error under ViewResult //
//Assert
Assert.IsInstanceOfType(result, typeof(ViewResult));
}
[TestMethod]
public void ConvertAsksForAViewTemplateNamedConvert()
{
//Arrange
var controller = new TemperatureConverterController();
String expectedViewTemplate = "Convert";
//Act
double x = 80;
double y = 25;
var result = controller.Convert(x, "1") as ViewResult;
////Assert
Assert.AreEqual<String>(expectedViewTemplate, result.ViewName);
}
Error is:
Error Cannot convert type 'string' to 'System.Web.Mvc.ViewResult' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion.
the problem is here
var result = controller.Convert(x, "1") as ViewResult;
your Convert method is returning string and you are casting it as ViewResult
Your convert method should looks like
public ActionResult Convert()
{
//Make a Model class and pass it to View
//...
return View(model_class_object);
}
Alternatively you can make controller like this
public ActionResult Convert()
{
ViewData["tempvalue"]=Convert(x, "1");
//Make a Model class and pass it to View
//...
return View();
}
and on your View you can just print it
#ViewData["tempvalue"].ToString()
In MVC the controller code should return an "ActionResult" object containing the model.
If the data you want to pass to view is simply a string use:
public ActionResult Convert()
{
//...
return View("your result here...");
}
You can refer to data returned by controller using the "Model" property in Views or Tests.
Let's go backwards for a minute here.
Controller
public class ConvertController : Controller
{
public ActionResult Convert(MyConvertViewModel vm)
{
if (vm == null) { return View("convert", new MyConvertViewModel { ShowResult = false }); }
if (vm.Option == 1)
{
vm.Result = FahrenheitToCelsius(vm.Input);
vm.OptionName = "Fahrenheit To Celsius";
}
else
{
vm.Result = CelsiusToFahrenheit(vm.Input);
vm.OptionName = "Celsius to Fahrenheit";
}
vm.ShowResult = true;
//not needed, just for an example
ViewData.Add("glosrob-example", "A value goes here!");
return View("convert", vm);
}
private static double CelsiusToFahrenheit(double temperatureCelsius)
{
double celsius = temperatureCelsius;
return (celsius * 9 / 5) + 32;
}
private static double FahrenheitToCelsius(double temperatureFahrenheit)
{
double fahrenheit = temperatureFahrenheit;
return (fahrenheit - 32)*5/9;
}
}
public class MyConvertViewModel
{
public double Result { get; set; }
public int Option { get; set; }
public double Input { get; set; }
public string OptionName { get; set; }
public bool ShowResult { get; set; }
}
View
#model MvcApplication1.Controllers.MyConvertViewModel
#{
ViewBag.Title = "Convert";
}
<h2>Convert</h2>
#using (Html.BeginForm("convert", "convert", FormMethod.Post))
{
<div>
Let's convert some temperatures!
</div>
<div>
#Html.LabelFor(x => x.Input, "Temp. To Convert")
#Html.TextBoxFor(x => x.Input)
</div>
<div>
#Html.LabelFor(x => x.Option, "Convert to ")
#Html.DropDownListFor(x => x.Option, new List<SelectListItem>
{
new SelectListItem {Text = "Celsius", Value = "1"},
new SelectListItem {Text = "Fahrenheit", Value = "2"}
})
</div>
<div>
<button type="submit">Convert It!</button>
</div>
}
#if (Model.ShowResult)
{
<p>#Model.OptionName : #Model.Input = #Model.Result</p>
}
disclaimer: there is a lot of shortcuts there, it is only included to give you an idea of what you should have.
So the view will post back data the user chooses, to the controller action Convert
The controller in turn will return a ViewResult object, and it will be rendered using the data captured in the view model MyConvertViewModel
Now we want to test this.
So here are some of the more important properties that it seems like you need to hook into
[TestMethod]
public void Not_A_Real_Test_But_Stuff_You_Will_Want_To_Use()
{
//arrange
var c = new ConvertController();
//act
var results = c.Convert(null) as ViewResult;
//now results is a ViewResult or null
var theViewModelProperty = results.Model as MyConvertViewModel;
var exampleResult = theViewModelProperty.Result;
var exampleInput = theViewModelProperty.Input;
//etc
//how about the view that was returned?
var theViewName = results.ViewName;
//or anything you put in the ViewData
var theViewData = results.ViewData["glosrob-example"];
Assert.Fail("This was not a real test!");
}
Hopefully this gives you an idea of how you can test for output from a controller method.
Edit: I'm not writing all your tests for you but as an e.g.
[TestMethod]
public void Convert_Should_Return_A_MyConvertViewModel()
{
//arrange
var c = new Controller();
//act
var result = c.Convert(null) as ViewResult;
//assert
Assert.IsNotNull(result);
Assert.IsInstanceOfType(result.ViewModel, typeof(MyConvertViewModel));
}
[TestMethod]
public void Convert_Should_Return_The_Correct_View()
{
//arrange
var c = new Controller();
//act
var result = c.Convert(null) as ViewResult;
//assert
Assert.IsNotNull(result);
Assert.AreEqual("convert", result.ViewName);
}

How can i return Json Result + Web api + validate model + actionfilters +OnActionExecuting method

string message = string.Empty;
public override void OnActionExecuting(HttpActionContext actionContext)
{
var modelState = actionContext.ModelState;
if (!modelState.IsValid)
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, modelState);
foreach (var key in modelState.Keys)
{
var state = modelState[key];
if (state.Errors.Any())
{
message = message + state.Errors.First().ErrorMessage;
}
}
}
Here i want to return message variable with Jsonresult, please help me on it.
Try this
public override void OnActionExecuting(HttpActionContext context)
{
var modelState = context.ModelState;
if (!modelState.IsValid)
{
var errors = new JObject();
foreach (var key in modelState.Keys)
{
var state = modelState[key];
if (state.Errors.Any())
{
errors[key] = state.Errors.First().ErrorMessage;
}
}
context.Response = context.Request.CreateResponse<JObject>(HttpStatusCode.BadRequest, errors);
}
}
From the client ajax request, on error, get the responseText to process the validation error messages.
You might want to pick a HttpStatusCode based on what you are trying to do, since the

How to add QueryString in OnActionExecuting()?

i want to add two queryString in current request URL if it is not exsist
Edited:
I tried this ---
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.RequestContext.HttpContext.Request.QueryString["mid"] == null && filterContext.RequestContext.HttpContext.Request.QueryString["mod"] == null)
{
mid = Convert.ToString(HttpUtility.ParseQueryString(filterContext.RequestContext.HttpContext.Request.UrlReferrer.Query)["mid"]);
mod = Convert.ToString(HttpUtility.ParseQueryString(filterContext.RequestContext.HttpContext.Request.UrlReferrer.Query)["mod"]);
if (!string.IsNullOrEmpty(mid) || !string.IsNullOrEmpty(mod))
{
RouteValueDictionary redirecttargetDictionary = new RouteValueDictionary();
NameValueCollection Qstr = null;
if (filterContext.HttpContext.Request.RequestType == "GET")
{
Qstr = HttpUtility.ParseQueryString(filterContext.HttpContext.Request.Url.Query);
foreach (string item in Qstr)
{
redirecttargetDictionary.Add(item, Qstr[item]);
}
if (Qstr["mid"] == null)
{
redirecttargetDictionary.Add("mid", mid);
}
if (Qstr["mod"] == null)
{
redirecttargetDictionary.Add("mod", mod);
}
filterContext.Result = new RedirectToRouteResult(redirecttargetDictionary);
}
}
}
This code works fine.
-check for quesrystring exsist if no
-then take qstring value from 'Urlreferrer'
-if request type is GET
-then add two querystring with exsisting querystring
But but I having problem if querystring in current request has null value url like http://localhost:53372/question/index?type=&stage.if this ll b the current request url then code ll check for mid n mod qstring as its not exsist it will add both the qstring with exsisting type n stage but value ll b null then before hitting action again OnActionExecuting() get call this time first 'if' is not true and then index method get call but I m not getting type n stage querystring which suppose to null I found url in address bar is http://localhost:53372/question/index?mid=1&mod=5.
If I remove filter the I got URL http://localhost:53372/question/index?type=&stage=&mid=1&mod=5 here I m getting both stage n type querystring though its null.
Edited--
[HttpGet]
public ActionResult Index(ProjectType? projectType, int? projectStageID, int? page)
{
int currentPageIndex = page.HasValue ? page.Value - 1 : 0;
IPagedList<ProjectModule> moduleList = null;
IDictionary<string, string> queryParam = new Dictionary<string, string>();
queryParam["ProjectType"] = string.Empty;
queryParam["ProjectStageID"] = string.Empty;
ViewBag.ProjectType = null;
ViewBag.ProjectStage = null;
ViewBag.message = "";
if ((projectType != null || projectType.HasValue) && projectStageID.HasValue && page.HasValue)
{
queryParam["ProjectType"] = Request.QueryString["ProjectType"];
queryParam["ProjectStageID"] = Request.QueryString["ProjectStageID"];
//
//Set View Bag
//
ViewBag.ProjectType = Enum.Parse(typeof(ProjectType), Request.QueryString["ProjectType"]);
ViewBag.ProjectStage = Convert.ToInt32(Request.QueryString["ProjectStageID"]);
//
// Set Query String formcollection for Pagging purpose
//
ViewBag.QueryParam = queryParam;
moduleList = new ProjectModuleService().GetProjectModulesByProjectStageID(Convert.ToInt32(Request.QueryString["ProjectStageID"])).ToPagedList(currentPageIndex, Utility.ConstantHelper.AdminDefaultPageSize); ;
if (moduleList.Count == 0)
{
ViewBag.message = "Record(s) not found.";
}
return View(moduleList);
}
else
{
if (!string.IsNullOrEmpty(Request.QueryString["ProjectType"]) && !string.IsNullOrEmpty(Request.QueryString["ProjectStageID"]) && !string.Equals(Request.QueryString["ProjectStageID"], "0"))
{
if (!string.IsNullOrEmpty(Request.Params.Get("Index")))
{
queryParam["ProjectType"] = Request.QueryString["ProjectType"];
queryParam["ProjectStageID"] = Request.QueryString["ProjectStageID"];
//
//Set View Bag
//
ViewBag.ProjectType = Enum.Parse(typeof(ProjectType), Request.QueryString["ProjectType"]);
ViewBag.ProjectStage = Convert.ToInt32(Request.QueryString["ProjectStageID"]);
//
// Set Query String formcollection for Pagging purpose
//
ViewBag.QueryParam = queryParam;
moduleList = new ProjectModuleService().GetProjectModulesByProjectStageID(Convert.ToInt32(Request.QueryString["ProjectStageID"])).ToPagedList(currentPageIndex, Utility.ConstantHelper.AdminDefaultPageSize); ;
if (moduleList.Count == 0)
{
ViewBag.message = "Record(s) not found.";
}
return View(moduleList);
}
else if (!string.IsNullOrEmpty(Request.Params.Get("Create")))
{
return RedirectToAction("Create", new { projectStageID = Convert.ToInt32(Request.QueryString["ProjectStageID"]) });
//return RedirectToAction("Create", new { projectStageID = Convert.ToInt32(Request.QueryString["ProjectStageID"]), projectType = Enum.Parse(typeof(ProjectType), Request.QueryString["ProjectType"]) });
}
}
if (Request.QueryString["ProjectType"] == "" || Request.QueryString["ProjectStageID"] == "" || string.Equals(Request.QueryString["ProjectStageID"], "0"))
{
ViewBag.message = "Please select all fields.";
return View();
}
return View();
}
}
What I m doing wrong?
Here what I understand that if there are no querystring in the URL,you need to add two query string parameters. If you are adding this two querystring parameters explicitly than, it will be default value for that queryparameters.
It's better to provide default value in action method instead of adding queryparameters in URL. You can achieve by following code.
public ActionResult ComposeEmail(int queryParameter1 = 0,string queryParameter2 = string.Empty)
{
}
Do let me know, if you have any query.

ActionFilter to read Contents before RedirectToAction

I wish to record deletes and edits, and thought the best way would be to apply An actionFilter
Attribute to my delete and edit [ post ] methods
But because the end results is a redirect to action, my Context.Result is always null
because there is only a Context.RedirectToAction results available.
Now before i go creating some code to plug into my delete and Edit functions, has anyone tried something like this!, and could you possibly advise?
Thanks
Action Code:
[HttpPost, ValidateInput(false)]
[SiteChangeLogger(LogType = "Update", TableName = "Affiliates")]
public ActionResult Edit(Affiliate affiliate, FormCollection form)
{
var existing = db2.Affiliates.SingleOrDefault(x => x.AffiliateId == affiliate.AffiliateId);
ViewBag.before = Common.Strings.Base64Encode(Common.Strings.ToJsonString(existing));
if (ModelState.IsValid)
{
try
{
var curFiles = new NameValueCollection();
curFiles["AffiliateLogo"] = affiliate.AffiliateLogo;
if (!String.IsNullOrWhiteSpace(form["AffiliateLogo"]))
{
UploadFiles(form,curFiles);
TryUpdateModel(affiliate, form);
var oldFileName = affiliate.AffiliateLogo;
var newFileName = Common.Strings.RandomFileName();
new WebImage(Server.MapPath("~/Content/images/" + affiliate.AffiliateLogo))
.Resize(200, 50, true, true)
.Crop(1, 1)
.Save(Server.MapPath("~/Content/images/" + newFileName), "png", true);
affiliate.AffiliateLogo = newFileName + ".png";
Common.Common.TryAndDeleteFile("~/Content/images/" + oldFileName);
}
else
{
affiliate.AffiliateLogo = existing.AffiliateLogo;
}
}
catch (Exception ex)
{
Common.Common.CompileErrorMessage(ex,"ADMIN.Affiliate.Edit");
}
finally
{
db.Entry(affiliate).State = EntityState.Modified;
db.SaveChanges();
}
ViewBag.after = Common.Strings.Base64Encode(Common.Strings.ToJsonString(affiliate));
return RedirectToAction("Index");
}
return View(affiliate);
}
my Filter Code
public override void OnResultExecuted(ResultExecutedContext fc)
{
var viewResult = fc.Result as ViewResult;
if(viewResult == null) return;
var beforeData = viewResult.ViewBag.before;
var afterData = viewResult.ViewBag.after;
if (beforeData == null && afterData == null) return;
var ctx = new SgeGamesContext();
var eventId = 0;
var siteChangeLogEvent = ctx.SiteChangeLogEvents.SingleOrDefault(x => x.SiteChangeLogEventName == LogType);
if (siteChangeLogEvent != null)
{
eventId = siteChangeLogEvent.SiteChangeLogEventId;
}
var model = new Sge.Games.Data.Models.SiteChangeLog
{
SiteChangeLogTable = TableName,
SiteId = 1,
SiteChangeLogAfterContent = afterData,
SiteChangeLogBeforeContent = beforeData,
SiteChangeLogEventId = eventId
};
ctx.SiteChangeLogs.Add(model);
ctx.SaveChanges();
base.OnResultExecuted(fc);
}
You could access the ViewBag directly, you don't need a ViewResult:
public override void OnResultExecuted(ResultExecutedContext fc)
{
var before = fc.Controller.ViewBag.before;
var after = fc.Controller.ViewBag.after;
...
}
Also you probably want to use the OnActionExecuted event instead of OnResultExecuted.

Resources