Can I access the ViewData from the HttpContext? - asp.net-mvc

Im working with a project that sets variables such as the current user profile object in its authorize action filter, storing them in the ViewData for access by the following action method.
The action method then calls functionality from the repository. I'm trying to find a way to access the ViewData from the repository WITHOUT modifying the repository's method signature, and am hoping there is a way I can track back to it via the HttpContext.Current functionality which I can call from the repository.
Can anyone help with this? Just to be clear, the only code that I can modify is within the repository method :(
public class MyController : Controller {
[MyAuthorize] // ViewData items are set here
public void MyAction(int id)
{
new MyRepository().DoSomething(id); // Need to access ViewData items within this repository method and am unable to alter the method signature :(
}
}

I'm pretty sure the answer is "no".
When you review the ASP.NET MVC source code, ControllerBase instantiates a ViewData dictionary on first use. Then when you call View(), a new ViewResult is instantiated with the ControllerBase.ViewData dictionary as a parameter. It does not look like it gets applied to a public static property or class like HttpContext which you could access from inside your repository.
I think your best bet would be to use HttpContext.Items which is built for this type of communication. Though probably not as ideal as just modifying the repository to accept the extra data.

Related

MVC - How to instantiate, store and make a typed variable available throughout the application, once per page view

I am developing an MVC app to serve multiple domains - each is a branch of a larger company.
A LocalBranch class stores details such as phone, address, email, location coordinates etc.
I want to create a single instance of this class per http request and have it available throughout the application - from within controllers, views, some helper classes and other code.
Is there a recommended way of doing this?
Right now I have it as a property on a BaseController and use ViewBagto pass it to views. But I would prefer it strongly typed in Views if possible.
I don't want to put it in an application variable, because we need to serve different values to different domains.
I would rather avoid a session variable if possible because we might scale up to use multiple servers in the future, and I've heard this doesn't play well with sessions.
Please feel free to update tags / title if you think there is a clearer way of expressing what I'm after. Thank you.
The best way to maintain your state in a web application per request is simply use the HttpContext class.
You need to store your state(LocalBranch) as an Item in the HttpContext:
HttpContext.Current.Items.Add("LocalBranch", GetLocalBranch());
You can fetch the Item all across your application like this:
LocalBranch branch = HttpContext.Current.Items["LocalBranch"] as LocalBranch;
The Items property is simply a key value Dictionary. The value is an object. You will have to check for nulls and this is really similar to the Session object you know. The main difference is the scope. The HttpContext is a dot net object that has a lifetime of an http request.
Now using the HttpContext the way I've shown you is the simplest way to do it.
You can go two steps forward and use a framework called Unity and add a lifetime to your objects.
Unity does much more and the lifetime management is just one gem.
You can create a custom HttpContext lifetime that generates objects per request. Something like this.
And them all you need to do is:
1.Register you LocalBranch class with the HttpContext lifetime.
2.Add a static Current property which will use the Unity container and resolve the correct instance of LocalBranch.
3.Use it something like this: LocalBranch.Current
BTW, you can use Unity's dependency injection for injecting objects into controllers and other modules. That's a better practice then just using the static Current property.
You kind of have two questions here. The first is "How do I create a single instance of this class per HttpRequest?" The second is "How do I make this available to strongly typed views?"
The first has pretty much been answered by #amir-popovich to use dependency injection. However, FWIW I would probably use Ninject instead of Unity (just preference, really) and I would probably implement it differently. I would not use HttpContext, and simply build a service (which is instanciated using Ninject's OnePerHttpRequest Module, passing the domain as an argument to get the proper values).
Then, in order to add these LocalBranch values to your strongly typed View Model, you can first create a base view model which holds this type:
public class BaseViewModel
{
public LocalBranch Branch {get;set;}
}
Then, make all of your current view models inherit this base type
public MyViewModel : BaseViewModel
{
public string SomeValue {get;set;}
}
Then in your controller, it is easy enough to add these values from the service you created from the first step
public ActionResult SomeAction()
{
var vm = new MyViewModel();
vm.Branch = LocalBranchService.GetLocalBranchValues(); //Local Branch Service has been injected with Ninject
//do other stuff
return View(vm);
}
However, that gets pretty tedious to add that to each controller action, so you can instead create a Result Filter to add it for you:
public class LocalBranchResultFilter : FilterAttribute, IResultFilter
{
public void OnResultExecuting(ResultExecutingContext filterContext)
{
//This method gets invoked before the ActionResult is executed.
filterContext.Controller.ViewData.Model.Branch = LocalBranchService.GetLocalBranchValues(); //Local Branch Service has been injected with Ninject
}
}
Now, you can just decorate your Controller and/or Actions with the filter (you could even set it in the Global Filters if you want).
You can embed the child actions into your layout or a view. You can even cache its output so you don't keep re-querying the database.
controller
[ChildActionOnly]
[OutputCache(Duration=500, VaryByParam="*")]
public ActionResult Info()
{
var localBranch = db.GetLocalBranch();
return PartialView("_Info", localBranch);
}
_Info view
This bit will get inserted into your other views
#model LocalBranch
<span>#Model.address</span>
<span>#Model.phone</span>
Use in _Layout or other view
<p>lorem ipsum...</p>
#Html.Action("Info")

Purpose of public NonAction methods in MVC

i have just started working in MVC and I have one doubt.
Instead of Nonaction method , we can create private method in controller or we can also write method in model and call that from controller.
So , what is the real purpose to use public NonAction method in MVC ?
(I restructured the answer to better address the questions in the comments)
I think, the attribute is here only for better flexibility. As a framework designer, one wants to relax coding constraints off the end user as much as possible. Requirement of not having public non-actions may sound good "in general" but may be too restrictive for some projects. Adding [NonAction] solves their problem (introduced by their bad design though) - and obviously you're not forced to use the attribute, so it's a win-win from a framework designer perspective.
Another reason may be legacy - in the earlier MVC versions only methods marked with [Action] where considered as actions. So when they relaxed the requirement (and all public methods became treated as actions) they kept [NonAction] so that developers won't get too confused.
In general, using NonAction is a bad practice - exactly for the reasons you stated. If something shouldn't be an action, it should not be public in the first place.
Problem with public non-action methods on the controller is that they make people tempted to instantiate your controller and call the method, instead of separating out the common logic:
Compare
public class MyController : IController
{
public ActionResult Foo(long orderId)
{
var order = new OrdersController().GetOrder(orderId); //GetOrder is public
...
}
}
with
public class MyController : IController
{
public ActionResult Foo(long orderId)
{
var order = _orderService.GetOrder(orderId);
...
}
}
The first approach leads to increased coupling between controllers and non-straightforward code in the actions. Code becomes difficult to follow and refactor, and cumbersome to mock/test.
Besides increased coupling, any public non-action method is a security hole - if you forget to mark it with [NonAction] (or, better, change away from public) - because it's treated as normal action and can be invoked externally. I know the original question kinda implies you surely would never forget to attach the attribute if needed, but it's also kinda important to understand what can happen if you would ;) Oh well, and as we're on this, it seems to me that "forgetting the attribute" is more theoretically probable, comparing to "forgetting to make the method private".
Sometimes people say having public non-actions is necessary for unit testing, but again, when something is not an action it most likely can be isolated in a separate class and tested separately. Moreover, even if it's not feasible for whatever reason, marking a method public for testing purposes only is a bad habit - using internal and InternalsVisibleTo is the recommended way.
This kind of situation may be caused by requirements some testing framework such as you need to do unit testing on that method then you to expose it although its a bad design but can't change these had to bear it out.
By default, the MVC framework treats all public methods of a controller class as action methods. If your controller class contains a public method and you do not want it to be an action method, you must mark that method with the NonActionAttributeattribute.
Real purpose to use public NonAction
To restrict access to non-action method to notify MVC framework that given controller method is not action.
When you try to run a method with NonAction attribute over URL you get the error 404 as response to request.
Ref: http://msdn.microsoft.com/en-us/library/dd410269%28v=vs.90%29.aspx
For Detail: http://weblogs.asp.net/gunnarpeipman/archive/2011/04/09/asp-net-mvc-using-nonactionattribute-to-restrict-access-to-public-methods-of-controller.aspx
This is beneficial when the Url are not case sensitive. So that for example if you have the request Home/About this goes to HomeController and About action, as well as hOmE/AbOUT is going to the same controller and same action method.
Like below
public class HomeController:Controller
{
....
public ViewResult About()
{
return View();
}
public ViewResult aBOut()
{
return View();
}
}
The framework can’t determine which about function to call, and throws the exception telling that the call is ambiguous.
Of course one way to fix this problem is to change the action name.
If for some reason you don’t want to change the action name, and one of these function is not an action, then you can decorate this non action method with NonAction attribute. Example:
[NonAction]
public ActionResult aBOut()
{
return View();
}
By default, the MVC framework treats all public methods of a controller class as action methods. If your controller class contains a public method and you do not want it to be an action method, you must mark that method with the NonActionAttribute attribute.
We are using controllers as binding drivers with custom ASP pipeline, each driver is responsible for rendering one section (partial view) of result page. Then we are using public methods like:
[NonAction]
publi int GetOrder()
to resolve sections order on page or other to resolve authorization for current user (e.g. if current section is editable or just read-only).
So you should not restrain yourself to think about Controller as only a way to handle requests but also as a tool to build your custom framework for rendering page. That way we keep our Controllers responsible for exactly one task and we are separating domain concerns.
ASP.NET is highly customizable. Assume you are going to change the default behavior of the framework by overriding the MVC HTTP handler. Maybe you want to customize the logging logic depending on the controller, which is used. Some controllers implement your ILoggingController interface with the method IControllerLogger GetLogger(). For this method you need to write a public non-action method.

