I'm not sure that inheritance of commands (which are bound to form parameters etc.) is a good mechanism for determining handlers for a request, this limits your ability to compose things easily (you run up against the limitations of single inheritance etc.).
Also would this be the mechanism used in place of things like filters - so effectively a handler of the base command class "WebCall" would behave like a BeforeAction filter (kinda). If so, isn't ordering of handlers then going to become an issue to implementing things like security, authentication etc. filters. Interesting discussion though. Cheers, - Alex On Mon, Mar 22, 2010 at 2:45 PM, John Simons <[email protected]>wrote: > Sorry I did a very simplistic example. > So here is something a bit more complex, and with a few more smarts. > > Lets say that as part of displaying /Products/List we also display on > the same screen a shopping cart + product specials + recommended > products, actually lets say that we do this for any url that is part > of the Products "area" (/Products/*). > > The way we do this using the Controller/Action is something like this: > public void List(){ > PropertyBag["cart"] = GetCart(); > PropertyBag["recommended"] = Recommended(); > PropertyBag["specials"] = Specials(); > PropertyBag["productsList"] = GetProductsList(); > } > > public void Search(){ > PropertyBag["cart"] = GetCart(); > PropertyBag["recommended"] = Recommended(); > PropertyBag["specials"] = Specials(); > } > > public void ComingSoon(){ > PropertyBag["cart"] = GetCart(); > PropertyBag["recommended"] = Recommended(); > PropertyBag["specials"] = Specials(); > PropertyBag["comingSoon"] = ComingSoon(); > } > > And yes I know you can do a bit of refactoring here or use Filters, > but the point is that an action method has a lot of responsibilities > with this model. > Also, remember that your controllers tend to not just have one single > action method but many (this can make the Controllers quite large > classes!). > > The way I would do this using Handles is (Note: I'm using inheritance > to work out what handles to execute): > > public class ProductsListWebCall : ProductsWebCall{ > > } > > public class ProductsWebCall : WebCall { > > } > > public class ProductsListHandler : > Handles<ProductsListWebCall> > { > public IEngineContext EngineContext { get; set; } > public IControllerContext ControllerContext { get; > set; } > > public void Handle(ProductsListWebCall webCall) > { > ControllerContext.PropertyBag["productsList"] > = GetProductsList(); > } > } > > public class ProductsSpecialsHandler : > Handles<ProductsWebCall> > { > public IEngineContext EngineContext { get; set; } > public IControllerContext ControllerContext { get; > set; } > > public void Handle(ProductsWebCall webCall) > { > ControllerContext.PropertyBag["specials"] = > Specials(); > } > } > > public class ProductsRecommendedHandler : > Handles<ProductsWebCall> > { > public IEngineContext EngineContext { get; set; } > public IControllerContext ControllerContext { get; > set; } > > public void Handle(ProductsWebCallwebCall) > { > ControllerContext.PropertyBag["recommended"] > =Recommended(); > } > } > > public class CartHandler : Handles<WebCall> > { > public IEngineContext EngineContext { get; set; } > public IControllerContext ControllerContext { get; > set; } > > public void Handle(WebCall webCall) > { > ControllerContext.PropertyBag["cart"] = > GetCart(); > } > } > > The advantage I get from using this model is hopefully total > separation of concerns on my handlers. > > I will write a post about this, with sample code that I hope will > clarify a lot of the unanswered question in this thread. > > Cheers > John > > > On Mar 22, 12:16 pm, Henry Conceição <[email protected]> > wrote: > > For me, it appears to be just a rename. What we used to call > > controller, is now called handler. With the downside that now I'm > > obligated to implement an extra class honoring the web call contract. > > But perhaps I didn't get the big picture... > > > > Cheers, > > Henry Conceição > > > > On Sun, Mar 21, 2010 at 9:38 PM, John Simons <[email protected]> > wrote: > > > Jan, > > > My line of thought at the moment is why have a controller at all? > > > See Chad Myers post on it: > > >http://www.lostechies.com/blogs/chad_myers/archive/2009/06/18/going-c. > .. > > > > > I have been hacking MR to bend it the way I want, so far I'm able to > > > convert a request into a command (using convention over configuration) > > > and execute that command with a simple interface. > > > Eg. > > > Assume a request comes in for /Products/List > > > I then convert this request into ProductsListWebCall > > > And then I go to my container and do the following: > > > var webCallHandlers = > > > windsorContainer.ResolveAll<Handles<TWebCall>>(new { EngineContext = > > > engineContext, ControllerContext = context}); > > > var webCall = > Activator.CreateInstance<TWebCall>(); > > > > > foreach (var handler in webCallHandlers) > > > { > > > handler.Handle(webCall); > > > } > > > And the Handle interface is: > > > public interface Handles<T> where T: WebCall > > > { > > > void Handle(T command); > > > } > > > > > public interface WebCall > > > { > > > } > > > > > As u can see I'm also injecting the ControllerContext and > > > EngineContext so that in the Handler I can do this: > > > public class ProductsListHandler : > > > Handles<ProductsListWebCall> > > > { > > > public IEngineContext EngineContext { get; set; } > > > public IControllerContext ControllerContext { get; set; > } > > > > > public void Handle(ProductsListWebCall webCall) > > > { > > > ControllerContext.PropertyBag["message"] = > "Hello from handler"; > > > } > > > } > > > > > Sorry about the formatting of the code, I'll try to write a blog post > > > about it soon. > > > > > Cheers > > > John > > > > > On Mar 16, 1:26 pm, Jan Limpens <[email protected]> wrote: > > >> From my point of view, I hope nobody minds my late involvement in this > > >> discussion, MR's future should concentrate less in features and more > > >> in architecture. > > > > >> After all, functionality like the one provided by > > >> SmartDispatcherController should be (and mainly is) provided as an > > >> aspect. > > > > >> The aforementioned functionality to render multiple controller actions > > >> into a single view inverts the mvc paradigm and is no good idea in my > > >> point of view. The view should not be able to make such decisions, > > >> that's the controllers job. > > >> The controller how it is today is a point of very low cohesion and one > > >> of the points that should be implemented in a very different way. > > >> Fortunately, with the availability of DynamicActions, the controller > > >> could actually become the aspect providing Action-registration node, > > >> it ought to be, imho. > > >> This would make reuse much more efficient and would allow for better > > >> composibility. Imagine, one has (fake MEF style) > > > > >> public class MyController { > > > > >> [Import] > > >> public void MyAction { > > >> } > > > > >> } > > > > >> [Export("MyController.MyAction")] > > >> public class MyActionContent : DynamicAction{ > > >> //impl > > > > >> } > > > > >> [Export("MyController")] > > >> public class MyActionLayout : DynamicAction{ > > >> //impl > > > > >> } > > > > >> this would solve composition pretty well - on the controller side. > > > > >> On the view side, I completely dig OpenRasta's codec and content > > >> negotiation paradigm. It is sad, MR does not offer such a clean > > >> implementation. > > > > >> Composite UI is much more difficult to envision, in my eyes, because, > > >> contrary to WebForms, we do not have externally programmable views (we > > >> can not say "Body.Insert(new Whatever())"). But from a separation of > > >> concerns point of view, this is a good thing, probably. Still all > > >> frameworks offering composite GUIs have this somewhere. The problem > > >> is, that a view in a composite world cannot know of what parts it > > >> consists, but probably the solution ought to be similar to the > > >> controller: the view as a registration point for sub views based on > > >> some conventions. > > > > >> <% SubViews > > >> .For(v => v.ForNode = "contentNode") > > >> .With(v => viewData.GetData(v)) > > >> .OrderedBy(v => layout.ApplyOrder(v)) %> > > > > >> Composition is a big deal (I'd love to read hammett's take on this, > > >> but both of his blogs seem abandoned...) and is something really > > >> difficult to implement currently. > > > > >> Probably I should have said IMHO, much more often, so please take this > > >> as the opinion this is. > > > > >> --Jan > > > > >> On Jan 24, 8:15 pm, Mauricio Scheffer <[email protected]> > > >> wrote: > > > > >> > But you would still have to place these concerns somewhere in the > > >> > layout or in the view, so it's the same as RenderAction. The only > > >> > advantage is the possibility of processing all these sub-actions in > > >> > parallel, but you'd lose the ability to define different parameters > > >> > for each sub-action (i.e. they would all get the same context, > whereas > > >> > with RenderAction you can define different querystring/parameters/ > > >> > context for each sub-action). > > >> > But the main problem I see with this is that I don't know who's > really > > >> > in control of the response. If they all run in parallel and Product/ > > >> > View decides that the product is offline and the response should be > > >> > redirected, what happens to the other actions? > > >> > PropertyBag would still be needed to render each sub-action. > > > > >> > Or maybe I got it all wrong and didn't understand you... > > > > >> > With RenderAction screen sections can be easily split among > developers > > >> > since they are orthogonal and ultimately just regular controllers. > > >> > Then the main controller does the final composition. > > > > >> > SubControllers are a similar concept: > http://mhinze.com/subcontrollers-in-aspnet-mvc/ > > > > >> > Anyone here knows Seaside? I hear it's great at composability, we > > >> > could borrow some ideas from it. > > > > >> > Cheers > > >> > Mauricio > > > > >> > On Jan 24, 6:34 pm, John Simons <[email protected]> wrote: > > > > >> > > Mauricio, thank you a lot for finding an article that highlights > the > > >> > > benefits of what I'm proposing. > > >> > > But in this article the author chose to use RenderAction to > separate > > >> > > the concerns, but by doing that we now have mixed concerns on our > view > > >> > > file(the template itself). > > >> > > What I'm proposing is to go one step further, and come up with > > >> > > hopefully total separation of concerns including on the view file. > > > > >> > > And because action takes care of one and only one concern (hence > the > > >> > > reason I said we don't need a PropertyBag any longer), we should > be > > >> > > able to render all these in parallel. > > > > >> > > This way of separation is used quite frequently in Windows > > >> > > applications where different developer teams take care of > different > > >> > > screen sections. > > > > >> > > My vision to register all this would be something like this: > > >> > > RoutingModuleEx.Engine.Add( > > >> > > new CompositeRoute("ProductRoute", > "/Products/<productId>/<action>") > > >> > > .ComposedOf( > > >> > > Controller("Product").Action("View"), > > >> > > Controller("Login").Action("Info"), > > >> > > Controller("ShoppingCart").Action("Summary"), > > >> > > Controller("CustomerFeedback").Action("List"), > > >> > > Controller("PurchasingHistory").Action("SummaryList")) > > >> > > WithLayout("productlayout") > > >> > > ); > > > > >> > > Cheers > > >> > > John > > > > >> > > On Jan 25, 1:12 am, Mauricio Scheffer <[email protected] > > > > >> > > wrote: > > > > >> > > > It's not about getting data in parallel, but a different way of > > >> > > > separating concerns. > > > > >> > > > I have found it useful to model reusable, orthogonal concerns to > a > > >> > > > page, things that not only display information but also have an > > >> > > > associated action. A good example ishttp:// > www.lostechies.com/blogs/jimmy_bogard/archive/2009/06/18/the-f... > > > > >> > > > On Jan 23, 7:05 pm, Ken Egozi <[email protected]> wrote: > > > > >> > > > > Nothing is stopping anyone from spawning these calls in > parallel, > > >> > > > > asynchronously, then get it all back, and spill the data into > the property > > >> > > > > bag. > > > > >> > > > > in my view, the Controller's job is exactly that (plus binding > data to/from > > >> > > > > http, and dealing with authentication via filters) > > >> > > > > and by "that" I refer to "call service layer to grab data, and > stuff the > > >> > > > > data into properyBag". > > > > >> > > > > I have had much success in the past using the CCR to get > required data in > > >> > > > > parallel. > > >> > > > > the nice thing is that you don't get many concurrency issues - > the data > > >> > > > > querying is parallel, however the Context access is either > before (when > > >> > > > > mining context data and pushing it to the service layer for > querying) or > > >> > > > > *after* querying, when serially pushing the returned data into > the prop=bag. > > > > >> > > > > so, I really don't thing that it is the FW responsibility, but > rather the > > >> > > > > programmers. > > > > >> > > > > On Sat, Jan 23, 2010 at 11:39 PM, Gauthier Segay > > >> > > > > <[email protected]>wrote: > > > > >> > > > > > Henri, > > > > >> > > > > > what John has explained will mean a single http request > triggering > > >> > > > > > multiple actions (potentially on multiple controllers), the > difference > > >> > > > > > of the MSMVC implementation with John proposition is that > each action > > >> > > > > > would be triggered in parallel (which I think need some > abstraction/ > > >> > > > > > encapsulation on what is possible to execute > > > > ... > > > > read more » > > -- > You received this message because you are subscribed to the Google Groups > "Castle Project Development List" group. > To post to this group, send email to [email protected] > . > To unsubscribe from this group, send email to > [email protected]<castle-project-devel%[email protected]> > . > For more options, visit this group at > http://groups.google.com/group/castle-project-devel?hl=en. > > -- You received this message because you are subscribed to the Google Groups "Castle Project Development List" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/castle-project-devel?hl=en.
