my problem right now is that parameter value in [httPost] Edit controller does not return any value...I have suspected that because of i'm using tuple as return value. i need help on solving this issue..thanks
below are my code.
Edit.cshml
#model Tuple<MyCOOEntity.CostAnalysisModel.FinishProductCompleteForm, MyCOOEntity.CostAnalysisModel.FinishProductCompleteForm>
.cs Controller code
[HttpPost]
public ActionResult Edit(FinishProductCompleteForm objUpdateFinishProductCompleteForm, string CommandUpdate, HttpPostedFileBase[] files, string id)
{
FinishProductCompleteForm objFinishProductCompleteFormUpdate = new FinishProductCompleteForm();
objFinishProductCompleteFormUpdate = FinishProductCompleteFormDAL.UpdateFinishProductCompleteFormDetails(id, objUpdateFinishProductCompleteForm);
FinishProductCompleteForm objRawMatDetails = FinishProductCompleteFormDAL.GetDashboardInfo(objUpdateFinishProductCompleteForm);
var tuple = new Tuple<FinishProductCompleteForm, FinishProductCompleteForm>(objFinishProductCompleteFormUpdate, objRawMatDetails);
return View(tuple);
}
and yes, I'm using tuple for same class(FinishProductCompleteForm) but returning different value.
Related
I'm trying to make a service to AB-test different views on a page. The service has a method that takes a variable amount of ViewResults and returns one of them after determining which version to serve. The problem is that the model applied to the last ViewResult in the arguments list is applied to all arguments. The below code is a simplified version of my code just to illustrate the setup:
This is the method in the service:
public ViewResult GetTestVariantView(params ViewResult[] views){
...omitted randomization code that returns an index
return views[index] ?? views[0]
}
This is how it's used in the controller:
public ActionResult Index(){
var modelOne = new PageViewModel(letter: "A");
var modelTwo = new PageViewModel(letter: "B");
var modelThree = new PageViewModel(letter: "C");
return _testingService.GetTestVariantView(
View("~/Views/_PageView.cshtml", modelOne),
View("~/Views/_SomeOtherPageView.cshtml", modelTwo ),
View("~/Views/_PageView.cshtml", modelThree));
}
I expect to get for example _PageView.cshtml with modelOne if the service returns index 0 of the params list - but no, I get _PageView.cshtml with modelThree. Somehow just the model is taken from the last entry though, because if the service returns index 1 I get _SomeOtherPageView.cshtml with modelThree.
I can't find any documentation or similar questions asked about how to resolve this or even do it in another way. Is there a more proper way to determine which view to present using an external method? I know I could return an index from the method and have a switch/ifelse statement in the controller but I'd like to avoid that if possible simply because it clutters the controller.
What are my options?
Looking at the source code, the model passed to the View method is stored in the ViewData collection, not the returned ViewResult. If you call View multiple times with different non-null models, you will overwrite the ViewData.Model property each time, and only the last value will be used.
As Camilo said, change your code so that you only call View once. For example:
public (string viewName, object model) GetTestVariantView(
params (string viewName, object model)[] views)
{
...
}
(string viewName, object model) = _testingService.GetTestVariantView(
("~/Views/_PageView.cshtml", modelOne),
("~/Views/_SomeOtherPageView.cshtml", modelTwo ),
("~/Views/_PageView.cshtml", modelThree));
return View(viewName, model);
I have a method defined like this:
public ActionResult MatchedBusinesses(List<Business> businesses)
{
if (businesses != null)
{
return View(businesses);
}
return View("NoMatchFound");
}
Then, in my other method I have something similar to this one:
var list = results.AsEnumerable().OrderBy(b => Math.Abs(Convert.ToInt32(temp) - Convert.ToInt32(b.Zip))).Take(5).ToList();
return RedirectToAction("MatchedBusinesses", "Home", list);
The point is that, for the list variable I get the 5 entries that I select using the query. But, then I want to pass that result to my other method, which will be used in other method's view. The problem is, when I call the other method, the businesses parameter is always null. How can I solve the problem? Clearly, I'm not passing the parameter to my MatchedBusinesses method correctly. Any idea, how to solve the problem?
You are using the overload of RedirectToAction where the 3rd parameter is object routeValues. Internally the method uses reflection to build the route values based on the names and the ToString() values of the objects properties.
It works only for properties that are value types, but for properties that are complex types, including collections, it will not bind because (in your case) the value is a string "List<YourAssembly.Business>" and a string cannot be bound to a collection.
You need to persist the collection before redirecting (e.g. database, session, TempData) and then retrieve the collection in the action result.
For example
var list = results.AsEnumerable()....
TempData["results"] = list;
return RedirectToAction("MatchedBusinesses", "Home");
public ActionResult MatchedBusinesses()
{
List<Business> businesses = (List<Business>)TempData["results"];
}
but use TempData with caution (if the user refreshes the browser, the data will be lost). Its better to persist the information to the database with some key, and then pass the key as a route parameter to the MatchedBusinesses() method so that you can retrieve the data from the database.
Edit
What you're trying to do doesn't make much sense. You cannot, and should not, attempt to send large and/or complex objects, like a List, using Route. Instead you should use POST, or follow Stephen Muecke's suggestion in using TempData
However, here's how you can correctly send simple values using RouteValue
You pass parameters by using
return RedirectToAction("ActionName", "ControllerName",
new { paramName = paramValue });
Or if the target Action it's in the same controller
return RedirectToAction("ActionName", new { paramName = paramValue });
The parameter name, is optional. But using
return RedirectToAction("ActionName", new { paramName = paramValue });
Implies that the target action accepts a parameter with the name paramValue.
Here are all the overloads for RedirectToAction
http://msdn.microsoft.com/en-us/library/system.web.mvc.controller.redirecttoaction%28v=vs.118%29.aspx
Try wrapping your parameter in your return statement in a blank object variable like so:
return RedirectToAction("MatchedBusinesses", "Home", new { businesses = list });
All of the route values for an action have to be one parameter, so it's passed as an object, and then split into the various parameters of the receiving action. Even if you have only one param, it's still looking for an object to split.
I am using MVC 4.
Is there a way to get action parameter names by route value.
public ActionResult Index(string id, string staffId)
{
ViewData.Add("idList", idList);
return View();
}
Suppose I have this "index" action. And the controller name is "TestController".
In the view, can I use the route value controller = "Test", action = "index", to get the parameter name list {"id, staffId"}. This route values are dynamic in view.
Use a Model. You shouldn't be putting everything in ViewData like that.
Create just a simple object that will contain the data that you need for the View, and pass the information that way.
I find the way my self. I see my question confusing. But here is what I am looking for.
var assembly = AppDomain.CurrentDomain.GetAssembliesFromApplicationBaseDirectory(
x => x.GetName().Name == "XXXX").Single();
var controllerTypes = assembly.GetTypes().Where(x => x.Name == Model.Controller + "Controller");
var controllerType = controllerTypes.Where(x => x.Namespace.Contains(Model.Area)).Single();
var action = controllerType.GetMethod(Model.Action);
var parameters = action.GetParameters();
But I am still not sure, if it's correct to put this logic in View.
My question is: How can I combine the two of these action results into one? There really seems no point in having the first one only to do one line. But I cant see a way out. Any ideas would be appreciated. The remaining I provide for background.
I am trying and successful in returning a partial view with the Json results I require but I am using two ActionResults of the same name (one with parameter one without) to achieve this. If I continue in this manner, I will have to repeat all my ActionResults twice. The problem I have with this is that the first action result does nothing more than literally this:
[HttpGet]
public ActionResult MyResults()
{
return PartialView();
}
That is used to return the view. Within the view I have some JQuery/Ajax which in turn calls another action result of the same name but with parameters. This action result effectively populates a Json object which is then parsed and rendered into the view above as a table. Effectively this actionresult does all the work. It looks something like:
[HttpPost]
public ActionResult MyResults(DataTablePrameters param)
{
//Get the full list of data that meets our needs
var fullList = _myResultsRepository.GetListByID(Id);
//Count the records in the set
int count = fullList.Count();
//Shorten the data to that required for the page and put into object array for Json
var result = from r in fullList.Skip(param.iDisplayStart).Take(param.iDisplayLength)
select new object[]
{
r.field1,
r.field2,
r.field3
};
//Return Json data for the Datatable
return Json(new
{
sEcho = param.sEcho,
iTotalRecords = param.iDisplayLength,
iTotalDisplayRecords = count,
aaData = result
});
}
Those of you not familiar with it, will not be aware that I am using DI/IOC and for brevity I have not included the details of this. But that is not my question. Also the above code used Datatables from the following site:
http://datatables.net/index
Which are actually quite good. And again, using all the above, my code works well. So I don't have problems with it. I know its somewhat inefficient because it loads the resultset into a variable does a count, then skip...take and so on but again, it works and this is not my question.
So again my only question is, how can I combine the two of them into one view. There really seems no point in having the first one only to do one line. But I cant see a way out. Any ideas would be appreciated.
Remove the [HttpPost] and [HttpGet] attributes from the ActionResult you want to use.
Check the validity of your fields contain in DataTablePrameters param like :
public ActionResult MyResults(DataTablePrameters param = null) {
if(string.IsNullOrEmpty(param.sEcho) && string.IsNullOrEmpty(param.iDisplayStart) && string.IsNullOrEmpty(param.iDisplayLength))
return PartialView();
//Do something
return Json(...);
}
In your view, you can still use the type:"POST" into your $.ajax() with the url:"/YourController/MyResults" like you already do i supose.
Assuming that the separation of POST and GET access is not desired with just one action left, wouldn't just making "param" optional do the trick?
public ActionResult MyResults(DataTablePrameters param = null) {
if(param == null)
return PartialView();
// Repository action...
return Json([...]);
}
Do I have to manually pass my strongly typed viewdata to the call return View(); ?
ie.
MyViewData vd = new MyViewData();
vd.Blah = "asdf asdfsd";
return View();
It seems if I pass it as a parameter, I have to repeat the view name also?
return View("index", vd);
you can simply pass the model the the View method:
MyViewData vd = new MyViewData();
vd.Blah = "asdf asdfsd";
return View(vd);
Normally you don't have to manually pass it, but your model has to have a constructor without parameters. Otherwise the framework won't know what values you would like it to pass there.
As for passing the view name, just check out all method overloads. If there is one with just the model as a parameter, then you can omit the view name.
You can do this:
public ActionResult Action()
{
var vd = new MyViewData();
vd.Blah = "asdf asdfsd";
ViewData.Model = vd;
return View();
}