New Posts New Posts RSS Feed: multiple controllers
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

multiple controllers

 Post Reply Post Reply
Author
svk View Drop Down
Newbie
Newbie


Joined: 11-Oct-2012
Posts: 7
Post Options Post Options   Quote svk Quote  Post ReplyReply Direct Link To This Post Topic: multiple controllers
    Posted: 11-Oct-2012 at 2:31pm
 
I just started looking at Breeze and I'm wondering if it will work properly in an environment with multiple api controllers - for example, a controller per entity (OrdersController, CustomersController, etc.).  The Breeze documentation does not explicitly recommend against this, but it does seem to suggest the use of a single controller, and the code samples use a single controller.  How does any of this relate to the meta data request and the building of models by Breeze on the client side?  Experimentation would probably answer this for me but I'm hoping for some quick clarification.  Thanks!
 
 
Back to Top
WardBell View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 31-Mar-2009
Location: Emeryville, CA,
Posts: 338
Post Options Post Options   Quote WardBell Quote  Post ReplyReply Direct Link To This Post Posted: 12-Oct-2012 at 2:13pm
I have thought about this too ... although I haven't explored it myself.

First ... I'd like to learn what motivates your question. Do you have a need? Please share.

I know very well that most Web API examples have a controller-per-type; the Web API routing conventions favor that too. So, like you, my first instinct was that Breeze should support that.  I got lathered up about it, actually, and was putting together a case for why we MUST support controller-per-entity.

But I couldn't make that case. In fact, it didn't make much for a Breeze application. Let me explain.

In a non-Breeze Web API controller, you're usually writing 4 or 5 controller methods (2 queries, insert, update, delete) for every type. Four to five methods is sufficient to justify dedicating a class to a type even if you do delegate most of the actual work to helper classes that do the actual data acces. Web API controllers are supposed to be thin

You could argue that the controller-per-type approach "separates concerns". If I have a new type or want to modify an existing controller, I'm won't have to disturb the code for an unrelated type. The price for this purity is a lot of files to manage and coordinate. Many folk happily make that trade-off ... particularly since a given controller for a type is bound to be ... what ... 30 lines of code or more.

In Breeze you generally need only one method per type ... a method returning an IQueryable<T>. That method could fit on a single line but more typically occupies 3 lines. You certainly can have more methods per Breeze type and that makes good sense for high profile types. But not for the 80% of types that typically are small and consumed "as is" by clients. I personally can't see the point of writing and maintaining 200 entity class files each with 3 substantive lines in them. I'm not that kind of a purist.

Aside: if you're really keen on the separation thing, consider putting each type in its own partial class, then and have the compiler combine them into a single Web API controller class. I might even use this 'partial class' approach to aggregate closely related types just so I didn't have one big controller class file for a 200 entity model. With partial class files you'd get your lexical/logical separation of concerns and you could use source control to identify/blame the source of changes on a per-file basis

On the other hand, I do see advantage to breaking up the service into separate controllers, each oriented toward a particular "module" or "workflow". Each handles the service needs of a submodel dedicated to the module/workflow. 

These separate controller/modules can have entity classes in common (e.g., a Customer class in the Order Management and Sales modules). They can have their own DbContexts too if you're using EF.  

This poses no problem for breeze on the client. When you create an EntityManager, you simultaneously target a controller by specifying the route to that controller in the service name.

Personally, in this situation, I'd have a different EntityManager per module/workflow. But an EntityManager can talk to multiple controllers; you change the service name to redirect its attention to another controller. And its cache can hold entities from different services/controllers.

But that's different than dedicating a controller-per-type. With controller-per-type, three challenges come immediately to mind. 

First, I think you'd end up with a metadata method and a save method for each type-focused controller. You could finesse that by dedicating a single controller to providing save and metadata services for all of your entity controllers. But you'd have to play some games on the client to make that work ... and it starts to seem hacky to me.

Second, assuming you wanted one EntityManager to manager several of your types on the client, you'd have to remember to change the EntityManager's service focus before performing a service operation affecting a different type. That would be a bit of a PITA if you were doing that a for every single entity type.

Third, you wouldn't be able to traverse entity graphs across services/controllers. If you had a customer entity in your Customer controller/service  and an order entity in your Order controller/service, you wouldn't be able to write "someCustomer.Orders" because they aren't in the same "service space". I'm sure you could monkey patch the types on the client to make it happen but that would be work ... work you could put into building a great application. You're also introducing more moving parts, more to test, more that can go wrong. Where is the benefit?

There may be other obstacles that I haven't thought of yet. Maybe some namespace issues? I don't know. Nothing is insuperable. 

I DO see value to a controller per module/workflow. In fact, I'd recommend that ... and also recommend that you correspondingly dedicate separate EntityManagers per module/workflow/service ... for while the EntityManager is designed to handle multiple services, I haven't thought of a good reason to do that yet.

But given the impediments to controller-per-type and no advantages that I can see, why go down the controller-per-type road?

Maybe you can school me otherwise. Make a case. If the case is compelling enough, we'll make it happen.

Great question though!
Back to Top
pawel View Drop Down
Newbie
Newbie
Avatar

Joined: 21-Sep-2012
Posts: 12
Post Options Post Options   Quote pawel Quote  Post ReplyReply Direct Link To This Post Posted: 15-Oct-2012 at 2:40am
"On the other hand, I do see advantage to breaking up the service into separate controllers, each oriented toward a particular "module" or "workflow". Each handles the service needs of a submodel dedicated to the module/workflow. "

I absolutely agree with this. We don't use EF on the server and it is absolutely natural to structure things this way. I can't see any advantage of having controller per type! For example "adding new order" doesn't mean adding new Order object - it means a lot more then this (new Order, new OrderItems for the new order, update OrderNumberGenerator, and so on). Breeze's EntityManager fits naturally in this scenario too.

