Declare ViewBag on controller - asp.net-mvc-3

I'm using ViewBag.Message with the same message several times into the methods on the controller.
It is possible to declare ViewBag.Message on the top of the class, so can be used in the whole controller without repeat the code?

Assuming Razor syntax you can achieve this with.
#{string pageMessage = ViewBag.Message.ToString();}
then pageMessage is a local variable available to the page, for example:
<h1>#pageMessage</h1>
EDIT
ViewBag is a dynamic object which is a member of the Controller base class so to just specify this once in the whole controller you could put something in your controller constructor.
public class MyController : Controller
{
public MyController()
{
ViewBag.ViewTime = DateTime.Now.ToString();
}
// rest of controller code
}

Related

Can't get log4net working in MVC3 sub-classed controller

I have an MVC3 application that I'd like to get log4net working in.
I got the code I'm using from this site
I can get the logging to work if I add this code to an Action method.
public ActionResult Index() {
log4net.ILog log = log4net.LogManager.GetLogger(this.GetType());
log.Info("Here I am in Index.");
return View();
}
I'd like to enable logging in all my controllers, so I added the following class to my project,
public class LoggingController :Controller {
protected log4net.ILog Log;
public LoggingController () {
Log = log4net.LogManager.GetLogger(GetType());
}
}
and I'm having my Home controller inherit from this class, LoggingController.
I've put a break point on my LoggingController's constructor and determined the constructor is being called, however my logging isn't working when done this way.
My question then is:
Why isn't this working?
OR
Is there a better way of accomplishing what I'm trying to do here?
Thanks in advance.
Why isn't this working?
Because the type argument you pass to the GetLogger method must match that of the containing type. You are passing HomeController (by using GetType()) instead of LoggingController which is where the variable is declared. Try like this:
public LoggingController () {
Log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
}

why TempData[] doesnt work with IE

İn my MVC3 project, there is plenty of TempData[] that I am using for passing datas between actions. And it works totaly perfect when I use Chrome. But in IE I can't get values of TempData[] items. if anyone knows whats the problem and how can I solve it?`
public class SomeController : Controller
{
public ActionResult SomeAction()
{
TempData["id"] = "someData";
return View();
}
}
public class AnotherController : Controller
{
public ActionResult AnotherAction()
{
string data = Convert.ToString(TempData["id"]);
return View();
}
}
`
You should never return a view from a controller action that stores something into TempData. You should immediately redirect to the controller action that is supposed to use it:
public class SomeController : Controller
{
public ActionResult SomeAction()
{
TempData["id"] = "someData";
return Redirect("AnotherAction", "Another");
}
}
public class AnotherController : Controller
{
public ActionResult AnotherAction()
{
string data = Convert.ToString(TempData["id"]);
return View();
}
}
The reason for this is that TempData survives only for a single additional request. So for example if inside the view you are sending an AJAX request to some controller action (no matter which) and then have a link in this view pointing to the target action, when the user is redirected to this target action TempData will no longer exist since it was lost during the AJAX request done previously.
If you need to store data for longer than a single redirect you could use Session.
If you need to store data for longer than a single redirect you should use Keep or Peek methods.
string data = TempData["id"].;
TempData.Keep("id");
or simply use,
string data = TempData.Peek("id").ToString();
Peek function helps to read as well as advice MVC to maintain “TempData” for the subsequent request.

Asp.net mvc 3- get the current controller instance (not just name)

I know how to get the current controller name
HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString();
But is there any way to get the current controller instance in some class (not in an action and not in a view)?
By default you can only access the current Controller inside a controller with ControllerContext.Controller or inside a view with ViewContext.Context. To access it from some class you need to implement a custom ControllerFactory which stores the controller instance somewhere and retrieve it from there. E.g in the Request.Items:
public class MyControllerFactory : DefaultControllerFactory
{
public override IController CreateController(RequestContext requestContext, string controllerName)
{
var controller = base.CreateController(requestContext, controllerName);
HttpContext.Current.Items["controllerInstance"] = controller;
return controller;
}
}
Then you register it in your Application_Start:
ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory());
And you can get the controller instance later:
public class SomeClass
{
public SomeClass()
{
var controller = (IController)HttpContext.Current.Items["controllerInstance"];
}
}
But I would find some another way to pass the controller instance to my class instead of this "hacky" workaround.
Someone will have to correct me if what I am doing is detrimental to the whole Asp.Net page life cycle / whatever but surely you can do this:
In controller
ViewBag.CurrentController = this;
In view
var c = ViewBag.CurrentController;
var m1 = BaseController.RenderViewToString(c, "~/Views/Test/_Partial.cshtml", null);
In my case, I had a base controller that all controllers extend. In that base controller lived a static method called RenderViewToString and it required a controller. Since I figured I could just instantiate a new instance of an empty controller at this point for c, I just sent it to the view in the lovely ViewBag container that exists in the world of Asp.Net MVC. For reasons I could not go into now, I could not retrieve the string in the controller and send just that back to the view (this was what I had done earlier before requirements changed).
The reason I have done it this way is in other languages like PHP and JS, there are similar simple ways to transfer classes around.

Get current controller in view

I have a View - _Edit which lives in News M/V/C.
I reuse the V/M via the CategoryController as:
return PartialView("/Views/News/_Edit.cshtml", model);
How from within the View - _Edit can I alert the controller name?
When I:
alert('#ViewContext. RouteData.Values["controller"].ToString()');
The Value is: News
However, the URL is: /Category/foobar
Is there a way to get the value 'Category' to alert? thanks
I have put this in my partial view:
#HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString()
in the same kind of situation you describe, and it shows the controller described in the URL (Category for you, Product for me), instead of the actual location of the partial view.
So use this alert instead:
alert('#HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString()');
I do it like this:
#ViewContext.RouteData.Values["controller"]
Create base class for all controllers and put here name attribute:
public abstract class MyBaseController : Controller
{
public abstract string Name { get; }
}
In view
#{
var controller = ViewContext.Controller as MyBaseController;
if (controller != null)
{
#controller.Name
}
}
Controller example
public class SampleController: MyBaseController
{
public override string Name { get { return "Sample"; }
}
Other way to get current Controller name in View
#ViewContext.Controller.ValueProvider.GetValue("controller").RawValue
Just use:
ViewContext.Controller.GetType().Name
This will give you the whole Controller's Name
You are still in the context of your CategoryController even though you're loading a PartialView from your Views/News folder.
You can use any of the below code to get the controller name
#HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString();
If you are using MVC 3 you can use
#ViewContext.Controller.ValueProvider.GetValue("controller").RawValue
For anyone looking for this nowadays (latest versions) of ASP.NET Core MVC, you can use:
#Context.Request.RouteValues["controller"].ToString()

MVC3 Razor: Is it Possible to Render a Legacy ASCX?

With the Razor view engine in MVC3,
Is it possible to render a legacy ascx?
I was expecting to be able to do something like:
#Html.RenderPartial("Footer.ascx")
Yes. Try this instead:
#Html.Partial("Footer")
or
#{ Html.RenderPartial("Footer"); }
Just wanted to add that I haven't seen a lot of people posting this solution:
Html.RenderAction("Footer", "Home");
This is better practise if you are using MVC, because you can specify any data you need in the controller instead of trying to manage it in a free-floating partial view. Very beneficial if you use a BaseController class to initialize all your calls.
public class HomeController : Controller {
// ...
[ChildActionOnly]
public PartialViewResult Footer() {
// do work
return PartialView();
}
// ...
}

Resources