Create multiple views and access with single action in controller - c#

i am having my views separated under subfolder, i have only one Action method in controller, i have my view names in the database, when i call the action method by passing the parameter (for instance: id = 1), it will fetch the view name from the database and the respective view will be load.
public ActionResult Index(int FormId)
{
var getViews = db.fetchViews.where id = 1; //get views from db
return view(getviews.viewName);
}
This is my views in the solution.
while i call the view from action method it says unable to find the views.
i cannot hardcode the subfolder in the Action method like this,
return View("~/Views/Form/Customer1/getviews.viewName");
any ideas would be appreciate...

If you can't move the views to the directory that the razor view engine is looking for, you can try this:
public ActionResult Index(int FormId)
{
var getViews = db.fetchViews.where id = 1; //get views from db
var viewpath = string.Format("~/Views/Form/{0}/{0}", getviews.viewName);
return View(viewpath);
}
Alternatively, you could create a custom RazorViewEngine that could search for the view in a subdirectory of the same name.
This post has a method of adding search view locations to the razor view engine, your custom search view format would be something like this:
new string[]
{
"~/Views/{1}/{0}/{0}.cshtml"
}

Like this?
public ActionResult Index(int FormId)
{
var viewName = "~/Views/Form/Customer" + FormId + "/customer" + FormId;
return View(viewName);
}

If you want the searching of views to be according to what you want, you can inherit the RazorViewEngine and modify the path where Razor will look at. You may see this SO post

Related

Get attribute of current controller action in MVC View

I wish to display the current action of the controller on my MVC View in a human readable format.
I understand you can acquire the name of the current action through:
#ViewContext.Controller.ValueProvider.GetValue("action")
this returns e.g. 'Index' in the example below
What I am looking to do is something like:
[DisplayName=Resources.Overview]
public ActionResult Index()
{
return View();
}
and then print that DisplayName on the page, some pseudo-code like:
#ViewContext.Controller.ValueProvider.GetValue("action").GetAttribute("DisplayName")
which would return 'Overview' from Resources
Is this possible?
You should first make a reflection to the method with Type.GetMethodInfo
string actionName = ViewContext.RouteData.Values["Action"]
MethodInfo method = type.GetMethod(actionName);
var attribute = method.GetCustomAttributes(typeof(DisplayNameAttribute), false);
if (attribute.Length > 0)
actionName = ((DisplayNameAttribute)attribute[0]).DisplayName;
else
actionName = type.Name; // fallback to the type name of the controller
And then you can pass the actionName to the View using something like
ViewBag.name = actionName;
and then get the Viewbag variable from the view
Why not just set the DisplayName inside the Viewbag and retrieve it in code, for every page that requires it?
For Example,
public ActionResult Index()
{
Viewbag.DisplayName = 'Resources.Overview'
return View();
}
then in any view that populates the DisplayName value, you can display it at the top with the following,
<head>
#ViewBag.DisplayName
</head>

ASP.NET - MVC 4 using a variable from a controller to a view

I have this controller like so:
public class PreviewController : Controller
{
// GET: Preview
public ActionResult Index()
{
string name = Request.Form["name"];
string rendering = Request.Form["rendering"];
var information = new InformationClass();
information.name = name;
information.rendering = rendering;
return View(information);
}
}
and in the view, I am trying to the information.name like so:
#ViewBag.information.name
I also tried just:
#information.name
but got the same error for both:
Cannot perform runtime binding on a null reference
What am I doing wrong?
You must use #Model.name in view. Not #ViewBag.information.name. Also in top of your view you must define something like this:
#model Mynamespace.InformationClass
And it would be better to use MVC's model binding feature. Therefore change your action method like this:
public class PreviewController : Controller
{
[HttpPost] // it seems you are using post method
public ActionResult Index(string name, string rendering)
{
var information = new InformationClass();
information.name = name;
information.rendering = rendering;
return View(information);
}
}
In the view just type
#Model.name
Since InformationClass is your model you just call its properties from the view using #Model
You need to set ViewBag.InformationName in your action:
ViewBag.InformationName = name;
And then in your view you could reference it:
#ViewBag.InformationName
Or if you're trying to work with the model data in the view, you'd reference it through this:
#Model.name
Please add that sample to your view file
#model Your.Namespace.InformationClass
That line is responsible for defining your model type. And after that you can just use:
#Model.name;

Is it possible to assign multiple actions to the same controller method?

