I'm creating asp.net mvc 5 application. in this application I have faced to problem passing data between controller methods.
Here the scenario step by step
I'm getting IEnumerable dataset to Create_Brochure method like this
public ActionResult Create_Brochure(IEnumerable<ProductsPropertiesVM> model)
{
IEnumerable<BrochureTemplateProperties> sample = model.Where....
return View(sample);
}
Then I need to save that IEnumerable<ProductsPropertiesVM> model to another IEnumerable object and use that in Create_Brochure_PDF() method
public ActionResult Create_Brochure_PDF()
{
IEnumerable<BrochureTemplateProperties> samplePDF = modelPDF....
return View(samplePDF);
}
for that I'did bit R&D part and came up solution with Sessions , Here the tutorial I followed
So I changed my code like this
but seems I'm having compile time errors though I followed exact as tutorial
1st controller method
[HttpPost]
[ValidateInput(false)]
public ActionResult Create_Brochure(IEnumerable<ProductsPropertiesVM> model)
{
IEnumerable<ProductsPropertiesVM> modelPDF = new IEnumerable<ProductsPropertiesVM>();
modelPDF = model;
IEnumerable<BrochureTemplateProperties> sample = model.Where(y => y.IsChecked)
.Select(y => new BrochureTemplateProperties
{
Property_ID = y.Property_ID,
IsChecked = y.IsChecked,
Property_Title = y.Property_Title,
Property_Value = y.Property_Value
});
TempData["TemplateData"] = modelPDF;
return View(sample);
}
2nd controller method
public ActionResult Create_Brochure_PDF()
{
IEnumerable<ProductsPropertiesVM> modelPDF = TempData["TemplateData"] as IEnumerable<ProductsPropertiesVM>;
IEnumerable<BrochureTemplateProperties> samplePDF = modelPDF.Where(y => y.IsChecked)
.Select(y => new BrochureTemplateProperties
{
Property_ID = y.Property_ID,
IsChecked = y.IsChecked,
Property_Title = y.Property_Title,
Property_Value = y.Property_Value
});
return View(samplePDF);
}
You can not instantiate interface..!
Replace
IEnumerable<ProductsPropertiesVM> modelPDF = new IEnumerable<ProductsPropertiesVM>();
modelPDF = model;
With
IEnumerable<ProductsPropertiesVM> modelPDF = model;
inside your Create_Brochure method.
Related
I've tried searching for an answer to this question, but I'm only getting responses like passing data to a Controller, which isn't what I'm asking about. If there is an answer to my question here on SO, please let me know.
We have a ViewModel that has another class instance (InventoryIn) as a property of the ViewModel class.
It's our intent to class the same view repeatedly, passing the ViewModel back to the same view. We populate the InventoryIn data in the view, but when it gets called a second time, the InventoryIn instance is empty.
The only explanation I can come up for this behavior is the InventoryIn constructor, where we do instantiate some properties. So, my question is when passing a ViewModel repeatedly to the same view, in a Controller, does the ViewModel's constructor always get invoked? We thought that wouldn't happen, but we might be wrong.
BTW, the structure of the view is it has two <form> tags. One with a button that posts to the same view, and the constructor is invoked with the same action method that was used when the view was first called. Then the second <form> tag has an action method that posts to a different view that's called from the same controller.
Addendum - Action Methods from the Controller
public IActionResult Step1()
{
var newSiteToSite = new SiteToSite();
//do stuff here with newSiteToSite
return View(newSiteToSite);
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Step2(SiteToSite SiteToSite)
{
// THIS COULD BE COMING FROM STEP 1 OR STEP 2
if (Step1IsValid(SiteToSite))
{
RefreshSiteToSite(SiteToSite);
// RETURN STEP 2 VIEW
return View("Step2", SiteToSite);
// STEP 1 IS INVALID
} else {
// RETURN STEP 1 VIEW
return View("Step1", SiteToSite);
}
}
The code for RefreshSiteToSite:
private void RefreshSiteToSite(SiteToSite siteToSite)
{
SetOriginatingLocation(siteToSite);
SetDestinationLocation(siteToSite);
int invOutItemPackageReceiptId = siteToSite.InvOutItemPackageReceiptID;
GetSiteToSiteById(siteToSite, invOutItemPackageReceiptId);
}
code from SetOriginatingLocation():
private void SetOriginatingLocation(SiteToSite siteToSite)
{
var originatingLocation = db.PharmLocations.Where(p => p.LocationId == siteToSite.OriginatingLocationID).FirstOrDefault();
if (originatingLocation != null)
{
siteToSite.OriginatingLocationCode = originatingLocation.LocationCode;
siteToSite.OriginatingLocationName = originatingLocation.Location;
siteToSite.OriginatingLocationAddress1 = originatingLocation.Address1;
siteToSite.OriginatingLocationAddress2 = originatingLocation.Address2;
siteToSite.OriginatingLocationLocCity = originatingLocation.LocCity;
siteToSite.OriginatingLocationLocState = originatingLocation.LocState;
siteToSite.OriginatingLocationLocZip = originatingLocation.LocZip;
siteToSite.OriginatingLocationPhoneMain = originatingLocation.PhoneMain;
siteToSite.OriginatingLocationPhoneAlt = originatingLocation.PhoneAlt;
siteToSite.OriginatingLocationFax = originatingLocation?.Fax;
siteToSite.OriginatingLocationContact1Name = originatingLocation?.Contact1Name;
siteToSite.OriginatingLocationContact2Name = originatingLocation?.Contact2Name;
}
}
SetDestinationLocation code:
private void SetDestinationLocation(SiteToSite siteToSite)
{
var destinationLocation = db.PharmLocations.Where(p => p.LocationId == siteToSite.DestinationLocationID).FirstOrDefault();
if (destinationLocation != null)
{
siteToSite.DestinationLocationCode = destinationLocation.LocationCode;
siteToSite.DestinationLocationName = destinationLocation.Location;
siteToSite.DestinationLocationAddress1 = destinationLocation.Address1;
siteToSite.DestinationLocationAddress2 = destinationLocation.Address2;
siteToSite.DestinationLocationLocCity = destinationLocation.LocCity;
siteToSite.DestinationLocationLocState = destinationLocation.LocState;
siteToSite.DestinationLocationLocZip = destinationLocation.LocZip;
siteToSite.DestinationLocationPhoneMain = destinationLocation.PhoneMain;
siteToSite.DestinationLocationPhoneAlt = destinationLocation.PhoneAlt;
siteToSite.DestinationLocationFax = destinationLocation?.Fax;
siteToSite.DestinationLocationContact1Name = destinationLocation?.Contact1Name;
siteToSite.DestinationLocationContact2Name = destinationLocation?.Contact2Name;
}
}
GetSiteToSiteByID code:
private void GetSiteToSiteById(SiteToSite siteToSite, int id)
{
var tmp = db.VwPart1SiteToSites.Where(p => p.InvOutItemPackageReceiptId == id).FirstOrDefault();
if (tmp != null)
{
if (siteToSite.CurrentVwPart1s == null)
{
siteToSite.CurrentVwPart1s = new List<VwPart1SiteToSite>();
}
siteToSite.CurrentVwPart1s.Add(tmp);
}
}
in this project i create cardGroup. in httpGet Method we get some needed info and pass to view to fill dropdown. when httpPost trigger if some field Date has Problem we must return error with addModelError but after return View, all ViewData Clear and Return Exception. how can handle this. just show error in view.
[HttpGet]
[Route("CreateCardGroup")]
public ActionResult CreateCardGroup()
{
var discounts =
UnitOfWork.DiscountPatternRepository.GetNotExpireDiscountPattern();
var discountDtos = discounts?.Select(c => new SelectListItem
{
Text = c.PatternTitle,
Value = c.Id.ToString()
}).ToList();
ViewData["DiscountPatterns"] = discountDtos;
var serials =
UnitOfWork.ChargeCardSerialRepository.GetNotAssignedSerials();
var serialDtos = serials?.Select(c => new SelectListItem
{
Text = c.SerialNumber.ToString(),
Value = c.Id.ToString()
}).ToList();
ViewData["ChargeSerials"] = serialDtos;
ViewData["CardSerialCount"] =
UnitOfWork.GiftCardSerialRepository.GetNotUsedGiftSerials();
return View();
}
[HttpPost]
[Route("CreateCardGroup")]
public ActionResult CreateCardGroup(CardGroupCreateDto dto)
{
if (!ModelState.IsValid)
return View(dto);
if(!UnitOfWork.DiscountPatternRepository
.IsCardGroupDateInRange(dto.DiscountPatternId,
dto.ActiveFromDate, dto.ActiveToDate))
{
ModelState.AddModelError("ActiveFromDate", #"Error In Date.");
return View(dto); <---Problem Here
}
var group = dto.LoadFrom();
var insertedId = UnitOfWork.CardGroupRepository.Add(group);
foreach (var rangeDto in group.CardGroupGiftSerialRanges)
{
for (var i = rangeDto.GiftCardSerialBegin; i <=
rangeDto.GiftCardSerialEnd; i++)
{
var serial =
UnitOfWork.GiftCardSerialRepository.GetBySerial(i);
if (serial != null)
{
serial.CardGroupGiftSerialRangeId = rangeDto.Id;
serial.DiscountPatternId = group.DiscountPatternId;
UnitOfWork.Complete();
}
}
}
return Redirect("/CardGroup");
}
From this article:
ViewData
ViewData is a property of ControllerBase class.
ViewData is used to pass data from controller to corresponding view
Its life lies only during the current request. If redirection occurs, then its value becomes null. It’s required typecasting for getting data and check for null values to avoid error.
So what's happening is once you've done your post back to the server, you're now in a different request, meaning, that you need to repopulate your ViewData items so that their values are populated again, or else they'll be null.
So I'd recommend refactoring your Dropdown population method into a private method on your controller and then call that method in your post when you find a validation error or are just returning by calling return View(dto).
If they're used in other controllers, you can add them to a LookupService or LookupRepository or even a general helpers class that contains your lookup logic (whatever fits into your UnitofWork pattern the best for you), to make them available to those other controllers, instead of having it as a private method as per my example.
So something like this for example:
[HttpGet]
[Route("CreateCardGroup")]
public ActionResult CreateCardGroup()
{
PopulateCreateCardGroupLookups();
return View();
}
[HttpPost]
[Route("CreateCardGroup")]
public ActionResult CreateCardGroup(CardGroupCreateDto dto)
{
if (!ModelState.IsValid)
{
PopulateCreateCardGroupLookups();
return View(dto);
}
if(!UnitOfWork.DiscountPatternRepository
.IsCardGroupDateInRange(dto.DiscountPatternId,
dto.ActiveFromDate, dto.ActiveToDate))
{
ModelState.AddModelError("ActiveFromDate", #"Error In Date.");
PopulateCreateCardGroupLookups();
return View(dto); <---Problem Here
}
var group = dto.LoadFrom();
var insertedId = UnitOfWork.CardGroupRepository.Add(group);
foreach (var rangeDto in group.CardGroupGiftSerialRanges)
{
for (var i = rangeDto.GiftCardSerialBegin; i <=
rangeDto.GiftCardSerialEnd; i++)
{
var serial =
UnitOfWork.GiftCardSerialRepository.GetBySerial(i);
if (serial != null)
{
serial.CardGroupGiftSerialRangeId = rangeDto.Id;
serial.DiscountPatternId = group.DiscountPatternId;
UnitOfWork.Complete();
}
}
}
return Redirect("/CardGroup");
}
private void PopulateCreateCardGroupLookups()
{
var discounts =
UnitOfWork.DiscountPatternRepository.GetNotExpireDiscountPattern();
var discountDtos = discounts?.Select(c => new SelectListItem
{
Text = c.PatternTitle,
Value = c.Id.ToString()
}).ToList();
ViewData["DiscountPatterns"] = discountDtos;
var serials =
UnitOfWork.ChargeCardSerialRepository.GetNotAssignedSerials();
var serialDtos = serials?.Select(c => new SelectListItem
{
Text = c.SerialNumber.ToString(),
Value = c.Id.ToString()
}).ToList();
ViewData["ChargeSerials"] = serialDtos;
ViewData["CardSerialCount"] =
UnitOfWork.GiftCardSerialRepository.GetNotUsedGiftSerials();
}
I am making my MVC application. I open my view with predefined parameters like this:
return RedirectToAction("PickGroupForHomework", "Account", new {subject_id = id, qty=model.qty });
And this works fine, the data subject_id and qty are passed correctly. However, my view PickGroupForHomework contains a form to fill, which is then validated. If the input is not valid, the window simply should reload with the data subject_id and qty as defined in previous view. I do this in such way:
public ActionResult PickGroupForHomework(PickGroupForHomeworkViewModel model)
{
ClassDeclarationsDBEntities2 entities = new ClassDeclarationsDBEntities2();
model.groups = entities.Groups.ToList();
model.users = entities.Users.ToList();
int id = model.subject_id;
var subj = entities.Subjects
.Where(b => b.class_id == model.subject_id)
.FirstOrDefault();
if (subj != null)
{
model.subject_name = subj.name;
}
if (ModelState.IsValid)
{
}
else
{
return View(model);
}
return View(model);
}
But the resulting URL does not contain the data I need, but just a plain view. How do I do it right?
In order for you wep app to work, you will need two actions, one to set your model up for the View and another to actually do the work to post and save your data:
public ActionResult PickGroupForHomework(int subject_id, int qty)
{
//Initialize your model here. Below is just an example.
ClassDeclarationsDBEntities2 entities = new ClassDeclarationsDBEntities2();
PickGroupForHomeworkViewModel model = new PickGroupForHomeworkViewModel();
model.groups = entities.Groups.ToList();
model.users = entities.Users.ToList();
model.subject_id = subject_id;
model.qty = qty;
return View("PickGroupForHomework", model);
}
[HttpPost]
public ActionResult PickGroupForHomework(PickGroupForHomeworkViewModel model)
{
ClassDeclarationsDBEntities2 entities = new ClassDeclarationsDBEntities2();
int id = model.subject_id;
var subj = entities.Subjects
.Where(b => b.class_id == model.subject_id)
.FirstOrDefault();
if (subj != null)
{
model.subject_name = subj.name;
}
if (ModelState.IsValid)
{
//Save to database
[code goes here]
//return to a View to show your results
return View("[Your view to see the results]")
}
//Model Validation did not pass
//or exception occurred go back to View
return View(model);
}
I have a web page that is using a number of different partial views and different viewmodels for each partial. One of the partials is for the ability for a user to change their username. Since we are going to allow email addresses as usernames now, I would like to pre-populate the textbox with their current email address from another partial view on the page. How can this be done properly so the value will be populated in the text box and then saved when the submit to the controller happens? Here is a brief code snippet from what I'm looking at:
The view:
#Html.TextBoxFor(model => model.NewUsername, new { id = "uName_change" }) #Html.ValidationMessageFor(model => model.NewUsername)
It's worth noting here that I have tried setting the current email address into ViewData and ViewBag and putting "#value = viewdatahere" into the textbox for properties, but this didn't populate the string, it just left it blank.
I just need to know how this is done. Any help is appreciated.
Edit to add controller POST and GET methods:
[HttpGet]
[ClaimsPrincipalPermission(System.Security.Permissions.SecurityAction.Demand, Resource = Resources.User, Operation = Operations.Edit)]
public ActionResult ChangeUsername(Guid uniqueUserId)
{
User user = UserManager.GetUser(uniqueUserId);
AuthorizationHelper.ConfirmAccess(Resources.User, Operations.Edit, user);
ChangeUsername model = new ChangeUsername(){UserGuid = user.Identifier,NewUsername = user.Username};
return View(model);
}
[HttpPost]
[ClaimsPrincipalPermission(System.Security.Permissions.SecurityAction.Demand, Resource = Resources.User, Operation = Operations.Edit)]
public ActionResult ChangeUsername(ChangeUsername changeUsername)
{
User usr = UserManager.GetUser(changeUsername.UserGuid);
AuthorizationHelper.ConfirmAccess(Resources.User, Operations.Edit, usr);
if (!ModelState.IsValid)
{
return View(changeUsername);
}
//setup request
SupportUser su = (SupportUser)ViewData["SupportUser"];
RequestData rqd = new RequestData(GetApplicationIdentifer(usr), su.clientIP, su.lanID);
UserUsernameChangeRequest request = new AdminUsernameChangeRequest(rqd,usr,changeUsername.NewUsername);
UserUsernameChangeResponse response = UserManager.ChangeUserUsername(request);
if (response.Status == UserProcessorStatus.Success)
{
var message = ("User has been updated successfully");
TempData["message"] = message;
return PartialView("_NewUsername", changeUsername);
}
switch (response.Status)
{
case UserProcessorStatus.DuplicateUsername:
{
ModelState.AddModelError("NewUsername", "Duplicate username");
changeUsername.AlternateUsernames = response.AlternateUsernames;
return PartialView(changeUsername);
}
default:
{
ModelState.AddModelError("NewUsername", String.Format("An unexpected error occured. Error Code:{0}, Message:{1}", response.Status, response.Message));
return PartialView(changeUsername);
}
}
}
There it is.
The last time that I tried to do this was with MVC 3, but I do know that this technique worked then. It's a stupid difference, that's why I pointed that out first.
You were very close with your attempt at it, but you need to set the property as #Value, not #value. I never looked to hard into why the capital made a huge difference. (Like I said, it's a stupid difference.)
var val = "Dummy Value";
#Html.TextBoxFor(model => model.NewUsername, new { id = "uName_change", #Value = val })
Here's how I'd do it.... in the main page set up a viewmodel that contains the other view models like this:
public class VMMain(){
public void VMMain(){
//don't forget null CTOR as MVC requires it...
}
public void VMMain(Guid userguid, string newusername){
UserGuid = userguid;
NewUserName = newusername;
Part1 = new VM1(UserGuid, NewUserName);
Part2 = new VM2();
Part3 = new VM3();
}
public VM1 Part1 {get;set;}
public VM2 Part2 {get;set;}
public VM3 Part3 {get;set;}
Guid UserGuid {get;set;}
string NewUsername {get;set;}
}
In your main view you can bind to anyone of these viewmodels and properties within them. Just make sure you have a property available to bind.
This would change your controller to look like this:
[HttpGet]
[ClaimsPrincipalPermission(System.Security.Permissions.SecurityAction.Demand, Resource = Resources.User, Operation = Operations.Edit)]
public ActionResult ChangeUsername(Guid uniqueUserId)
{
User user = UserManager.GetUser(uniqueUserId);
AuthorizationHelper.ConfirmAccess(Resources.User, Operations.Edit, user);
var model = new VMMain(){UserGuid = user.Identifier,NewUsername = user.Username};
And now you can bind to say Partial ViewModel 1 that has that property like this:
#Html.TextBoxFor(p => model.Part1.NewUsername,
new { id = "uName_change" })
#Html.ValidationMessageFor(p => model.Part1.NewUsername)
return View(model);
}
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
pass data from Action To Another Action
I have a view in which I submit a form and depending on the results I want to redirect to an action. The view that correspondes to and action is strongly-typed and it should accept a ResultsViewModel.
I'm trying to pass the ResultsViewModel using T4MVC.
Below is the code:
[HttpPost]
public virtual ActionResult AddEntity(string viewModel)
{
//Deserialize using Json.NET
var entity = JsonConvert.DeserializeObject<MyEntity>(viewModel);
var success = DoSomething(); //returns boolean
if(success)
{
var result = new ResultsViewModel { MyEntity = entity, MessageId = 1};
return RedirectToAction(MVC.MyController.ResultsPage(result));
}
var result = new ResultsViewModel { MyEntity = entity, MessageId = 2};
return RedirectToAction(MVC.MyController.ResultsPage(result));
}
public virtual ActionResult ResultsPage(ResultsViewModel viewModel)
{
return View(viewModel);
}
When the code reaches
public virtual ActionResult ResultsPage(ResultsViewModel viewModel)
{
return View(viewModel);
}
viewModel is always equal to null.
I know I can do something like this:
return RedirectToAction("ResultsPage", new { viewModel = result });
EDIT: I tried the return RedirectToAction("ResultsPage", new { viewModel = result }); and I'm also getting a null in my viewModel.
However I'm trying to figure out why/how to pass an object using T4MVC.
Thanks,
Use TempData
[HttpPost]
public virtual ActionResult AddEntity(string viewModel)
{
//Deserialize using Json.NET
var entity = JsonConvert.DeserializeObject<MyEntity>(viewModel);
var success = DoSomething(); //returns boolean
if(success)
{
var result = new ResultsViewModel { MyEntity = entity, MessageId = 1};
return RedirectToAction(MVC.MyController.ResultsPage(result));
}
var result = new ResultsViewModel { MyEntity = entity, MessageId = 2};
TempData["Result"] = result;
return RedirectToAction(MVC.MyController.ResultsPage(result));
}
public virtual ActionResult ResultsPage()
{
ResultsViewModel model = (ResultsViewModel)TempData["Result"];
return View(model);
}