4

I'm working on a Winforms project with sql server, splitted in several assemblies.

The first assembly Entities contains DTO like :

public class Attribution
{
    public short UserId { get; set; }
    public User User { get; set; }
}
public class User
{
    public short Id { get; set; }
}

The second assembly Repository is accessing Sql Server database.

The third assembly Service is the link between previous.

There are other layers but this is not the point. I need of course DTO's everywhere in the app.

In sql server, Attribution.UserId and User.Id are the same datas, located in 2 separate tables, linked by Ìnner join.

Attribution.UserId must be public because I need access from Repository,Service, etc... But I don't need it in the "logical" part of the app, what I need is Attribution.User.

At this time I have a UserService class in which there is a GetUser() method and I call this method to get the user in my AttributionService.GetAttribution() method.

Is there a way to restrict access to Attribution.UserId property to Service assembly? Or is it a kind of "good practice violation" to query a User DTO in AttributionService class?

Many thanks for your recommandation.

`

Rand Random
  • 7,300
  • 10
  • 40
  • 88
Gadsweb
  • 53
  • 10
  • 1
    `I need of course DTO's everywhere in the app` this is quite a thing. I would recommend this post ;-) https://stackoverflow.com/questions/23648832/viewmodels-in-mvc-mvvm-seperation-of-layers-best-practices I would recommend to sepperate your layers. But; if that hasn't been done from the beginning it's going to be a hard nut to crack. – Stefan Nov 24 '17 at 08:35
  • 2
    In addition to @mjwills's comment; you can make internals visible to friend assemblies: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/assemblies-gac/friend-assemblies – Stefan Nov 24 '17 at 08:41
  • @Stefan. Yes I have 5 layers and DTO's are in a separate assembly, that's why properties must be public. For exemple I need `User` in the comboboxes of the Forms or in controllers... – Gadsweb Nov 24 '17 at 08:51
  • No mjwills, It couldn't be `internal`. Properties must be accessed from `Service` or `Repository` assemblies. – Gadsweb Nov 24 '17 at 08:54
  • Add an interface, which exposes only what you want to expose. Have your existing class implement the interface. When dealing in your existing code, pass around the concrete type. When passing it to the "logical" code pass out the interface instead. – mjwills Nov 24 '17 at 08:55

1 Answers1

4

One option would be to make the set of the property internal and the use the InternalsVisibleTo attribute to grant access to internals to the Repository assembly.

Another less technical and more logical option would be to make the setter private and let the only way for it to be modified be the classes constructor. That way, your repository can get users built, but nobody can modify the ID later.

As a last option you could create an interface that contains only what the non-repository classes should have access to and pass this around. I'm not a big fan because that means you have to cast it back to your concrete class in the repository and that basically means your repository is lying (saying it accepts an ISomething, but then throwing if the ISomething is not the exact, concrete Something it expects).

nvoigt
  • 75,013
  • 26
  • 93
  • 142
  • I thought at the last one but for me an interface for a DTO will increase complexity for this type of use. – Gadsweb Nov 24 '17 at 09:07
  • I'm not sure to understand the second one. I get with the repository the Attribution DTO and the UserId which is a part of this DTO. I don't know this UserId when I construct an Attribution. But maybe I'm wrong. I have tried the 1st solution and It seems to be easy to implement and do the trick. Many thanks for your help. – Gadsweb Nov 24 '17 at 09:14