So I have bought into the “thin controller, fat model” guideline. That to me means that as little code as possible is in the controller, and most/all of the actual business logic is in the model (or in separate repository/services code).
In fact, I like the idea of the controller being a VERY simple conduit between the view and the model, and mostly concerned with calling an appropriate method in the model to do something, catch exceptions that then are added as ModelErrors, and deciding what view to go to next. Keep it as simple as possible.
At least I bought all this until I tried to write some code in my model that dealt with anything related to identity and roles.
It seems all the info required is in the Controller base class. So the only way I can think of to really access that in a Model method is by passing it as parameters? That gets really ugly really fast.
How can I access the info (IPrincipal, Session info etc) from within the Models?
I’ve solved this by creating a base Controller (and inheriting every controller from that) and a base Model (forcing each Model in my apps to inherit from that).
In the 2 base objects I’ve added 2 properties
containing the readonly user informations (userId is also session stored, but for UserInfo I’ve used MemoryCache).
in this way I’ve got everything accessible from both my controllers and models ( even in Views obvioulsy).
Informations are setted just in the base controller (by overriding the OnAuthentication or using a custom AuthorizeAttribute).
I don’t know if this is politically correct, but since I’m not bound to ASP.NET authoring (got to use SSO with Kerberos style), I’ve choose to implement in this way.
EDIT: How I do this:
I have an
HomeControllerwhich simply stores userId in session then forwards to the real starting point of the webapp (a controller which extends myBaseController)This pattern is secured by having the Authorize attribute on the base controller, each derived controller will have it applyed for each action, thus the OnAuthorization method of the base controller (or the one in your derived controller if you need to override for special cases) will be fired (e.g. No way to access without passing at least once from the HomeController/Index())
mock of the base controller:
Of course you need an HomeController not inherithing from the base (the entry point of your webapp)
The StartController inherits from BaseController, thus each action needs OnAuthorize invocation before, since the StartController doesn’t override it, the BaseController one is called.
More or less this is everything, as a bonus I add the HttpStatusCodeWithJon class.
this class is usefull to trigger STATUS errors for Ajax callbacks. If you use jQuery you can then use a global ajax error function to manage this.
This is it, maybe it’s not elegant, maybe is not politically correct, but does almost everything I need, it’s somewhat centralized, and for my current project works.
For models, simply add a public get, private set property for userid and userInfo and have them set in your model constructor (since each model is created in a controller you should have no problems at all on invoking the base model constructor via
: base(params)Warning: the code is a mock of the real thing (so can have typos or missing something), I’ve avoided to paste my business logic and reworked some parts, I guess it can be taken as a good hand drawn roadmap.
Let me know if this helps or if you need other infos.
PS:I was almost forgetting. Ff you work with ASP.NET profiles, Identities, I suggest you to look at the AuthorizeAttribute class, you can extend it and create your own Authorize Attribute, in that case, you don’t need to write the OnAuthorization on the base controller or having inheritance (I still suggest you to have a base model and a base controller), but you’ll provide that method in your Attribute. It’s cleaner. I’ve not done it because of some legacy constraint with my Single Sign On solution, but will migrate to that.
Automatically Injection in the model can be done extending the ModelBinder (or registering a custom one). Never looked deep in that, I prefer another approach for data filtering (it’s authorization not authentication, for me is app based and cannot rely on ASP.NET profiling)
The approach I would probably use is having a business object taking care of DataFiltering
Assume you’ve got an action like
you can change it to something like
or if you want to keep everything in your model, just add the UserId parameter to the DoSomething method. Yeah we’re working with object, but there’re cases in which an object can also rely on external data (not only on data members or properties).
This is a pretty neat and fast solution, major downside is adding a param to each vm business method, but it’s better than scanning every single action in order to inject it (at least the compiler gives an error on each calls)
Will look further in injecting a sproperty in a model extending the default modelbinder as soon as I’ll be free from some javascript namespaces nightmare I’m actually in. But if I recall correctly I’ve seen something like that on the net (Phil Haak or ScottGu’s blogs or even here on SO), just search for Injecting data in a Model at runtime.