Checking object access using ActionFilters

I have been happily using a BaseController class with a custom ActionFilterAtribute, overriding OnActionExecuting(). I use this BaseController class for all my controllers as a convenient way of checking the id route value when it is passed in to the Controller.
This worked fine... I check for an id value, and if it exists I check to see the controller name which determines the type of object that the id belongs to.
But then... I started to get errors which are created when a PartialView is called in ControllerB and presenting the same id in the FilterContext that was used for the parent Controller/View. For example say I have a url of localhost/Project/Details/5 where Project is the controller and Details the action with an id=5. Controller "Notes" gets called due to a PartialView and my ActionFilter is triggered this time for Controller "Notes" and the original "Project" id. The user is permitted access to ProjectId=5 but not NoteId=5
I hope this makes sense - I am struggling to explain. I now need to either find some way of ignoring the PartialView, or handling it, or using a different approach altogether. My end goal is to be able to check object access in my application based on the id of an object. Is there a "best approach" for this kind of problem? Maybe I need to write a filter for every controller? Or possibly check the Action name as well so I know when to ignore "id"?
My BaseController...
public class AccessCheckAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
int id;
if (filterContext.RouteData.Values["id"] != null)
{
if (int.TryParse(filterContext.RouteData.Values["id"].ToString(), out id))
{
SPTdb db = new SPTdb();
switch (filterContext.RouteData.Values["Controller"].ToString().ToLower())
{
case "project":
project = db.Projects.Find(id);
I think this problem can be solved by using SQL query. You pass the table name and also with [key/value] of your object identity.

Dependency Injection into an MVC action method

I'm wondering if this is possible. I have a typical MVC action method with a signature that looks like this:
public ActionResult View(MyModel model)
{
IAnObject myObject = new AnObject();
//several lines of code follow.....
return View(model);
}
I'd like to get rid of that new keyword and inject an instance of IAnObject into the action method. But I'm not sure if MVC allows for this, injecting a class along side a model in an action method? Has anyone run across this, and are there ways of tackling it? (Our IoC container is Windsor, in case that makes a difference.)
If you are expecting to inject this reference into the action method as a parameter, you can look to the ControllerActionInvoker, which has an InvokeActionMethod method, which I believe is called from InvokeAction. This method has a list of parameters passed into it, and a description of the action (ActionDescriptor class). This action descriptor has a GetParameters method that will give you more detailed information about the parameter, such as type information that you would need for the dependency injector. I've not done this, so I don't know quite how it works out, but it seems possible.
I also don't know how that might affect how MVC selects an action method to post to, so factor that in.
You may want to do your injection in OnActionExecuting which is called before any action on the controller is executed. This will give you context such as the Request but will allow you to set member variables - thus 'simulating' constructor injection. And of course you only have to do it once for the whole controller.
[NonAction]
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
_myService = .........; // get from IoC container
base.OnActionExecuting(filterContext);
}
Well, I agree with the guys on the comments, but if you want to take an instance in the method scope, try to get it from your container of IoC, something like this:
public ActionResult View(MyModel model)
{
// take from the container of IoC
IAnObject myObject = _continerIoC.Resolve<IAnObject >();
//several lines of code follow.....
return View(model);
}
Avoid using the new to create your instance and your concrete type in the container and decouple your controller from dependecies/references.
I really consider using constructor/property Injection. There is a method injection too.

How to make an MVC AttributeFilter to verify posted file extension

I have a controller that handles file uploads. Ultimately I would like to be able to create attribute to decorate my controller actions like [HttpPostedFileType("zip")] or something similar.
Currently I created this extension method which I use in the action.
public static string GetFileExtension(this HttpPostedFileBase file)
{
if (!file.FileName.Contains('.'))
throw new FormatException("filename does not contain extension");
return file.FileName.Split(".".ToCharArray()).Last();
}
The action signature is
[HttpPost]
public ActionResult Shapefile(HttpPostedFileBase file)
{
file.GetFileExtension()
...
}
I started to create a HttpPostedFileTypeAttribute and was thinking I'd override the OnActionExecuting method and call the extension. In this case with posted files, I can get the Http request and loop over the files but with mvc's model binding having a HttpPostedFileBase or an enumeration of those is much cleaner than the asp 1.x way of getting to the files.
My question is, can I get the parameters in the attribute on action executing or have they not been bound yet since the life cycle hasn't hit the action method yet? Should I create a model with a HttpPostedFileBase property and create a validation attribute? Recommendations?
filterContext has a ActionParameters dictionary. I can just use that.

Resources