views:

465

answers:

3

I'm new to EF4 and haven't had any experience with it before. So, bare with me if this is very simple question. I have my POCO entities (.tt file) in BOL, the .edmx file (EDM) in DAL and my webapp in Presentation layer. All the business logic goes to BLL layer. Here are the references:

UI->BLL-DAL-BOL
BLL->DAL-BOL
DAL->BOL
BOL->None of my project.

1- Is my understanding of layers distinction correct? Am I in the right direction? 2- How can I use ASP.NET Membership provider with entities. Should I implement membership, persistence ignorant too and map all user tables in sql server to entities?

2- How can I add custom validation? I don't mean maxlength or valid email..., I mean something like access levels. For example I want certain users be able to modify a field (say productprice) in my website. Where should I use the User.IsInRole method? the BLL doesn't have any reference to user info. should I pass some parameters to BLL (like "bool CanChangePrice") to clarify access levels?

+1  A: 

1- Your distinction of the layers seem correct to me. I wouldn't reference the DAL in the UI, as in my projects, I prefer that only the middle layer access the DAL. But it's not wrong. So you seem in the right direction.

2- To my knowledge there is no MembershipProvider that works with EF.
So in projects where we used Membership, here is what we did :

  • created the tables with the aspnet_regsql.exe
  • configure the Web.Config to use the SqlMembershiptProvider
  • added in the web.config ANOTHER connection string (one for Membership and one for EF)
  • Built the EDMX file with all tables, including the Membership ones.

In the code, a UserManager / RoleManager (BLL or DAL it depends on your architecture) get the informations using standard Membership methods. And always use the Membership objects, not EF ones. So in fact the user / roles management part is separated from the EF.

We only use the aspnet_* EF entities when there is a link between your custom tables and a Membership table (for instance, when you want to link one of your table with the aspnet_Users table to keep a reference of the user that inserted a data).

3- For the right management, I would use a BLL RightManager that would allow the UI to know if the user can change the field (so you can disable it, or prevent input), and to use this information in your validation method.
In my project I use a Right table and I associate a Right with a Role. In the RightManager provide a RequestRight(Right) method.
If your Right management is too simple to create tables, just use User.IsInRole() in your RightManager (so I would use it in BLL).
I would place the validation method in the UI if it is "basic" and in the BLL if it contains more complex rules (involving DAL access for instance).

Julien N
If you don't reference dal in the UI how can you access the edmx context? is using repository pattern in BLL and access context from there a good idea?
Kamyar
In my architecture, only the DAL should access the context... Every database operation is performed by the DAL. I have some helpers in DAL to perform attach / detach operations (although I agree it's not necessary, but it's just to keep a clean separation between layers).What I do is a ContextManager (a Singleton) that manages the context and exposes a "Context" member. And almost every DAL method start with "var ctx = ContextManager.Instance.Context".I'm not familiar with the repository pattern but it seem like a good idea but why in BLL ? The context is a DAL object, no ?
Julien N
Using repository pattern in BLL allows us to create objects and lists which are returned from DAL. But considering your architecture (Only DAL should have access to context), then the pattern should be implemented in DAL. I have to admit your approach is a clean way to separate layers.
Kamyar
+3  A: 

Wow Kamyar, just a few questions wrapped up in this one;-) I'm not sure if I'll cover all the possible ground, but here goes.

ProjectStructure
- generally your structure of projects is correct, and the references you have are correct. Some may argue that you want to separate your concerns a bit and break some of the references, but personally I find your structure workable.

  • As a practical matter I tend to keep my EDXM and POCOs in the same project. I just have an Entities folder that contains the EDXM and Model.Context.tt, a POCO folder for Model.tt and my Virtual POCO's (below), and a Repository folder for my repository & unit of work.

  • I also create a file called VirtualPOCOs witch is a partial class bound to the POCOs generated by your T4's. My designs tend to be pretty tightly bound to database structure. The VirtualPOCO's give me a little flexibility to deviate from DB design inthose one-off situations. Not to much goes in here, just those few very specific needs every project seems to have.

  • You may also want to consider a repository, table data gateway, or active record setup. All of these patterns will likely combined with a Unit of Work. There are tons of design patterns and your needs or preferences may push you to one or the other. The point here is to shield the upper layers from accessing the EF4 context directly. This way you can centralize connection & transaction management and ensure upper layers are only using POCOs and not accidentally holding on to linq-to-sql objects.

Membership Provider
There is a definitely a schism between the MembershipProvider and EF. You can, however, download the source code for the SQLMembershipProvider and convert it over to use EF. I actually did this conversion. The file is about 1500 lines long, but doesn't have a huge amount of ADO code.

What you didn't ask, but I think I should address, is whether you want to use Membership provider at all. If you're doing basic membership management and roles then the Membership, Roles, and Profile provider can save you a lot of time. For an in depth tour of the capabilities check out the series over at 4GuysFromRolla (http://www.4guysfromrolla.com/articles/120705-1.aspx).

If your needs are more complex then, IMHO, the membership provider breaks down pretty quickly. For example, when a user registers for your site you immediately have to create rows in a handful of different tables. Well, the membership provider is registered through webconfig and uses the membership provider interface. It only accepts certain fields in the create function. So what's a boy to do? Well, you can open a larger scale transaction up in your controller, run the membership providers add user function, run your own MyCustomUserStuff(), then commit the transaction. Two reason I find this unappealing are that I've now got transactional code seeping way up my call stack and if all i need to do is add a few extra fields I've now doubled my database calls needlessly.

I guess I just found the membership provider pretty restricting, and once got in there and made my own custom membership provider the benefits of using MS's model quickly fell away.

Validation
I think the answer here is a resounding --it depends. Are your permissions pretty static? i.e. those in the "SiteManagers" group can edit all over the site? Or are your permissions much more fine grained? Meaning SiteManagers have access to these 75 fields spread across these 22 tables, or is it more table based? Additionally, how mutable are the permissions ? Does your site admin need to be able to frequently turn access on/off or off to various fields in different tables?

I think I need to hear more on your requirements for a specific answer. Keep in mind that the more fine grained you make your permissions the more of a configuration head ache the client will have understanding & managing all the permissions.

Also, what back-end are you using? Many DBA's face these decisions. One often used strategy in that world is to create a series of views where each view exposes the columns users have. For example, the EmployeesHR view would expose just those columns that HR people have access to, and the EmployeeDirectory would expose jsut those fields that the directory has access to. Then HR users are given permission to the HR view, but not the underlying table. Just a thought.

Anyway, hope this helps.

EBarr
it definitely helped a lot. Thanks you.
Kamyar
A: 

about EF & Membership as i know, you dont need to use any db provider instead of membership provider but if you want, you can map membership tables in EF and create additional method to common provider

BenyBlack