Create controller base class (partial) - c#

Since my #html.render action crashes my dev and prod servers i have to use partials(crap).
I tried creating public partial controller{} class so i can set needed data for all my views but i am having no luck (everything breaks).
I am coming from LAMP cakePHP background and really need simplicity.
I need to know how to create a partial base controller(that doesnt override the regular base controller) and how to access multiple models from the class.
Thank you!

public class BaseController: Controller
{
public override OnActionExecuting(...) { ... }
public override OnActionExecuted(... context)
{
if (context.Result is ViewResult)
((ViewResult)context.Result).ViewData["mycommondata"] = data;
}
...
}
public class MyController1: BaseController
{
}
I.e. just derive from your new base controller class.
However I'd suggest you to ask here why your RenderPartial "crashes" - since it can be a better way for you, and it obviously shouldn't crash.

better way to create base controller
public class Controller : System.Web.Mvc.Controller
{
public shipsEntities db = new shipsEntities();
public Controller()
{
ViewData["ships"] = db.ships.ToList();
}
}
that way the rest of controllers follow regular convention
public class MyController : Controller

Related

Abstracting a large number of similar ASP.NET MVC Actions (C#)

A new MVC 5 app that I'm working on references a large-ish collection (4 assemblies, about 500 classes each) of data models generated from a 4GL environment. The basic interaction has the MVC app present and populate a model instance, then (after model validation), hand the model instance off to a provider for processing.
The initial approach I've used is, for each model, create
a scaffolded razor view bound to the model,
a partial controller class with a pair of actions (GET/POST) the model
All of the actions are part of the same controller class which has a couple of private methods to implement the GET & POST actions exposed in each of the partials.
So, the structure is like:
|
|--\Controllers
|
|--MyController.cs
|--MyController.MDL001.cs
|--MyController.MDL002.cs
|-- ...
|--MyController.MDL500.cs
|--\Views
|
|--\My
|--\MDL001.cshtml
|--\MDL002.cshtml
|-- ...
|--\MDL500.cshtml
And the implementation of each partial controller follows the pattern:
public partial class MyController
{
public ActionResult ProcessMDL001(MDL001Model modelInstance)
{
return ProcessModel(modelInstance);
}
public ActionResult MDL001()
{
return ShowModel("MDL001");
}
}
Where methods ProcessModel(...) and ShowModel(...) are defined in MyController.cs
I want to keep MVC's model binding and validation functioning but also am keen on avoiding a few thousand nearly-identical concrete action implementations. Is there some pattern/approach using routing, generics, dynamics, etc. that can help here?
Assuming that you can roughly treat each class the same, you can handle this with generics:
public class BaseController<T> : Controller
where T : class, new
{
public ActionResult Process(T modelInstance)
{
return ProcessModel(modelInstance);
}
...
}
But, you would need to use subclasses instead of partial classes. Essentially, you're just going to implement the action once, and then subclass this base controller to specify the type for the controller instance you're working with:
public MDL001ModelController : BaseController<MDL001Model>
{
}
If no additional type-specific actions are needed, then that code alone is all you subclass would need to be. However, you can always add additional actions that will only apply to this particular controller instance.
If there are pieces of the common actions that you need to customize slightly, such as validation logic or something, you can provide hooks in your actions. Something along the lines of:
public class BaseController<T> : Controller
where T : class, new
{
public ActionResult ActionWithHook(T model)
{
DoSomeWork(model);
return View();
}
// By default this does nothing, but can be overridden to do something
internal virtual void DoSomeWork(T model)
{
}
}
Then:
public MDL001ModelController : BaseController<MDL001Model>
{
internal override void DoSomeWork(MDL001Model model)
{
// Do something
}
}

How do I inherit from an ActionFilter attribute in a assembly in the same project but not directly referenced?

What I am asking my not even be possible (I am skeptical) but I have been tasked to do this exact thing so please if its not possible or dumb please explain why.
I have a base project that contains an ActionFilter attribute that overrides OnActionExecuting. It does nothing as it is supposed to be a base class to inherit from.
namespace mybaseproject
public class BaseActionAttribute : ActionFilterAttribute
{
public string ActionName {get;set;}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
}
}
I have a second project that references 'mybaseproject' and uses BaseActionAttribute.
namesapce mysecondproject
public class MyController : Controller
{
[BaseAction(ActionName="Index")]
public ActionResult Index()
{
//do stuff
}
}
I have a third project that references both 'mybaseproject' and 'mysecondproject'. It has an ActionFilterAttribute that inherits from the base one and has all of the real code to process.
using mybaseproject;
namespace mythirdproject
public class DerivedActionAttribute : BaseActionAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// do all the real stuff
base.OnActionExecuting(filterContext);
}
}
What the desired effect is for the BaseActionAttribute in mysecondproject to use the code in DerivedActionAttribute of mythirdproject. I don't see how this can work because mysecondproject has no reference to mythirdproject. They just reside in the solution. I have tried using Authorize attribute as well but my breakpoint never gets hit in the derived attribute when I call my action in the second project.
This was how I was told to tackle the problem. Either I misunderstood or am taking the wrong approach, or this is just not possible.
Which one? Thanks ahead for listening.

