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>
Related
I have a controller:
public ActionResult Index(string id)
{
ViewBag.ReloadedFromEmailForm = id;
return View();
}
The controller can be called from RouteConfig (as its default) with param id = null and can be called from some other controller which is returning
return RedirectToAction("Index", "Home", new {id = 1});
Now I want to get that id = 1 but in my url when I turn on app, to set just like regular without any param.
How to achieve that?
Now: localhost:8888/Index/1
What I want: localhost:8888/Index/ (but still I want to fill in ViewBag).
Solved. I didn't realize that property name id already in a route config,and automatically maps in url. All I needed to do was to change my prop to anything else, like foobar :)
I'm trying to call controller and a view from it dynamically, I'm retrieving controller name and view name from database, then I want to execute that as the view result of Page/Index url.
Basically I'm trying to do something like this:
public class PageController : Controller
{
public ActionResult Index()
{
var controllerName = // logic to get Controller name (already have)
var ViewName = // logic to get View name (already have)
Return View(ControllerName, ViewName); // I want to achieve this functionality without redirect
}
}
I have tried Server.TransferRequest but that causes HttpContext.Items to be cleared which I don't want it to happen, also I don't want to redirect, Is there any other way?
It is simple...But i think of some other reason you want something like this..
public class PageController
{
public ActionResult Index()
{
//Let
var controllerName = "Common"// logic to get Controller name (already have)
var ViewName = "Index" // logic to get View name (already have)
return RedirectToAction("Index", "Common", new { id = "1" });
}
}
and in Controller
public class CommonController : Controller
{
// Initialize with Default value
public ActionResult Index(String id = "0")
{
//Call from PageController
if (id == "1")
{
//Do some stuff
}
//Do other stuff of CommonController
return View();
}
}
So presuming, you want to return a the result of an action based on strings. You could use reflection to do this. So something along the lines of:
public ActionResult Index()
{
var controllerName = // logic to get Controller name (already have)
var viewName = // logic to get View name (already have)
//get the current assembly
Type t = typeof(PageController);
Assembly assemFromType = t.Assembly;
//get the controller type from the assembly
Type controllerType = assemFromType.GetType("Namespece." + controllerName);
//get the action method info
MethodInfo actionMethodInfo = controllerType.GetMethods(viewName);
//create an instance of the controller
object controllerInstance = Activator.CreateInstance(controllerType, null);
//invoke the action on the controller instance
return (ActionResult)actionMethodInfo.Invoke(controllerInstance, null);
}
This is untested and TBH I wouldn't recommend doing this. It's far from efficent.. there also an assumption here that your action doesn't need parameters which may or may not be true. The other option (and almost definitely the better option) is to use a Redirect as discussed by other people.
With this MVC still might have problems locating the view. You may also need to hard code your view path in the action you want to invoke. Basically what you want is very problematic and have I mentioned I wouldn't recommend doing this
I bet you are looking for RedirectToAction("ActionName", "ControllerName");
I have used the method below to get a string version of a view. Perhaps you can modify it to return a view based on your controller and view. The part where it returns IView.
protected string RenderPartialViewToString(string viewName, object model)
{
if (string.IsNullOrEmpty(viewName))
viewName = ControllerContext.RouteData.GetRequiredString("action");
ViewData.Model = model;
using (StringWriter sw = new StringWriter())
{
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
viewResult.View.Render(viewContext, sw);
return sw.GetStringBuilder().ToString();
}
}
I found a solution: https://stackoverflow.com/a/24475934/5485841
you can return a dummy view that has Html.RenderAction inside it. You can pass controller name and view name by ViewBag or Model.
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
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;
I have an action defined like this:
public ActionResult TempOutput(string model)
{
return View(model);
}
And also, I have its view defined like this:
#model String
#{
ViewBag.Title = "TempOutput";
}
<h2>TempOutput</h2>
<p>#Model</p>
Then, at one place, I have a return statement like this:
return RedirectToAction("TempOutput", "SEO", new { model = "Tester text" });
And the point is that when I get to my TempOutput view I get an error message saying "The view 'Tester text' or its master was not found or no view engine supports the searched locations.". But I jsut want to print the value of the string inside my view. How can I achieve it?
You are calling different override of View than you want:
View(string viewName);
You want to call View(string viewName, string masterName, object model) like following:
return View(null, null, model);
You can also specify explicit value (i.e. "TempOutput") for view name.
Alternatively you can force selecting View(object model) override by casting "model" to object:
return View((object)model);
Or, you can overload it using Named Arguments
return View(model: model)
If I remember correctly if you have to use the RedirectToAction you can pass model data like this:
TempData["model"] = "Tester text";
return RedirectToAction("TempOutput", "SEO");
More information about TempData found here.