I have a simple MVC Controller that returns a list of files from folders based on View action. Index() action contains a list of Collections so then user clicks on CollectionOne, the corresponding view is populated. The same behavior is applied to other collections.
The problem is, I have a lot redundant code that I have been able to manage at certain degree by using a private ActionContent() method invoked by all actions. So whenever I have a new collection to add to website, I just add a ActionResult for this Collection and invoke ActionContent() method.
Is there any way to optimize this code to make it more dynamic, without adding a new ActionResult every time a need to post a new collection?
My controller looks like this:
public class PortfolioController : Controller
{
public ActionResult CollectionOne()
{
return View(ActionContent());
}
public ActionResult CollectionTwo()
{
return View(ActionContent());
}
private IEnumerable<string> ActionContent()
{
const string folder = #"~/Content/images/portfolio/";
var path = folder + ControllerContext.RouteData.Values["action"];
var files = Directory
.EnumerateFiles(Server.MapPath(path))
.Select(Path.GetFileName);
return files;
}
}
I want to turn it into something like this (to avoid redundancy) using ActionNames or maybe proper route mapping:
public class PortfolioController : Controller
{
[ActionName("CollectionOne")]
[ActionName("CollectionTwo")]
[ActionName("CollectionThree")]
public ActionResult PortfolioCollection()
{
const string folder = #"~/Content/images/portfolio/";
var path = folder + ControllerContext.RouteData.Values["action"];
var files = Directory
.EnumerateFiles(Server.MapPath(path))
.Select(Path.GetFileName);
return View(files);
}
}
That's what parameters are for:
public ActionResult PortfolioCollection(string id)
{
const string folder = #"~/Content/images/portfolio/";
var files = Directory
.EnumerateFiles(Server.MapPath(folder + id))
.Select(Path.GetFileName);
return View(files);
}
You can make a custom route to assign any URL pattern you want.

How do I go back to the previous view through a hyperlink in ASP.NET MVC?

I have models (POCO entities) like Student, Course, Standard etc. I have corresponding controllers such as StudentController etc. I have a view Index for each model which displays the list of all the corresponding entities in DB. For example, StudentController.Index() returns the /Student/Index view. However, if there are no Student records in the DB, instead of returning the Index view , I redirect to the Empty action method of the Navigation controller, i.e. NavigationController.Empty(), which returns the /Navigation/Empty view. This is done for all model entity classes.
Now, on the empty page, I wish to have a hyperlink to go back to the previous page. So I created an action method called GoBack() in the NavigationController class, in which I redirect to the previous view. But how can I access the information about what the previous page was in this action method? Or is there a better way to do this? I do not want to use the back button.
As far as I'm concerned there are a couple of routes to take here. You could use sessions or the application cache to store a las visited page, and then get that page (by storing a route for instance) in the GoBack() action using a RedirectToAction.
But maybe a nicer and stateless aproach would be to render the hyperlink by having a view model having two properties for last used controller & action. Then you could pass these from the action result calling the /Navigation/Empty action (when there aren't any records).
ViewModel
public class NavigationVM
{
public string LastAction {get;set;}
public string LastController {get;set;}
}
Navigation Controller Action
public ActionResult Empty(string lastAction, string lastController)
{
var vm = new NavigationVM()
{
LastAction = lastAction,
LastController = lastController
}
return View(vm);
}
View
#model = Namespace.NavigationVM
#Html.ActionLink("LinkName", Model.LastAction, Model.LastController)
EDIT
If you then need to find out from where the students controller was called (in your example) you can go about this the same way. I.e.: Render the link to the StudentsController with extra route values.
StudentController:
public ActionResult Index(string lastAction, string lastController)
{
.... // no students
return RedirectToAction("Empty", "Navigation", new RouteValueDictionary(new { lastAction = "Index", lastController= "Student"}));
}
View with hyperlink to students controller (use the action and controller that rendered this view as lastAction and lastController respectively):
#Html.ActionLink("Get students", "Index", "Student", new { lastAction= "Index", lastController = "CallingController" }, null)

View to String from another controller

i have done as Vdex suggested here:
https://stackoverflow.com/a/5801502/973485
And used the RenderPartialToString method he found. And it works perfectly like this:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Test()
{
string t = ViewToString.RenderPartialToString("Index", null, ControllerContext);
return Content(t);
}
}
But if i want to render the Home > Index from another Controller, i get:
Value cannot be null.
Parameter name: controllerContext
Like this:
public class FooController : Controller
{
public ActionResult Index()
{
string t = ViewToString.RenderPartialToString("Index", null, new HomeController().ControllerContext);
return Content(t);
}
}
Is there any way to pass a View from another Controller to a string? I have tried many different methods, and it all of them fails at the ControllerContext. Many thanks!
Update: Why i need to do this:
Imagine i have a website full of widgets, the amount of widgets on each page is dynamic, so i cannot hardcode them in my cshtml file. But in that file there are different areas defined where the widgets gets printet out. To print out these widget i have a list of IWidgetController wich contains alle the different Widgets available, and the interface sais that they need to containe a ActionResult for edit, new and view. example of widgets: CalenderController, NewsController, GalleryController and so on... So in those areas i need to print out the content of each of those Controllers. Now i could also load the URLHTML but i figured doing it from the inside would be faster... right?
Try this:
string t = ViewToString.RenderPartialToString("Index", null, this.ControllerContext);
Anyway, why do you need to convert to a string?

Categories