How can I spread custom object through my MVC application?

Let say I have an object that is similar for each user that try to access to my website.
A sort of Session Scope object, which should be visible on every View/Model/Controller inside my whole "application".
I'd like to create it when I call a page and populate it through data coming from my own database.
Than, on View (as example) calling myObject.Title.
On WebForms I'm doing this extending a class of the UserControl, such as:
public class iUserControl : System.Web.UI.UserControl
{
protected MyCurrentPage myCurrentPage;
public iUserControl()
{
}
protected override void OnLoad(EventArgs e)
{
myCurrentPage = new MyCurrentPageWrapper();
}
}
than, for each UserControl, somethings like this:
public partial class context_pippo_MyOwnUserControl : iUserControl
on MVC I can't see any extension for each controls, so how can I could achieve this kind of process? I'd like to get rid about storing elements on Session.
If I understand question correctly, I think I've done something similar in one project.
I had something like this:
public interface IControllerBaseService
{
IUserService UserService {get;set;}
ShoppingMode ShoppingMode {get;set;}
...
}
public abstract class ControllerBase : Controller, IControllerBaseService
{
public IUserService UserService {get;set;} // this is injected by IoC
public ShoppingMode ShoppingMode
{
get
{
return UserService.CurrentShoppingMode; // this uses injected instance to get value
}
...
}
As long, as I user IoC container to create controller instances, UserService property is injected by container.
You can access now your interface from view like this:
(IControllerBaseService)ViewContext.Controller
To have a shortcuts for most common used properties in IControllerBaseService, I had several extension methods, something like this:
public static ShoppingMode CurrentShoppingMode(this HtmlHelper helper)
{
return ((IContollerBaseService)helper.ViewContext.Controller).ShoppingMode;
}
So in view it looked like #Html.CurrentShoppingMode()

C# Centralizing repeating VIewData in MVC

When a user log in into my application i want to show his name throughout the whole application. I am using the asp.net MVC framework. But what i don't want is that is have to put in every controller something like:
ViewData["User"] = Session["User"];
This because you may not repeat yourself. (I believe this is the DRY [Don't Repeat Yourself] principle of OO programming.)
The ViewData["User"] is on my masterpage. So my question is, what is a neat way to handle my ViewData["User"] on one place?
You can do this fairly easily in either a controller base-class, or an action-filter that is applied to the controllers/actions. In either case, you get the chance to touch the request before (or after) the action does - so you can add this functionality there.
For example:
public class UserInfoAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(
ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
filterContext.Controller.ViewData["user"] = "Foo";
}
}
...
[HandleError, UserInfo]
public class HomeController : Controller
{...}
(can also be used at the action (method) level)
or with a common base-class:
public abstract class ControllerBase : Controller
{
protected override void OnActionExecuting(
ActionExecutingContext filterContext)
{
ViewData["user"] = "Bar";
base.OnActionExecuting(filterContext);
}
}
[HandleError]
public class HomeController : ControllerBase
{...}
It's been a year, but I've just stumbled across this question and I believe there's a better answer.
Jimmy Bogard describes the solution described in the accepted answer as an anti-pattern and offers a better solution involving RenderAction: http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/06/18/the-filter-viewdata-anti-pattern.aspx
Another method for providing persistent model data through out your entire application is by overriding the DefaultFactoryController with your custom one. In your CustomerFactoryController, you would hydrate the ViewBag with the model you are wanting to persist.
Create a base class for your models with UserName property:
public abstract class ModelBase
{
public string UserName { get; set; }
}
Create a base class for you controllers and override it's OnActionExecuted method. Within it check if model is derrived from BaseModel and if so, set it's UserName property.
public class ControllerBase : Controller
{
protected override void OnActionExecuted(
ActionExecutedContext filterContext)
{
var modelBase = ViewData.Model as ModelBase;
if (modelBase != null)
{
modelBase.UserName = "foo";
}
base.OnActionExecuted(filterContext);
}
}
Then you will be able to display user's UserName in the view like this:
<%= Html.Encode(Model.UserName) %>
See also:
ASP.NET MVC Best Practices, Tips and Tricks

MVC Attributes on Controllers and Actions

Is there a way to add an Attribute on the Controller level but not on a specific action. For example say if i had 10 Actions in my Controller and just 1 of those Actions does not require a specific attribute I created.
[MyAttribute]
public class MyController : Controller
{
public ActionResult Action1() {}
public ActionResult Action2() {}
[Remove_MyAttribute]
public ActionResult Action3() {}
}
I could potentially move this Action into another controller (but dont like that) or I could apply the MyAttribute to all actions except from Action3 but just thought if there is an easier way?
I know my answer is a little late (almost four years) to the game, but I came across this question and wanted to share a solution I devised that allows me to do pretty much what the original question wanted to do, in case it helps anyone else in the future.
The solution involves a little gem called AttributeUsage, which allows us to specify an attribute on the controller (and even any base controllers!) and then override (ignore/remove) on individual actions or sub-controllers as needed. They will "cascade" down to where only the most granular attribute actually fires: i.e., they go from least-specific (base controllers), to more-specific (derived controllers), to most-specific (action methods).
Here's how:
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method, Inherited=true, AllowMultiple=false)]
public class MyCustomFilterAttribute : ActionFilterAttribute
{
private MyCustomFilterMode _Mode = MyCustomFilterMode.Respect; // this is the default, so don't always have to specify
public MyCustomFilterAttribute()
{
}
public MyCustomFilterAttribute(MyCustomFilterMode mode)
{
_Mode = mode;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (_Mode == MyCustomFilterMode.Ignore)
{
return;
}
// Otherwise, respect the attribute and work your magic here!
//
//
//
}
}
public enum MyCustomFilterMode
{
Ignore = 0,
Respect = 1
}
(I heard you like attributes, so I put some attributes on the attribute! That's really what makes the magic work here at the very top: Allowing them to inherit/cascade, but only allowing one of them to execute.)
Here's how it is used now:
[MyCustomFilter]
public class MyBaseController : Controller
{
// I am the application's base controller with the filter,
// so any derived controllers will ALSO get the filter (unless they override/Ignore)
}
public class HomeController : MyBaseController
{
// Since I derive from MyBaseController,
// all of my action methods will also get the filter,
// unless they specify otherwise!
public ActionResult FilteredAction1...
public ActionResult FilteredAction2...
[MyCustomFilter(Ignore)]
public ActionResult MyIgnoredAction... // I am ignoring the filter!
}
[MyCustomFilter(Ignore)]
public class SomeSpecialCaseController : MyBaseController
{
// Even though I also derive from MyBaseController, I can choose
// to "opt out" and indicate for everything to be ignored
public ActionResult IgnoredAction1...
public ActionResult IgnoredAction2...
// Whoops! I guess I do need the filter on just one little method here:
[MyCustomFilter]
public ActionResult FilteredAction1...
}
I hope this compiles, I yanked it from some similar code and did a little search-and-replace on it so it may not be perfect.
You have to override/extend the default attribute and add a custom constructor to allow exclusion. Or you can create your custom attribute for exclusion (in your example is the [Remove_MyAttribute]).
Johannes gave the correct solution and here is how I coded it... hope it helps other people.
[MyFilter("MyAction")]
public class HomeController : Controller
{
public ActionResult Action1...
public ActionResult Action2...
public ActionResult MyAction...
}
public class CompressFilter : ActionFilterAttribute
{
private IList _ExcludeActions = null;
public CompressFilter()
{
_ExcludeActions = new List();
}
public CompressFilter(string excludeActions)
{
_ExcludeActions = new List(excludeActions.Split(','));
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpRequestBase request = filterContext.HttpContext.Request;
string currentActionName = (string)filterContext.RouteData.Values["action"];
if (_ExcludeActions.Contains(currentActionName))
return;
...
}
You could exclude a specific action by passing it to the main attribute:
[MyAttribute(Exclude="Action3")]
EDIT
My example was from the head (as you can see the following is VB.NET, maybe that's where it went wrong), this is how I implemented:
<Models.MyAttribute(Exclude:="Action3")> _
Public Class MyController
Inherits System.Web.Mvc.Controller
End Class
The usual pattern for what you are trying to do is to have and attribute with a boolean parameter that indicates if the attribute is applied or not.
Ex:
[ComVisible] which is equivalent with [ComVisible(true)]
or
[ComVisible(false)]
inf your case you would have:
[MyAttribute] // defaults to true
and
[MyAttribute(false)] for applying the attribute on excluded members

Categories

Resources