P.S.
Currently we don't use EF the normal way. We model-first the DTOs for each "module" or "workflow" just to have the DTOs (POCO) and EDMX to feed breeze with metadata (we have EdmxToMetadata() function on the server). As bonus we have a diagram for each group of DTOs. We have no ContextProvider<> and no EF's Context on the server (we use another framework for the application business model). 
Each ApiController exposes  IQuerables of our DTO classes and performs SaveChanges() related to single module/workflow.

Back to Top
WardBell View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 31-Mar-2009
Location: Emeryville, CA,
Posts: 338
Post Options Post Options   Quote WardBell Quote  Post ReplyReply Direct Link To This Post Posted: 15-Oct-2012 at 3:14am
Sounds just fine to me. You won't be needing the Breeze.Net EFContextProvider. You may want to look at the source for that component to see how it makes sense of the "JObject saveBundle" coming from the client. We expect to breakout some of the steps into distinct helper methods so it will be easier to craft your own "provider". Until then ... have at the source.

Happy coding!
Back to Top
pawel View Drop Down
Newbie
Newbie
Avatar

Joined: 21-Sep-2012
Posts: 12
Post Options Post Options   Quote pawel Quote  Post ReplyReply Direct Link To This Post Posted: 15-Oct-2012 at 3:34am
I keep Breeze.Build.sln open on my left screen all the time :)
Back to Top
svk View Drop Down
Newbie
Newbie


Joined: 11-Oct-2012
Posts: 7
Post Options Post Options   Quote svk Quote  Post ReplyReply Direct Link To This Post Posted: 15-Oct-2012 at 11:42am
Thanks for the comprehensive reply - it was a big help.  What got me looking at Breeze is our JavaScript/SPA client.  Breeze seems to solve many of the data access challenges such a client faces.  However, our aim is to create a single API that is both private and public - the same API to be consumed by our SPA client and by other applications (primarily native mobile apps).  While Breeze solves problems by simplifying data access for our SPA, using it means that we would likely need to create and maintain a completely separate API and the two would accomplish certain tasks (like creating and saving entities) differently.  
 
So, the original question about a controller per entity was driven by the public API requirement and the preference for a more resource style API (and no, I'm not looking to start a rest/rpc debate! :-)).  Since reading your reply and getting a better understanding of Breeze, I see that it is probably not the best fit for our situation.  That said, if I'm missing something, please let me know - much of this is new to me.
Back to Top
WardBell View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 31-Mar-2009
Location: Emeryville, CA,
Posts: 338
Post Options Post Options   Quote WardBell Quote  Post ReplyReply Direct Link To This Post Posted: 15-Oct-2012 at 5:30pm
Hi @svk. Please help me understand the issues better. I get the public/private distinction. But I must have a different vision of what that means. Most applications in my experience offer different behavior and resources publically than they do privately. Their service APIs tend to diverge accordingly.
I suppose that the native mobile app won't be able to use Breeze. If you can't use Breeze on those clients, you're back to square one for them no matter how you slice it. You might as well write controller per class with all the methods and follow the advice people usually give for that kind of thing. I imagine you'll have all kinds of logic in those controllers to suit the non-Breeze client requests. But more to the point, you have a much more significant development effort ahead of you with regard to client-side data management.
 
Then you turn to your SPA which you think could use Breeze on the client ... and save you much heartache there. Because such a client is going to be an HTML/JavaScript, not a native client, you won't be able to re-use the native client code. That was a given, right?
 
On the server you should be able to use the same data layer and backend. You don't want business logic in your controllers anyway. You want such logic in your model and data layer.
 
What you couldn't re-use is all of the type-specific controllers that target the public mobile platforms. You'd have to create a Breeze-style controller if you wanted to go Breeze for SPA.
 
This is where you lose me. How hard is it to create and maintain that Breeze-style controller? In the simple case (which may be totally adequate) it has exactly one metadata method, exactly one save method, and one query per exposed type.
 
That one query method is usually such boiler plate that you could generated it with T4 or something if you wanted to ... although in this case I'd probably say that copy-and-paste is hard to beat (I can't believe I'm saying that but the effort to do something clever to avoid 100 lines of one-time-only code doesn't seem worthwhile to me as I write this post). If any of the types got complicated (likely), I'd take the easy route and pull these into a partial class.
 
Sure your public and private APIs won't be automatically in sync. But I'm having a heck of a time understanding why they should be. They're different audiences aren't they?
 
I appreciate that you are not fetishizing REST. It that is not your hobby horse, than the only objection I can imagine is that you don't want to maintain a simple Breeze controller in addition to the mess of entity controllers that support your native mobile clients. That's a tax to be sure. But your alternative is what? How are you going to manage data on the SPA? That's going to take a ton of code to write, test and maintain. I must be missing something.
 
Let's put this all to the side. Let me ask YOU a question. What kind of controller do you wish we supported? What would it look like? Can you give me a sketch of it's API? Maybe you have a great idea here! There really isn't anything fundamental in Breeze that requires it to talk to a single controller; we just couldn't think of a good reason to have more. Make the case and we'll adapt.
 
Take me to school :)


Edited by WardBell - 15-Oct-2012 at 5:32pm
Back to Top
svk View Drop Down
Newbie
Newbie


Joined: 11-Oct-2012
Posts: 7
Post Options Post Options   Quote svk Quote  Post ReplyReply Direct Link To This Post Posted: 04-Nov-2012 at 8:08am
@ward... you've made a compelling enough argument that I am getting my hands dirty.  I am, however, running into problems (see my post in the "Entity manager cache not working" thread).  Anyway, I will revisit this topic once better informed.  Thanks for your help!
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down